The edge.* family (2 verbs). Every verb enters through the one front door: it is capability-checked, permission-checked, scope-checked and audited before it runs (see Security & permissions). Each entry below lists its capability, risk class (which fixes the minimum autonomy level), the minimum caller permission, its availability tier, whether it is idempotent, and any outbound egress.
Attachedge.attach
| Property | Value |
|---|---|
| Capability | matter.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Core - always on (MCP tier 1) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
The ONE
verb-minted write path for ANY primitive<->primitive association: a TYPED, directed entity_edge row,
polymorphic endpoints by entity_node_type (migration 0026). GENERALISES the former matter.attach
(CC-OPBOX 34 B2): the destination may be ANY attachable node type (not just MATTER), and the edge may
carry an additive weight (migration 0091, DEC-19). matter.attach is RETAINED as a thin alias of
this verb (dst forced MATTER) for caller compatibility.
RATIO (CC-OPBOX 34): entity_edge is a REGENERABLE DERIVED INDEX (INV-2). This verb is the canonical
relationship verb that mints a VERB-minted edge (source_column_id NULL); the LINK-column-derived edges
are NOT minted here (they are an in-tx continuation of the LINK-write/column.add verb via
regen_link_edges, covered by THAT verb’s single append_event). There is NO standalone edge CRUD beyond
this attach/detach pair (R1) and NO bearerless side effect (R2): the write is inside the kernel tx,
RLS-bound + atomic + audited (C2/C5).
HONOURS SENSITIVITY AT THE VERB (INV-11, BOTH endpoints): the caller MUST be able to READ both the src
and the dst, or the verb mints the not-found-equivalent deny (anti-enumeration). A governed confidential
node (MATTER/DOCUMENT/FILE_RECORD) goes through assert_can_read; a non-confidential node (PARTY /
TABLE_ROW) is existence-checked in THIS workspace (RLS already scopes it).
IDEMPOTENT on the C9 dedup tuple (uq_entity_edge_dedup) with source_column_id IS NULL: re-attaching
the same (src, dst, kind) edge is a no-op-shaped success (ON CONFLICT DO NOTHING, read back the
existing id) - never a duplicate edge. AUDIT (CC-OPBOX 34 B4 / R3): the SINGLE event of record is this
verb’s dispatch-level append_event (registry.rs audits one event per verb keyed on the OUTPUT), so the
OUTPUT names the minted edge endpoints + edge_kind + source_column_id - NO second append_event (R3: the
derived index carries none; no double-audit). data_plane.rs added no in-file append_event before, but
every verb WAS dispatch-audited; the gap closed is the PAYLOAD richness, not an unaudited write.
Input { srcType, srcId, dstType, dstId, edgeKind?, metadata?, weight? } (fields ending in ? are optional)
Call POST /v/edge.attach with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool edge.attach.
Detachedge.detach
| Property | Value |
|---|---|
| Capability | matter.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Core - always on (MCP tier 1) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
The twin of edge.attach: DELETEs the
VERB-minted edge on the C9 dedup tuple WHERE source_column_id IS NULL (so it NEVER retires a
LINK-column-derived edge - those are owned by regen_link_edges + the source_column_id ON DELETE
CASCADE, CC-OPBOX 34 B3). IDEMPOTENT: detaching an absent edge is a no-op-shaped success (deleted=false).
AUDIT (CC-OPBOX 34 B4 / R3): the dispatch-level append_event audits this verb’s OUTPUT, which names the
RETIRED edge endpoints + edge_kind + source_column_id - the single event of record, no second append.
INV-11: the caller must be able to READ both endpoints (the same fence edge.attach applies), so a detach
cannot probe a restricted node’s existence. RLS-scoped + the explicit workspace predicate.
Input { srcType, srcId, dstType, dstId, edgeKind? } (fields ending in ? are optional)
Call POST /v/edge.detach with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool edge.detach.