Commit b91e40b
fix(dogfood): the authz conformance matrix rows state each decision in words instead of a tracker number (stage 5b) (#21265)
Fixes #20752
Clause-②: no
**Stage 5b, the last stage of the `domain:cli` lane under the
maintainer's A / A ruling (5902360492): the authz conformance matrix.**
Stages 1 to 5a (PR #21172, PR #21188, PR #21219, PR #21231, PR #21250)
emptied every other row of this lane; this PR empties the last one, so
the lane's share of the ledger burn-down is zero once it lands. Text
only: no row id, `state`, `covers` key, `proof` file or enforcement site
moves, and the file's code comments are untouched.
## What this does
The `summary`, `enforcement` and `note` strings of
`packages/qa/dogfood/test/authz-conformance.matrix.ts` sent the reader
to a tracker number for the reason behind a row. In form D, as the
earlier stages applied it, the number goes. Where the sentence already
said what was decided, only the citation goes. Where it leaned on the
number, it now says the decision in words.
All 76 ledgered occurrences of 46 cards, at 43 string sites (claim
`5942403129`, ledger read at `a23be7498e`): 16 `summary`, 10
`enforcement`, 17 `note` strings. 22 sites now say something in words;
21 already stated the decision and only lose the citation.
Every cited card was read first. Six answer 404 and were read through
the commit that decided them: 10243 (`266436a7f`), 12176 (`7986d973f`),
11757 (`4d25d22d4`), 8710 (`04d03c3a0`), 8711 (`2ce1eb41b`) and 8811
(`d6e793507`). The 10145 and 10243 phrases on the automation row reuse
stage 3's `route-ledger.ts` wording for the same decisions, and the 5519
floor is named the way stage 3 named it (the domain-wide anonymous
floor, refused before dispatch).
Two notes cite `describe` titles in other packages that carry a
bracketed tag. Those titles are quoted without the tag, so each quote
stays a literal substring of the real title and is still findable by
search.
### The 43 sites (line numbers are the same at base and head)
| Site | Cited | Form | The text now says (new fragment) | Decision read
from |
|---|---|---|---|---|
| `:161` `rls-by-id-write` summary | 1994 | citation only | by-id write
enforcement | PR 1994 (RLS re-checked on the pre-image of a by-id
update/delete) |
| `:162` `rls-by-id-write` enforcement | 7665 | citation only |
write-scope DERIVATION: when no update/delete-class policy applies |
card 7665 via PR 7792 (an empty write-class policy set derives its scope
from the caller's select narrowing); the sentence after the colon
already says it |
| `:164` `rls-by-id-write` note | 7685, 7665, 7665, 7792, 7685 | words
(tag dropped; three phrases worded) | Re-verified ... — that was the
hole through which a contributor PATCHed records it could not read, and
... since the fix that derives a missing write scope from the select
narrowing, that file carries ... whose probe persona holds object
read+edit narrowed by select-only RLS and so reaches this class — | card
7665 (a by-id write was not gated by record visibility under select-only
RLS); PR 7792 (option A: derive the write scope from the select
narrowing); card 7685 comment 5264791326 (measurement first: a probe
persona with object read+edit narrowed by select-only RLS; both rows
stay enforced) |
| `:174` `controlled-by-parent` note | 7685, 7665 | tag dropped; one
phrase worded | Re-verified as `enforced` on its OWN evidence ... when
the select-derived write-scope derivation its master depends on is
ablated. | card 7685 comment 5264791326 (re-verified by measurement, not
downgraded); card 7665 / PR 7792 |
| `:177` `multi-tenant-write-postimage` summary | 2937 | words | (forged
INSERT / Finding 1 re-point — a forged OR re-pointed organization_id
cannot cross the tenant wall) | card 2937 (an INSERT carrying a forged
organization_id crossed the tenant wall; Layer 0 gains an insert
post-image check) |
| `:179` `multi-tenant-write-postimage` note | 2937, 2937, 2937 |
citation only + suite titles named in words | INSERT a forged
cross-tenant organization_id or UPDATE ... (the "Layer 0 insert
post-image tenant guard" suite + the Finding 1 "Layer 0 update
post-image tenant guard (cross-tenant re-point)" suite) | card 2937; the
two describe titles in plugin-security/authz-matrix-gate.test.ts, quoted
without their bracket tags so each stays a substring of the real title |
| `:181` `multi-tenant-exemption-posture` enforcement | 2956 | citation
only | reads the carried ctx.posture rung (ADR-0099 D1) | PR 2956 (carry
the derived posture rung on ExecutionContext); the phrase 'the carried
ctx.posture rung' already says it |
| `:182` `multi-tenant-exemption-posture` note | 2937 | suite title
named in words | (the Finding 2 "Layer 0 cross-tenant exemption requires
the platform posture" suite + "ADR-0099 P1 ...") | the describe title in
plugin-security/authz-matrix-gate.test.ts |
| `:195` `org-write-validation` note | 2937 | words | — the
forged-organization_id INSERT defect one call site down. | card 2937 |
| `:213` `anonymous-deny-meta` summary | 2567 | words | (uniform
anonymous posture, surface 1) | card 2567 (the anonymous-deny posture
must be uniform across every HTTP surface that reaches ObjectQL) |
| `:228` `anonymous-deny-meta` note | 11373, 12176 | citation only +
words | For most of this row's life ... five since the retirement of
slash-bearing metadata item names un-mounted the compound save | card
11373 (measure first; the note goes on to state the measured refusal);
card 12176 answers 404, read through landing commit 7986d97 (stage 3
of the ruled retirement of slash-bearing metadata item names: un-mounts
the compound arities) |
| `:236` `anonymous-deny-actions` summary | 2567, 5519 | words |
(uniform anonymous posture, surface 2: refused 401 before dispatch, as
`/data` and `/meta` are) | card 2567; card 5519 (anonymous /actions and
/automation requests are refused 401 before dispatch, the same baseline
as /data and /meta) |
| `:244` `anonymous-deny-actions` note | 5519 | words | — before the
gate, an anonymous `POST /actions/showcase_task/showcase_mark_done/:id`
was measured answering 200 with the update applied. | card 5519 |
| `:245` `anonymous-deny-automation` summary | 2567, 5519 | words |
(uniform anonymous posture, surface 3: refused 401 before dispatch, as
`/data` and `/meta` are) | card 2567; card 5519 |
| `:246` `anonymous-deny-automation` enforcement | 10145, 10243, 7900,
3801, 5561 | words (stage 3 route-ledger twin wording) | DELETE /:name`,
the definition writes on the metadata plane, plus enablement `POST
/:name/toggle` since the 2026-08-23 ruling that enablement is an
authoring write, ... the run-state reads (the `sys_automation_run` read
grant) and `resume` (keyed on the node the run is suspended on,
fail-closed for a node that declares no resumeAuthority) carry their own
| card 10145 (flow definition writes are authored metadata, so
manage_metadata gates them); card 10243 answers 404, read through
landing commit 266436a (enablement is an authoring write, ruling of
2026-08-23); card 7900 via commit 627e65a (run-state reads consult
the sys_automation_run read grant); card 3801 (resume gated on the
suspended node); card 5561 (no declared resumeAuthority fails closed);
the 10145 and 10243 phrases reuse stage 3's route-ledger.ts wording |
| `:253` `anonymous-deny-automation` note | 5519 | words | which the
original anonymous-surface report did not record. | card 5519 |
| `:263` `anonymous-deny-packages` summary | 7033, 7023 | citation only
| anonymous-deny on the package-management surface | cards 7033 and 7023
(the /packages domain carried no authorization predicate; the row's
enforcement already states the domain-wide gate); same shape as the
sibling analytics row |
| `:300` `realtime-delivery-authz` summary | 2992 | words | (a latent
surface: identity admission is owed before any client transport ships) |
card 2992 (GraphQL and realtime must satisfy identity admission before a
client transport ships) |
| `:302` `realtime-delivery-authz` note | 9083, 9083 | tag dropped +
words | Clearing that red ... Before that admission rule landed, this
note promised a gate that did not exist | card 9083 (a TRANSPORT-WIRED
key may be classified only by an enforced row); the sentence after the
tag already says it |
| `:310` `mcp-http-identity` enforcement | 2698 | citation only | (403
on none) | card 2698 (OAuth 2.1 for /api/v1/mcp, scope-gated tool
families); the sentence already says it |
| `:320` `mcp-http-identity` note | 3167 | citation only | proven
end-to-end: the proof boots | card 3167 (identity admission first); the
sentence after the colon states what the proof drives |
| `:332` `readonly-static-write` summary | 2948, 3003, 3043 | citation
only + words | UPDATE AND INSERT (first at the data-write ingress;
in-engine ...) | cards 2948 and 3003 (strip static readonly on
non-system UPDATE); card 3043 (tighten the INSERT exemption, first
enforced at the data-write ingress) |
| `:333` `readonly-static-write` enforcement | 2948, 5591 | citation
only | (caller-supplied VALUES only — ... the caller also sent) | card
2948; card 5591 (strip the caller-supplied value, never a hook stamp);
the parenthetical already says both |
| `:335` `readonly-static-write` note | 3003, 3043, 3003 | words | The
originating field report: ... The INSERT face followed: ... a step
SHORTER than the draft-then-PATCH route, | card 3003 (readonly was
UI-only; a non-admin self-approved by PATCH); card 3043 (the INSERT
exemption let the same caller POST an approved record) |
| `:340` `declarative-rbac-seeding` summary | 2077 | citation only |
seeded at boot | card 2077 (activate declarative roles + sharingRules at
runtime) |
| `:355` `ownership-anchor-guard` summary | 3004 | citation only |
without the transfer grant | card 3004 (owner_id is system-managed for
non-privileged writers) |
| `:358` `bulk-write-owner-scoping` summary | 2982 | citation only | not
just single-id writes | card 2982 (bulk writes owner-scoped on
OWD-private objects) |
| `:361` `public-form-managed-anchors` summary | 3022 | citation only |
(owner_id / organization_id / audit / id) | card 3022 (a public-form
submit cannot supply owner_id or other server-managed anchors) |
| `:362` `public-form-managed-anchors` enforcement | 3004 | words |
complements the step 3.5 owner-anchor guard | card 3004 |
| `:378` `hierarchy-widening` enforcement | 7807 | citation only | the
runtime was narrowed to the declaration | card 7807 (business_unit
expands exactly one unit, as declared) |
| `:381` `rls-compiler-fail-closed` enforcement | 4983 | citation only |
hoisted out of plugin-security so lint/... | card 4983 (wire the
ADR-0056 D4 authoring gate to the one predicate definition) |
| `:385` `secure-by-default-posture` enforcement | 11757 | words | (the
gate's other carrier, sys_scim_provider, retired once the stable SCIM
line stopped deriving a provider model) | card 11757 answers 404, read
through landing commit 4d25d22 (retire the rc.1-era sys_scim_provider;
stable @better-auth/scim derives no scimProvider model) |
| `:387` `flow-run-as` summary | 1888 | citation only | under the run's
effective identity | card 1888 (enforce runAs) |
| `:390` `flow-run-as` note | 1888 | words | but its enforce-or-remove
decision chose ENFORCE and implemented it for flow data nodes | card
1888 (decision required: enforce or remove; enforced) |
| `:420` `permission-set-active` summary | 8613 | citation only |
(ADR-0049) | card 8613 (the active flag on both grant catalogues is
enforced) |
| `:422` `permission-set-active` note | 8613 | citation only | "the
`active` flag on the grant catalogues (ADR-0049)" | card 8613; the
describe title in core/security/resolve-authz-context.test.ts, quoted
without its tag so it stays a substring of the real title |
| `:423` `position-active` summary | 8613 | citation only | (ADR-0049) |
card 8613 |
| `:443` `grant-validity-window` enforcement | 10982 | citation only |
accessible_org_ids and the org-administration role projection | card
10982 (window-filter the role projection too); the present-tense list
already says it |
| `:445` `grant-validity-window` note | 8811, 8711, 8710, 10982, 11089,
10982, 9377, 7976 | tags dropped + words | NO `covers` ... Per the
2026-08-15 maintainer ruling ... by the 2026-08-15 ruling that
access-conferring paths filter and addressing paths do not, because
approval ROUTING ... `sys_member` ... last-admin-guard.ts's ... the role
projection as window-filtered now; ... is now cited: ... the
mutual-attribution contract (a cited proof file names the rows it
proves) is satisfied. | 8811 (404) via d6e7935 (adds this row); 8711
(404) via 2ce1eb4 (ruled narrowing of the completeness claim to
routes); 8710 (404) via 04d03c3 (ruling 2026-08-15: access-conferring
paths filter deactivated positions, addressing paths do not); card
10982; card 11089 (the last-admin-guard note went stale after 10982);
card 9377 (cite delegation-of-duty as this row's proof); card 7976 (a
proof file names the rows it proves, checked both ways) |
| `:452` `agent-visibility` summary | 1901 | citation only | listing
scope | card 1901 (agent visibility not enforceable without owner/org
anchors; removed per D8) |
| `:453` `agent-visibility` note | 1901, 1884 | citation only |
`visibility` deleted) ... at the chat route; | card 1901; card 1884
(enforce access/permissions at the chat route) |
| `:462` `requireAuth-removed` note | 3963, 7976 | words + tag dropped |
ADR-0056 D2, completed by deleting the switch once every session-less
surface was declared: the `requireAuth: false` opt-out is RETIRED ...
The `showcase-anonymous-deny.dogfood.test.ts` CITATION WAS DROPPED |
card 3963 (step 1: public as a declared capability; step 2: delete
api.requireAuth, an auth-less stack fails at boot); card 7976 (mutual
attribution, already named in the sentence) |
| `:466` `allow-transfer-restore-purge` note | 1883, 3004, 12497, 1883 |
words + citation only | ADR-0049 → roadmap M2, which builds the
lifecycle ops and their RBAC bits as one batch: the ops still do not
exist ... owner_id door. ... RETIRED 2026-08-26 (maintainer ruling:
retire the two bits now rather than carry them unenforceable until M2):
| card 1883 (M2: build undelete/purge and their RBAC bits in one batch);
card 3004; card 12497 (ruled 2026-08-26: retire allowRestore/allowPurge,
the keys return with M2) |
## The ledger
`scripts/doc-authoring-prose-id.baseline.json`, recomputed with `node
scripts/check-doc-authoring.mjs --census-ledger` (refuses any growth):
| | occurrences | (file, id) pairs | files | matrix row |
|---|--:|--:|--:|--:|
| base `434c6c7cab` | 359 | 251 | 87 | 76 occurrences / 46 cards |
| head | 283 | 205 | 86 | absent |
- Exactly the matrix row leaves: 48 lines deleted, 0 added. The other 86
rows compare equal as JSON.
- Recomputed again after merging `origin/main` (`8dea55d314`):
byte-identical.
- `pnpm check:doc-authoring`: exit 0 before and after. Its cross-package
line reads 300 pinned sites across 87 files at base and 257 across 86 at
head, "no growth, no burn-down unrecorded".
- The census's other 257 sites are the same before and after (file, line
and ids).
## Text only
A scratch TypeScript-AST comparison of the file at base `434c6c7cab` and
head: 1695 skeleton nodes on both sides, identical; 280 string literals
on both sides, 43 values changed, owned by `summary` 16, `enforcement`
10, `note` 17 and nothing else; 255 comment trivia blocks on both sides,
byte-identical. Its three controls each behave: a renamed property key
reads "skeleton DIFFERS", a changed `state` value is reported as owned
by `state`, and an edited comment reads "not identical".
## Pins
None. Nothing mechanical reads these three fields: the companion test
imports the rows for `id`, `state`, `proof`, `covers` and `enforcement`
presence, and the census and blind-spot test read only the header
docblock and the `covers` arrays. A whole-repo fixed-string search for
the text around each of the 76 removed ids (224 fragments, `docs/qa/**`
included) found 12 fragments with hits, every one a code comment, a
release-owned CHANGELOG entry, a `describe` title or a liveness note,
none asserting this file's text. So no pin moved and no ablation is
owed.
## Verification
- Build: `pnpm turbo run build --filter='@objectstack/dogfood^...'
--concurrency=2`: 63/63 tasks.
- Tests: `pnpm --filter @objectstack/dogfood exec vitest run
--maxWorkers=2 test/authz-conformance.test.ts
test/authz-probe-blind-spot.test.ts`: 2 files, 90 tests passed. These
are the only consumers of the module and of its text.
- Typecheck: `pnpm --filter @objectstack/dogfood typecheck` exit 0;
`--listFilesOnly` lists the matrix file and the companion test.
- Gates: `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands` at `3005a8b6d1` derives 54
commands; all 54 run, exit 0. `check:dual-build-cjs-loads` first
answered exit 3 (PREREQUISITE NOT MET: 8 unrelated packages without
`dist/`); after a full workspace build (72/72) it exits 0 and that rerun
is the recorded result. `--ran` reconciliation: 54 derived, 54 run, 0
NOT-MEASURED, 0 UNRUN.
- Lint: full `pnpm lint` at `3005a8b6d1`: exit 0, no findings.
- Tests and typecheck ran at `0dbdbd759b`; the merge after it brought
one `docs/adr` file and no package input.
## Changeset
None, with `skip-changeset`: `@objectstack/dogfood` is `private: true`,
and the ledger is a repository script file. No `.changeset/*.md` is
touched.
## Acceptance notes
- **Code comments** in the matrix file still cite cards (33 comment
lines, the bracketed tracker tags and the block-comment headers among
them). They are not runtime strings and not on the ledger, so they are
outside ruling 5902360492 and this claim. Noted, not filed.
- **Two `describe` titles the notes quote** carry a bracketed tag:
`plugin-security/src/authz-matrix-gate.test.ts` (the Layer 0 insert,
update and exemption suites) and
`core/src/security/resolve-authz-context.test.ts` (the `active`-flag
suite). Test bodies are outside the gate's reading and belong to those
packages, not to this lane. Noted, not filed.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 2791138 commit b91e40b
2 files changed
Lines changed: 43 additions & 91 deletions
File tree
- packages/qa/dogfood/test
- scripts
0 commit comments