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
Collaborator

S2 contract 1 of 9 (webui-audit, T10 targeted-update ruling). One new file: docs/requirements/hierarchy-schema.md.

Turns PRD D2/D9/D13 (Part I §4) and native-kanban SOT Amendment A1 (§8) into the concrete schema contract for the tenancy/authorization structure record class:

  • companies → estates → platform_projects → workspaces, NOT NULL RESTRICT parent FKs — exactly-one chain by construction, no edge tables, no detached states
  • platform_projects named to avoid the ratified collision with the workspace-internal projects planning table (A1 §8.1.4)
  • hierarchy_grants attachment shape (exactly-one-of subject and target, CHECK-enforced); role vocabulary and evaluation deferred to contract 2
  • transfer = single audited parent-FK update, both-sides authority, zero business-row mutation (A1 chain maintenance)
  • no owner columns: ownership is the grant structure (embedded ruling for Jason)
  • Gateway-only mutation path, semantic audit, fail-closed bottom-up deletion
  • verification matrix incl. real-Postgres constraint witnesses (ci-postgres service in the test step)

Independent review (gate 16) to follow before merge. No self-merge without review.

S2 contract 1 of 9 (webui-audit, T10 targeted-update ruling). One new file: docs/requirements/hierarchy-schema.md. Turns PRD D2/D9/D13 (Part I §4) and native-kanban SOT Amendment A1 (§8) into the concrete schema contract for the tenancy/authorization structure record class: - companies → estates → platform_projects → workspaces, NOT NULL RESTRICT parent FKs — exactly-one chain by construction, no edge tables, no detached states - platform_projects named to avoid the ratified collision with the workspace-internal projects planning table (A1 §8.1.4) - hierarchy_grants attachment shape (exactly-one-of subject and target, CHECK-enforced); role vocabulary and evaluation deferred to contract 2 - transfer = single audited parent-FK update, both-sides authority, zero business-row mutation (A1 chain maintenance) - no owner columns: ownership is the grant structure (embedded ruling for Jason) - Gateway-only mutation path, semantic audit, fail-closed bottom-up deletion - verification matrix incl. real-Postgres constraint witnesses (ci-postgres service in the test step) Independent review (gate 16) to follow before merge. No self-merge without review.
fred added 1 commit 2026-08-26 23:10:58 +00:00
docs: hierarchy schema contract (S2 contract 1, D2)
ci/woodpecker/pr/ci Pipeline was canceled
7ef620cda7
Turns PRD D2/D13 and kanban-SOT Amendment A1 into a concrete schema
contract: companies/estates/platform_projects/workspaces with NOT NULL
RESTRICT parent chains (chain uniqueness by construction), per-parent slug
scoping, hierarchy_grants attachment shape (vocabulary deferred to
contract 2), transfer as single audited parent-FK update requiring
both-sides authority, no owner columns (ownership = grants), fail-closed
bottom-up deletion, Gateway-only mutation path, and a verification matrix
with real-Postgres constraint witnesses.
fred added 1 commit 2026-08-26 23:29:56 +00:00
- tenancy-FK exemption: canonical workspace_id is the one permitted
  business->class reference; all other forms forbidden with control test
- record class = 4 node tables + hierarchy_grants per A1 8.1.2
- grant uniqueness via UNIQUE NULLS NOT DISTINCT (or 6 partial indexes);
  NOT NULL on role/granted_by/name/slug
- grant FK delete actions split: target cascade, principal RESTRICT
- audit parity: REQ-AUD-001 guarantees, same-transaction outbox,
  deletion-safe snapshot linkage, cascade coverage, rollback witness
- roll-up never-a-write restored to full A1 strength (no canonical writes)
- ownership invariant completed via contract 2; both-sides transfer rule
  marked new policy; legacy premise corrected
- corrected cardinality witness (one-parent-per-child + sibling control)
- provenance fixes: REQ-MIG-001 attribution dropped, projects table
  described accurately, D8-rank-1 claim removed
fred added 1 commit 2026-08-26 23:43:04 +00:00
fred added 1 commit 2026-08-26 23:48:16 +00:00
fred added 1 commit 2026-08-26 23:55:18 +00:00
fred added 1 commit 2026-08-27 00:02:13 +00:00
fred added 1 commit 2026-08-27 00:09:03 +00:00
fred added 1 commit 2026-08-27 00:18:14 +00:00
fred added 1 commit 2026-08-27 00:31:13 +00:00
The 'one live importer' claim was false: the measured production importer
set of the db migration runner has four members (Gateway database module
via the barrel, storage Postgres adapter, fleet-backlog and gateway-verify
CLI commands via literal dynamic import). The enumeration example now
names all four, the import analysis resolves literal dynamic import()
routes, and a non-literal dynamic import of the db package fails the
assertion. Injection-only consumers (schema-check) have no import edge.
rev-code-01 approved these changes 2026-08-27 00:43:46 +00:00
rev-code-01 left a comment
Member

APPROVED — rev-code-01, pinned to head e3b0375211d7e09d2dff03b83c31ae56f57e29fc (re-verified unmoved immediately before posting).

Scope: doc-only, single file docs/requirements/hierarchy-schema.md (+380 lines vs merge-base 49b79434, nine revisions). This contract is the anchor the rest of the S2 set cites; verified independently of the terra r1-r9 chain, with my own measurement of every load-bearing claim:

  1. Rev-9 importer enumeration (the r9 delta) re-measured by me. My own migration-symbol sweep (runMigrations|runPgliteMigrations|getMigrationStatus|readJournalTags|applyMigrationsByHash over production sources, tests excluded) finds exactly the four named members: apps/gateway/src/database/database.module.ts (barrel static), packages/storage/src/adapters/postgres.ts (barrel static), packages/mosaic/src/commands/fleet-backlog.ts (literal dynamic await import('@mosaicstack/db'), destructuring both migration runners), packages/mosaic/src/commands/gateway/verify.ts (literal dynamic import at :101). Exhaustiveness control: the wider @mosaicstack/db importer list minus symbol users leaves only schema-symbol consumers and string mentions. schema-check.ts is injection-only as claimed (SchemaCheckDeps interface, its only @mosaicstack/db hits are remediation-message strings). No nonliteral dynamic import of the db package exists in code (only .md docs). The four-member claim is exact.
  2. A1 citations verbatim: §8.1.2 record class (tenancy/authorization structure records incl. hierarchy-level access grants; §3 invariant 10 and REQ-TEN-001 not applying to the class), §8.1.4 naming (platform-project vs the workspace-internal planning projects; MUST NOT merge), §8.2.2/§8.2.3/§8.3 acceptance rows — all match native-kanban-sot.md lines 388-458. REQ-AUD-001 (line 193) and REQ-API-001 (line 206) exist as cited.
  3. Codebase facts: planning projects table carries no workspace_id and sits under the ─── Brain ─── section comment ("so labeled" accurate); legacy teams.owner_id/manager_id + team_members.role exist exactly as §4.4 disparages (schema.ts:127-151); none of the five contract tables exist today (0 hits — clean implementation slate); pinned drizzle-orm 0.45.1 exposes nullsNotDistinct() (unique-constraint.d.ts:10), so §3.2's mechanism is real.
  4. The §6.3(b) writer-coverage apparatus is internally coherent across its nine-revision history: three prongs + composition rules (no generic raw-SQL helper allowlisted; allowlisted modules may not export caller-supplied-SQL execution), infrastructure register exempt from prong (iii) only, re-export-aware + literal-dynamic-import-resolving analysis, nonliteral db dynamic import failing outright, runtime code-construction primitives failing outright, and the honest detection-scope statement (static prongs exactly; beyond-syntax evasions owned by §5.1 review/audit — not claimed for CI). The rev-8→9 fix (one-live-importer → four-member measured set) is the kind of measured-not-asserted completeness the register itself demands.
  5. Cross-contract consistency with contract 2 (my review id 324) re-confirmed at this head: §3.1 grant shape + role-vocabulary ownership, §4.2 both-sides new-policy flag, §4.4 initial-owner naming, §6.5 transfer tests citing back — no contradictions.

Gates run by me in a fresh worktree at this head: format:check rc=0 (pinned prettier; rev-8 file also clean — no style delta in rev 9); typecheck rc=0 (45/45); lint rc=0 (25/25). (Docs-only PR; web-deps build not needed for typecheck here, but typecheck ran the full 45-task matrix.)

Non-blocking notes:

  • [S1] §6.3(b) is now a ~700-word single paragraph inside one bullet; the writer-allowlist / infrastructure-register / importer-enumeration triple would be easier to implement-and-audit split into lettered sub-items in a future editorial pass. No semantic change requested.

