docs(rollup): revision 2 — membership locality, executable no-oracle predicate, closed schema enumeration, widened fixtures (terra F1-F7)
ci/woodpecker/pr/ci Pipeline was canceled
ci/woodpecker/pr/ci Pipeline was canceled
This commit is contained in:
@@ -16,6 +16,23 @@ read-only roll-up query over only readable workspaces, at every
|
|||||||
hierarchy level, as its own non-mutating query tool, dependent on ranks
|
hierarchy level, as its own non-mutating query tool, dependent on ranks
|
||||||
1–3.
|
1–3.
|
||||||
|
|
||||||
|
Revision 2 (terra review F1–F7): membership-only readability is now
|
||||||
|
workspace-local — it contributes at the workspace node only and never
|
||||||
|
promotes ancestor visibility; upward aggregation requires an effective
|
||||||
|
chain role, and §1 defines direct vs effective grants in contract 2's
|
||||||
|
terms (F1). The no-oracle rule gains a defined equivalence predicate
|
||||||
|
(normalized byte equality with an enumerated volatile-field set) and a
|
||||||
|
partial-scope hidden-sibling witness (F2). §2.5 enumerates the closed
|
||||||
|
semantic result and denial schemas field-by-field, including the
|
||||||
|
explicit-zero representation (F3). Cache invalidation, when a cache
|
||||||
|
exists, is witnessed per invalidator class (F4). Non-authoritative and
|
||||||
|
never-gate rules gain an import-graph/data-flow witness, and the
|
||||||
|
mutation check is aligned to contract 1 §6.7's both-table zero-write
|
||||||
|
assertion (F5). The fixture gains a second estate with distinct counts
|
||||||
|
and explicit company-, estate-, project-grant, and membership cases
|
||||||
|
(F6). The §5.3 legacy-row exclusion and pre-rank no-obligation rules
|
||||||
|
are disclosed as drafting additions (F7).
|
||||||
|
|
||||||
This contract binds the projection semantics (§2), reader authorization
|
This contract binds the projection semantics (§2), reader authorization
|
||||||
semantics (§3), read-only enforcement (§4), dependencies and phase
|
semantics (§3), read-only enforcement (§4), dependencies and phase
|
||||||
timing (§5), witnesses (§6), and disclosed drafting additions (§7). It
|
timing (§5), witnesses (§6), and disclosed drafting additions (§7). It
|
||||||
@@ -30,16 +47,26 @@ row with contract 5 (`tool-gateway-mapping.md`).
|
|||||||
1. **Roll-up**: the read-only projection of per-workspace task counts
|
1. **Roll-up**: the read-only projection of per-workspace task counts
|
||||||
by status, aggregated up the contract 1 parent chain (workspace →
|
by status, aggregated up the contract 1 parent chain (workspace →
|
||||||
platform-project → estate → company).
|
platform-project → estate → company).
|
||||||
2. **Readable workspace** (for a given reader): a workspace where the
|
2. **Effective chain role** (at a node, for a reader): the role
|
||||||
reader's authorization permits reading task state — either
|
contract 2 §3 evaluation yields at that node — from a grant on the
|
||||||
workspace membership under the SOT's own membership rules
|
node itself (a **direct grant**) or from a grant on an ancestor
|
||||||
(REQ-ID-001), or an effective chain role at that workspace per
|
whose domain covers it (an **inherited grant**, contract 2 §3.2).
|
||||||
contract 2 §3 evaluation. The role vocabulary is contract 2 §2's;
|
The role vocabulary is contract 2 §2's; this contract adds no role
|
||||||
this contract adds no role and no new authority source.
|
and no new authority source.
|
||||||
3. **Aggregation scope** (of a hierarchy node, for a given reader):
|
3. **Chain-readable workspace** (for a reader): a workspace where the
|
||||||
the set of readable workspaces in that node's descendant subtree
|
reader's effective chain role permits reading task state.
|
||||||
(for a workspace node, the workspace itself if readable).
|
4. **Member-readable workspace** (for a reader): a workspace readable
|
||||||
4. **Projection**: a generated, non-authoritative view in the sense of
|
only through workspace membership under the SOT's own membership
|
||||||
|
rules (REQ-ID-001), with no effective chain role. Membership
|
||||||
|
confers workspace-local semantics only (contract 2 §3.1, §7.4): it
|
||||||
|
never contributes authority, visibility, or aggregation upward.
|
||||||
|
5. **Aggregation scope** (of a hierarchy node, for a reader): the set
|
||||||
|
of chain-readable workspaces in that node's descendant subtree;
|
||||||
|
plus, when the node is itself a workspace, that workspace if it is
|
||||||
|
chain-readable or member-readable. A member-readable workspace
|
||||||
|
therefore contributes to exactly one node's aggregation scope: its
|
||||||
|
own.
|
||||||
|
6. **Projection**: a generated, non-authoritative view in the sense of
|
||||||
`native-kanban-sot.md` §3 invariant 5 — derived from SOT rows,
|
`native-kanban-sot.md` §3 invariant 5 — derived from SOT rows,
|
||||||
never an import source, never authoritative.
|
never an import source, never authoritative.
|
||||||
|
|
||||||
@@ -60,35 +87,68 @@ row with contract 5 (`tool-gateway-mapping.md`).
|
|||||||
aggregation — metrics, trends, forecasting, scoring, velocity,
|
aggregation — metrics, trends, forecasting, scoring, velocity,
|
||||||
cross-workspace derived analytics, dashboards computed across
|
cross-workspace derived analytics, dashboards computed across
|
||||||
workspaces — remains a `native-kanban-sot.md` §6 non-goal
|
workspaces — remains a `native-kanban-sot.md` §6 non-goal
|
||||||
(§8.2.4). The response schema is closed (§6.7 witness): adding any
|
(§8.2.4). The response schema is closed (§2.5; §6.7 witness):
|
||||||
field beyond identifiers, names of visible nodes, and status
|
adding any field is an amendment to this contract.
|
||||||
counts is an amendment to this contract.
|
|
||||||
4. **Non-authoritative.** No consumer may treat roll-up output as a
|
4. **Non-authoritative.** No consumer may treat roll-up output as a
|
||||||
source of record; it is recomputable at any time from SOT rows and
|
source of record; it is recomputable at any time from SOT rows and
|
||||||
is never imported, persisted as authoritative state, or used to
|
is never imported, persisted as authoritative state, or used to
|
||||||
gate work.
|
gate or deny work (witness §6.8 — both the write-path and the
|
||||||
|
decision-path prohibitions are witnessed).
|
||||||
|
5. **Closed semantic schema.** The successful result consists of
|
||||||
|
exactly these semantic fields, and no others:
|
||||||
|
- `node`: the queried node — exactly `id`, `type` (one of the four
|
||||||
|
contract 1 levels), `name`.
|
||||||
|
- `totals`: one entry per status value of the typed lifecycle —
|
||||||
|
every status key present, a count of zero represented explicitly
|
||||||
|
as `0`, never by key absence.
|
||||||
|
- `children`: the reader-visible (§3.2) child nodes of `node`,
|
||||||
|
each carrying exactly the same `id`/`type`/`name`/`totals`
|
||||||
|
shape, recursively down to the workspaces in the reader's
|
||||||
|
aggregation scope. A node outside §3.2 visibility never appears
|
||||||
|
at any depth.
|
||||||
|
There are no optional result fields. The denial/nonexistent
|
||||||
|
response is the contract 5 §4.2 not-found-class error envelope
|
||||||
|
with no fields beyond that envelope. The wire DTO is expressed
|
||||||
|
under contract 5 §4.1, and MUST be a faithful serialization of
|
||||||
|
exactly this semantic field set: a wire field with no
|
||||||
|
corresponding semantic field above is a conformance defect.
|
||||||
|
|
||||||
## 3. Reader authorization semantics
|
## 3. Reader authorization semantics
|
||||||
|
|
||||||
1. **Scope rule.** A reader's roll-up over any node aggregates ONLY
|
1. **Scope rule.** A reader's roll-up over any node aggregates ONLY
|
||||||
the reader's aggregation scope (§1.3). An unreadable workspace
|
the reader's aggregation scope (§1.5). An unreadable workspace
|
||||||
contributes nothing to any total — not a count, not a row, not a
|
contributes nothing to any total — not a count, not a row, not a
|
||||||
presence marker.
|
presence marker. A member-readable workspace contributes only at
|
||||||
|
the workspace node itself (§1.4–§1.5): querying it directly
|
||||||
|
succeeds; it never appears in, and never adds to, any ancestor's
|
||||||
|
response for that reader.
|
||||||
2. **Node visibility.** A node appears in a roll-up response iff the
|
2. **Node visibility.** A node appears in a roll-up response iff the
|
||||||
reader's aggregation scope at that node is non-empty, or the
|
reader's aggregation scope at that node is non-empty, or the
|
||||||
reader holds a grant on the node itself (contract 2 §3.2 makes the
|
reader holds an effective chain role at the node (§1.2 — direct or
|
||||||
node and its subtree the grant's domain). Per the ruling below, a
|
inherited; contract 2 §3.2 makes a grant's domain the node and its
|
||||||
granted node whose aggregation scope is empty appears with zero
|
subtree, so an ancestor grant makes empty descendants visible per
|
||||||
counts; a node the reader has no authority on does not appear at
|
the ruling). Per the ruling below, a node with an effective chain
|
||||||
all.
|
role but an empty aggregation scope appears with zero counts.
|
||||||
|
Workspace membership alone never makes any non-workspace node
|
||||||
|
visible. A node where the reader has neither an effective chain
|
||||||
|
role nor a non-empty aggregation scope does not appear at all.
|
||||||
3. **No existence oracle.** The response MUST NOT disclose the
|
3. **No existence oracle.** The response MUST NOT disclose the
|
||||||
existence, count, name, or any property of unreadable workspaces
|
existence, count, name, or any property of unreadable workspaces
|
||||||
or of nodes outside §3.2 visibility — no "N workspaces hidden"
|
or of nodes outside §3.2 visibility — no "N workspaces hidden"
|
||||||
fields, no total-vs-visible discrepancy fields. A query naming a
|
fields, no total-vs-visible discrepancy fields. A query naming a
|
||||||
node outside §3.2 visibility returns the same response as a query
|
node outside §3.2 visibility MUST satisfy the §3.4 response
|
||||||
naming a nonexistent node (fail closed, `rbac-grant-model.md` §3.5
|
equivalence with a query naming a nonexistent node (fail closed,
|
||||||
pattern: a decision path that cannot read grant state denies).
|
`rbac-grant-model.md` §3.5 pattern: a decision path that cannot
|
||||||
4. **Live evaluation.** Readability is evaluated per contract 2 §3.5
|
read grant state denies).
|
||||||
|
4. **Response equivalence predicate.** Two responses are equivalent
|
||||||
|
when they carry the identical HTTP status, the identical contract
|
||||||
|
5 §4.2 error code, and byte-identical bodies after normalizing
|
||||||
|
exactly the declared volatile envelope fields — correlation id and
|
||||||
|
response timestamp, and nothing else. The implementing PR declares
|
||||||
|
that volatile-field list in the witness; any additional
|
||||||
|
normalization is a conformance defect. This is contract 5 §4.2's
|
||||||
|
same code/status/shape rule made executable.
|
||||||
|
5. **Live evaluation.** Readability is evaluated per contract 2 §3.5
|
||||||
(live rows or transactionally-invalidated cache). Revocation
|
(live rows or transactionally-invalidated cache). Revocation
|
||||||
propagates per contract 2 §6: the next roll-up query decided after
|
propagates per contract 2 §6: the next roll-up query decided after
|
||||||
the revoking transaction commits excludes the revoked scope.
|
the revoking transaction commits excludes the revoked scope.
|
||||||
@@ -106,8 +166,8 @@ row with contract 5 (`tool-gateway-mapping.md`).
|
|||||||
3. **Freshness.** v1 computes the roll-up live from SOT rows at query
|
3. **Freshness.** v1 computes the roll-up live from SOT rows at query
|
||||||
time. A cache is an implementation option only if it is
|
time. A cache is an implementation option only if it is
|
||||||
invalidated in the same transaction as any task, hierarchy, grant,
|
invalidated in the same transaction as any task, hierarchy, grant,
|
||||||
or membership mutation that affects it, and it is never
|
or membership mutation that affects it (each invalidator class
|
||||||
authoritative (§1.4).
|
witnessed, §6.5), and it is never authoritative (§1.6).
|
||||||
|
|
||||||
## 5. Dependencies and phase timing
|
## 5. Dependencies and phase timing
|
||||||
|
|
||||||
@@ -117,55 +177,100 @@ row with contract 5 (`tool-gateway-mapping.md`).
|
|||||||
after them and reads their surfaces; it defines none of them.
|
after them and reads their surfaces; it defines none of them.
|
||||||
2. The roll-up query is one tool with one Gateway mapping row under
|
2. The roll-up query is one tool with one Gateway mapping row under
|
||||||
contract 5's regime (request/result/error/audit contracts there);
|
contract 5's regime (request/result/error/audit contracts there);
|
||||||
this contract binds its semantics, not its wire shape.
|
this contract binds its semantics (§2.5 defines the semantic
|
||||||
|
fields the contract 5 §4.1 DTO serializes), not its wire encoding.
|
||||||
3. Legacy task rows outside the typed lifecycle are not aggregated;
|
3. Legacy task rows outside the typed lifecycle are not aggregated;
|
||||||
the roll-up begins counting a workspace's tasks when they exist in
|
the roll-up begins counting a workspace's tasks when they exist in
|
||||||
the typed surface. No roll-up obligation attaches to v1 before
|
the typed surface. No roll-up obligation attaches to v1 before
|
||||||
ranks 1–3 exist.
|
ranks 1–3 exist. Both rules are drafting additions disclosed in §7
|
||||||
|
(they trace to no §8 sentence).
|
||||||
|
|
||||||
## 6. Verification requirements
|
## 6. Verification requirements
|
||||||
|
|
||||||
Binding on the implementing PRs. Every witness names, in its
|
Binding on the implementing PRs. Every witness names, in its
|
||||||
implementation, the exact endpoints/tools, tables, and fixtures it
|
implementation, the exact endpoints/tools, tables, and fixtures it
|
||||||
exercises. The base fixture seeds two companies; under company A an
|
exercises. The base fixture seeds two companies; under company A **two
|
||||||
estate with two platform-projects and three workspaces with known task
|
estates with distinct, non-identical count profiles**: estate A1 with
|
||||||
counts across at least three statuses; under company B one workspace.
|
two platform-projects and three workspaces, estate A2 with one
|
||||||
|
platform-project and one workspace, all with known task counts across
|
||||||
|
at least three statuses; under company B one workspace.
|
||||||
|
|
||||||
1. **Correctness witness:** for a reader authorized on all of company
|
1. **Correctness witnesses:** for a reader holding a direct company-A
|
||||||
A, roll-up totals at workspace, platform-project, estate, and
|
grant, roll-up totals at every level equal the seeded sums — each
|
||||||
company level equal the seeded counts, keyed by the typed status
|
workspace, each platform-project, estate A1 and estate A2
|
||||||
values, with no double count across the chain.
|
separately (their distinct profiles asserted distinct), and the
|
||||||
2. **Scope witnesses:** a reader with a grant on one platform-project
|
company total equal to A1+A2 — keyed by the typed status values,
|
||||||
sees exactly its subtree's counts at every queryable level; a
|
with no double count across the chain. For a reader holding a
|
||||||
workspace-member-only reader sees exactly that workspace; for a
|
direct estate-A1 grant, the estate-A1 result equals the A1 sum and
|
||||||
reader authorized on two of three sibling workspaces, the parent
|
a company-A query returns company A with exactly A1's contribution
|
||||||
totals equal the two readable workspaces' sum.
|
(estate A2 invisible). Each of the four grant levels — company,
|
||||||
|
estate, platform-project (below), workspace — has an explicit
|
||||||
|
case; none is simulated by unioning workspace access.
|
||||||
|
2. **Scope witnesses:** a reader with a direct grant on one
|
||||||
|
platform-project sees exactly its subtree's counts at every
|
||||||
|
queryable level; for a reader authorized on two of three sibling
|
||||||
|
workspaces, the parent totals equal the two readable workspaces'
|
||||||
|
sum. **Membership locality (§1.4):** a member-only reader queries
|
||||||
|
the workspace directly and receives its counts; the same reader
|
||||||
|
querying the workspace's parent (or any ancestor) receives the
|
||||||
|
§3.4-equivalent nonexistent-node response, and no ancestor
|
||||||
|
response for any other reader changes because of that membership.
|
||||||
3. **No-oracle witnesses:** the sibling-workspace response above
|
3. **No-oracle witnesses:** the sibling-workspace response above
|
||||||
contains no field disclosing the third workspace's existence
|
contains no field disclosing the third workspace's existence
|
||||||
(closed-schema comparison against a reader authorized on all
|
(closed-schema comparison against a reader authorized on all
|
||||||
three: identical field set, differing only in counts and visible
|
three: identical field set, differing only in counts and visible
|
||||||
nodes); a query by an unauthorized reader naming company B returns
|
nodes). **Partial-scope hidden node:** the reader who sees the
|
||||||
a response byte-equivalent in shape and status to the same query
|
parent and two siblings queries the hidden third workspace by its
|
||||||
naming a random nonexistent id.
|
real id — the response satisfies the §3.4 equivalence predicate
|
||||||
4. **Empty-vs-hidden witness (ruling):** a reader granted on an empty
|
against the same query naming a nonexistent id, under one fixed
|
||||||
platform-project receives it with zero counts; with the grant
|
request context with the declared volatile-field normalization.
|
||||||
deleted, the same query returns the nonexistent-node response.
|
**Cross-tenant:** an unauthorized reader naming company B receives
|
||||||
5. **Mutation witnesses:** the roll-up surface rejects every mutating
|
a response §3.4-equivalent to naming a nonexistent id. Each
|
||||||
|
equivalence check is executable byte comparison after the declared
|
||||||
|
normalization, not a shape judgment.
|
||||||
|
4. **Empty-vs-hidden witness (ruling):** a reader granted (direct
|
||||||
|
chain grant) on an empty platform-project receives it with zero
|
||||||
|
counts — every status key present at `0` (§2.5); with the grant
|
||||||
|
deleted, the same query returns the §3.4-equivalent
|
||||||
|
nonexistent-node response. An inherited-grant case: a company
|
||||||
|
grant makes an empty descendant platform-project visible with zero
|
||||||
|
counts.
|
||||||
|
5. **Cache-invalidation witnesses (conditional):** bound only if the
|
||||||
|
implementation caches — for EACH invalidator class, prime the
|
||||||
|
cache, commit one mutation of that class, and assert the next
|
||||||
|
query reflects it: a task status change, a task creation, a
|
||||||
|
membership removal (the member-readable workspace disappears from
|
||||||
|
its own node's next query), a workspace reparenting (both old and
|
||||||
|
new parent totals correct), and a grant revocation. A live
|
||||||
|
(cacheless) v1 implementation records that fact and the witnesses
|
||||||
|
bind at the PR that introduces a cache.
|
||||||
|
6. **Mutation witnesses:** the roll-up surface rejects every mutating
|
||||||
verb/command; a crafted attempt to issue a write through the
|
verb/command; a crafted attempt to issue a write through the
|
||||||
roll-up's database path fails at the read-only boundary (§4.2);
|
roll-up's database path fails at the read-only boundary (§4.2);
|
||||||
after any roll-up query, an SOT row diff is empty.
|
after any roll-up query, the row diff is empty across BOTH the
|
||||||
6. **Revocation witness:** after revoking the grant that made a
|
workspace tables and the hierarchy tables (contract 1 §6.7's
|
||||||
|
both-table zero-write assertion).
|
||||||
|
7. **Closed-schema witness:** the response is asserted field-exact
|
||||||
|
against the §2.5 enumeration — `node` (id/type/name), `totals`
|
||||||
|
(every typed status present, explicit zeros), `children`
|
||||||
|
(recursive, visible only) — and a response carrying any field
|
||||||
|
outside the enumeration fails the assertion (carve-out boundary,
|
||||||
|
§2.3). The denial envelope is asserted field-exact against
|
||||||
|
contract 5 §4.2's envelope.
|
||||||
|
8. **Non-authoritative and never-gate witnesses:** (a) a static
|
||||||
|
production import-graph inventory (hierarchy contract §6.3 style,
|
||||||
|
production code over `apps/` and `packages/`, tests excluded)
|
||||||
|
shows no production module imports the roll-up query module or its
|
||||||
|
result DTO into any SOT write path, any authorization/gating
|
||||||
|
decision path, or any persistence beyond the response lifetime —
|
||||||
|
asserted in both directions (the roll-up module's consumers are
|
||||||
|
enumerated and each is a presentation surface); (b) a behavioral
|
||||||
|
probe: with roll-up output artificially perturbed (test double),
|
||||||
|
no authorization outcome and no work-gating decision anywhere in
|
||||||
|
the fixture suite changes — proving no gate consumes it.
|
||||||
|
9. **Revocation witness:** after revoking the grant that made a
|
||||||
subtree readable, the next roll-up query excludes it (contract 2
|
subtree readable, the next roll-up query excludes it (contract 2
|
||||||
§6.2 bound).
|
§6.2 bound).
|
||||||
7. **Closed-schema witness:** the response schema is asserted
|
|
||||||
field-exact against §2.1/§3.2 (identifiers, visible-node names,
|
|
||||||
status counts) — a field outside the closed set fails the
|
|
||||||
assertion (carve-out boundary, §2.3).
|
|
||||||
8. **Non-authoritative witness:** no production module imports roll-up
|
|
||||||
output into SOT writes; a static route inventory (hierarchy
|
|
||||||
contract §6.3 style, production code over `apps/` and `packages/`,
|
|
||||||
tests excluded) shows the roll-up query modules perform no SOT
|
|
||||||
writes and no module feeds roll-up responses into a write path.
|
|
||||||
|
|
||||||
## 7. Drafting additions (PRD §12.1 disclosure)
|
## 7. Drafting additions (PRD §12.1 disclosure)
|
||||||
|
|
||||||
@@ -176,16 +281,25 @@ read-only nature, and the no-oracle acceptance are traced to
|
|||||||
|
|
||||||
1. The §3.2 node-visibility rule and the granted-but-empty behavior
|
1. The §3.2 node-visibility rule and the granted-but-empty behavior
|
||||||
(the ruling below).
|
(the ruling below).
|
||||||
2. The §3.3 nonexistent-node response equivalence as the concrete
|
2. The §3.3–§3.4 nonexistent-node response equivalence, with its
|
||||||
no-oracle mechanism.
|
normalized-byte-equality predicate, as the concrete no-oracle
|
||||||
|
mechanism.
|
||||||
3. The §4.2 read-only-transaction mechanical enforcement.
|
3. The §4.2 read-only-transaction mechanical enforcement.
|
||||||
4. The §4.3 cache option with transactional invalidation.
|
4. The §4.3 cache option with transactional invalidation and the
|
||||||
5. The §2.3 closed response schema as an amendment boundary.
|
§6.5 per-invalidator witnesses.
|
||||||
|
5. The §2.5 closed response schema as an amendment boundary.
|
||||||
|
6. The §1.4 membership-locality rule — membership-only readability
|
||||||
|
contributes at the workspace node only (this contract's
|
||||||
|
reconciliation of `native-kanban-sot.md` §8.1.3 "authorized on"
|
||||||
|
with contract 2 §3.1/§7.4's workspace-local membership).
|
||||||
|
7. The §5.3 legacy-row exclusion and the §5.3 pre-rank no-obligation
|
||||||
|
rule.
|
||||||
|
|
||||||
## Ruling request
|
## Ruling request
|
||||||
|
|
||||||
Ruling requested (one decision): shall a node the reader is granted on
|
Ruling requested (one decision): shall a node the reader holds an
|
||||||
but whose aggregation scope is empty appear in the roll-up with zero
|
effective chain role on (direct or inherited, §1.2) but whose
|
||||||
counts (recommended — it lets the UI show a granted-but-empty subtree
|
aggregation scope is empty appear in the roll-up with zero counts
|
||||||
|
(recommended — it lets the UI show a granted-but-empty subtree
|
||||||
honestly) — or, as the alternative, be indistinguishable from a
|
honestly) — or, as the alternative, be indistinguishable from a
|
||||||
nonexistent node until it contains a readable workspace?
|
nonexistent node until it contains a readable workspace?
|
||||||
|
|||||||
Reference in New Issue
Block a user