Skip to content

Commit 2ce1eb4

Browse files
Jack Qclaude
andauthored
docs(qa): narrow the authz conformance matrix's completeness claim to what its ratchet checks (#8711) (#9026)
Half (2), the ruled remainder of #8711 (half (1) landed in #8812). Maintainer ruling: narrow the matrix's written claim to what the mechanism delivers (Option A) — no primitive-discovery ratchet (Option B, measured unachievable in general form), option C (a declaration-side ratchet) deliberately left unruled and preserved as a separate finding. The matrix header and its companion test's header claimed a new declared-but-unenforced primitive "breaks CI." That is true only for the curated set of HTTP/transport entry points `discover()` enumerates (15 probes over 11 named source files) — a primitive enforced by a predicate inside an existing resolver adds no entry point and can be neither UNCLASSIFIED nor STALE, which is exactly why the #8613 `active` flag sat outside the ledger for its whole inert period without breaking CI. Both headers now state the narrowed, routes-completeness claim with the measured numbers so it is load-bearing: 43 of 50 rows carry no `covers` key at all (7 rows, 9 keys, every one an HTTP/transport pin), 37 of the 43 `enforced` rows are in-resolver predicates outside the ratchet entirely, and 5 of the 9 `covers` keys that do exist are gate-pins that vanish (failing CI) when the guard call they name is deleted — the real anti-regression value, preserved. Outside the curated table, "one row per primitive" is stated as the hand-maintained invariant it actually is. Prose and comments only. `discover()`, `PROBES`, `HIGH_RISK`, `checkLedger`, and every row's `state`/`enforcement`/`covers`/`proof` are untouched — the conformance test still reports 15 passed (15), unchanged, which is the evidence this boundary was respected. Claude-Session: https://claude.ai/code/session_01NaS1PAHJcPfAA2acnV53Tn Co-authored-by: Claude <noreply@anthropic.com>
1 parent 67f2892 commit 2ce1eb4

3 files changed

Lines changed: 64 additions & 16 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
"@objectstack/dogfood": patch
3+
---
4+
5+
docs(qa): narrow the ADR-0056 D10 authz conformance matrix's advertised completeness claim to what its ratchet actually checks (#8711)
6+
7+
The matrix header and its companion test's header previously read as though
8+
a new declared-but-unenforced authorization primitive would "break CI." It
9+
would not, for most of the ledger: the completeness `discover()` ratchets is
10+
over a **curated table of HTTP/transport entry points** (15 probes over 11
11+
named source files), not over primitives. A primitive enforced by a predicate
12+
inside an existing resolver — the `sys_permission_set.active` /
13+
`sys_position.active` rows added in #8812 are the normal case, not an
14+
exception — adds no entry point, so it can be neither UNCLASSIFIED nor STALE.
15+
16+
Both headers now say so explicitly, carrying the measured numbers so the
17+
narrowed claim is load-bearing rather than vague: 43 of the matrix's 50 rows
18+
carry no `covers` key at all, 37 of the 43 `enforced` rows are exactly that
19+
in-resolver shape, and — preserved, because it is real — 5 of the file's 9
20+
`covers` keys are gate-pins that vanish (and fail CI) when the guard call
21+
they name is deleted. Prose and comments only; nothing about the ratchet's
22+
checking behaviour, the `discover()` table, or any row changes. Maintainer
23+
ruling on #8711 (Option A): narrow the claim, do not build a
24+
primitive-discovery ratchet (measured unachievable in general form).

