Skip to content

docs(plugin-auth): re-anchor the dead tracker citations to the commits that decided them - #20634

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-20596-plugin-auth-citations
Sep 29, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-20596-plugin-auth-citations

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #20596
Clause-②: no

What changed

This is the third stage of the domain:services lane of the dead-citation sweep. It covers packages/plugins/plugin-auth/src/** and nothing else. By census, it is the largest package in the lane that no open PR or in-flight claim holds (the claim, 5888562941, gives the order). Later stages cover the other packages, so this PR says Part of and the card stays open.

Every comment or docblock site in scope that cited a tracker number answering 404 has been rewritten in ruling C+D's form C (comment 5749154545 on #19123), by the method of stages 1 and 2 (PR #20609 as 422db788a, PR #20626 as b80ab579d). That is 95 sites on 95 lines in 31 files, covering 16 numbers:

  • the 52 census sites (all of this package's census sites);
  • 38 sites in test comments, which the census defers;
  • 5 sites in the hyphen-joined spelling #13398-class, which the gate's extractor does not match at all (see Acceptance notes).

Each rewritten line now cites the commit in origin/main history that decided what the line describes, and it says in its own words what that commit decided. No ADR or ruling-record file records the decision behind any of the 16 numbers, so every anchor is a commit: 15 distinct shas (#11477 and #12029 share one, because #12029 was the pull request that settled #11477). No number was dropped.

Only comments changed. Every touched source file keeps its line count (107 lines out, 107 in, over 31 files), so no line citation into these files moves. 12 of those 107 lines hold no dead citation; they are reflow or a lost referent, listed under Wordings below. No code token moves (see the guard below).

No citation number is added. Every tracker number on an added line was already on the line it replaces. Over the whole diff, added minus removed is 0 or negative for every number (the gate's own extractCitations over the diff: 103 citations removed, 13 added, all 13 kept resolving numbers), and no number is new to the diff. No PR number stands on an added line.

Twenty-one dead sites are left on purpose, all of them test titles (see the list below).

One more file: a patch changeset for @objectstack/plugin-auth, because the rewritten docblocks ship (see Changeset below).

Census: plugin-auth, before and after

Instrument (A1). The gate's own node scripts/check-issue-citations.mjs --census --json, read-only and unchanged. The count below is its allocated-but-absent findings under packages/plugins/plugin-auth/. Each run counts as a reading only because its board frontier equals the newest issue number, read by a separate request just before and just after the run.

reading tree board whole-repo allocated-but-absent plugin-auth sites lines files numbers
before base b80ab579d, run 2026-09-29T10:43:31Z to 10:47:03Z enumerated, 185 pages, frontier #20629 (newest #20628 before, #20629 after), 18,456 numbers 1,955 52 52 13 12
after head 5ae64e8b8, run 11:12:05Z to 11:15:37Z enumerated, 185 pages, frontier #20630 (newest #20630 before and after), 18,457 numbers 1,903 0 0 0 0

The before count matches the 52 that census 5884031174 read at f11b5f20. The whole-repo drop is 52, exactly this diff's census sites. The resolves tally is 32,832 in both runs, and resolves-as-pull-request (1,984) and cross-repo-unjudged (995) did not move either. No run was truncated or discarded: all three enumerations in this stage (two census runs and the supplementary board below) read 185 pages at the newest frontier.

Supplementary instrument, the whole scope. The census does not read test files or strings, and this stage's scope includes test comments. So a second reading runs the gate's own exported extractCitations (whole-file and comment-prose projections) and classifyCitation over every .ts file under plugin-auth/src (178 files). It uses one board, enumerated by the gate's own enumerateBoard at 10:50:47Z (185 pages, frontier #20629, equal to the newest).

reading citations dead src comment test comment src string test string
before, b80ab579d 2,150 111 52 38 0 21
after, 9fd0ebf10 2,060 21 0 0 0 21

Its src-comment column equals the census's 52, which is the control on the second instrument. The 1,966 resolving, 46 pull-request and 27 cross-repo citations are the same in both readings. Neither instrument sees the 5 #13398-class sites; a plain grep for the 16 numbers over plugin-auth/src at the head finds only the 21 test titles (and the digits 11477 inside test fixture e-mail addresses and a password, which are code tokens, not citations).

Per-number table

Sites and files count all dead sites the gate sees in scope at the base (comments and strings, tests included). rewritten / left counts the sites rewritten and the sites left. Each anchor was read in its message and diff, not only its subject.

number sites / files rewritten / left anchor: what it decided
#8676 22/6 18/4 d6e80b28b: sys_account.password and previous_password_hashes are flagged internal: true, and every reader is recovered through the engine's privileged accessor (the adapter readback table gains password; plugin-auth's own raw-engine reads get recoverInternalFieldsForSystemRead). Its subject names #8676
#8734 4/2 3/1 f8eb73601: the last-admin guard's standing-key lists are bound to what resolveAuthzContext actually reads (STANDING_KEYS_BY_TABLE / STANDING_KEY_EXCLUSIONS and the correspondence gate). Its subject names #8734
#10165 1/1 1/0 801296050: lifecycle ttl gains an onlyWhen row filter (maintainer ruling option A on #10165, quoted in its message). The same anchor the spec stages gave this number
#10366 3/2 2/1 bbe643c08: the localhost trusted-origin substitution is gated to non-production. Its diff writes both rewritten lines and its changeset names #10366
#11343 19/8 18/1 c0714eb5d: walled platform-admin elevation requires a VERIFIED owner-email match (a fail-closed allow-list over email_verified), the bootstrap replays on the verifying sys_user update, and the dev-admin seed stamps its account verified. Its message names #11343 as the card it completes
#11477 6/3 3/3 6dd3e6968: /admin/remove-user gets the raw-mount shading /admin/ban-user has, so authorization runs before the break-glass guard (ruled option A on #11477, as its message records)
#11626 1/1 1/0 a6eca9223: check:engine-double-contract admits a single-verb engine double on the contract it DECLARES, a second admission route beside sibling inference. Its diff names that route #11626
#11640 11/6 7/4 bf8d129b5: a walled deployment whose declared owner has no verification path gets a loud, named warning at boot, and boot proceeds (maintainer ruling 2026-08-25, option A). Its subject names #11640
#11741 4/2 2/2 b706af987: SendEmailInput gains an optional organizationId, threaded from the producers that hold one (the invitation among them). The same anchor stages 1 and 2 and the spec stages gave this number
#11757 4/4 4/0 4d25d22d4: the rc.1-era sys_scim_provider platform object is retired. Every #11757 site in the tree before it says the object "retires under #11757"
#12029 2/2 2/0 6dd3e6968: #12029 was the pull request itself; this is its squash commit, the gate-then-delegate mount on /admin/remove-user
#13398 6/2 3/3 e238c79f0: the published-sink ruling, that raising a log level must never widen a published sink. No record of the ruling exists in the repo; this commit's pin is the earliest text in history that records it (see Wordings)
#14762 21/4 19/2 35e94c96b: auth OTP SMS and auth mail read the recipient's own sys_user.locale, one rung above the request and the deployment default, in the order ruled for #14788. Its diff carries #14762 24 times
#14902 3/2 3/0 61821e54c: a plain unique index over duplicate rows is loud and non-fatal (the boot continues), and os migrate plan stops calling it safe. Its message names #14902 as the card it ends
#14998 2/1 2/0 f1e91595f: the batch-6 admin endpoint graphs load at module top, not inside each clocked case, which removed the cold-import timeout flake
#15092 2/1 2/0 9e9f03abe: settleSelfRegistrationGrant's trailing filter no longer silently DROPS a malformed permission-set row; it refuses. The only commit in history that names #15092

Plus 5 #13398-class sites the gate does not extract, anchored like the other #13398 sites: boot-sign-in-reachability.ts:109, :512, boot-sign-in-reachability.test.ts:595, tenancy-service.ts:249, :257-258.

Every cited sha matches exactly one commit (git rev-parse --disambiguate, count 1 for each), and every one is an ancestor of the base (merge-base --is-ancestor, exit 0 for all 15; the history is complete, --is-shallow-repository false, 15,083 commits). A line-origin pickaxe (git log -S on each dead line's exact text) found each line entering either in its anchor commit or in a later commit that cites that commit's decision: for example 4d5b4f832 (the operator-provisioned stamp) and 4f65837a7 (the L3 re-anchor) cite c0714eb5d's verified-owner rule, f074616e6 (invitation locale) cites 35e94c96b's stored rung, 8064e6da1 (the has-permission mount) cites 6dd3e6968's seam, and 9bd4344e4 carries the account-identity-preflight text that cites 61821e54c.

Wordings to check

  • #13398 → e238c79f0, and not stage 2's 953a81f4a. Stage 2 anchored its one #13398 site at 953a81f4a (2026-09-02) as the earliest application of the published-sink ruling. In this package, e238c79f0 (2026-08-31) already records it: its pin in durability-swallow-repair.test.ts says raising the level "means widening a published sink — refused as actively harmful by the maintainer's" ruling. It is earlier, and it is in this package, so it is the anchor here. Its own commit message still calls the level "[Decision] plugin-sharing's refused-backfill report lands at warn where AGENTS.md puts it at error — and the card that was supposed to carry the level is CLOSED #13398's question", which is why the lines say "the published-sink ruling (commit e238c79)" rather than claiming that commit made the ruling.
  • Reflow, 11 lines with no dead site (every file keeps its line count):
    • auth-manager.ts:7554-7557: 「routes that LEVEL question to the published-sink ruling (commit e238c79) and tells this batch to fix the SILENCE only」, the rest of the paragraph reflowed unchanged (3 lines).
    • durability-swallow-repair.test.ts:36-40 (4 lines) and :527-529 (2 lines): the same substitution, and 「which routes that question there」 became 「which keeps that question」, because "there" pointed at the number.
    • tenancy-service.ts:257-258: 「exactly what the sink ruling (commit e238c79) forbids」 (1 line).
    • find-envelope-limb-removal.test.ts:47-48: 「also carried the silent-DROP shape, and commit 9e9f03a fixed it in the OPPOSITE direction」 (1 line).
  • A lost referent, 1 line. auth-plugin.ts:2738-2739: 「(the fix(auth): authorize before the break-glass guard on /admin/remove-user #12029 worked reading — a shadow is accounted for …)」 became 「(as it read commit 6dd3e69's remove-user mount — a shadow is accounted for …)」. check:auth-mount-ledger has counted a shadowing mount since 26dea1495; the "worked reading" was that PR's application of it to /admin/remove-user, which 6dd3e6968 mounts.
  • sys-session-ttl-sweep.test.ts:230: 「the naive policy commit 8012960 existed to make avoidable」, where 801296050 is the ttl.onlyWhen filter the ablation removes.
  • durability-swallow-repair.test.ts:62: the flake report became a pointer to the commit that removed the flake (f1e91595f), with #15603 kept beside it.
  • auth-manager.ts:5629: 「the pre-plugin-auth: auth SMS (OTP / invite texts) and request-less auth mail keep the deployment locale — sys_user.locale exists now and is not read #14762 deployment-default behaviour」 became 「the deployment default, as before commit 35e94c9」.

The 21 sites left

  • Test titles (21 sites). describe / it titles, which are string tokens: admin-remove-user-gate-ordering.test.ts:207, :263, :298 (#11477), auth-email-locale.test.ts:528 and auth-manager.test.ts:2545 (#14762), auth-manager.test.ts:1562 (#10366), :2866, :2880 (#11741), :4105 and internal-field-readback.test.ts:219, :230, :286 (#8676), auth-plugin-walled-owner-verification-path.test.ts:87, :193, :317, :384 (#11640), durability-swallow-repair.test.ts:159, :567, :670 (#13398), last-admin-standing-keys.test.ts:61 (#8734) and walled-owner-operator-stamp.test.ts:355 (#11343). Tokens, left as they were, as stages 1 and 2 left theirs.
  • There is no non-test string, no generated file and no quoted ruling carrying a dead number in this package.

Mechanical guard: no code token moves

The guard compares the TypeScript parser's leaf nodes, with comments as trivia and JSDoc nodes excluded, base b80ab579d against head. Template literals are therefore read in context. It ran over all 31 touched .ts files.

  • Real run: 158,646 base tokens, 0 files with a token change (exit 0).
  • Comment control in auth-manager.ts (As above — the flagged column to Likewise — the flagged column): 0 files changed, as expected (exit 0).
  • Positive control, a code token changed in auth-manager.ts (a fourth element added to the fields projection of the password-reuse read): DIFFER (exit 1).
  • Positive control, one digit changed inside a kept test title (admin-remove-user-gate-ordering.test.ts:207): DIFFER (exit 1).

Every mutation went through scripts/ablation-replace.mjs, and each landed (anchor 1 to 0, blob changed). Each restore was proven byte-identical to the HEAD blob (c0bdef025a39, ec83f09f556e), with git diff HEAD empty and a clean tree afterwards.

Changeset

This change ships bytes, so a patch changeset for @objectstack/plugin-auth (.changeset/20596-plugin-auth-provenance-anchors.md) is included. It says only that the provenance comments were re-anchored.

Measured on the built package (A3): files[] is dist, README.md and CHANGELOG.md. After the build, the rewritten comments reach dist: 35e94c96b appears 8 times in each of dist/index.d.ts, index.d.mts, index.js and index.mjs; f8eb73601 twice in each declaration file; bf8d129b5 and e238c79f0 once in each of the four; d6e80b28b and 4d25d22d4 twice in each runtime file; c0714eb5d and 61821e54c once in each declaration file; b706af987 once in each runtime file. Positive control: the unchanged line 「read best-effort off the identity row.」 beside a shipped rewrite is found once in index.d.ts and once in index.js. A never-written negative phrase appears nowhere. No dead number of the 16 is left anywhere in dist.

Gates (head 5ae64e8b8)

  • Citation judging, as CI runs it: pnpm check:issue-citations (self-test) exits 0. node scripts/check-issue-citations.mjs exits 0: the diff-scoped run judged 5 citations across 14 files, and all 5 resolve.
  • Doc authoring: pnpm check:doc-authoring exits 0, with the sibling-package prose ids at their baseline and no growth.
  • Derived gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 5ae64e8b8 derived 65 commands: all 57 derived at dispatch, plus check:duration-unit-keys, check:engine-double-contract, check:logger-receiver-detach, check:objectql-double-limit, check:query-options-erasure, check:type-check-coverage, check:type-check-debt and check:where-matcher. It was re-derived after a fresh git fetch (origin/main a918fe7fd, 2 commits ahead, neither touching plugin-auth): the same 65. Each ran with its exit code captured before any pipe, and all 65 exit 0. --ran, fed each command with its exit code, reports 65 run, 0 NOT MEASURED (a derived zero), 0 unrun, and exits 0. A full turbo run build of ./packages/* and ./packages/*/* ran first under the shared verify lock (71 of 71 tasks, exit 0), so no gate hit an unbuilt workspace.
  • Tests and typecheck, under the verify lock:
    • pnpm --filter @objectstack/plugin-auth test: 115 files and 2,464 tests pass. That is every test file in the package, the 17 touched ones included.
    • pnpm --filter @objectstack/plugin-auth typecheck exits 0 (tsc main, tsconfig.examples.json, and check:test-typecheck held at its ledger). The main program reads 63 non-test files; the tsconfig.test.json program reads all 178 files under src/, the 115 test files included, and all 31 touched files are in it (--listFiles).
  • Lint, as a proven narrowing: eslint --no-inline-config --format json over the 31 touched .ts files gives 31 files, 0 errors and 0 warnings. All 31 are in eslint's own population (isPathIgnored is false for each). eslint.config.mjs never enables type-aware linting (no parserOptions.project, as its own line 328 states), so a comment edit here cannot move the verdict on any untouched file. The repo-wide pnpm lint is CI's run.
  • Control bytes: pnpm check:nul-bytes exits 0, and a raw scan of the 32 changed files for control bytes finds none.

