docs: contract 2 Amendment 1 — company-CRUD capability (S2 follow-up) #1477
@@ -28,10 +28,13 @@ Amendment 1 (company-CRUD capability): defines the capability class that
|
||||
contract 1 Amendment 1 (Ruling 4b, 2026-08-28) and hierarchy schema §5.5
|
||||
anticipate. §8 defines the capability as a platform-scoped, admin-assigned,
|
||||
audited delegation of exactly the hierarchy schema §5.5 company visibility
|
||||
command — no read surface, no other company operation. The hierarchy role
|
||||
command — no read command, no other company operation; the mutation's
|
||||
inherent existence disclosure is ratified as a bounded carve-out to
|
||||
hierarchy schema §6.7/§2.8 (§8.1). The hierarchy role
|
||||
vocabulary (§2), every evaluation rule (§3), and grant management (§4) are
|
||||
untouched: the capability is not a `hierarchy_grants.role` value and
|
||||
evaluates outside the chain. Until this amendment ratifies, the capability
|
||||
evaluates outside the chain; capability-row deletion joins §6.1's
|
||||
revocation enumeration (§8.4). Until this amendment ratifies, the capability
|
||||
class is empty and
|
||||
the visibility command remains admin-only (hierarchy schema §5.5 states
|
||||
this fallback; the shipped gate at
|
||||
@@ -269,32 +272,66 @@ companies remain hierarchy `owner` operations (§2.3, §5); none of those is
|
||||
part of this capability, and widening it to any other operation is a
|
||||
further amendment, not an implementation decision.
|
||||
|
||||
1. **Content: exactly one command, no read surface.** Holding the
|
||||
capability authorizes executing the hierarchy schema §5.5 visibility
|
||||
command (`companies.visibility`, both directions:
|
||||
1. **Content: exactly one command, no read command, disclosure stated.**
|
||||
Holding the capability authorizes executing the hierarchy schema §5.5
|
||||
visibility command (`companies.visibility`, both directions:
|
||||
`private → directory` and `directory → private`) on any company in the
|
||||
deployment. It authorizes nothing else — and in particular it carries
|
||||
**no read surface**: no company enumeration, no structure read, no
|
||||
existence probe beyond what every authenticated user already has (the
|
||||
§2.8 directory listing). The practical flow this implies is
|
||||
deliberate: to publish a private company, the holder is given the
|
||||
target identifier by the requesting company `owner` out of band; to
|
||||
unpublish, the target is already directory-listed. A curation listing
|
||||
for capability holders, if ever wanted, is a further amendment with its
|
||||
own disclosure analysis under hierarchy schema §6.7.
|
||||
deployment, and no other command of any family. It confers **no read
|
||||
command**: no company enumeration, no curation listing, no structure
|
||||
read. The practical flow this implies is deliberate: to publish a
|
||||
private company, the holder is given the target identifier by the
|
||||
requesting company `owner` out of band; to unpublish, the target is
|
||||
already directory-listed. A curation listing for capability holders,
|
||||
if ever wanted, is a further amendment with its own disclosure
|
||||
analysis under hierarchy schema §6.7.
|
||||
|
||||
**Existence disclosure carve-out, stated rather than pretended away:**
|
||||
exercising a mutation inherently discloses its target's existence.
|
||||
The command's result distinguishes an existing company (success, for
|
||||
private and directory targets alike) from a nonexistent id
|
||||
(`not_found`), so a holder presenting candidate ids learns existence —
|
||||
exactly as a platform admin already does through the same command.
|
||||
This amendment ratifies that disclosure as part of the §5.5 curation
|
||||
authority, bounded as follows: the mutation result and its audit event
|
||||
disclose to the holder the target's existence and its old/new
|
||||
visibility values, and **nothing else** — no name, slug, structure,
|
||||
content, grant, or membership information. A successful publish
|
||||
additionally makes the target directory-listed to every authenticated
|
||||
user; that is the command's ratified purpose (hierarchy schema §5.5),
|
||||
not a leak. Hierarchy schema §6.7's existence-oracle rule and §2.8's
|
||||
directory-only disclosure are amended by exactly this carve-out for
|
||||
capability holders and are otherwise untouched. Witnessed in §8.6.3.
|
||||
|
||||
2. **Holding: platform-scoped assignment, user subjects only.** The
|
||||
capability is not a hierarchy grant: it attaches to no node, has no
|
||||
role, and never enters §3 chain evaluation. It is held via a
|
||||
`platform_capabilities` table: `id`, `user_id` (FK `users`, NOT NULL),
|
||||
`capability` (text, NOT NULL, constraint-checked against exactly
|
||||
`company_crud`), `granted_by` (FK `users`, NOT NULL), `created_at`;
|
||||
UNIQUE (`user_id`, `capability`). No team subjects (§1.4's suspension
|
||||
reasoning applies with more force here — a workspace-bound team holding
|
||||
deployment-wide curation authority has no ratified meaning), no expiry
|
||||
column: revocation is row deletion, as everywhere in this contract.
|
||||
3. **Assignment is instance administration.** Only platform admins
|
||||
(`users.role = 'admin'`) may assign or revoke the capability —
|
||||
assignment delegates a slice of instance administration and is itself
|
||||
`platform_capabilities` table whose column set is exactly (nothing
|
||||
else, per the contract 1 §2.7 exhaustiveness discipline):
|
||||
- `id` — uuid, primary key;
|
||||
- `user_id` — uuid, NOT NULL, FK `users` **ON DELETE RESTRICT**;
|
||||
- `capability` — text, NOT NULL, constraint-checked against exactly
|
||||
`company_crud`;
|
||||
- `granted_by` — uuid, NOT NULL, FK `users` **ON DELETE RESTRICT**;
|
||||
- `created_at` — timestamptz, NOT NULL;
|
||||
- UNIQUE (`user_id`, `capability`).
|
||||
|
||||
Both user FKs are RESTRICT for the same reason contract 1 §3.3 pins
|
||||
RESTRICT on principal FKs: the identity contract (§7.3) gates user
|
||||
deletion, and a cascade here could silently destroy a capability
|
||||
without its §8.3 revocation audit event. Revocation is row deletion
|
||||
through the §8.3 command — there is no other removal path, no expiry
|
||||
column, and no tombstone. A deactivated holder confers nothing while
|
||||
deactivated: identity contract §7.1 denies all authorization to
|
||||
deactivated accounts, and the §8.4 predicate evaluates on the
|
||||
authenticated live user. No team subjects (§1.4's suspension reasoning
|
||||
applies with more force here — a workspace-bound team holding
|
||||
deployment-wide curation authority has no ratified meaning).
|
||||
|
||||
3. **Assignment is instance administration on the normal admin surface.**
|
||||
Only platform admins (`users.role = 'admin'`) may assign or revoke the
|
||||
capability, through an ordinary admin command (the same command class
|
||||
`AdminGuard` governs, §1.1) — not through direct table writes.
|
||||
Assignment delegates a slice of instance administration and is itself
|
||||
an instance-administration act under §1.1. A capability holder as such
|
||||
may NOT assign or revoke it (no self-propagation). Every assignment
|
||||
and revocation is a semantic audit event carrying actor, verb, subject
|
||||
@@ -302,11 +339,19 @@ further amendment, not an implementation decision.
|
||||
§4.5 (`platform-capability:company-crud` — a bare `company_crud` in
|
||||
any serialized artifact is non-conformant).
|
||||
4. **Evaluation and revocation follow this contract's existing rules.**
|
||||
The hierarchy schema §5.5 command's authorization predicate is: `users.role = 'admin'`
|
||||
OR a live `platform_capabilities` row (`user_id`, `company_crud`) —
|
||||
evaluated live and fail-closed per §3.5 (unreadable capability state
|
||||
denies). Revocation propagates per §6: the next authorization decision
|
||||
on any transport decides against the deleted row, within §6.2's bound.
|
||||
The hierarchy schema §5.5 command's authorization predicate is:
|
||||
`users.role = 'admin'` OR a live `platform_capabilities` row
|
||||
(`user_id`, `company_crud`). Both disjuncts are evaluated live and
|
||||
fail closed per §3.5 — **independently**: with capability state
|
||||
unreadable (fault), the capability disjunct denies, but a platform
|
||||
admin whose `users.role` is readable remains authorized through the
|
||||
admin disjunct; with role state unreadable, the admin disjunct denies
|
||||
likewise. A decision that can read neither denies. Capability-row
|
||||
deletion is hereby added to §6.1's enumerated revocation paths:
|
||||
it propagates identically, under §6.2's bound, on every transport —
|
||||
no new HTTP/MCP command authorized by the deleted row after the
|
||||
revoking transaction commits, and any cached authorization is
|
||||
invalidated in the revoking transaction (§3.5).
|
||||
5. **What it does not confer**, stated so implementing PRs cannot drift:
|
||||
no hierarchy grant or effective role at any node; no workspace
|
||||
authorization or membership; no content, structure, or roll-up read;
|
||||
@@ -319,24 +364,58 @@ further amendment, not an implementation decision.
|
||||
subject holding both.
|
||||
6. **Verification requirements** (extends §7, binding on implementing
|
||||
PRs):
|
||||
1. Vocabulary: the `capability` CHECK constraint rejects any value
|
||||
outside `company_crud` (real-PostgreSQL witness, `ci-postgres`
|
||||
service in the `test` CI step).
|
||||
2. Conferral exactness: a non-admin holder succeeds on the visibility
|
||||
command in both directions with contract 1 §5.2's audit event
|
||||
(old and new values as semantic content); the same holder, with no
|
||||
other grants, is refused a workspace command, receives the
|
||||
1. Schema witnesses (real PostgreSQL, `ci-postgres` service in the
|
||||
`test` CI step): the `capability` CHECK constraint rejects any
|
||||
value outside `company_crud`; NOT NULL enforced on every declared
|
||||
NOT NULL column; UNIQUE (`user_id`, `capability`) rejects a
|
||||
duplicate; both user FKs reject a dangling reference AND deleting a
|
||||
referenced user is refused (RESTRICT witnessed in both directions);
|
||||
the table's column set is exactly the §8.2 declared set (contract 1
|
||||
§6.2 discipline).
|
||||
2. Capability-only command matrix — the witness that proves "exactly
|
||||
one command", not merely "at least one": a non-admin holder with no
|
||||
other grants succeeds on the visibility command in **both**
|
||||
directions with contract 1 §5.2's audit event (old and new values
|
||||
as semantic content), and the **same** actor is refused, case by
|
||||
enumerated case: every hierarchy mutation family (company/child
|
||||
create under another's node, rename, delete, transfer); grant
|
||||
create/change/revoke; the workspace read and write command
|
||||
families; roll-up reads; structure reads — including the
|
||||
not-found-indistinguishable refusal on a structure read of the very
|
||||
company they just mutated (hierarchy schema §6.7), cannot create a
|
||||
grant, and derives no MCP scope — the §7.4 deny-by-default matrix
|
||||
gains this cell.
|
||||
3. Assignment authority: a non-admin — including a current capability
|
||||
holder — is refused assign and revoke; every assign/revoke produces
|
||||
its audit event with the namespaced string (§8.3).
|
||||
4. Revocation and fail-closed: after row deletion, the ex-holder's
|
||||
next visibility command is refused; with capability state
|
||||
unreadable (fault injection), the decision denies (§3.5).
|
||||
5. Owner-as-such refusal re-witnessed: hierarchy schema §6.9's
|
||||
company they just mutated (hierarchy schema §6.7); every
|
||||
instance-administration surface other than the visibility command
|
||||
(user management, system settings, provider configuration, and
|
||||
capability assign/revoke itself); and MCP scope derivation yields
|
||||
nothing — the §7.4 deny-by-default matrix gains this row. Company
|
||||
creation compares against an eligible-user baseline: the holder's
|
||||
create behaves exactly as any active user's — always `private`,
|
||||
and a creation request carrying a visibility argument is refused
|
||||
for holder and baseline alike (contract 3 §5.2).
|
||||
3. Disclosure bound (§8.1 carve-out witnessed): the mutation result
|
||||
for a private-valid target, a directory-valid target, and a
|
||||
nonexistent id is exactly {success, success, `not_found`}; no
|
||||
result or error payload carries name, slug, structure, content,
|
||||
grant, or membership data; the holder's audit-visible surface
|
||||
carries only existence and old/new visibility.
|
||||
4. Assignment path, both polarities: a platform admin assigns and
|
||||
revokes through the normal admin command (positive witnesses —
|
||||
assign then observe the §8.6.2 allow, revoke then observe deny); a
|
||||
non-admin — including a current capability holder — is refused
|
||||
assign and revoke; every assign/revoke produces its audit event
|
||||
with the namespaced string (§8.3); a direct-write path that skips
|
||||
the command surface is non-conformant (the §8.3 command is the only
|
||||
writer of `platform_capabilities`).
|
||||
5. Revocation joins the §7.6 matrix: assignment is decision-time-live
|
||||
(capability assigned → the holder's next visibility command allows,
|
||||
no re-login); after row deletion, the ex-holder's next visibility
|
||||
command is refused **on every exposed transport**, measured with
|
||||
the revocation and the decision on distinct physical connections; a
|
||||
cached-authorization implementation proves transactional
|
||||
invalidation (§3.5). Fail-closed fault witnesses, both disjuncts
|
||||
(§8.4): with `platform_capabilities` unreadable, a non-admin holder
|
||||
is denied while a platform admin remains authorized; with role
|
||||
state unreadable, the admin disjunct denies.
|
||||
6. Owner-as-such refusal re-witnessed: hierarchy schema §6.9's
|
||||
owner-cannot-publish witness re-asserted with the
|
||||
`platform_capabilities` table present and empty for that owner.
|
||||
|
||||
@@ -363,7 +442,7 @@ embedded:
|
||||
|
||||
- Decision: the company-CRUD capability is a platform-scoped,
|
||||
admin-assigned, audited delegation of exactly the hierarchy schema §5.5
|
||||
visibility command — no read surface, no other company operation. Say
|
||||
"agreed" or
|
||||
name the additional operations (or the curation listing) you want it to
|
||||
carry.
|
||||
visibility command — no read command, no other company operation, with
|
||||
the mutation's inherent existence disclosure ratified as a bounded
|
||||
carve-out (§8.1). Say "agreed" or name the additional operations (or
|
||||
the curation listing) you want it to carry.
|
||||
|
||||
Reference in New Issue
Block a user