packages/qa/dogfood/test/authz-conformance.matrix.ts

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,31 @@
66
// primitive, each in EXACTLY ONE honest state (enforced / experimental /
77
// removed). `enforced` rows name their runtime enforcement site; high-risk
88
// enforced rows additionally reference an end-to-end dogfood proof. The
9-
// companion test (`authz-conformance.test.ts`) asserts the matrix is complete,
10-
// that every referenced proof file exists, AND that the row ↔ proof pairing is
11-
// MUTUAL — so "the permission model is landed" is a CHECKED artifact, not a
12-
// one-time scan. A new fail-open (a declared-but-unenforced primitive) or a
13-
// deleted proof breaks CI.
9+
// companion test (`authz-conformance.test.ts`) asserts every referenced proof
10+
// file exists and that the row ↔ proof pairing is MUTUAL (#7976 below), AND
11+
// ratchets completeness over a CURATED table of HTTP/transport entry points
12+
// (`discover()`: 15 probes over 11 named source files) — a new ungated route
13+
// there is UNCLASSIFIED, a deleted guard is STALE, and either breaks CI.
14+
//
15+
// [#8711] That completeness is over ROUTES, not over primitives: a primitive
16+
// enforced by a predicate inside an existing resolver adds no entry point, so
17+
// it can be neither UNCLASSIFIED nor STALE. Measured against the rows below:
18+
// 43 of 50 carry no `covers` key at all (7 rows, 9 keys, every one an
19+
// HTTP/transport pin), and 37 of the file's 43 `enforced` rows are exactly
20+
// that in-resolver shape — the ADR-0049/#8613 `active` rows among them (see
21+
// their own block further down) are the normal case, not an exception. Of the
22+
// 9 `covers` keys that DO exist, 5 are GATE pins tied to the enforcement call
23+
// itself, not merely a function name — delete `shouldDenyAnonymous` from
24+
// `/actions`, `/automation` or `/packages`, or drop the MCP context-threading
25+
// / stdio principal binding, and the pinned key vanishes from source, its row
26+
// goes STALE, and CI catches the regression. That anti-regression property is
27+
// real and is what this file mechanically delivers. Outside the curated
28+
// table, "one row per primitive, each in EXACTLY ONE honest state" is a
29+
// HAND-MAINTAINED invariant, not a checked one: a primitive added without its
30+
// row is not something this ratchet can see (a primitive-discovery ratchet
31+
// was measured unachievable in general form — there is no syntactic signature
32+
// for "a predicate that decides a grant"; `isRowActive` looks exactly like any
33+
// other `.filter()`).
1434
//
1535
// [#7976] Existence used to be the whole `proof` contract, which meant a row
1636
// could cite a file exercising a NEIGHBOURING primitive and stay green forever:
@@ -236,12 +256,13 @@ export const AUTHZ_CONFORMANCE: AuthzPrimitive[] = [
236256
// RATCHET, not an omission: `discover()` enumerates HTTP entry points from a
237257
// curated per-file probe table, and a predicate inside an existing resolver
238258
// adds no entry point — so neither flag could ever have surfaced as
239-
// UNCLASSIFIED during the whole period it was inert, despite this file's
240-
// header claiming a declared-but-unenforced primitive breaks CI. These two
241-
// rows restore the ledger's stated invariant; whether the invariant's
242-
// advertised SCOPE should be narrowed to what the ratchet can check, or the
243-
// ratchet widened to reach in-resolver predicates, is the open half of #8711
244-
// and is deliberately NOT settled here.
259+
// UNCLASSIFIED during the whole period it was inert. These two rows restore
260+
// the ledger's stated invariant. [Resolved — maintainer ruling on #8711,
261+
// 2026-08-15] The invariant's advertised SCOPE is narrowed to what the
262+
// ratchet can check, not the ratchet widened to reach in-resolver
263+
// predicates like this one — widening was measured unachievable in general
264+
// form. See this file's header for the narrowed claim and the measured
265+
// numbers.
245266
{ id: 'permission-set-active', summary: '`sys_permission_set.active` — a deactivated permission set grants nothing (ADR-0049 / #8613)', state: 'enforced',
246267
enforcement: 'core/security/resolve-authz-context.ts step 6b — isRowActive drops the row BEFORE any derivation, so a deactivated set contributes no name to `grants.permissions`, no systemPermissions and no tabPermissions, AND `hasPlatformAdminGrant` cannot be read off a deactivated `admin_full_access`; plugin-security/security-plugin.ts dbLoader applies the SAME predicate, which is the only place a set reached by NAME is judged (position names are commonly reused as set names, so an ACTIVE position carries a DEACTIVATED set\'s name that far); plugin-auth/last-admin-guard.ts carries `active` in PERMISSION_SET_STANDING_KEYS so deactivating the last admin set is judged as an emptying rather than read as a bootstrap window',
247268
note: 'Unit-proven; an e2e dogfood proof is a follow-on, the same disposition as the ADR-0105 block above and for the same reason — the flag is a predicate inside the grant resolver, not an HTTP surface, so there is no route for a dogfood boot to drive at it directly. core/security/resolve-authz-context.test.ts "[#8613] the `active` flag on the grant catalogues (ADR-0049)" covers the derivation half, including THE HIGH-BLAST-RADIUS CASE (a deactivated admin_full_access confers no PLATFORM_ADMIN) and that deactivating ONE set leaves the others granting; plugin-security/permission-set-active.test.ts covers the loader half, including THE REACHABILITY CASE (a position name reaching a deactivated set of the same name) plus its non-vacuous twin (the same request with the set ACTIVE does resolve); core/security/row-active.test.ts pins the predicate itself (absent grants, junk does not revoke, 0/1 deactivates). Deliberately NOT in HIGH_RISK: that list marks primitives guarding object data through a sibling HTTP entry point, and this one guards grant DERIVATION. The honest upgrade path is a real proof (seed a deactivated set, drive REST as its holder, observe the refusal), not re-citing a neighbouring file.' },

packages/qa/dogfood/test/authz-conformance.test.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
22
//
3-
// ADR-0056 D10 — the authorization conformance matrix is a CHECKED artifact.
4-
// Refactored onto the reusable ADR-0060 `checkLedger` helper: one call asserts
5-
// every shared invariant (valid state, enforced-has-site, experimental/removed-
6-
// has-note, proof-file-exists, high-risk-has-proof). A new fail-open or a deleted
7-
// proof breaks the build.
3+
// ADR-0056 D10 — the authorization conformance matrix is a CHECKED artifact,
4+
// within the scope the mechanism can see: routes are ratcheted, primitives are
5+
// hand-maintained (see the matrix's own header for the narrowed claim and the
6+
// measured numbers — #8711). Refactored onto the reusable ADR-0060
7+
// `checkLedger` helper: one call asserts every shared invariant (valid state,
8+
// enforced-has-site, experimental/removed-has-note, proof-file-exists,
9+
// high-risk-has-proof). A row that regresses one of THOSE invariants, or a
10+
// deleted proof, breaks the build.
811
//
912
// #2567 Phase 2 — the anonymous-deny SURFACES are additionally pinned by the
1013
// `discover()` ratchet: this test STATICALLY enumerates the data/meta/graphql

0 commit comments

Comments
 (0)