docs(service-automation): re-anchor the dead tracker citations to the commits and ADR that decided them - #20816
Conversation
… commits and ADR that decided them Comment and docblock prose only, under packages/services/service-automation/src. 73 dead sites on 73 lines in 27 files (44 census sites, 24 test-comment sites, and 5 hyphen-joined sites the census grammar cannot see) now cite the commit in this repository's history that decided what the line describes, or ADR-0126 section 7.2 where that ADR records the decision, and say in their own words what was decided. Anchors: c5a7448, 9d7f725, ae6dcf6, ecdfc94, 7307191, 18d816a, 8155855, f90e820, 02b4123, 266436a, e238c79, fa5d137, 1408fe3, 7901b2d, 8c7cca1; and ADR-0126 section 7.2. Three changed lines carry no dead number: two in crud-nodes.ts correct a statement that was stale when it landed (the update door already answered a unique violation with the DUPLICATE_RECORD envelope), and one in flow-activation-ledger.test.ts carries the anchor its reflowed neighbour lost. Every file keeps its line count; no code token moves. Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H Co-authored-by: Claude <noreply@anthropic.com>
…ce comments The rewritten docblocks and inline comments ship in dist (index.js, index.cjs, index.d.ts, index.d.cts), so the package owes a patch note. Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H Co-authored-by: Claude <noreply@anthropic.com>
…tten test headers named Two test-file docblock headers that named a dead tracker number were rewritten to a commit; later lines in the same docblock still speak of "the card" / "the issue" that number named. Each header now names that card or issue by the commit behind it, so the later lines keep their antecedent. Both lines already carried a rewritten dead site; no other line changes and no code token moves. Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 6500f191b9e0b0e5d9493a501541759b084295d0 && git checkout 6500f191b9e0b0e5d9493a501541759b084295d0
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 4cc5bcd858a71d17e8b7f3e1224b91c1331efc3f a602c4003cd21afb3daa1a0f20fd14eb1a53499d && git checkout -B drift-repro 4cc5bcd858a71d17e8b7f3e1224b91c1331efc3f && git merge --no-ff a602c4003cd21afb3daa1a0f20fd14eb1a53499d
node scripts/docs-audit/affected-docs.mjs --json 4cc5bcd858a71d17e8b7f3e1224b91c1331efc3f
|
Contract reviewServed-tier: ① Derived judgmentsRead against
② Semver level
③ Boundary flagsThe dev report (
Nothing is escalated. Implemented-by: VERDICT: PASS |
Part of #20596
Clause-②: no
What changed
This is the fourteenth stage of the
domain:serviceslane of the dead-citation sweep. It coverspackages/services/service-automation/src/**and nothing else. By the seat's claim (5905919247), it is the largest package left in the lane, and it was free once theengine.tswork of the previous holder landed asc8111a575. Later stages cover the other packages, so this PR saysPart ofand 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 13 (the latest is PR #20789, landed as
8acdae9d8). That is 73 sites on 73 lines in 27 files, covering 14 numbers:#11504,#16709,#8778) stand only in test files here, and each was read on its own and answers 404;#13398-classspelling (a hyphen after the digits), 2 inengine.tsand 3 in test files.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: 15 distinct commit shas, plus ADR-0126 §7.2 on 2 lines, per ruling C's order (the ADR first where it records the decision; see the per-number table). No number was dropped.
Only comments changed. Every touched source file keeps its line count (76 lines out, 76 in, over 27 files), so no line citation into these files moves. 73 of the 76 changed lines carried a dead citation; the other three are listed under Wordings. No code token moves (see the guard below).
No citation number is added. The only tracker numbers on added lines are the live
#14095,#14456,#8287and the cross-repohotcrm#1206, each once and each on the line it already stood on. No number is new to the diff, no number grew, and no PR number is the citation on an added line.17 dead sites are left on purpose: 16 test titles and 1 runtime string (see the list below).
One more file: a
patchchangeset for@objectstack/service-automation, because the rewritten prose ships (see Changeset below).Census:
service-automation, before and afterInstrument (A1). The gate's own
node scripts/check-issue-citations.mjs --census --json, read-only and unchanged. The count below is itsallocated-but-absentfindings underpackages/services/service-automation/. Each run counts as a reading only because its board frontier equals the newest issue or pull-request number, read by a separate request just before and just after the run. In two of the three runs a new number was opened while the run was enumerating; each frontier equals the newest number at the run's end, which is the criterion (stages 7, 11 and 13 met the same shape).allocated-but-absent8acdae9d8, run 2026-09-30T07:03:52Z to 07:07:25Z3511e88cc(comments and changeset), run 07:32:02Z to 07:35:27Za602c4003, run 07:58:50Z to 08:02:19ZThe whole-repo drop is 44, exactly this diff's census sites. The
resolvestally is 33,096 in all three runs, andresolves-as-pull-request(1,984) andcross-repo-unjudged(1,003) did not move either. No run was truncated or discarded: all three enumerations read 187 pages at the newest frontier.The seat's census counted 45 here at
6bff748b. The difference is one#10243comment line that36d043be1(PR #20724) removed fromengine.tsin the meantime; the other seven commits since then add or remove no dead site in this package's non-testsrc.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) andnamesThisRepositoryover every.tsfile underservice-automation/src(191 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 itallocated-but-absent, and alive when the gate's own census-scope extraction judged it and the census did not report it. 39 numbers are covered by neither, because they stand only in test files or strings here; each was read on its own through the read-only tools (2 answer 404:#11504and#16709; 18 answer 200 as issues; 19 answer 200 as pull requests, 18 of them also the squash suffix of a commit onmain).8acdae9d8a602c4003Its src-comment column equals the census's 44, which is the control on the second instrument. The 2,874 live citations and 60 cross-repo citations are the same in both readings, and the drop of 68 citations is exactly the rewritten sites the gate's grammar can see. A third, raw reading (every
#followed by 2 to 6 digits, whatever surrounds it) finds 3,078 occurrences before and 3,005 after: the 68, plus the 5#13398-classsites only this reading sees.Per-number table
Sites and files count every dead occurrence in scope at the base (comments and strings, tests included, and the 5 hyphen-joined sites).
rewritten / leftcounts the sites rewritten and the sites left. Each anchor was read in its message and diff, not only its subject.#11060815585513(PR #11347): flow value expressions gain exactlyround/floor/ceil/abs/min/max, mirrored 1:1 from the CEL stdlib, and an unknown name in call position becomes the loudFlowExpressionFunctionErrorinstead of a silentnull. Its message records the maintainer ruling on#11060(2026-08-23, option A) and its diff names the number 18 times;git blameputs 11 of the 12 lines in it, and the twelfth (end-node-refused-outcome.test.ts:333) was written later. The lint lane's anchor for the same number#10243engine.ts:2315,flow-activation-ledger.test.ts:1024): the durable ledger row replaces the process-localflowEnabledmap, "retiring the #10243 leak's mechanism rather than refining it" (docs/adr/0126-packaged-metadata-customization-model.md:339-340), which is what both lines say is the point.02b41232d(PR #10996) on 9 lines, the ones that say the map "measured" leaking: the recorded measurement that tenant A's toggle answered 200 and tenant B and the platform admin read the flow back off.266436a7f(PR #11660) on 2 lines: it implements the maintainer ruling on#10243(option A, toggle joins themanage_metadatawrite set), which is the gateflow-activation-store.ts:67says the difference "turned on", and it wrote the "mitigating but not exculpating" record thatflow-activation-ledger.test.ts:272quotes. The runtime lane's anchors for the same number#14419c5a7448d5(PR #14948):create_recordsurfacesengine.insert's classifiedDUPLICATE_RECORDcode on the node result, the engine copies it onto$error, andtry_catchpreserves it across its own binding; deliberately scoped tocreate_record. Its message's last line names#14419as its card, its diff names the number 13 times, andgit blameputs 8 of the 11 lines in it (the other 3 were written by later commits it precedes). The spec lane's anchor for the same number#13398e238c79f0(PR #13592): the earliest text in this repository that records the maintainer's published-sink ruling as made — raising a log level by widening a published sink that declares noerroris "refused as actively harmful". Every line here states that ruling ("forbids raising a site toerrorwhere doing so means GROWINGerror?onto a published sink"). Stage 3's anchor, and the one the stage-3 review recommended for this package#16659ecdfc9411(PR #17334): a time-triggered flow declares its acting organization on its start node, the engine lifts it onto the binding, and the triggers run the flow as it.git blameputs the 4engine.ts/suspended-run-store.tslines in it. The 5 lines innotify-zero-delivery-visibility.integration.test.tswere written byae6dcf6a4, an ancestor ofecdfc9411, in the future tense ("once #16659 lands"); they now name the landed commit (see Wordings). Stage 12's anchor#136487307191db(PR #14388): the publicresumedoor normalises an absent signal to{}, and the chokepoints take a non-optional signal, so a signal-less resume is held to the screen contract. Its diff names#136488 times;git blameputs 5 of the 6 lines in it#1368118d816a50(PR #14452): the spec half of the contained-failure contract, which declares the run-levelfailed, the loop iteration throughtry/catch, and row identity on$error. Its subject names#13681. The lines were written by the services halves (d30ccb9bd,b7225477b), both descendants. The spec lane's anchor for the same sentence ("one level up")#17123ae6dcf6a4(PR #17339): anotifynode reportsselected, the recipients it addressed, so a zero-delivery run stops reading like a run with nothing to notify. Its diff writes#171234 times, andgit blameputs both lines in it. New to the sweep#87071408fe385(PR #8777): audit rows are stamped from the record's own organization. Stage 7's anchor#167098c7cca1ce(PR #16739): its item 1 pins the restore verb's drop of a stale hot consumed-suspension copy, and it created this test file. Stage 7's anchor#10062fa5d137ab(PR #12942): publishedsrcmay import only declared workspace dependencies; its diff moved this import to@objectstack/metadata-core. Subject names it#143909d7f7259f(PR #14603): both driver exits ofengine.updateanswer a unique violation with theDUPLICATE_RECORDenvelope. Subject names it. The runtime and rest lanes' anchor#11504f90e82024(PR #12611): registersFLOW_INPUT_SCHEMA_INVALID, the line's subject; its diff names#115045 times. The spec and runtime lanes' anchor#87787901b2dd2(PR #8905): the stamp-onlytenancy.organizationFielddeclaration the line names. Stage 6's anchorEvery cited sha matches exactly one commit (
git rev-parse --disambiguate, count 1 for each of the 15), and all 15 are ancestors of the base (merge-base --is-ancestor, exit 0 for each; reverse leg, base against each anchor, exit 1 for each; control legs exit 0: stage 1's landing422db788a, and the repository's root commit, which lies deeper than every anchor; the history is complete,--is-shallow-repositoryfalse, 15,178 commits). Each of the 14 numbers answers 404 on the issues endpoint, which serves pull requests too, read one by one.No ADR,
scripts/adr-anchors/file or otherdocs/page records the decision of any of the 14 (adocs/auditscensus row names#10062as a gate's origin, anddocs/qachecklist rows name#10243; neither is a decision record), except ADR-0126, which records the retirement#10243's measurement led to (§7.2) and the operator gate (§5). The#10243lines that describe the measurement or the ruling cite those commits; the two lines that describe the retirement cite the ADR.Wordings to check
notifydelivers nothing on a multi-organization install: the run carries no organization, so the tenant-scoped inbox/delivery writes are refused (#8844) while the run reads healthy #16659]」 became 「[commit ecdfc94]」 on 4 lines, 「[[finding]service-datasource's published source type-imports from a dev-only workspace dependency — the one instance repo-wide, and nothing checks the class #10062]」 became 「[commit fa5d137]」, and every parenthesised(#N)became(commit SHA)in place.create_recordcollapses the engine'sDUPLICATE_RECORDenvelope to a string, so a flow'stry_catch/faultedge still cannot tell "already there" from "the store is down" #14419 —」, 「A notify node that enqueued NOTHING reports the same as one that delivered:unmeasured=0makes a zero-delivery run indistinguishable from a successful one #17123 —」, 「Flow field expressions can call no function butNOW()/TODAY()— every other identifier is rewritten tonull, so a computed money value can never be rounded to its field's declaredscale#11060 —」, 「[finding] Three residues from the #15358 contract review: an unpinned stale-hot drop, a thrown third read that leavesstranded, and a malformed host verdict that aborts the whole scan #16709 item 1 —」 at the head of a docblock or comment became 「Commit c5a7448 —」 and so on, the form stage 13 used.notify-zero-delivery-visibility.integration.test.ts:4now opens 「The card behind commit ae6dcf6:」, andflow-field-expression-scale.integration.test.ts:4「The end-to-end oracle for the issue behind commit 8155855」. The docblocks below them go on speaking of 「the card's reading」, 「the card's ⭐」 and 「the third value-producing surface the issue names」; the headers keep that antecedent. This landed as its own commit,a602c4003, and every reading was re-run on it.#13398. 「a [Decision] plugin-sharing's refused-backfill report lands atwarnwhere AGENTS.md puts it aterror— and the card that was supposed to carry the level is CLOSED #13398-class raise: that ruling forbids」 became 「a raise under the published-sink ruling (commit e238c79): that ruling forbids」; 「outside [Decision] plugin-sharing's refused-backfill report lands atwarnwhere AGENTS.md puts it aterror— and the card that was supposed to carry the level is CLOSED #13398's class」 became 「outside the sink ruling's (commit e238c79) class」; 「([Decision] plugin-sharing's refused-backfill report lands atwarnwhere AGENTS.md puts it aterror— and the card that was supposed to carry the level is CLOSED #13398-class)」 became 「(the published-sink ruling, commit e238c79)」.#10243. 「the map Decide whether POST /api/v1/automation/:name/toggle belongs in the manage_metadata write set — it mutates flow enablement with no authoring capability #10243 measured leaking」 became 「the map commit 02b4123 measured leaking」 (and alike on 9 lines); 「the whole point of Decide whether POST /api/v1/automation/:name/toggle belongs in the manage_metadata write set — it mutates flow enablement with no authoring capability #10243」 became 「the whole point of ADR-0126 §7.2」; 「the one Decide whether POST /api/v1/automation/:name/toggle belongs in the manage_metadata write set — it mutates flow enablement with no authoring capability #10243 turned on」 became 「the one the toggle ruling (commit 266436a) turned on」; 「Decide whether POST /api/v1/automation/:name/toggle belongs in the manage_metadata write set — it mutates flow enablement with no authoring capability #10243 — the retired mechanism is GONE」 became 「ADR-0126 §7.2 — the retired mechanism is GONE」.flow-activation-ledger.test.ts:271-272. 「the Decide whether POST /api/v1/automation/:name/toggle belongs in the manage_metadata write set — it mutates flow enablement with no authoring capability #10243 map's "cold boot reads enabled: true again" was recorded as mitigating-but-not-exculpating」 became 「the retired map's … was recorded (commit 266436a) as mitigating-but-not-exculpating」. The anchor moved one line down, onto the verb it dates;:272is one of the three changed lines that carried no dead number.crud-nodes.ts:439-441, a statement that was stale when it landed. 「engine.updatestill leaks the raw driver error (engine.updatestill leaks the raw driver unique-violation error — the same defect one verb over from the insert door, with the whole UPDATE statement as its message #14390, not yet fixed) — those node results have nothing structured to surface yet」 became 「engine.updategained the sameDUPLICATE_RECORDenvelope for a unique violation (commit 9d7f725), but those node results are untouched here — this repair was scoped tocreate_recordalone.」9d7f7259fis an ancestor ofc5a7448d5, the commit that wrote the sentence, so the update door already carried the envelope when "not yet fixed" landed;c5a7448d5's message states thecreate_record-only scope.:439and:441are the other two changed lines with no dead number.#16659in the notify test, future tense. 「Why A schedule-triggered flow'snotifydelivers nothing on a multi-organization install: the run carries no organization, so the tenant-scoped inbox/delivery writes are refused (#8844) while the run reads healthy #16659 landing does not close this」 became 「Why commit ecdfc94 does not close this」; 「the shape a scheduled flow has once A schedule-triggered flow'snotifydelivers nothing on a multi-organization install: the run carries no organization, so the tenant-scoped inbox/delivery writes are refused (#8844) while the run reads healthy #16659 lands」 became 「the shape a scheduled flow takes under commit ecdfc94」; 「as it fires once A schedule-triggered flow'snotifydelivers nothing on a multi-organization install: the run carries no organization, so the tenant-scoped inbox/delivery writes are refused (#8844) while the run reads healthy #16659 lands」 became 「as it fires under commit ecdfc94」.#13681. 「the measurement these tests reproduce (Aloopnode aborts the entire flow run when one iteration's node fails — a single bad row kills a whole scheduled sweep, and there is no per-iteration containment to opt into #13681) found」 became 「the measurement behind commit 18d816a, reproduced here, found」: the measurement was the card's, and18d816a50is the contract that answered it.#11060. 「the LOUD half of the Flow field expressions can call no function butNOW()/TODAY()— every other identifier is rewritten tonull, so a computed money value can never be rounded to its field's declaredscale#11060 ruling」 became 「the LOUD half of the ruling commit 8155855 records」; 「the exact silence Flow field expressions can call no function butNOW()/TODAY()— every other identifier is rewritten tonull, so a computed money value can never be rounded to its field's declaredscale#11060 removes」 became 「the exact silence commit 8155855 removed」; 「before Flow field expressions can call no function butNOW()/TODAY()— every other identifier is rewritten tonull, so a computed money value can never be rounded to its field's declaredscale#11060 this wrote the field as undefined」 became 「before commit 8155855 …」.#14419. 「a different door than automation:create_recordcollapses the engine'sDUPLICATE_RECORDenvelope to a string, so a flow'stry_catch/faultedge still cannot tell "already there" from "the store is down" #14419's original bug」 became 「a different door than the bug commit c5a7448 fixed」; 「the whole point of automation:create_recordcollapses the engine'sDUPLICATE_RECORDenvelope to a string, so a flow'stry_catch/faultedge still cannot tell "already there" from "the store is down" #14419」 became 「the whole point of commit c5a7448」.#16709. 「[finding] Three residues from the #15358 contract review: an unpinned stale-hot drop, a thrown third read that leavesstranded, and a malformed host verdict that aborts the whole scan #16709 item 1 —」 became 「Commit 8c7cca1, item 1 —」: the item numbering is that commit's own.The 17 sites left
describe/ittitles, left as stages 1 to 13 left theirs:contained-failure-visibility.test.ts:184andloop-dying-body-steps.test.ts:298(#13681);create-record-duplicate-code.test.ts:51,:133,:255(#14419);notify-zero-delivery-visibility.integration.test.ts:403,:535(#17123);screen-resume-signal-less.test.ts:81,:134,:187(#13648);template-functions.test.ts:44,:162,:202andflow-field-expression-scale.integration.test.ts:83(#11060);flow-activation-ledger.test.ts:1027(#10243);stale-hot-consumed-suspension.test.ts:157(#16709).builtin/template.ts:192, the tail of the unknown-function refusal ("(Before Flow field expressions can call no function butNOW()/TODAY()— every other identifier is rewritten tonull, so a computed money value can never be rounded to its field's declaredscale#11060 this name was silently rewritten to null …)"). A runtime string takes form D, not this card's comment-only form C, and the shrink-onlydoc-authoring-prose-idbaseline already holds it (template.ts:#11060: 1), socheck:doc-authoringsees no growth.src, listed and left, not edited in this stage: the shippingREADME.mdnames no dead number (#4336,#4414, both live).tsconfig.test.jsonnames the dead#13176on 2 lines (5, 73) and the dead#14916on 1 line (54); its other numbers are live.vitest.config.tsnames only live numbers. The release-ownedCHANGELOG.mdnames 7 of the 14 numbers on 13 lines.Mechanical guard: no code token moves
The guard compares, base
8acdae9d8against head, over all 27 touched.tsfiles:forEachChildwalk, so comments are trivia and JSDoc nodes are never visited). String and template literals are therefore read in full.getChildrenwalk, so punctuation and keywords are included; JSDoc nodes skipped).Results:
a602c4003: 47,982 base leaf tokens, 0 files with a token change on either reading (exit 0).engine.ts(「which folds nothing and rejects nothing.」 to 「which folds nothing and refuses nothing.」): 0 files changed, as expected (exit 0).engine.ts(function applyResumeSignal(tofunction applyResumeSignalX(): DIFFER on the identifier (exit 1).flow-activation-ledger.test.ts:1027,#10243to#10244): DIFFER on the string literal (exit 1).Every mutation went through
scripts/ablation-replace.mjs(wrap mode) under a shell trap that restores by absolute path, and each landed (anchor 1 to 0, blob changed). Each restore was proven byte-identical to the HEAD blob (26e9be7dc174,e78e505fa3be), withgit diff HEADempty and a clean tree afterwards. The controls ran on3511e88ccand again ona602c4003.Changeset
This change ships bytes, so a
patchchangeset for@objectstack/service-automation(.changeset/20596-service-automation-provenance-anchors.md) is included. Its body is stage 4's (plugin-security, the other stage with an ADR anchor), word for word, with the package name changed.Measured on the built package (A3), after a full workspace build in which this package was a cache miss (71 of 71 tasks, at
9b0d34213, which holds every source-line change):files[]isdist,README.mdandCHANGELOG.md, and the package is not private.dist/index.d.tsanddist/index.d.ctscarry the rewritten docblocks atengine.ts:354,:362,:529,:2112,:2119,:2315,:2331,:5224,:7984andflow-activation-store.ts:67(e.g.02b41232d4 times,c5a7448d5twice,ecdfc9411and7307191dbonce each).dist/index.jsanddist/index.cjscarry the kept comments atengine.ts:2315,:2331,:3565,:3581,:5224,:7984,notify-node.ts:449,suspended-run-store.ts:714andsys-automation-run.object.ts:112.engine.ts:2112and before:2119once in each declaration file and 0 in the JS; theFlowActivationStoredocblock opener besideflow-activation-store.ts:67once in each declaration file; and the neighbours of three stripped rewrites (crud-nodes.ts:438,suspended-run-store.ts:952,template.ts:24) 0 everywhere.dist.dist; the one#11060in each JS entry is the kept runtime string attemplate.ts:192.The two commits after
9b0d34213add the changeset and change two test-file comment lines, which the bundle does not include.Gates (final head
a602c4003)pnpm check:issue-citationsexits 0 (self-test, 114 cases, 8 batteries).node scripts/check-issue-citations.mjsexits 0: the diff-scoped run judged the 2 citations the change adds on its surface (the live#14095and#8287, each on the line it already stood on), and both resolve.pnpm check:doc-authoringexits 0 (the sibling-package prose-id baseline holds, no growth).node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackata602c4003(after a fresh fetch) derived 63 commands. They are the 64 derived at dispatch lesspnpm check:error-code-casing, which the derivation now lists as a roster family (below).--ran, fed each command with its exit code, reports 63 run, 0 NOT MEASURED (a derived zero), 0 unrun, and exits 0.turbo run buildof./packages/*and./packages/*/*ran first under the shared verify lock (71 of 71 tasks, exit 0), so no gate hit an unbuilt workspace.3511e88ccbefore the referent commit.node scripts/check-changeset-fixed.mjs,pnpm check:authz-resolver,pnpm check:error-code-casingandpnpm check:filter-alias-parity, each exit 0.a602c4003:pnpm --filter @objectstack/service-automation test: 157 files pass and 1,974 tests pass, every tracked test file undersrc/, the 16 touched ones included.pnpm --filter @objectstack/service-automation typecheckexits 0 (tsc --noEmitplus the test-layer check ontsconfig.test.json).tsc --listFilesputs all 27 touched files in both programs..tsfiles, gives 27 files, 0 errors and 0 warnings (its--format jsonoutput). All 27 are in eslint's own population (none reported ignored; adistfile, as the control, is ignored).eslint.config.mjsnever enables type-aware linting (noparserOptions.project, as its own lines 327-328 state), so a comment edit here cannot move the verdict on any untouched file. The repo-widepnpm lintis CI's run.pnpm check:nul-bytesexits 0, and a raw scan of the 28 changed files for control bytes finds none.Acceptance notes
CITATION_RErefuses a hyphen after the digits, so a dead#N-wordcitation (#13398-class) is invisible to the diff gate and to the census #20636). At the base:#N-word11 lines, of which the 5#13398-classlines were dead and are rewritten here; the 6 left are live (#5912twice,#5048,#5186) or cross-repo (hotcrm#548twice).#A/#B13 lines of the number-slash-number shape, plus 6 lines where the slash followsADR-0049(ADR-0049/#1888); every second number is live.option #Nnone. URL-spelled none. So the claim's 11 / 13 / 0 / 0 hold, and at the head the first is 6.option #Nposition, dormant.NON_CITATION_HEADSalso excuses a number after 「clause」, andsuspended-run-store-consume-log-cause.test.ts:408reads 「The consequence clause finding(service-automation): engine.ts 还剩三处同形的 warn message 拼接 —— forgetSuspendedRun / cancelRun / listSuspendedRunsDurable,是 #5912+#6230 之后该文件的最后一批 #6299 asked for」, a real citation of the live#6299. Acrosspackages/**/srcthere are 4 such sites, all in test files, a surface the gate defers anyway, so nothing dead hides there today. Recorded for check-issue-citations closeout (extractor spellings):CITATION_RErefuses a hyphen after the digits, so a dead#N-wordcitation (#13398-class) is invisible to the diff gate and to the census #20636's family, not filed.notify-zero-delivery-visibility.integration.test.ts:72still calls the organization-less cron tick 「the shape production builds now」, written beforeecdfc9411landed; it carries no number and lost no referent here.suspended-run-store.test.ts:904namestenancy.organizationField, which502f179cchas since retired from the authorable surface (stage 7 recorded the same drift inplugin-approvals).update_recordstill surfaces nocode. The corrected sentence atcrud-nodes.ts:439-441is now true thatengine.updatecarries theDUPLICATE_RECORDenvelope whileupdate_recorddoes not surface it. That is an observation with no reported pull, recorded here.#11060→815585513;#10243→02b41232d(the measurement),266436a7f(the ruling) or ADR-0126 §7.2 (the retirement), per line;#14419→c5a7448d5;#13648→7307191db;#13681→18d816a50;#17123→ae6dcf6a4;#14390→9d7f7259f;#11504→f90e82024;#10062→fa5d137ab; and the reused#13398→e238c79f0,#16659→ecdfc9411,#16709→8c7cca1ce,#8778→7901b2dd2,#8707→1408fe385.mainat8acdae9d8.mainhas since moved five commits (41dcf1188,96e724475,df67985b0,cfa931535,5bed1f6ca). None touchespackages/services/service-automation/src,scripts/check-issue-citations.mjsor.changeset/config.json, and none is a path in this diff. Two of them move gate inputs (scripts/doc-authoring-prose-id.baseline.json, whose change isdriver-sqlrows only, and onescripts/adr-anchors/file forpackages/spec), so those families ran here against the base's copies; this diff moves no code token and no runtime string, so nothing here can interact with them. No merge was taken; the merge queue rebuilds on the merged generation.Generated by Claude Code