docs: hierarchy schema contract (S2 contract 1, D2) #1435

Merged
fred merged 9 commits from contract/hierarchy-schema into next 2026-08-27 16:39:16 +00:00
Showing only changes of commit f5e3165ea5 - Show all commits
+27 -6
View File
@@ -20,6 +20,16 @@ guarantees with deletion-safe linkage (§5.2); roll-up never-a-write restored
to full A1 strength (§5.4); §6 rebuilt with bounded observables for every
MUST (allowlist, command surface, audit, corrected cardinality witness).
Revision 3 (terra re-review residuals): §4.3 transfer write inventory
reconciled with §5.2 — the transaction's writes are the single class-row
mutation plus that mutation's §5.2 audit writes (event + outbox record),
not "exactly two writes"; §6.3 extended with a closed writer-coverage
witness so an unregistered internal writer cannot pass a registered-route
inventory. (Terra's finding-8 residual — a stale contract 2 §7.8 backlink
to contract 1 §6.2 — was already fixed in contract 2 revision 2, which
cites §6.5; measured against `origin/contract/rbac-grants` head
`501112d2`.)
Scope: the tenancy/authorization structure record class — companies,
estates, platform-projects, workspaces, hierarchy grants, their parentage,
and constraints. Out of scope: the RBAC grant vocabulary and evaluation
@@ -143,8 +153,11 @@ shape contract 2 attaches to:
introduced by this contract pair** (D2/A1 do not state it); its
evaluation semantics are contract 2 §5. The structural half — that the
transfer command evaluates it before mutating — binds here.
3. A transfer transaction contains exactly two writes: the single-row
parent-FK update and its audit event (§5.2). There are no multi-row
3. A transfer transaction mutates exactly one class-table row — the
single-row parent-FK update and contains, beyond that, only the
§5.2 audit writes for that mutation (the audit event and its
hierarchy-outbox record, committing in the same transaction). No other
class, business, or orchestration row changes. There are no multi-row
transfer batches at the schema level; bulk moves are N audited
transfers.
4. Hierarchy records have no `owner_id`. Ownership in the hierarchy IS the
@@ -213,10 +226,18 @@ Binding on the implementing PRs (extends A1 §8.3):
2. Column allowlist: an information_schema assertion that each class
table's column set is exactly the set declared in §2/§3 — the bounded
observable for no-payload (§2.7) and no-`owner_id` (§4.4).
3. Command surface: an inventory assertion over the Gateway's registered
hierarchy routes/commands proving the mutation surface is exactly the
declared hierarchy command family — no generic CRUD endpoint and no
non-command write path touches class tables (§5.1).
3. Command surface: two witnesses, both required (§5.1). (a) Route
inventory: an assertion over the Gateway's registered hierarchy
routes/commands proving the registered mutation surface is exactly the
declared hierarchy command family — no generic CRUD endpoint. (b)
Writer coverage — the closed allowlist a route inventory cannot
provide: a static CI assertion over the Gateway and package sources
that write references to the class-table schema symbols (insert,
update, delete) occur only in an explicitly enumerated allowlist of
hierarchy command/repository modules. The allowlist is closed: a new
writer anywhere else fails the assertion until the allowlist is
extended in the same PR, so an unregistered internal or raw-SQL write
path is surfaced in CI and review rather than passing unnoticed.
4. Audit witnesses: for each mutation class (create, rename, transfer,
grant create/change/revoke, delete) — the event exists after commit
with actor/verb/target and same-transaction atomicity; a rolled-back