Acceptance notes

  • The gate's extractor does not see a hyphen-joined number. CITATION_RE ends in a lookahead that refuses a following hyphen, so #13398-class is not a citation to either the diff gate or the census, dead or alive. This stage rewrote the 5 such sites in plugin-auth because they are the same dead number in the same comment prose. At the head, 10 dead #N-word sites remain in packages/**/src (a raw line scan of .ts files against the cached board): service-automation 5 (all #13398-class), rest 2, plugin-security 1, runtime 1, spec 1. The census cannot count them, so a later stage reaching those packages has to look for them by hand. No instrument change here.
  • The census instrument did not truncate in this stage. Three enumerations read 185 pages each at the newest frontier.
  • Anchors the next stages can reuse. These numbers stand elsewhere on the census at the head: #11343 in plugin-security (6) and types (2), anchor c0714eb5d; #14902 in driver-sql (7) and cli (1), anchor 61821e54c; #13398 in service-automation (4, plus the 5 hyphen-joined sites), anchor e238c79f0; #8734 in core (2), anchor f8eb73601; #10165 in objectql (2) and platform-objects (1), anchor 801296050; #11757 in platform-objects (2), anchor 4d25d22d4; #11741 in plugin-email (2), anchor b706af987; #8676 in platform-objects (1), anchor d6e80b28b.
  • Base. The branch is 2 commits behind origin/main (a918fe7fd, read at 11:20Z). Neither touches plugin-auth, this changeset or any of these 16 numbers, so there was no merge.