CI note: 2838 running on this head at review time (as fred noted; prior #1435 pipelines all killed/canceled under queue load). Merge waits on 2838 terminal green. First in the S2 merge order — landing it unblocks the #1436/#1438/#1439 refs their contracts already cite.

**APPROVED — rev-code-01, pinned to head `e3b0375211d7e09d2dff03b83c31ae56f57e29fc`** (re-verified unmoved immediately before posting). Scope: doc-only, single file `docs/requirements/hierarchy-schema.md` (+380 lines vs merge-base 49b79434, nine revisions). This contract is the anchor the rest of the S2 set cites; verified independently of the terra r1-r9 chain, with my own measurement of every load-bearing claim: 1. **Rev-9 importer enumeration (the r9 delta) re-measured by me.** My own migration-symbol sweep (`runMigrations|runPgliteMigrations|getMigrationStatus|readJournalTags|applyMigrationsByHash` over production sources, tests excluded) finds exactly the four named members: `apps/gateway/src/database/database.module.ts` (barrel static), `packages/storage/src/adapters/postgres.ts` (barrel static), `packages/mosaic/src/commands/fleet-backlog.ts` (literal dynamic `await import('@mosaicstack/db')`, destructuring both migration runners), `packages/mosaic/src/commands/gateway/verify.ts` (literal dynamic import at :101). Exhaustiveness control: the wider `@mosaicstack/db` importer list minus symbol users leaves only schema-symbol consumers and string mentions. schema-check.ts is injection-only as claimed (`SchemaCheckDeps` interface, its only `@mosaicstack/db` hits are remediation-message strings). No nonliteral dynamic import of the db package exists in code (only .md docs). The four-member claim is exact. 2. **A1 citations verbatim:** §8.1.2 record class (tenancy/authorization structure records incl. hierarchy-level access grants; §3 invariant 10 and REQ-TEN-001 not applying to the class), §8.1.4 naming (platform-project vs the workspace-internal planning `projects`; MUST NOT merge), §8.2.2/§8.2.3/§8.3 acceptance rows — all match `native-kanban-sot.md` lines 388-458. REQ-AUD-001 (line 193) and REQ-API-001 (line 206) exist as cited. 3. **Codebase facts:** planning `projects` table carries no `workspace_id` and sits under the `─── Brain ───` section comment ("so labeled" accurate); legacy `teams.owner_id`/`manager_id` + `team_members.role` exist exactly as §4.4 disparages (schema.ts:127-151); none of the five contract tables exist today (0 hits — clean implementation slate); pinned drizzle-orm 0.45.1 exposes `nullsNotDistinct()` (unique-constraint.d.ts:10), so §3.2's mechanism is real. 4. **The §6.3(b) writer-coverage apparatus is internally coherent** across its nine-revision history: three prongs + composition rules (no generic raw-SQL helper allowlisted; allowlisted modules may not export caller-supplied-SQL execution), infrastructure register exempt from prong (iii) only, re-export-aware + literal-dynamic-import-resolving analysis, nonliteral db dynamic import failing outright, runtime code-construction primitives failing outright, and the honest detection-scope statement (static prongs exactly; beyond-syntax evasions owned by §5.1 review/audit — not claimed for CI). The rev-8→9 fix (one-live-importer → four-member measured set) is the kind of measured-not-asserted completeness the register itself demands. 5. **Cross-contract consistency** with contract 2 (my review id 324) re-confirmed at this head: §3.1 grant shape + role-vocabulary ownership, §4.2 both-sides new-policy flag, §4.4 initial-owner naming, §6.5 transfer tests citing back — no contradictions. Gates run by me in a fresh worktree at this head: `format:check` rc=0 (pinned prettier; rev-8 file also clean — no style delta in rev 9); `typecheck` rc=0 (45/45); `lint` rc=0 (25/25). (Docs-only PR; web-deps build not needed for typecheck here, but typecheck ran the full 45-task matrix.) Non-blocking notes: - [S1] §6.3(b) is now a ~700-word single paragraph inside one bullet; the writer-allowlist / infrastructure-register / importer-enumeration triple would be easier to implement-and-audit split into lettered sub-items in a future editorial pass. No semantic change requested. CI note: 2838 running on this head at review time (as fred noted; prior #1435 pipelines all killed/canceled under queue load). Merge waits on 2838 terminal green. First in the S2 merge order — landing it unblocks the #1436/#1438/#1439 refs their contracts already cite.
fred merged commit 07624140e4 into next 2026-08-27 16:39:16 +00:00
Sign in to join this conversation.