docs(plugin-audit): re-anchor the dead tracker citations to the commits that decided them - #20737
Conversation
…ts that decided them Stage 9 of the domain:services dead-citation sweep (ruling C+D, form C). Every comment or docblock site under packages/plugins/plugin-audit/src 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. Comments only: each touched 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>
The rewritten docblocks and inline comments reach the published dist entry files, so the package ships changed bytes. Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 3 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 — 9 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 7c67cd23ee2a7a47fb78447250eb55cebed64984 && git checkout 7c67cd23ee2a7a47fb78447250eb55cebed64984
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f927864ea056f79d04ad8d62f1a7c13afed31d07 d6e67afa539247334a8c1867e0128efd39acd6c8 && git checkout -B drift-repro f927864ea056f79d04ad8d62f1a7c13afed31d07 && git merge --no-ff d6e67afa539247334a8c1867e0128efd39acd6c8
node scripts/docs-audit/affected-docs.mjs --json f927864ea056f79d04ad8d62f1a7c13afed31d07
|
Contract reviewServed-tier: ① Derived judgmentsRead against
② Semver level
③ Boundary flagsThe dev report (
Nothing is escalated against this PR. Implemented-by: VERDICT: PASS Generated by Claude Code |
Part of #20596
Clause-②: no
What changed
This is the ninth stage of the
domain:serviceslane of the dead-citation sweep. It coverspackages/plugins/plugin-audit/src/**and nothing else. By the seat's census at the claim (5900808881), it is the largest package in the lane that no in-flight work holds. 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 8 (PR #20609 as
422db788a, PR #20626 asb80ab579d, PR #20634 as4d04b6be3, PR #20658 as9a4b2bb38, PR #20693 as0e9ad74fb, PR #20708 as9b384f63a, PR #20717 ascbaf04c1f, PR #20729 asd2820876f). That is 56 sites on 55 lines in 16 files, covering 16 numbers:#9719/#9798(comment-access-hooks.ts:35).Each rewritten line now cites the commit in
origin/mainhistory that decided what the line describes, and says in its own words what was decided: 15 distinct shas. No number in this package has an ADR or ruling record of its own in the repository (a grep ofdocs/adr/for all 16 finds none; the rest ofdocs/cites#11507and#11374only as evidence, in an audit table and a QA checklist), 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 (56 lines out, 56 in, over 16 files), so no line citation into these files moves. 1 of those 56 lines holds no dead citation: it is a reflow line, 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:
#10101(3 lines),#8287(3),#5928(2),#9974(2),#4630(2), and#8144,#9719,#12069and#19054once each. Each resolves. Over the whole diff, added minus removed is 0 for every number, and no number is new to the diff. No PR number is the citation on an added line: the twoPR #Nspellings in scope became their pull request's squash commit.23 dead sites are left on purpose, all of them string literals (see the list below).
One more file: a
patchchangeset for@objectstack/plugin-audit, because some of the rewritten docblocks and inline comments ship (see Changeset below).Census:
plugin-audit, 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/plugins/plugin-audit/. 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.allocated-but-absentd2820876f, run 2026-09-29T23:11:55Z to 23:15:11Za9a4ea478, run 23:26:11Z to 23:29:20ZThe before count matches the seat's census at the claim and A1 (23 sites). The whole-repo drop is 23, exactly this diff's census sites. The
resolvestally is 32,995 in both runs, andresolves-as-pull-request(1,984) andcross-repo-unjudged(995) did not move either. The after run was taken ona9a4ea478; the headd6e67afa5adds 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) andnamesThisRepositoryover every.tsfile underplugin-audit/src(45 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 that census judged it on this board anywhere (its--listextraction, 37,084 citations over 2,613 files) and did not report it. The 10 numbers the census never saw, because they stand only in test files or strings here, were read one by one on the issues endpoint: 7 answer 200 (#602,#1532,#4186,#7291,#7333,#16312,#20494), and#8852,#12143and#12147answer 404, on the pulls endpoint too.d2820876fa9a4ea478Its src-comment column equals the census's 23, which is the control on the second instrument. The 572 live citations and the 6 cross-repo citations are the same in both readings, and the drop of 55 citations is exactly the rewritten sites the gate's grammar sees. A third, raw reading (every
#followed by 2 to 6 digits, whatever surrounds it) finds 672 occurrences and 79 dead before, 616 and 23 after. Beyond the gate's grammar it sees 2 dead sites before (the#9719/#9798comment, rewritten, and the[#8203/#11507]test title, left) and 1 after (that title). Its only unjudged tokens areobjectui#10520,cloud#340,cloud#1395and the decision-batch ordinal#153.Per-number table
Sites and files count every dead occurrence in scope at the base (comments and strings, tests included).
rewritten / leftcounts the sites rewritten and the sites left. Each anchor was read in its message and diff, not only its subject, andgit blameat the base puts every rewritten line in its anchor commit or in a later commit that descends from it (merge-base --is-ancestorexit 0 for all 56 line and anchor pairs).#1150788b9d749a:sys_activity.typeis declared an open, author-extensible vocabulary whose options are the built-in set, per the maintainer ruling of 2026-08-24, direction 4. Its body names#11507twice. The spec stages' anchor#87071408fe385: an audit row is stamped from the record's own organization, not the actor's, applying the maintainer's ruling on#8287; the precedence flips torecordOrgId ?? sess.tenantId, and the organization column is resolved from the schema (resolveRecordOrganizationField, first written in this file). Its subject names it. Stage 7's anchor#9798c7655d472(PR #9993): thesys_commentaccess-hook registration declares the whole-operation dispatch#9719built, so the#4630unscoped multi-delete refusal reaches the handler through the wired engine; the update half is split out. Its body ends with the closing line for#9798. Thelintstage's anchor#168298d4690b8f: the read-audit ledger write declarespreserveAudit, so a record-view row keeps the VIEW instant;isSystemis kept for the readonly strip, and the new integration pin runs the real stamp hook. Its body ends with the closing line for#16829. New to the sweep#657569787f07b: the hook registration surface gainsexcludeObjects("global except these objects"), refusing'*'and blank members on it. The squash commit of the pull request that was#6575(404 on the pulls endpoint too);#5928, the card it answers, stays beside it. New to the sweep#11374f64668d3c, the squash commit of#12143, for the two object comments: sourced bounds on the keyed text columnssys_activity.record_idandsys_audit_log.record_id(255, the physicalidcolumn), route A.3954fb7df, for the test's statement of the rule: the route A ruling that keyed identity columns declare a sourcedmaxLength; its subject names#11374 route A. Both are stage 4's anchors for the sibling lines inplugin-security#10091da891e0ef(PR #10169):sys_attachment'sbeforeUpdategate, uploader or parent editor, with the attach rule on the NEW parent when a row is re-pointed. Its body names#10091. Stage 6's anchor#14927ab489388b(PR #17450): a lost audit row is reported once per cause, keyed on the errorcode, and the datasource remedy prints only for the missing-table cause; its message records that the measuredERR_SYSTEM_WRITE_ORGANIZATION_REQUIREDrefusal had sent its operator to a working datasource. It names#14927in its diff only (the 3 lines it wrote). New to the sweep#87787901b2dd2(PR #8905): the stamp-onlytenancy.organizationField, option A per the maintainer ruling on#8778. Its subject names it. The anchor of stages 4, 6 and 7#6523aa4b90d9a(PR #7068): enforcement contracts take the fullExecutionContext. Its subject names#6523#6206aa4b90d9a: the same commit, whose body applies "the #6206 ruling default (converge on the full envelope, keep no per-site subset contracts)", written as the full-envelope ruling, the form of stages 2, 6 and 7#885251bb277ef: thesys_activity.typewriter census; its message records the objectui mirror as unguarded in both directions, filed as#8852, and not asserted here because this package cannot import objectui. The commit that wrote the line. New to the sweep#116741cba33f16(PR #11961): the load-time warning and the ordering constraint documented at the four pointer-pair sites. Its subject names it; blame puts the line in it. Stage 7's anchor#12147945e91a13: the class-level keyed-text-bounds gate over every*.object.ts, retiring the per-package rule this file carried. It names#12147in its diff only. Stage 4's anchor for the sibling file#12143f64668d3c: the squash commit of the pull request that was#12143(404 on both endpoints), where the dependency-graph measurement was made. Stage 4's anchor#1167109b4f4e4e(PR #12557): records which source revision a generated translation leaf was filled from. The anchor the identicaltranslations/index.tsline already carries in five packages onmainEvery cited sha matches exactly one commit (
git rev-parse --disambiguate, count 1 for each of the 15), and every one is an ancestor of the base (merge-base --is-ancestor, exit 0 for all 15; control leg: stage 1's landing422db788aexit 0; the history is complete,--is-shallow-repositoryfalse, 15,143 commits). Each of the 16 numbers answers 404 on the issues endpoint.Wordings to check
[#N]became[commit SHA];[#N route A]became[commit f64668d3c, route A], the form stage 4 gave the sibling lines;[#8707 / #10101]and[#8144 / #8707 / #10101]keep the live numbers beside the sha.sys-activity.object.ts:59-60. 「Maintainer ruling 2026-08-24 on / [Decision] Issys_activity.typea closed platform vocabulary or an author-extensible one? Both readings are true of the code today #11507 (direction 4 of the four that card framed)」 became 「Maintainer ruling 2026-08-24, / executed by commit 88b9d74 (direction 4 of the four weighed)」. Line 59 is the one reflow line: only its last word changed, and it carries no number. 「that card」 would have lost its referent.sys_activity.typea closed platform vocabulary or an author-extensible one? Both readings are true of the code today #11507」,sys-activity.object.ts:92andactivity-type-vocabulary-enforcement.test.ts:332, became 「re-open the ruling (commit 88b9d74)」: a card that answers 404 cannot be re-opened, and the instruction is about the decision.sys-activity-type-open-vocabulary.test.ts:14, the attribution above a verbatim maintainer ruling: 「on [Decision] Issys_activity.typea closed platform vocabulary or an author-extensible one? Both readings are true of the code today #11507 (direction 4 of the four the card framed)」 became 「on the card behind commit 88b9d74 (direction 4 of the four it framed)」, so line 15's 「Recorded on the card as:」 keeps its referent. Line 15, which carries the ruling 「四维分析一致的,接手你的建议。」, and the quoted block under it are untouched.sys_activity.typea closed platform vocabulary or an author-extensible one? Both readings are true of the code today #11507 changed」 and 「the [Decision] Issys_activity.typea closed platform vocabulary or an author-extensible one? Both readings are true of the code today #11507 ruling」 became 「the open-vocabulary ruling (commit 88b9d74)」; 「[Decision] Issys_activity.typea closed platform vocabulary or an author-extensible one? Both readings are true of the code today #11507 — the declaration」 became 「Commit 88b9d74 — the declaration」.audit-writers.ts:193) and 「(hook 注册契约只能表达「命中这些对象」,无法表达「全局但排除这些对象」—— #5860 因此在 plugin-audit 内无法落地 #5928, PR feat(spec,objectql): hook 注册面新增 excludeObjects,可表达「全局但排除这些对象」 (#5928) #6575)」 (audit-hook-object-scope.test.ts:19) becamecommit 69787f07bbeside the kept#5928; 「measured on PR fix(plugin-audit,plugin-security): declare sourced bounds on the four keyed text columns that break MySQL schema-sync #12143」 (plugin-keyed-text-bounds.test.ts:21) became 「measured on commit f64668d」.#8707ruling phrases,audit-writers.test.ts:1882and:1922. 「the ORDER the Audit rows are stamped from the ACTOR's active organization in preference to the record's own — and the record-side fallback cannot seesys_api_key.active_organization_id#8707 ruling set」 became 「the ORDER commit 1408fe3 set」, and 「Audit rows are stamped from the ACTOR's active organization in preference to the record's own — and the record-side fallback cannot seesys_api_key.active_organization_id#8707's ruling reasons about」 became 「commit 1408fe3 reasons about」: the ruling was the maintainer's on#8287, which stays on those lines, and1408fe385's message carries the reasoning.audit-writers.ts:1402「because Audit rows are stamped from the ACTOR's active organization in preference to the record's own — and the record-side fallback cannot seesys_api_key.active_organization_id#8707 reordered」 became 「because commit 1408fe3 reordered」, the flip its message states.#14927, three lines. 「the cause measured on Asys_audit_logwrite refused by the system-write organization rule is swallowed by plugin-audit's best-effort catch, so the audit row about a defective record is LOST silently — surfaced by #13636's admission #14927」 became 「the cause commit ab48938 records」 (audit-writers.ts:789,audit-writers.test.ts:1211), and 「The measured Asys_audit_logwrite refused by the system-write organization rule is swallowed by plugin-audit's best-effort catch, so the audit row about a defective record is LOST silently — surfaced by #13636's admission #14927 misdirection」 became 「The misdirection commit ab48938 records」 (audit-writers.test.ts:1370).sys-activity-type-vocabulary.test.ts:91. 「Filed as [观察]sys_activity.typehas a set-equal mirror in objectui, and the guard on each side is pinned to its own literal — so the mirror cannot detect drift #8852;」 became 「Commit 51bb277 recorded it;」.comment-access-hooks.test.ts:404-405. 「the finding:SharingExecutionContext是同族第四个窄 enforcement 契约类型(sharing / approval / report 三个服务共用),#6206 裁决的「不留 per-site 子集」默认尚未覆盖它 #6523 contract's unit is the envelope / and 同族第三处组装:share-link 路由把授权信封裁成 4 个字段后直接当 enforcement context 喂给 engine.find ——group租户姿态下 Layer 0 墙恒判否 #6206 forbids」 became 「the unit of commit aa4b90d's contract is the envelope / and the full-envelope ruling forbids」;comment-access-hooks.ts:222「(finding:SharingExecutionContext是同族第四个窄 enforcement 契约类型(sharing / approval / report 三个服务共用),#6206 裁决的「不留 per-site 子集」默认尚未覆盖它 #6523 / the 同族第三处组装:share-link 路由把授权信封裁成 4 个字段后直接当 enforcement context 喂给 engine.find ——group租户姿态下 Layer 0 墙恒判否 #6206 ruling)」 became 「(commit aa4b90d / the full-envelope ruling)」.audit-writers.test.ts:1648, a section rule: the trailing rule was shortened from 10 characters to 2 so the line stays near its old width.:1653「That day is spec: audit stamping needs a read-neutral organization declaration —tenancy.tenantFieldcannot servesys_api_keywithout walling the credential table (#8707 remainder) #8778」 became 「That day came with commit 7901b2d」.read-audit.test.ts:43. 「precisely how / plugin-audit's read-audit rows back-datecreated_atto the VIEW instant through anisSystemreliance the audit hook never honoured, so every batchedsys_audit_logread row now gets the FLUSH instant #16829 shipped」 became 「precisely how / the defect fixed by commit 8d4690b shipped」.comment-access-hooks.ts:35, the gate-invisible site: 「(The #4757 unscoped multi-delete refusal on sys_attachment never fires through ObjectQL.delete — per-row hook dispatch bypasses it #9719/The #4630 unscoped multi-write refusals on sys_comment never fire through the wired engine — per-row dispatch bypasses resolveTargetRows on both verbs #9798 built」 became 「(The #4757 unscoped multi-delete refusal on sys_attachment never fires through ObjectQL.delete — per-row hook dispatch bypasses it #9719/commit c7655d4 built」.The 23 sites left
#11507: thesys_activity.typefield'sdescription(objects/sys-activity.object.ts:121) and its four generated copies (translations/{en,es-ES,ja-JP,zh-CN}.objects.generated.ts:125). They are runtime strings, all five are held by the shrink-onlydoc-authoring-prose-idbaseline, and the generated files are left as A5 says. They ship indist(see Changeset).describe/ittitles:activity-type-vocabulary-enforcement.test.ts:315(the gate-invisible[#8203/#11507]),sys-activity-type-open-vocabulary.test.ts:70(#11507),audit-writers.test.ts:1420,:1659(two sites,#8707and#8778) and:1873(#8707),comment-access-hooks.test.ts:690(#9798),plugin-keyed-text-bounds.test.ts:90(#11374),read-audit-view-instant-preservation.integration.test.ts:121(#16829);#11507:activity-type-vocabulary-enforcement.test.ts:249,:352,:355,:378,:380, andsys-activity-type-open-vocabulary.test.ts:83,:90,:110,:152.*.source-hashes.generated.tsheaders carry none either (PR docs(cli): re-anchor the dead tracker citations in packages/cli/src to the commits that decided them, and the source-hashes header at its producer #20656 fixed their producer).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
d2820876fagainst head. Template literals are therefore read in context. It ran over all 16 touched.tsfiles.audit-writers.ts(「the cause commit ab48938 records」 to 「… recorded」): 0 files changed, as expected (exit 0).audit-writers.ts(createRecordOrganizationResolver(engine)givenas any): DIFFER (exit 1).audit-writers.test.ts:1873,#8707to#8708): 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 (2dbd2059e8f5,8ec28790da22), withgit diff HEADempty and a clean tree afterwards.Changeset
This change ships bytes, so a
patchchangeset for@objectstack/plugin-audit(.changeset/20596-plugin-audit-provenance-anchors.md) is included. Its body is stage 8's, word for word, with the package name changed.Measured on the built package (A3):
files[]isdist,README.mdandCHANGELOG.md. After the build, part of the rewritten prose reachesdist:c7655d472twice in each ofdist/index.jsandindex.mjsand once in each ofindex.d.tsandindex.d.mts(theCommentAccessEngineoption docblock is on an exported interface);88b9d749aandf64668d3ctwice, and1cba33f16and8d4690b8fonce, in each JS file (the object-definition comments and aread-audit.tscomment). The comments inaudit-writers.tsandtranslations/index.tsdo not reachdist(0 for each of their anchors). Positive controls: the unchanged line 「below carries into the contract; this comment carries the reasoning.」, in the same docblock as the shipped rewrite atsys-activity.object.ts:60, is found once in each JS file, and the unchanged line beside the shipped rewrite atcomment-access-hooks.ts:77once in each declaration file. A never-written negative phrase appears nowhere indist. Of the 16 dead numbers, only#11507is left indist, 5 times in each JS file: the keptdescriptionstring and its four generated copies.Gates (head
d6e67afa5)pnpm check:issue-citations(self-test, 114 cases, 8 batteries) exits 0.node scripts/check-issue-citations.mjsexits 0: the diff-scoped run judged 11 citations across 6 files, and all 11 resolve (they are the live numbers that already stood on the rewritten lines).pnpm check:doc-authoringexits 0; the sibling-package prose-id baseline holds (808 pinned sites, no growth), which includes the five kept#11507strings.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackatd6e67afa5derived 64 commands: all 57 derived at dispatch, pluscheck:dispatcher-error-vocabulary,check:engine-double-contract,check:objectql-double-limit,check:query-options-erasure,check:type-check-coverage,check:type-check-debtandcheck:where-matcher. Each ran with its exit code captured before any pipe, and all 64 exit 0.--ran, fed each command with its exit code, reports 64 run, 0 NOT MEASURED (a derived zero), 0 unrun, and exits 0. A fullturbo 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.origin/mainand that one input,scripts/engine-double-contract.pinned.json, changed there:mainadded one pinned row forpackages/objectql/src/protocol-packaged-dashboard-base.test.ts, a file outside this diff. The family is in the 64 either way and exits 0 on this tree.node scripts/check-changeset-fixed.mjs,pnpm check:authz-resolver,pnpm check:error-code-casingandpnpm check:filter-alias-parity, each exit 0.pnpm --filter @objectstack/plugin-audit test: 26 files pass and 366 tests pass.vitest list --filesOnlynames 26 files, all the tracked test files, the 10 touched ones included.pnpm --filter @objectstack/plugin-audit typecheckexits 0.tsc --listFiles:tsconfig.jsonholds the 6 touched source files (19srcfiles; it excludes tests), andtsconfig.test.json, which the script'scheck:test-typecheckstep compiles, holds all 45 files undersrc/, all 16 touched files included.eslint --no-inline-config --format jsonover the 16 touched.tsfiles gives 16 files, 0 errors and 0 warnings. All 16 are in eslint's own population (isPathIgnoredis false for each; 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 17 changed files for control bytes finds none.Acceptance notes
CITATION_RErefuses a hyphen after the digits and a/before the#(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), andNON_CITATION_HEADSexcuses a number after the word 「option」. In this package:#N-word: none.#A/#B: 11 lines, the claim's 11, over 14 distinct numbers. Two second numbers are dead:#9798incomment-access-hooks.ts:35, rewritten, and#11507in the test titleactivity-type-vocabulary-enforcement.test.ts:315, left as a string. The other 12 numbers resolve.option #N: none.The raw scan agrees: nothing dead beyond the gate is left outside a kept string.
descriptionstring is a runtime string with a dead number.sys_activity.type'sdescriptionships to the metadata API, the i18n bundles anddist, and ends 「(maintainer ruling 2026-08-24, [Decision] Issys_activity.typea closed platform vocabulary or an author-extensible one? Both readings are true of the code today #11507)」. It and its four generated copies are held by thedoc-authoring-prose-idbaseline, so they belong to the runtime-string lane (form D), not to this stage, as stages 1, 2 and 4 left theirs.sys-activity.object.ts:60,sys-activity-type-open-vocabulary.test.ts:14); the rest are unchanged, as in stage 8.#11507and#11374outside the census surface.docs/qa/platform-checklist/areas/records-forms.json(4 lines) anddocs/audits/gate-census-2026-09.md(1 line) cite them as evidence.docs/is outside this stage's surface; noted for [finding] dead tracker citations outsidepackages/spec/srchave no carrier: #20234 sweeps only the spec tree, and PR #20554 makes 26 more visible (pre-#N/Pre-#N) in cli, drivers, metadata, objectql, plugins, runtime and types #20556, the carrier of dead citations outsidepackages/spec/src.#16829→8d4690b8f;#6575→69787f07b;#14927→ab489388b;#8852→51bb277ef;#9798→c7655d472;#11507→88b9d749a.mainatd2820876f.mainhas since moved three commits (f05919b82,99786f930,1940afdaf). They touchpackages/spec,packages/metadata-protocol, one newpackages/objectqltest file, a design doc, three changesets andscripts/engine-double-contract.pinned.json(one added row for that test file), and no file underplugin-audit,scripts/check-issue-citations.mjsor.changeset/config.json, so no merge was taken; the merge queue rebuilds on the merged generation.Generated by Claude Code