Generated by Claude Code

…s that decided them

Comment and docblock prose under packages/plugins/plugin-auth/src only. Each
site that cited a tracker number answering 404 now cites the commit in this
repository's history that decided what the line describes, and says in its
own words what that commit decided. 95 sites on 95 lines in 31 files, 16
numbers, 15 anchor commits; 12 further lines are reflow or a lost referent.
No code token moves; every file keeps its line count.

Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Sep 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-auth, touching 14 documentable anchor(s). ⚠️ 8 changed file(s) yielded no anchor (packages/plugins/plugin-auth/src/account-identity-preflight.ts, packages/plugins/plugin-auth/src/admin-has-permission-endpoint.ts, packages/plugins/plugin-auth/src/boot-sign-in-reachability.ts, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/kernel/contracts/auth-service.mdx (via AuthManager (symbol, a top-level class))
  • content/docs/kernel/services-checklist.mdx (via AuthManager (symbol, a top-level class))
  • content/docs/permissions/authentication.mdx (via AUTH_MODEL_TO_PROTOCOL (symbol, a top-level const object), AuthManager (symbol, a top-level class))
What this run could not see
  • 8 changed file(s) yielded no anchor (packages/plugins/plugin-auth/src/account-identity-preflight.ts, packages/plugins/plugin-auth/src/admin-has-permission-endpoint.ts, packages/plugins/plugin-auth/src/boot-sign-in-reachability.ts, …) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 15 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 3f45b6cc13fb4646fab723a517225aa911cf17b8 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from c4a47225ecdc86307e57be0db6d528e010b2c3fb — the merge of head 5ae64e8b84d7913079dd4f172d05d54f279de4dc into base 3f45b6cc13fb4646fab723a517225aa911cf17b8, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin c4a47225ecdc86307e57be0db6d528e010b2c3fb && git checkout c4a47225ecdc86307e57be0db6d528e010b2c3fb
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 3f45b6cc13fb4646fab723a517225aa911cf17b8 5ae64e8b84d7913079dd4f172d05d54f279de4dc && git checkout -B drift-repro 3f45b6cc13fb4646fab723a517225aa911cf17b8 && git merge --no-ff 5ae64e8b84d7913079dd4f172d05d54f279de4dc

node scripts/docs-audit/affected-docs.mjs --json 3f45b6cc13fb4646fab723a517225aa911cf17b8

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 3f45b6cc13fb4646fab723a517225aa911cf17b8 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 29, 2026 12:03
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit 4d04b6b Sep 29, 2026
36 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20596-plugin-auth-citations branch September 29, 2026 12:18
veigajoao pushed a commit to veigajoao/objectstack that referenced this pull request Sep 29, 2026
…mmits and ADRs that decided them (objectstack-ai#20658)

Part of objectstack-ai#20596
Clause-②: no

## What changed

This is the fourth stage of the `domain:services` lane of the
dead-citation sweep. It covers `packages/plugins/plugin-security/src/**`
and nothing else. By census it is the largest package in the lane; it
waited while its own fixes were in flight, and the claim (`5890784382`)
records that they have all landed. Later stages cover the other
packages, so this PR says `Part of` and the card stays open.

Every comment or docblock site in scope that cited a tracker number
answering 404 has been rewritten in ruling C+D's form C (comment
5749154545 on objectstack-ai#19123), by the method of stages 1 to 3 (PR objectstack-ai#20609 as
`422db788a`, PR objectstack-ai#20626 as `b80ab579d`, PR objectstack-ai#20634 as `4d04b6be3`). That
is **266 sites on 258 lines in 51 files, covering 40 numbers**:

- 140 census sites (all of this package's census sites except the 3
generated headers, see below);
- 123 sites in test comments, which the census defers;
- 3 sites in comment prose that the gate's extractor does not match at
all: one hyphen-joined (`objectstack-ai#8919-era`) and two slash-joined second numbers
(`objectstack-ai#6483/objectstack-ai#6608`, `objectstack-ai#11184/objectstack-ai#11343`), see Acceptance notes.

Each rewritten line now cites the record in this repository that decided
what the line describes, and says in its own words what was decided. Two
numbers have an in-repo decision record, and it is preferred: `objectstack-ai#11082`
cites **ADR-0055's amendment** (2026-09-07, transitive chains compose),
and `objectstack-ai#6609` cites **ADR-0094 D5-R**, which records that conflict ruling
(option A, accept the tightening). Every other number cites the commit
in `origin/main` history that decided it: **36 distinct shas**. Three
pairs share one anchor because one number was the pull request that
settled the other (`objectstack-ai#6483` and `objectstack-ai#6608`, `objectstack-ai#16607` and `objectstack-ai#16722`, `objectstack-ai#16608`
and `objectstack-ai#16805`); `objectstack-ai#12143` was itself a pull request, and its squash commit
`f64668d3c` is also where route A (`objectstack-ai#11374`) reached this plugin's key
columns. No number was dropped.

Only comments changed. Every touched source file keeps its line count
(266 lines out, 266 in, over 51 files), so no line citation into these
files moves. 8 of those 266 lines hold no dead citation; they are
reflow, listed under Wordings below. No code token moves (see the guard
below).

**No citation number is added.** Every tracker number on an added line
was already on the line it replaces. Over the whole diff, added minus
removed is 0 or negative for every number (the gate's own
`extractCitations` over the diff: 277 citations removed, 14 added, all
14 kept resolving numbers on the lines they already stood on), and no
number is new to the diff. No PR number stands on an added line.

Sixty-five dead sites are left on purpose: 60 test strings, 2 operator
log strings and 3 generated headers (see the list below).

One more file: a `patch` changeset for `@objectstack/plugin-security`,
because the rewritten docblocks ship (see Changeset below).

## Census: `plugin-security`, before and after

**Instrument (A1).** The gate's own `node
scripts/check-issue-citations.mjs --census --json`, read-only and
unchanged. The count below is its `allocated-but-absent` findings under
`packages/plugins/plugin-security/`. Each run counts as a reading only
because its board frontier equals the newest issue number, read by a
separate request just before and just after the run.

| reading | tree | board | whole-repo `allocated-but-absent` |
plugin-security sites | lines | files | numbers |
|---|---|---|---|---|---|---|---|
| before | base `cd901d7a5`, run 2026-09-29T13:00:53Z to 13:04:37Z |
enumerated, 185 pages, frontier objectstack-ai#20647 (newest objectstack-ai#20646 before, objectstack-ai#20647
after), 18,474 numbers | 1,707 | **143** | 140 | 22 | 28 |
| after | head `aa067dad3`, run 13:29:02Z to 13:32:37Z | enumerated, 185
pages, frontier objectstack-ai#20649 (newest objectstack-ai#20649 before and after), 18,476 numbers
| 1,567 | **3** | 3 | 3 | 1 |

The before count matches the 143 that census `5884031174` read at
`f11b5f20`. The 3 left are the generated `objectstack-ai#11671` headers. The
whole-repo drop is 140, exactly this diff's census sites. The `resolves`
tally is 32,878 in both runs, and `resolves-as-pull-request` (1,984) and
`cross-repo-unjudged` (995) did not move either. The after run was taken
on `aa067dad3`; the head `f90c9b123` adds only the changeset. No run was
truncated or discarded: all three enumerations in this stage (two census
runs and the supplementary board below) read 185 pages at the newest
frontier.

**Supplementary instrument, the whole scope.** The census does not read
test files or strings, and this stage's scope includes test comments. So
a second reading runs the gate's own exported `extractCitations`
(whole-file and comment-prose projections) and `classifyCitation` over
every `.ts` file under `plugin-security/src` (216 files). It uses one
board, enumerated by the gate's own `enumerateBoard` at 13:08:21Z (185
pages, frontier objectstack-ai#20647, equal to the newest).

| reading | citations | dead | src comment | test comment | src string |
test string |
|---|---|---|---|---|---|---|
| before, `cd901d7a5` | 2,746 | **327** | 143 | 123 | 2 | 59 |
| after, `aa067dad3` | 2,483 | **64** | 3 | 0 | 2 | 59 |

Its src-comment column equals the census's 143, which is the control on
the second instrument. The 2,307 resolving, 88 pull-request and 24
cross-repo citations are the same in both readings. A third, raw reading
(every `#` followed by digits, judged against the same board, whatever
surrounds it) finds 331 dead occurrences before and 65 after: the 4 it
sees beyond the gate are the three prose sites above and one more second
number inside a kept test title.

## Per-number table

Sites and files count every dead occurrence in scope at the base
(comments and strings, tests included, gate-invisible spellings
included). `rewritten / left` counts the sites rewritten and the sites
left. Each anchor was read in its message and diff, not only its
subject.

| number | sites / files | rewritten / left | anchor: what it decided |
|---|---|---|---|
| `objectstack-ai#6206` | 2/1 | 1/1 | `8e13ca876`: share-link enforcement takes the
whole authz envelope (option-A ruling); it adds this package's
`group`-posture repro. Stage 2's anchor |
| `objectstack-ai#6216` | 1/1 | 1/0 | `f586f1a89`: one `ExecutionContext` assembler,
with the closed-field-set pin. The anchor the spec, runtime and rest
stages gave it |
| `objectstack-ai#6483` | 14/5 | 14/0 | `ee58392e1`: ADR-0005's allow-list enforced,
nine unapproved types (`permission` among them) rolled back to
`allowOrgOverride: false`. Its message records the zero-row measurement,
the `allowRuntimeCreate` boundary and this suite's stub blind spot. The
spec stages' anchor |
| `objectstack-ai#6564` | 1/1 | 1/0 | `54299caad`: the per-row `ISharingService` write
verdict becomes tri-state (allow / abstain / deny); `objectstack-ai#6564` was that
pull request |
| `objectstack-ai#6608` | 11/5 | 11/0 | `ee58392e1`: `objectstack-ai#6608` was the pull request
itself; this is its squash commit |
| `objectstack-ai#6609` | 3/2 | 3/0 | ADR-0094 D5-R: the record of that conflict
ruling (option A, accept the tightening), executed by objectstack-ai#6858 |
| `objectstack-ai#8692` | 10/3 | 9/1 | `712e185db`: the 2026-08-15 ruling, option A:
the seed insert stamps `managed_by: 'platform'` explicitly, forward
only, and the resync skip warn stops claiming intent |
| `objectstack-ai#8714` | 15/2 | 10/5 | `42b05af89`: explain reports a deactivated
permission set or position through the shared held-state vocabulary. The
anchor the spec stage gave it |
| `objectstack-ai#8757` | 14/3 | 10/4 | `6feac910b`: the 2026-08-15 ruling: the master
gate is the sole row-write authority for a `controlled_by_parent`
detail; delegated writes keep both floors |
| `objectstack-ai#8772` | 5/2 | 5/0 | `8abada3ba`: the freeze note, Direction 4 of the
2026-08-16 master-reference ruling; it names the two ramp legs and the
three shapes this guard alone refuses |
| `objectstack-ai#8778` | 2/1 | 1/1 | `7901b2dd2`: option A, a stamp-only,
read-neutral `tenancy.organizationField`. The spec stage's anchor |
| `objectstack-ai#8804` | 2/1 | 2/0 | `db923a3a8`: `objectstack-ai#8804` was the measurement pull
request: a seeder-created row is stored `'admin'`, and resync reports
resynced 0 / resyncSkipped 8 |
| `objectstack-ai#8839` | 7/3 | 6/1 | `c25b2d52a`: the 2026-08-15 ruling, reading 1:
one per-object `sys_comment` delete policy, so moderation stops being
dead behind the floor |
| `objectstack-ai#8865` | 14/2 | 12/2 | `498f4e884`: the 2026-08-15 ruling, direction
1: leg 1 of the master gate drops the platform ownership floor on a
sharing `allow` |
| `objectstack-ai#8919` | 1/1 | 1/0 | `b5378550e`: `/meta` publish and rollback gated
on `manage_metadata`; it created the write-door census whose count rule
the line applies. The rest stage's anchor |
| `objectstack-ai#11082` | 18/2 | 13/5 | ADR-0055's amendment (2026-09-07):
`controlled_by_parent` composes across a chain, bounded, failing closed.
One implementation-only line (the factory split) cites `61713314e`, the
commit that landed it |
| `objectstack-ai#11343` | 13/6 | 12/1 | `c0714eb5d`: walled elevation requires a
VERIFIED owner-email match, and the bootstrap replays on the verifying
`sys_user` update. Stage 3's anchor |
| `objectstack-ai#11374` | 3/2 | 2/1 | `3954fb7df`: route A, the 2026-08-24 ruling to
declare a sourced `maxLength` on every keyed text column; the
object-file line cites `f64668d3c`, which applied it to this plugin's
key columns |
| `objectstack-ai#11451` | 20/4 | 18/2 | `c33f18592`: the curated half's existence
read becomes one batched `$in` carrying the `objectstack-ai#8470` predicate; the
reconcile is equality-gated; the derived half's batching is filed, not
decided |
| `objectstack-ai#11518` | 35/7 | 31/4 | `e1d773eb7`: the unscoped existence page cap
is measured, not trusted: one row more than the budget, and an
overflowing page degrades loudly to the per-item read |
| `objectstack-ai#11520` | 17/2 | 15/2 | `1a6855226`: the derived half is batched too,
unnarrowed, on its own index; a derived name whose read cannot answer is
declined |
| `objectstack-ai#11671` | 4/4 | 1/3 | `09b4f4e4e`: generated translation leaves
record the source revision they were filled from. Stages 1 and 2's
anchor |
| `objectstack-ai#11702` | 1/1 | 0/1 | a test title only; nothing to rewrite |
| `objectstack-ai#11703` | 15/3 | 13/2 | `5cb62d88b`: `clone_permission_set` carries
all five copied facets; the params list is the payload. The runtime
stage's anchor |
| `objectstack-ai#11725` | 3/1 | 2/1 | `1e79aa4f8`: the probe of the trash and restore
door, which pinned its unreachability and measured the residual |
| `objectstack-ai#11753` | 2/2 | 2/0 | `0e4e51b0a`: `ActionParamSchema.carryOver`, the
carry-over ruling's schema half. The spec stage's anchor |
| `objectstack-ai#11843` | 5/4 | 4/1 | `5619aace3`: the 2026-08-25 ruling, option B:
the packaged-permission-set lock registered at the metadata door. The
verbatim quotation 「11843 同意」 is kept as written |
| `objectstack-ai#12020` | 7/2 | 7/0 | `9cfc1f7e9`: the lock extended to the restore
leg, refusing on the durability channel; the residual tripwire inverted
in the same change |
| `objectstack-ai#12143` | 2/1 | 2/0 | `f64668d3c`: `objectstack-ai#12143` was the pull request
itself: each plugin's keyed-text-bounds pin reads the widths off its own
registration path |
| `objectstack-ai#12144` | 11/1 | 6/5 | `3a04b0125`: the shared identifier schemas
pinned to the storage columns that bound them; the ceiling is
storage-owned |
| `objectstack-ai#12147` | 1/1 | 1/0 | `945e91a13`: the class-level keyed-text-bounds
gate over every `*.object.ts`, superseding the per-package pins |
| `objectstack-ai#13176` | 6/5 | 6/0 | `a68c61267`: this package's test files put in
front of tsc through the sibling `tsconfig.test.json` |
| `objectstack-ai#14484` | 2/1 | 1/1 | `3f64fe6c6`: `organization_id` stamped on every
`sys_record_share` write, with the backfill and the tenancy-ledger
admission; it adds this test file. Stage 2's anchor |
| `objectstack-ai#16518` | 7/2 | 3/4 | `470746ae4`: `current_user.accessible_org_ids`
resolved into the RLS variable bag |
| `objectstack-ai#16607` | 8/3 | 4/4 | `1d73d45c1`: RLS membership staged on the write
`check` path, so a membership-keyed check resolves on a bare insert |
| `objectstack-ai#16608` | 13/4 | 6/7 | `a016f08b8`: the insert-side RLS `check`
judges the row that will be stored, after `beforeInsert` |
| `objectstack-ai#16682` | 22/4 | 18/4 | `9b9581b11`: the `single`-posture promotion
target is chosen, not sampled: the order stated to the driver, the
declared owner preferred and required verified, bounded pages with a
loud ceiling |
| `objectstack-ai#16722` | 1/1 | 1/0 | `1d73d45c1`: `objectstack-ai#16722` was the pull request
itself |
| `objectstack-ai#16805` | 1/1 | 1/0 | `a016f08b8`: `objectstack-ai#16805` was the pull request
itself; its message records the contract review's findings |
| `objectstack-ai#16861` | 7/2 | 6/1 | `1c83ca226`: the `already_have_admin` guard
stops letting the org-admin row count decide: two ordered, bounded legs
that warn with the number examined |
| `objectstack-ai#19307` | 5/3 | 4/1 | `8f6d83147`: the duplicate-name refusal on
`sys_permission_set` carries `UNIQUE_VIOLATION`, and the packaged-set
lock answers first. The spec stage's anchor |

Every cited sha matches exactly one commit (`git rev-parse
--disambiguate`, count 1 for each of the 36), and every one is an
ancestor of the base (`merge-base --is-ancestor`, exit 0 for all 36; the
history is complete, `--is-shallow-repository` false, 15,092 commits).
Where an earlier stage already anchored a number, this stage reuses that
anchor after checking it against this package's lines.

## Wordings to check

- **Two ADR anchors.** `objectstack-ai#11082`: ADR-0055's only amendment (2026-09-07)
is the in-repo record of the chain decision, so the tags read `[ADR-0055
amendment]`; `security-plugin.ts:8027` (the thrower split into a
factory) is an implementation detail the ADR does not record, so it
cites `61713314e`. `objectstack-ai#6609`: the lines already named ADR-0094 D5-R, and
now say it records ruling A (`permission-set-projection.ts:32`, `:535`,
`permission-set-projection.test.ts:498`).
- **A stale claim corrected, `errors.ts:184-185`.** The line said the
publish-time lint was 「open and unruled」. The ruling of 2026-08-16 made
that false; `8abada3ba` corrected the sibling paragraph in
`security-plugin.ts` and missed this one. It now says the ruling (commit
`8abada3ba`) orders the lint ramp and that the ramp has not landed,
which matches the `security-plugin.ts` paragraph (1 reflow line).
- **A vanished pull-request body,
`permission-set-projection.test.ts:14-16`.** The lines quoted the body
of the pull request, which answers 404. They now state what
`ee58392e1`'s own message records about the same blind spot: this suite
stubs `saveMetaItem`, and the real gate is pinned by the dogfood cases
and a dedicated 403 suite (2 reflow lines).
- **The same, `packaged-permission-set-restore-leg.test.ts:47`.**
「recorded on objectstack-ai#12020's PR」 became 「was measured for commit 9cfc1f7」;
the line itself already states the measurement.
- **A referent, `bootstrap-system-capabilities.test.ts:1148`.** 「this
file's own objectstack-ai#8919-era rule」: the count rule it applies lives in the
write-door census that `b5378550e` created (the rule's text is
`bb920ee08`'s), not in this file. The line now says so.
- **Dead comment ids dropped with their issues.** `comment 5306089973`
(`security-plugin.ts:8093`) and `comment 5587754690`
(`bootstrap-platform-admin-walled-owner.test.ts:482`). The verbatim
maintainer quotation under the second is untouched.
- **Words where the anchor is one line away.**
`bootstrap-platform-admin.ts:630` (「a pre-ruling install」, anchor on
`:628`), `bootstrap-platform-admin-walled-owner.test.ts:493` (「the
TRIAGE seat's」, anchors on `:463` and `:482`), `security-plugin.ts:8137`
(「that ruling」, anchor on `:8132`),
`identifier-storage-ceiling-pin.test.ts:51` (「the triage fence at the
top of this file」, anchors on `:13` and `:25`),
`packaged-permission-set-lock.test.ts:94` (anchor on `:95`).
- **Reflow, 8 lines with no dead site** (every file keeps its line
count): `bootstrap-platform-admin.ts:267-268`, `errors.ts:185`,
`identifier-storage-ceiling-pin.test.ts:26` (「dispatch」 became 「scope」,
because the dispatch was the card's),
`packaged-permission-set-lock.test.ts:95`,
`permission-set-projection.test.ts:15-16`, `security-plugin.ts:8094`.
- **Box-drawing rulers.** `security-plugin.ts:3078` and
`bootstrap-platform-admin.ts:715`, `:1110`, `:1149` gave up as many
trailing rule characters as the anchor added, keeping at least one.

## The 65 sites left

- **Test titles, 57 sites.** `describe` / `it` titles, which are string
tokens, left as stages 1 to 3 left theirs:
`bootstrap-declared-capabilities.test.ts:454`;
`bootstrap-platform-admin-existing-holder-scan.test.ts:297`;
`bootstrap-platform-admin-promotion-selection.test.ts:281`;
`bootstrap-platform-admin-seeded-provenance.test.ts:184`;
`bootstrap-platform-admin-walled-owner.test.ts:504`, `:569`, `:587`;
`bootstrap-seed-round-trips.test.ts:795` (two numbers), `:980`;
`bootstrap-system-capabilities.test.ts:968`, `:1096`;
`controlled-by-parent-chain.test.ts:460`, `:540`, `:578`;
`controlled-by-parent-detail-write-authority.test.ts:594`, `:650`,
`:669`, `:708`, `:724`, `:813`; `explain-engine.test.ts:171`, `:203`,
`:853`, `:873`, `:893`; `identifier-storage-ceiling-pin.test.ts:125`,
`:143`, `:160`; `insert-check-post-image.test.ts:573`, `:612`, `:662`,
`:775`, `:838`, `:875`, `:939`;
`objects/default-permission-sets.test.ts:299`;
`packaged-permission-set-lock-gate.test.ts:183`;
`packaged-permission-set-lock.test.ts:647`, `:812`, `:813`;
`packaged-permission-set-restore-leg.test.ts:264`, `:265`;
`permission-set-duplicate-name-refusal.test.ts:195`;
`plugin-keyed-text-bounds.test.ts:67`;
`record-share-tenant-wall.test.ts:149`;
`rls-accessible-org-ids-plumbing.test.ts:191`, `:256`, `:325`, `:382`;
`rls-check-membership-staging.test.ts:388`, `:400`, `:439`, `:505`;
`security-plugin.test.ts:153`; `share-link-tenant-wall.test.ts:239`;
`tenant-layer.test.ts:237`.
- **Test assertion messages, 3 sites.** String literals passed to
`expect`: `identifier-storage-ceiling-pin.test.ts:172`, `:193`
(`objectstack-ai#12144`) and `packaged-permission-set-lock.test.ts:694` (`objectstack-ai#11703`).
- **Operator log strings, 2 sites.** `security-plugin.ts:7864` and
`:7872`, the two `logger.error` lines of the chain guards (`objectstack-ai#11082`).
Runtime strings are form D, and the shrink-only `doc-authoring-prose-id`
baseline already holds both (`security-plugin.ts`, `objectstack-ai#11082: 2`).
- **Generated headers, 3 sites.**
`translations/{es-ES,ja-JP,zh-CN}.source-hashes.generated.ts:8`
(`objectstack-ai#11671`). Their producer is a string literal in `packages/cli`,
outside this lane; the pointer is on objectstack-ai#20594.
- There is no quoted ruling carrying a dead number in this package: the
one verbatim quotation, 「11843 同意」, carries no `#`.

## Mechanical guard: no code token moves

The guard compares the TypeScript parser's leaf nodes, with comments as
trivia and JSDoc nodes excluded, base `cd901d7a5` against head. Template
literals are therefore read in context. It ran over all 51 touched `.ts`
files.

- Real run: 221,086 base tokens, **0 files with a token change** (exit
0).
- Comment control in `seed-name-lookup.ts` (`TWO events, ONE
consequence` to `TWO events, ONE result`): 0 files changed, as expected
(exit 0).
- Positive control, a code token added in `seed-name-lookup.ts` (an
extra key in the batched read's `where`): DIFFER (exit 1).
- Positive control, one digit changed inside a kept test title
(`bootstrap-system-capabilities.test.ts:1096`): DIFFER (exit 1).

Every mutation went through `scripts/ablation-replace.mjs`, and each
landed (anchor 1 to 0, blob changed). Each restore was proven
byte-identical to the HEAD blob (`36e6be731e6a`, `e1f66feaa6fc`), with
`git diff HEAD` empty and a clean tree afterwards.

## Changeset

This change ships bytes, so a `patch` changeset for
`@objectstack/plugin-security`
(`.changeset/20596-plugin-security-provenance-anchors.md`) is included.
It says only that the provenance comments were re-anchored.

Measured on the built package (A3): `files[]` is `dist`, `README.md` and
`CHANGELOG.md`. After the build, the rewritten comments reach `dist`:
`ADR-0055 amendment` appears 4 times in each of `dist/index.d.ts`,
`index.d.mts`, `index.js` and `index.mjs`; `6feac910b`, `498f4e884`
twice in each of the four; `c0714eb5d`, `e1d773eb7`, `db923a3a8`,
`470746ae4`, `1d73d45c1`, `9b9581b11` once in each of the four;
`ee58392e1` 3 times and `1c83ca226` twice in each declaration file;
`5cb62d88b` 4 times and `c25b2d52a` 3 times in each runtime file.
Positive control: the unchanged line 「declared the key's SHAPE」 beside a
shipped rewrite (`rls-compiler.ts:88-89`) is found once in `index.d.ts`,
beside 「Until commit 470746a nobody did」. A never-written negative
phrase appears nowhere. The only dead numbers left in `dist` are the two
kept `objectstack-ai#11082` log strings in the runtime files.

## Gates (head `f90c9b123`)

- **Citation judging, as CI runs it:** `pnpm check:issue-citations`
(self-test) exits 0. `node scripts/check-issue-citations.mjs` exits 0:
the diff-scoped run judged 9 citations across 19 files, and all 9
resolve.
- **Doc authoring:** `pnpm check:doc-authoring` exits 0, with the
sibling-package prose ids at their baseline and no growth.
- **Derived gates:** `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` at `f90c9b123` derived 66 commands:
all 57 derived at dispatch, plus `check:duration-unit-keys`,
`check:dispatcher-error-vocabulary`, `check:engine-double-contract`,
`check:logger-receiver-detach`, `check:objectql-double-limit`,
`check:query-options-erasure`, `check:type-check-coverage`,
`check:type-check-debt` and `check:where-matcher`. It was re-derived
after a fresh `git fetch` (`origin/main` `c6b37cd08`, 3 commits ahead):
the same 66. Each ran with its exit code captured before any pipe, and
all 66 exit 0. `--ran`, fed each command with its exit code, reports 66
run, 0 NOT MEASURED (a derived zero), 0 unrun, and exits 0. A full
`turbo run build` of `./packages/*` and `./packages/*/*` ran first under
the shared verify lock (71 of 71 tasks, exit 0), so no gate hit an
unbuilt workspace.
- **Roster families the derivation lists outside its commands** (their
rosters sit in directories this diff touches): `node
scripts/check-changeset-fixed.mjs`, `pnpm check:error-code-casing` and
`pnpm check:filter-alias-parity`, each exit 0.
- **Tests and typecheck, under the verify lock:**
- `pnpm --filter @objectstack/plugin-security test`: 147 files pass,
3,202 tests pass and 23 skip. That is every test file in the package,
the 32 touched ones included.
- `pnpm --filter @objectstack/plugin-security typecheck` exits 0 (`tsc`
main, `tsconfig.scripts.json`, and `check:test-typecheck` at zero). The
main program reads 69 non-test files; the `tsconfig.test.json` program
reads all 216 files under `src/`, the 147 test files included, and all
51 touched files are in it (`--listFiles`).
- **Lint, as a proven narrowing:** `eslint --no-inline-config --format
json` over the 51 touched `.ts` files gives 51 files, 0 errors and 0
warnings. All 51 are in eslint's own population (`isPathIgnored` is
false for each). `eslint.config.mjs` never enables type-aware linting
(no `parserOptions.project`, as its own line 328 states), so a comment
edit here cannot move the verdict on any untouched file. The repo-wide
`pnpm lint` is CI's run.
- **Control bytes:** `pnpm check:nul-bytes` exits 0, and a raw scan of
the 52 changed files for control bytes finds none.

## Acceptance notes

- **The gate's extractor does not see a number after a slash either.**
`CITATION_RE` opens with a lookbehind that refuses a `/` before the `#`
(`scripts/check-issue-citations.mjs:449`), so in `#A/#B` only `#A` is a
citation to the diff gate and the census, dead or alive. It is the same
blind-spot family as the hyphen spelling (objectstack-ai#20636). This stage rewrote
the two such prose sites in `plugin-security`
(`permission-set-overlay-discard.ts:25`,
`platform-owner-wall-bypass.ts:69`) because they are the same dead
numbers in the same comment prose. A raw scan of `packages/**/src` `.ts`
files against the board finds 33 dead second numbers of this shape at
the base and 31 at the head (one of them the kept title
`bootstrap-seed-round-trips.test.ts:795`), in 14 packages. The census
cannot count them, so a later stage has to look for them by hand. No
instrument change here.
- **The hyphen spelling in this package** (objectstack-ai#20636 names 1 here on
`main`) was `bootstrap-system-capabilities.test.ts:1148`, rewritten. 9
dead `#N-word` sites remain in `packages/**/src` at the head, none in
this package.
- **The census instrument did not truncate in this stage.** Three
enumerations read 185 pages each at the newest frontier.
- **Anchors the next stages can reuse.** These numbers stand elsewhere
on the census at the head: `objectstack-ai#11374` in `drivers` (16),
`platform-objects` (14) and `plugin-audit` (2), anchor `3954fb7df`
(route A); `objectstack-ai#6216` in `core` (8), `mcp` (1) and `plugin-hono-server`
(1), anchor `f586f1a89`; `objectstack-ai#6483` (8) and `objectstack-ai#6608` (4) in
`metadata-protocol`, anchor `ee58392e1`; `objectstack-ai#6206` in `core` (2),
`plugin-approvals` (3), `plugin-audit` (1) and `service-storage` (1),
anchor `8e13ca876`; `objectstack-ai#8778` in `metadata-core`, `plugin-approvals` and
`service-storage`, anchor `7901b2dd2`; `objectstack-ai#16608` (4) and `objectstack-ai#16805` (2) in
`objectql`, anchor `a016f08b8`; `objectstack-ai#11343` in `types` (2), anchor
`c0714eb5d`; `objectstack-ai#8692` in `cli` (2), anchor `712e185db`; `objectstack-ai#12144` in
`metadata-protocol` (1), anchor `3a04b0125`; `objectstack-ai#16682` in `core` (1),
anchor `9b9581b11`.
- **Base.** The branch is 3 commits behind `origin/main` (`c6b37cd08`,
read at 13:54Z). None touches `plugin-security` or any of these numbers;
they add three unrelated changesets and move one row of
`scripts/doc-authoring-prose-id.baseline.json` (a `packages/lint`
entry), so there was no merge.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants