Skip to content

docs(service-storage): re-anchor the dead tracker citations to the commits that decided them - #20708

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

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

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #20596
Clause-②: no

What changed

This is the sixth stage of the domain:services lane of the dead-citation sweep. It covers packages/services/service-storage/src/** and nothing else. By the seat's census at the claim (5896394242), it is the largest package in the lane that no in-flight work holds. 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 to 5 (PR #20609 as 422db788a, PR #20626 as b80ab579d, PR #20634 as 4d04b6be3, PR #20658 as 9a4b2bb38, PR #20693 as 0e9ad74fb). That is 42 sites on 41 lines in 15 files, covering 8 numbers:

  • 27 census sites (every census site this package has);
  • 15 sites in test comments, which the census defers.

Each rewritten line now cites the commit in origin/main history that decided what the line describes, and says in its own words what was decided: 7 distinct shas. No number in this package has an ADR or ruling record of its own in the repository (a grep of docs/adr/ for all 8 finds none, and the repository keeps no other ruling-record file for them), so every anchor is a commit, per ruling C's order. No number was dropped.

Only comments changed. Every touched source file keeps its line count (43 lines out, 43 in, over 15 files), so no line citation into these files moves. 2 of those 43 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: #12069 (translations/index.ts:29), #10246 (storage-service-plugin.ts:392) and the cross-repo cloud#1395 (backfill-sys-file-organizations.ts:86). Over the whole diff, added minus removed is 0 or negative for every number, and no number is new to the diff. No PR number stands on an added line.

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

One more file: a patch changeset for @objectstack/service-storage, because the rewritten docblocks and inline comments ship (see Changeset below).

Census: service-storage, 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/services/service-storage/. 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 service-storage sites lines files numbers
before base 31ed06763, run 2026-09-29T18:42:47Z to 18:46:12Z enumerated, 186 pages, frontier #20702 (newest #20702 before and after), 18,529 numbers 1,254 27 27 8 8
after head 5db5155a2, run 18:55:34Z to 18:58:50Z enumerated, 186 pages, frontier #20702 (newest #20702 before and after), 18,529 numbers 1,227 0 0 0 0

The before count matches the seat's census at the claim (27 sites in 8 files, at 6bff748b). The whole-repo drop is 27, exactly this diff's census sites. The resolves tally is 32,967 in both runs, and resolves-as-pull-request (1,984) and cross-repo-unjudged (994) did not move either. The after run was taken on 5db5155a2; the head 09d2ecc96 adds only the changeset. No run was truncated or discarded: both enumerations read 186 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 namesThisRepository over every .ts file under service-storage/src (71 files). It takes its verdicts from the before census's own board reading rather than from a second enumeration: a number is dead when that census reported it allocated-but-absent, and alive when that census judged it on this board anywhere (its --list extraction, 4,943 numbers) and did not report it. The three numbers the census never saw, because they stand only in test files (#13996, #15607, #17571), were read one by one on the issues endpoint, and each answers 200.

reading citations dead src comment test comment src string test string
before, 31ed06763 608 53 27 15 0 11
after, 5db5155a2 566 11 0 0 0 11

Its src-comment column equals the census's 27, which is the control on the second instrument. The 554 live citations and the 1 cross-repo citation are the same in both readings, and the drop of 42 citations is exactly the rewritten sites. A third, raw reading (every # followed by 2 to 6 digits, whatever surrounds it) finds 53 dead occurrences before and 11 after, and its residue equals the gate's residue site for site.

Per-number table

Sites and files count every dead occurrence 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, and git blame at the base puts each rewritten line in that commit or in a later one that applied it.

number sites / files rewritten / left anchor: what it decided
#13178 19/5 14/5 f087c376f: the sys_file / sys_upload_session update and delete doors take the acting organization and scope the statement to it (they stamp nothing), and the upload routes bind the session they had resolved and discarded. New to the sweep
#13279 11/4 11/0 6a180e42d: a failed permission-store read raises AuthzStoreUnavailableError (503) instead of reading as zero grants, and the transports' fail-closed nets, this package's file-read authorizer among them, re-raise it. The anchor of stages 2 and 5 and of the rest, runtime and types stages
#10091 9/3 5/4 da891e0ef: sys_attachment beforeUpdate gated by the uploader-or-parent-editor rule, the attach rule on a re-point, and the update-verb refusal of an unscoped multi-update. New to the sweep
#11427 6/3 4/2 c3c72a4bc: record file-field hydration asks the reap guard's held-file question, through the batched findHeldFiles this package adds, so hydration and the download path agree about a tombstoned sys_file. Its message ends with a reference to #11427. New to the sweep
#6206 3/2 3/0 aa4b90d9a: the full-envelope ruling applied to the sharing contract; ISharingService takes the whole ExecutionContext, and its docblock says callers "MUST NOT rebuild a subset of it". Stage 2's anchor, named there as the full-envelope ruling
#6523 3/2 3/0 aa4b90d9a: the same commit, which was #6523's change (its subject names it). Stage 2's and the spec stage's anchor
#8778 1/1 1/0 7901b2dd2: stamp-only tenancy.organizationField, with its consumers scope-pinned by the maintainer's ruling (the pin text is in its diff). The spec and plugin-security stages' anchor
#11671 1/1 1/0 09b4f4e4e: the source-hashes provenance companion. The identical translations/index.ts line in service-messaging, plugin-sharing and plugin-security already cites it

Every cited sha matches exactly one commit (git rev-parse --disambiguate, count 1 for each of the 7), and every one is an ancestor of the base (merge-base --is-ancestor, exit 0 for all 7; the history is complete, --is-shallow-repository false, 15,120 commits). Each of the 8 numbers answers 404 on the issues endpoint, read one by one before the rewrite.

Wordings to check

The 11 sites left

  • Test titles, 11 sites. describe / it titles, which are string tokens, left as stages 1 to 5 left theirs: attachment-access-hooks.test.ts:232, :314, :640, :932 (#10091); tenant-audit-update-delete-half-repairs.test.ts:151, :224, :345, :552, :664 (#13178); tombstone-hydration-download-agreement.test.ts:148, :326 (#11427).
  • There is no operator string, assertion message, generated header or quoted ruling carrying a dead number in this package. The generated *.source-hashes.generated.ts headers are untouched and carry none. The verbatim maintainer quotations in scope (5 lines: 「同意」 three times, 「12745 A回,其他同意。」 and 「批 Remove explicit pnpm version from workflows to fix version conflict #7 同意」) carry no dead number and are untouched.

Mechanical guard: no code token moves

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

  • Real run: 20,143 base leaf tokens, 0 files with a token change (exit 0).
  • Comment control in storage-routes.ts (Bound, not discarded to Bound and not discarded): 0 files changed, as expected (exit 0).
  • Positive control, a code token added in storage-routes.ts (const { fileId, eTag } = req.body ?? {}; given a trailing ?? undefined): DIFFER (exit 1).
  • Positive control, one digit changed inside a kept test title (tombstone-hydration-download-agreement.test.ts:148): 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 (44ecc8e64ae0, ee84cf718a6f), with git diff HEAD empty and a clean tree afterwards.

Changeset

This change ships bytes, so a patch changeset for @objectstack/service-storage (.changeset/20596-service-storage-provenance-anchors.md) is included. It says only that the provenance comments were re-anchored, in stage 5's words.

Measured on the built package (A3): files[] is dist, README.md and CHANGELOG.md. After the build, the rewritten comments reach dist: f087c376f 6 times and da891e0ef once in each of dist/index.d.ts and index.d.cts; f087c376f 4 times and da891e0ef once in each of index.js and index.cjs. Positive controls: the unchanged line 「the parent record — the delete rule, applied to the verb that could」 beside the shipped rewrite at attachment-access-hooks.ts:28 is found once in each declaration file, and the unchanged line 「standard catalog code — the same both-verbs pairing the derived」 beside the shipped rewrite at :470 once in each JS file. A never-written negative phrase appears nowhere in dist. None of the 8 dead numbers is left anywhere in dist.

Gates (head 09d2ecc96)

  • 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 3 citations (#12069 and #10246 resolve; cloud#1395 is cross-repo), each already on the line it replaces.
  • Doc authoring: pnpm check:doc-authoring exits 0.
  • Derived gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 09d2ecc96 derived 65 commands: all 56 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. 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.
  • Roster families the derivation lists outside its commands (their rosters sit in directories this diff touches): node scripts/check-changeset-fixed.mjs, pnpm check:authz-resolver, pnpm check:error-code-casing and pnpm check:filter-alias-parity, each exit 0.
  • Tests and typecheck, under the verify lock:
    • pnpm --filter @objectstack/service-storage test: 40 files pass and 627 tests pass. That is every test file in the package, the 7 touched ones included.
    • pnpm --filter @objectstack/service-storage typecheck exits 0 (tsc on tsconfig.json, the scripts program, and the test layer on tsconfig.test.json). --listFiles on both tsconfig.json and tsconfig.test.json shows all 71 files under src/, the 40 test files included, and all 15 touched files in the program.
  • Lint, as a proven narrowing: eslint --no-inline-config --format json over the 15 touched .ts files gives 15 files, 0 errors and 0 warnings. All 15 are in eslint's own population (isPathIgnored is false for each; a dist file, as the control, is ignored). eslint.config.mjs never enables type-aware linting (no parserOptions.project, as its own lines 327-328 state), 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 16 changed files for control bytes finds none.

Acceptance notes

  • The gate-invisible spellings, grepped as the claim asked. CITATION_RE refuses a hyphen after the digits and a / before the # (check-issue-citations closeout (extractor spellings): CITATION_RE refuses a hyphen after the digits, so a dead #N-word citation (#13398-class) is invisible to the diff gate and to the census #20636). In this package there is no #N-word spelling at all. There are 11 #A/#B lines carrying 13 second numbers (attachment-access-hooks.ts:215, :217, :434; attachment-access-hooks.test.ts:217; attachment-lifecycle.ts:177; file-reference-lifecycle.test.ts:226; local-storage-adapter.test.ts:35; metadata-store.test.ts:41; storage-route-ledger.ts:74, which chains four; storage-routes.metadata-outage.test.ts:67; tombstone-download-live-reference.test.ts:50), and every second number on them is live: #5574, #9974, #5541, #5480, #3833 and #3847 by the census's own board, and #5197 and #3870 read one by one (200). So nothing there needed rewriting. The claim counted 12 such spellings on main; this reading is 11 lines and 13 second numbers, with nothing dead among them either way. The raw scan above, which sees both spellings, agrees.
  • The census instrument did not truncate in this stage. Both enumerations read 186 pages at the newest frontier.
  • Anchors the next stages can reuse, each checked here: #13178 → f087c376f; #10091 → da891e0ef; #11427 → c3c72a4bc; #13279 → 6a180e42d; #6206 / #6523 → aa4b90d9a; #8778 → 7901b2dd2; #11671 → 09b4f4e4e.
  • Base. The branch is 4 commits behind main (defc7f7b5, read at 19:31Z). None touches service-storage, scripts/check-issue-citations.mjs or .changeset/config.json, so there was no merge.

Generated by Claude Code

…mmits that decided them

42 comment and docblock sites under packages/services/service-storage/src
cited tracker numbers that answer 404. Each 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: the sys_attachment beforeUpdate gate
(da891e0), the full-envelope ruling on the sharing contract (aa4b90d),
batched held-file hydration (c3c72a4), the stamp-only organizationField
scope pin (7901b2d), the source-hashes provenance companion (09b4f4e),
the update/delete doors scoped to the acting organization (f087c37) and the
loud permission-store outage (6a180e4).

Comments only: every file keeps its line count and no code token moves.

Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H
Co-authored-by: Claude <noreply@anthropic.com>
…e comments

The rewritten docblocks and inline comments ship in all four dist entry
files, so the package publishes changed bytes.

Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s 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/service-storage, touching 5 documentable anchor(s). ⚠️ 4 changed file(s) yielded no anchor (packages/services/service-storage/src/attachment-lifecycle.ts, packages/services/service-storage/src/backfill-sys-file-organizations.ts, packages/services/service-storage/src/file-reference-lifecycle.ts, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

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

  • content/docs/permissions/system-context.mdx (via installAttachmentAccessHooks (symbol, a top-level function))
What this run could not see
  • 4 changed file(s) yielded no anchor (packages/services/service-storage/src/attachment-lifecycle.ts, packages/services/service-storage/src/backfill-sys-file-organizations.ts, packages/services/service-storage/src/file-reference-lifecycle.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 — 7 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 defc7f7b504e22b9e2c12a5374ebb255efe9b7da → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 04358c57f8a4227618405fc6769a6dcf753d2091 — the merge of head 09d2ecc96ad65f66dafc6fa91311fce800e81d2d into base defc7f7b504e22b9e2c12a5374ebb255efe9b7da, 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 04358c57f8a4227618405fc6769a6dcf753d2091 && git checkout 04358c57f8a4227618405fc6769a6dcf753d2091
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin defc7f7b504e22b9e2c12a5374ebb255efe9b7da 09d2ecc96ad65f66dafc6fa91311fce800e81d2d && git checkout -B drift-repro defc7f7b504e22b9e2c12a5374ebb255efe9b7da && git merge --no-ff 09d2ecc96ad65f66dafc6fa91311fce800e81d2d

node scripts/docs-audit/affected-docs.mjs --json defc7f7b504e22b9e2c12a5374ebb255efe9b7da

⚠️ 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 defc7f7b504e22b9e2c12a5374ebb255efe9b7da → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 09d2ecc96ad65f66dafc6fa91311fce800e81d2d
Local-runs: none

① Derived judgments

Read against main at the merge-base 31ed06763. origin/main (fetched for this record) stands five commits past that base — 35587f76c, a8acee28d, ed5476870, defc7f7b5, 735594bea — and none of the five touches packages/services/service-storage, this PR's changeset, .changeset/config.json or scripts/check-issue-citations.mjs, so the net diff against main is the merge-base diff and the two-dot and three-dot diffstats agree: 16 files, +53/−43 — 15 source files under packages/services/service-storage/src/** (8 modules, 7 test files) and one changeset. The head 09d2ecc96 adds only the changeset on top of 5db5155a2, which holds every source line.

  • Accept-set: no change — right. No Zod schema, REST handler, query-parameter set, refusal text, log text or runtime string moves. 43 source lines out, 43 in; every one of the 86 changed source lines opens with a comment marker after whitespace (//, *, /**), 0 fall outside one. Each of the 15 touched source files has additions equal to deletions, so no line citation into these files moves. The dev's parser leaf-token guard (0 files with a token change; both positive controls DIFFER) says the same and is not repeated here.
  • Public surface: no change — right. No export added, removed or renamed (src/index.ts is untouched); no packages/spec file touched, so no generated artifact is owed.
  • Published bytes: changed — right, and it decides ②. @objectstack/service-storage (17.5.0, not private, files = dist, README.md, CHANGELOG.md, types = dist/index.d.ts, build = tsup then check-dts-emitted) emits declarations, and rewritten docblocks sit on declarations src/index.ts exports: StorageMetadataStore.updateFile / deleteFile / updateSession / deleteSession and the StorageWriteContext section in metadata-store.ts, the options docblock in storage-routes.ts (:42), and the module docblock over installAttachmentAccessHooks (attachment-access-hooks.ts:28). So dist/index.d.ts changes. The dev's A3 build reading (f087c376f six times and da891e0ef once in each declaration file, with a positive and a negative control) is consistent with that count of exported sites; this record does not repeat the build.
  • The 8 numbers are dead — right. Each of #6206 #6523 #8778 #10091 #11427 #11671 #13178 #13279 answers 404 on the issues endpoint (board read 2026-09-29T19:43Z). No ADR names any of them, per the PR's docs/adr grep, so ruling C's first rung is empty and a commit is the right anchor for every one.
  • The 7 anchors — each right. Each abbreviated sha resolves to exactly one commit (rev-parse --disambiguate, count 1 for all 7) and is an ancestor of the base (merge-base --is-ancestor, exit 0 for all 7), read from the shared object store after the fetch. For each, the commit's message or diff names the number it replaces, and the decision the rewritten line states is the commit's:
    • #13178 → f087c376f: the subject names it; its diff is metadata-store.ts and storage-routes.ts — the four update/delete doors given the StorageWriteContext (scoping, not stamping) and the upload routes binding the session they had resolved and discarded, which is what every rewritten line says.
    • #13279 → 6a180e42d: the message names #13279 four times beside the maintainer's verbatim ruling; it says the outage "answered a 403 byte-identical to a genuine capability denial", so 「the confusion commit 6a180e4 was made to prevent」 (four sites) and 「the relay that block has run since commit 6a180e4」 are faithful; the re-raise in the authorizer's catch (storage-service-plugin.ts:1229) is that commit's.
    • #10091 → da891e0ef: the message names #10091; the subject is the sys_attachment beforeUpdate uploader-or-parent-editor gate.
    • #11427 → c3c72a4bc: the message names #11427 and describes exactly the hydration/download divergence and the batched findHeldFiles its diff adds to attachment-lifecycle.ts; 「the divergence commit c3c72a4 fixed」 is the right tense.
    • #6206 and #6523 → aa4b90d9a: the subject names #6523, the body applies 「the 同族第三处组装:share-link 路由把授权信封裁成 4 个字段后直接当 enforcement context 喂给 engine.find —— group 租户姿态下 Layer 0 墙恒判否 #6206 ruling default (converge on the full envelope, keep no per-site subset contracts)」, and its diff writes the ISharingService docblock in packages/spec/src/contracts/sharing-service.ts — 「Callers MUST NOT rebuild a subset of it」, wrapped over two lines, which is why a single-line search misses it. The quoted words at attachment-access-hooks.ts:127-129 and the test's :766 and :914-916 are that docblock, so 「the full-envelope ruling … (commit aa4b90d)」 sits beside its own text. Stage 2's anchor for the same pair.
    • #8778 → 7901b2dd2: the subject names it (Option A per the maintainer ruling); its diff carries 「⛔ Scope-pinned by the spec: audit stamping needs a read-neutral organization declaration — tenancy.tenantField cannot serve sys_api_key without walling the credential table (#8707 remainder) #8778 ruling: this is ONE stamp-only declaration key … a consumer other than audit stamping needs its own ruling」, which is what backfill-sys-file-organizations.ts:86 now states as 「scope-pinned by its ruling (commit 7901b2d; …); a fourth needs its own maintainer ruling」.
    • #11671 → 09b4f4e4e: the seat's ACCEPT read this one as named in neither subject nor body and took it on content; the commit's diff names #11671 five times (its own changeset subject, the --source-hashes flag help, the generated-header producer), so the anchor holds on the same evidence the other six do. The anchor stages 1, 2 and 4 used for the identical translations/index.ts line.
  • Citation accounting — right. Over the diff (raw # plus digits): the 43 removed source lines carry 42 dead occurrences on 41 lines (#13178 14, #13279 11, #10091 5, #11427 4, #6206 3, #6523 3, #8778 1, #11671 1; attachment-access-hooks.test.ts:766 carries two) plus the live #10246, #12069 and cloud#1395; the 2 removed lines carrying none are the reflow lines the body lists (attachment-access-hooks.test.ts:916, storage-service-plugin.ts:1059), each the continuation of a rewritten sentence. Added lines carry exactly #10246, #12069 and cloud#1395, each on the line it already stood on (delta 0); no number is new to the diff, none grew, no PR #N stands on an added line, and 7 distinct shas stand on added lines.
  • The 11 sites left — right, and the list is exact. A grep of the 8 numbers over service-storage/src at the head returns exactly 11 lines, every one a describe or it title — attachment-access-hooks.test.ts:232, :314, :640, :932; tenant-audit-update-delete-half-repairs.test.ts:151, :224, :345, :552, :664; tombstone-hydration-download-agreement.test.ts:148, :326 — the same 11 the body lists. Titles are string tokens, left as stages 1 to 5 left theirs. The three *.source-hashes.generated.ts headers carry no dead number, and no operator string, assertion message or quoted ruling in this package does.
  • The gate-invisible spellings — right. At the head under service-storage/src: no #N-word spelling; 11 #A/#B lines carrying 13 second-number occurrences over 8 distinct numbers (#3833 #3847 #3870 #5197 #5480 #5541 #5574 #9974), and each of the 8 resolves (HTTP 200; #3870 as a pull request), board read 2026-09-29T19:43Z. The claim's count of 12 against the reading's 11 lines changes nothing: nothing dead stands there either way.
  • The remaining wordings — each right. file-reference-lifecycle.ts:111 (the update/delete halves 「in commit f087c37」 beside the live #12745 / #12928), storage-service-plugin.ts:1058-1059 (「that card」, whose referent left with the number, → 「since commit 6a180e4 landed」), the test heading at attachment-access-hooks.test.ts:621 (「Commit da891e0's gate」), and translations/index.ts:29 (the ruling #12069 kept live, the companion's commit beside it).
  • Form — consistent with the landed stages 1 to 5 (422db788a, b80ab579d, 4d04b6be3, 9a4b2bb38, 0e9ad74fb): the word commit plus the abbreviated sha in the position where the number stood, the decision carried in the sentence. The four reused anchors (6a180e42d, aa4b90d9a, 7901b2dd2, 09b4f4e4e) are the ones this card's thread records for the same numbers.
  • Check-runs on the head, the gate verdicts (read 2026-09-29T19:44Z): 34 check-runs, all completed — 31 success, 3 skipped (Build Docs, Console Pin Gate, Packed-tarball smoke (opt-in): paths-filtered or opt-in, not verdicts against), 0 failure, 0 in progress. Every one of the seven required contexts is success: Lint & Repo Gates (which carries check:issue-citations and check:doc-authoring, the two gates this diff answers to), TypeScript Type Check, Test Core (the aggregate, with all six shards success), Dogfood Regression Gate, Build Core, Temporal Conformance (live PG + MySQL), Governed Surface Queue Guard. Check Changeset, Check PR Size, Part-of PR must not also close its card and The card this PR closes must claim this branch are success too. A read one minute earlier had caught the Test Core aggregate still in_progress behind six green shards; nothing was awaited, the read was simply repeated. Nothing was built, run or re-run locally.

② Semver level

  • .changeset/20596-service-storage-provenance-anchors.md declares '@objectstack/service-storage': patch — matches what the diff publishes. The package is released and dist/index.d.ts carries the rewritten docblocks, so bytes ship; skip-changeset would be wrong (it is for a diff that publishes nothing from any released package), and the PR carries no such label. Not minor: no accept set widens and no surface is added. The body is truthful (comments only; no type, schema, export, log or refusal text, or runtime behaviour change), carries no tracker number and no model identifier, follows stage 5's landed form, and the filename carries the card number. service-storage sits in the fixed group (.changeset/config.json:72) beside the five packages whose stages declared the same level.
  • Clause-②: no — right. It is line 2 of the PR body under Part of #20596, and the claim (5896394242) declares the same. The diff widens no accept set, so no arm is owed and no minor is owed. Nothing breaks, so no ADR-0087 marker is owed; Check Changeset on the head is success.
  • Not a governed-surface diff (no path under docs/adr/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md); 96 changed lines, under the 5,000-line human-merge threshold; head repo equals base repo; Governed Surface Queue Guard on the head is success. A draft with Part of #20596 on line 1 and no closing keyword anywhere in the body, so the card stays open for the remaining stages.

③ Boundary flags

The dev report (5897256689) has open_questions: [] and out_of_scope_findings: []. Its eight deviations, each answered:

  1. 15 test-comment sites beyond the census's 27 — answered, in scope. The claim's surface is comment and docblock prose under service-storage/src/**; test comments are that, and stages 1 to 5 rewrote theirs. The head grep above confirms the residue is titles only.
  2. The supplementary and raw readings judged against the before census's own board reading rather than a second enumeration, after a scratch enumeration script was refused by the local permission layer and deliberately not re-routed — answered, immaterial to the verdict. The census instrument itself ran unchanged, twice, at the newest frontier (27 → 0, whole-repo drop exactly 27), and this record reproduces the residue independently: the head grep returns the 11 titles and nothing else, every kept second number resolves, and every replaced number is 404. Not re-routing a refused run is the right call, and it is disclosed.
  3. Lines reworded beyond the anchor, plus 2 reflow lines — answered, right (① above). Each rewording was checked against its anchor commit's message or diff; every file keeps its line count.
  4. The claim's 12 gate-invisible spellings against a reading of 0 #N-word and 11 #A/#B lines, all live — answered, right. Verified at the head (① above); nothing there needed rewriting.
  5. The harness attribution reminder versus AGENTS.md's trailer pair — answered, right. Both head commits end with the model-free pair AGENTS.md prescribes (the session trailer and the plain co-author line), no model identifier appears in either message, and the PR body's footer is the session-URL form the PR-body surface keeps.
  6. Labels — answered. documentation, size/s, tests, tooling are the labeler's; no skip-changeset, which is right.
  7. Branch base four commits behind main at the report, five at this read — answered, right. None of the five touches a path in this diff or an input the citation gate derives from (① above), so the queue's rebuild has nothing to reconcile by hand.
  8. The report comment posted through post-stamped.mjs from the shared checkout after the worktree was removed, nothing edited — answered, immaterial here. A read of the tool, not a write to the tree; the head's check-runs and this record's own reads are what the verdict rests on.

Two readings that are not flags on this PR: the Docs Drift Check advisory names content/docs/permissions/system-context.mdx through installAttachmentAccessHooks, whose only change is a docblock citation, so that page cannot have been falsified; and the ACCEPT's note that #11671 → 09b4f4e4e is 「named in neither」 understates the evidence (① above) — nothing to change. Nothing is escalated.

Implemented-by: claude/issue-20596-service-storage-citations
Reviewed-by: session_01XY5uCwTjZj7884yYtyur4H

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 29, 2026 19:49
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit 9b384f6 Sep 29, 2026
36 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20596-service-storage-citations branch September 29, 2026 20:06
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/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants