diff --git a/docs/requirements/hierarchy-schema.md b/docs/requirements/hierarchy-schema.md index 389fda16..b7af38d0 100644 --- a/docs/requirements/hierarchy-schema.md +++ b/docs/requirements/hierarchy-schema.md @@ -84,7 +84,10 @@ definition is a follow-up amendment to contract 2 — until it ratifies, admin-only); §6.1 and §6.9 add the witnesses; §6.7's existence-oracle rule is scoped around the ratified directory carve-out. Top-level creation (contract 3 §5.2) is unchanged and always yields a private -company. +company. Upstream, SOT Amendment A2 (native-kanban-sot.md §9, this PR) +expressly extends A1 §8.1.2 to admit the visibility column and A1 +§8.1.3 to admit the directory function — this contract relies on that +amendment, not on a reinterpretation of A1. Scope: the tenancy/authorization structure record class — companies, estates, platform-projects, workspaces, hierarchy grants, their parentage, @@ -102,12 +105,11 @@ legacy flat data (future work; see §1.3). (payload prohibition, mutation path, audit) binds all five tables. Class rows carry parentage, naming, grant, audit-linkage, and visibility-class data only — never task, plan, or any business/orchestration payload. - Visibility (`companies.visibility`, §2.8) is ratified by Amendment 1 as - authorization/disclosure data: it controls what the class discloses - about its own nodes, which sits inside A1 §8.1.2's - tenancy/authorization purpose for the class — it is not a payload - field, carries no business content, and widens the payload prohibition - for nothing else. + Visibility (`companies.visibility`, §2.8) is admitted into that + enumeration by SOT Amendment A2 §9.1.1, which expressly extends A1 + §8.1.2 for exactly this one column: it is disclosure data about the + class's own nodes — not a payload field, carries no business content, + and widens the payload prohibition for nothing else. References from business/orchestration rows into the class are limited to exactly one form: the canonical `workspace_id` tenancy column that REQ-TEN-001 requires on every canonical row, referencing @@ -168,8 +170,8 @@ decision under A1; this contract pins only that they stay distinct tables.) one of two classes, carried by `visibility`: - `private` (the default): the company is disclosed only to subjects holding a grant on it or on a descendant — the resting state every - company is created in. Ruling 4 §5.2 open creation survives - unchanged: it creates private companies. + company is created in. Open creation under contract 3 §5.2 + (Ruling 4) survives unchanged: it creates private companies. - `directory`: the company is listed in the deployment-wide company directory. Directory listing discloses **existence, name, and slug to every authenticated user — nothing else**: no subtree structure, @@ -415,8 +417,12 @@ Binding on the implementing PRs (extends A1 §8.3): 4. Audit witnesses: for each mutation class (create, rename, transfer, visibility change, grant create/change/revoke, delete) — the event exists after commit - with actor/verb/target and same-transaction atomicity; a rolled-back - mutation leaves no event (rollback witness); a node delete's cascaded + with actor/verb/target and same-transaction atomicity, and the + event's outbox record exists after the same commit — state row, + audit event, and outbox record are witnessed as one transaction + (REQ-AUD-001); a rolled-back + mutation leaves no event and no outbox record (rollback witness); a + node delete's cascaded grant deletions are each covered by events; events survive deletion of their target (query the events of a deleted node). 5. Transfer tests: parent-FK update moves the subtree resolution and @@ -436,7 +442,8 @@ Binding on the implementing PRs (extends A1 §8.3): endpoints mutate no canonical state anywhere (assert zero writes across hierarchy AND workspace tables, not hierarchy only); readers see aggregates only over workspaces they are authorized on, with no - cross-tenant existence oracles (A1 §8.3 acceptance 3) beyond the one + cross-tenant existence oracles (A1 §8.3 acceptance 3, as narrowed by + A2 §9.1.2) beyond the one ratified carve-out — the §2.8 company directory, witnessed in §6.9. 8. Real-PostgreSQL coverage for every constraint witness (unique/CHECK/ RESTRICT/NULLS NOT DISTINCT behavior), using the `ci-postgres` service @@ -454,8 +461,9 @@ Binding on the implementing PRs (extends A1 §8.3): yields `visibility = 'private'` and accepts no visibility argument; each visibility change emits its §5.2 audit event carrying old and new values — the full audit pattern for the mutation class - (same-transaction atomicity, rollback leaving no event, - actor/verb/target, outbox delivery) is §6.4's, which enumerates + (same-transaction atomicity of state row, audit event, and outbox + record; rollback leaving no event and no outbox record; + actor/verb/target) is §6.4's, which enumerates visibility change; this item adds only the old/new-value payload assertion. diff --git a/docs/requirements/native-kanban-sot.md b/docs/requirements/native-kanban-sot.md index 9ba524fe..63738e4d 100644 --- a/docs/requirements/native-kanban-sot.md +++ b/docs/requirements/native-kanban-sot.md @@ -456,3 +456,54 @@ this line is weakened. - Negative tests prove roll-up endpoints cannot mutate state and that a reader sees aggregates only over workspaces they are authorized on (no cross-tenant existence oracles). + +## 9. Amendment A2 — company visibility classes and the company directory + +**Status:** amendment to Amendment A1, added by reviewed PR under Ruling 4b +(operator ruling, 2026-08-27; decision owner Jason; recorded in the webui-audit +lane RULINGS.md). Everything in §§1–8 remains binding verbatim, with exactly +the two express modifications below. Nothing else is weakened. The detailed +contract text lives in the hierarchy schema contract +(`hierarchy-schema.md` §2.8, §5.5, §6.9); this amendment changes only what A1 +itself permits, so that contract does not stretch A1 by interpretation. + +### 9.1 What A2 modifies in A1 + +1. **Class data (extends §8.1.2's first constraint).** The tenancy/authorization + structure record class additionally carries **visibility-class data**: the + single column `companies.visibility`, values `private` | `directory` + (hierarchy schema §2.8). Visibility is disclosure data about the class's own + nodes — what a company row reveals about its own existence — and is part of + the class's tenancy/authorization purpose. It is not business or + orchestration payload. §8.1.2's payload prohibition is widened for nothing + else: hierarchy tables still MUST NOT carry task, plan, or any other + business/orchestration payload, and this amendment admits exactly this one + column. +2. **The company directory (extends §8.1.3's function enumeration).** The + hierarchy serves one additional, express, narrow runtime function: the + **company directory** — a read-only disclosure listing of exactly the + companies whose `visibility = 'directory'`, revealing existence, name, and + slug to every authenticated user of the deployment and nothing else. It + mutates nothing, confers no authority, evaluates no grant down the chain, + and aggregates nothing (it is not a roll-up). §8.3's + no-cross-tenant-existence-oracle acceptance is narrowed by exactly this one + ratified carve-out: the directory is the sole permitted existence + disclosure, and it discloses only directory-class companies (witnessed in + hierarchy schema §6.7 and §6.9). Private companies remain undisclosed to + non-granted subjects everywhere, including the directory. + +### 9.2 What A2 explicitly does not change + +1. Content access stays grant-only under the RBAC grant model contract: + directory listing discloses existence, never content, membership, or any + authority (Ruling 3 unchanged; hierarchy schema §2.8). +2. Visibility changes are hierarchy mutations on the existing §8.2.3 audited + mutation path — audited maintenance of the class's own structure in + §8.1.3's sense, not a further runtime function. Authorization for them is + defined in hierarchy schema §5.5 (platform admins plus the future + company-CRUD capability; owner-as-such cannot publish). +3. Company creation is unchanged and always yields `visibility = 'private'` + (onboarding wizard §5.2); this amendment adds no creation path and no + default-open disclosure. +4. Every other constraint of A1 — §8.1.2's remaining bullets, §8.2 in full, + and §8.3's other acceptance criteria — is untouched.