Repository navigation
fix(metadata-protocol): two comments cite ADR-0094 D3 for boot reconciliation, which is that record's D4 #15247
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Sep 4, 2026 分诊路由(本评论来自分诊座位)· R+150 ·
date -u实测 2026-09-04T20:15:43Zdomain:engine·documentation·pm:queue·priority:p3。落点packages/metadata-protocol⇒ 车道表metadata*归 engine。两处现验(同一次调用,
origin/main):protocol.recovery-doors-mutation-projector.test.ts:20 … or a boot reconciliation (ADR-0094 D3), re-derived it. protocol.ts:20062 … write or boot reconciliation (ADR-0094 D3) eventually heals it.⇒ 两处都在。对照:
ADR-0094 D4的拼写散布在plugin-security的四五个文件里 ⇒ D4 才是这个机制的通行拼法,这两处是离群值,你的论证成立。p3 判据:两处注释文本,零行为。⛔ 但按 Prime Directive #13 的机制,一个引错小节的注释比没有引用更坏 —— 它把下一个作者送到 write-through 重定向表,而他要找的是
kernel:ready收敛过程。⇒ 「看起来合理的错答案」,值得修,不值得插队。⭐ 修法就是
D3→D4两处,⛔ 别顺手「统一」同文件里其他ADR-0094 D3引用 —— 你已经测过:那些指的是真正的 D3(data-door write-through),是对的。
Generated by Claude Code
Dispatch ·
domain:engineexecution roundPM session
session_01ARYe3yQTQCUFm5qPYNgKaJ. Assignee set at dispatch time.
⛔ The assignee field is not proof of who holds this card — several seats run under one shared GitHub identity, so this comment is the claim record.Zone 1 — binding, do not re-litigate
- Two sites,
D3→D4, comment text only. ⛔ No behaviour, no assertion, no test semantics. - ⛔⛔ Do NOT "harmonise" the other
ADR-0094 D3citations in the same files. The card measured that those refer to the genuine D3 (data-door write-through) and are correct. Changing them would turn a two-line fix into a regression. - The two outliers are the exception, not a convention: every other citation of boot reconciliation in the tree already spells it D4 (
plugin-security'spermission-set-projection.ts,permission-set-drift.ts,permission-set-overlay-discard.ts,security-plugin.ts,permission-set-projection.test.ts, including the log stringsreconciled (ADR-0094 D4)andbackfill into metadata FAILED (ADR-0094 D4)).
Zone 2 — PM readings, falsifiable, ⛔ NOT binding — re-derive and re-declare
- The two sites as triage measured them on
origin/main— ⛔ re-locate by TEXT and report the lines you actually found:packages/metadata-protocol/src/protocol.recovery-doors-mutation-projector.test.ts:20—… or a boot reconciliation (ADR-0094 D3), re-derived it.packages/metadata-protocol/src/protocol.ts:20062—… write or boot reconciliation (ADR-0094 D3) eventually heals it.
- Read ADR-0094 yourself before writing. The claim is that boot reconciliation is
### D4 — Boot reconciliation and the migration/backfill pathwhile### D3 — Data-door writes are redirected into metadata (write-through)is a different decision.⚠️ ⛔ Do not take that from this comment — the ADR is a governed surface you may read but ⛔ must not edit. ⚠️ Run the card's own census and publish it with its control:git grep -n "ADR-0094 D3\|ADR-0094 D4" -- packages/, then classify every hit as genuine D3 / genuine D4 / the two outliers. ⛔ A count is not a classification, and this card's whole risk is changing a citation that was already right.⚠️ Adjacency onprotocol.ts, stated so you check rather than assume: PR docs(metadata-protocol): thegetMetaItemsgate enumerates sixrest-server.tscall sites, not five, and names the transitive diagnostics door #16117 (a docblock edit around:6800) was in the merge queue when this was dispatched, and [finding] The same expired justification stands at the 409 raise site: protocol.ts argues duplicatePackage hasno response schema in packages/spec at all, which is false #16125 is filed against a different sentence in the same file at:14967but is not dispatched. Your site is at:20062— far from both. ⛔ Still: cut from currentorigin/main, run the directed in-flight check before claiming, and report what you found. ⛔ Do not fix [finding] The same expired justification stands at the 409 raise site: protocol.ts argues duplicatePackage hasno response schema in packages/spec at all, which is false #16125's sentence here.- Clause-② reading:
no. Two comment lines.⚠️ Re-derive from your own diff — and note the boilerplate's flavours: a comment-only diff does changedist/*.js.map(sourcemaps embedsourcesContent) and that is ⛔ not a surface change; prove it with an untouched-text control. - ⛔ A comment-only diff is not a no-op for any gate that cites a LINE NUMBER. This edit is length-neutral (
D3→D4), so nothing should move — ⭐ but prove that rather than assuming it, and run the anchor/census family anyway.
Zone 3 — suggested route (⛔ not binding)
Prime Directive #13's mechanism is the whole reason this is worth a card: a comment naming an ADR section sends the next author to the decision they are standing on, and a wrong section sends them to a plausible-looking wrong answer — worse than no citation at all. So the deliverable is two characters, and the PR body's job is the census that proves you changed exactly the two that were wrong.
Generated by Claude Code
- Two sites,
Claim:
domain:engineexecution seat, sessionsession_01ARYe3yQTQCUFm5qPYNgKaJ.
Branch:claude/issue-15247-adr-0094-d4-citation
PR: #16153 (draft)⚠️ Corrected from the first version of this comment, which opened**Claim:— bold-decorated, soCLAIM_COMMENT_MARKER(/^\s*>?\s*Claim(?:ed)?\s*:/mi) did not match andcheck-clause2-carriers --pair 16153returned exit 4 with "the declaration is MISPLACED". Same failure shape the boilerplate names for theClause-②line itself, one level up: markdown decoration turns a declaration into an absent one. Now unbolded, with aBranch:line sogoverningClaimcan see it.Cut from
origin/main=932acc3df41e016812cfc17ffe1527fd7b5df538in a dedicated worktree. Branch pushed empty at that sha as the write-route probe before the first edit. The assignee arrived already set by the PM; per the shared identity this comment is the ownership record.Sites re-located by TEXT on my base (
⚠️ one line number drifted from the triage reading, which was taken on1bc3c092a):packages/metadata-protocol/src/protocol.recovery-doors-mutation-projector.test.ts:20 * name, or a boot reconciliation (ADR-0094 D3), re-derived it. [triage said :20 — MATCHES] packages/metadata-protocol/src/protocol.ts:20024 // write or boot reconciliation (ADR-0094 D3) eventually heals it. [triage said :20062 — DRIFTED, same sentence]In-flight check on
protocol.ts, run before claiming: #16117 is still open, not merged (+34 -4,@@ -7290region), and #16123 also touches the file (+8 -3,@@ -7290,9 +7290,14 @@). Both sit ~13,000 lines above:20024; no overlap, and this diff is length-neutral so it moves nothing for them either. #16125 is an open issue (finding, not dispatched) against a different sentence at:14967— not touched here.
DECLARED AFTER MEASURING — the closing step. Built
@objectstack/metadata-protocolat head, swappedprotocol.tsback toorigin/main, rebuilt, diffed all 24 files itsfiles: ["dist"]publishes: 22 byte-identical; the only two that differ aredist/index.js.mapanddist/index.cjs.map.index.d.ts,index.d.cts,index.jsandindex.cjsare byte-identical either side.The sourcemap delta is shown normal with an untouched-text control: a pre-existing sentence from the same docblock this diff does not touch —
registry to the target version— lives in exactly those two.mapfiles and in none of the other 22, the same distribution as the changed text. Mutation proved on disk before measuring (blob426728d2ato89436302d, byte-identical toorigin/main's blob); restore proved after (whole-treegit status --porcelainempty, rebuiltdist/byte-identical to the pre-ablation snapshot across all 24 files). Corroborated by the repo's own instrument: on the restore legablation-dist-preflightexpecting the marker present exits 1, reporting it foundONLY in 2 sourcemap files and in no executable output.Clause-②: no
Generated by Claude Code
Generated by Claude Code
os-dev-report
{ "issue": 15247, "status": "done", "branch": "claude/issue-15247-adr-0094-d4-citation", "pr": "https://github.com/objectstack-ai/objectstack/pull/16153", "premise_still_valid": true, "summary": "Two comments citing `ADR-0094 D3` for boot reconciliation now cite D4. Confirmed against ADR-0094 itself, read not taken secondhand: `### D3 — Data-door writes are redirected into metadata (write-through)` at :133 is the plugin-security engine middleware that translates non-system data-door writes; `### D4 — Boot reconciliation and the migration/backfill path` at :185 opens \"At `kernel:ready`, after the ADR-0086 D5 package seeding, `plugin-security` runs a convergence pass\" and covers overlays-to-records, the one-time backfill and drift healing. Sites re-located by TEXT, not by the dispatched line numbers: the test-file header is at :20 as triage said, but protocol.ts is at :20024 on my base 932acc3df, not the :20062 triage measured on 1bc3c092a. Comment text only; no behaviour, assertion or test semantics. Draft PR #16153, label `skip-changeset`, no changeset file. Also answered the Docs Drift Check on the PR (comment 5556653811) with the extended census the PM relay asked for.", "census": { "command": "git grep -n \"ADR-0094 D3\\|ADR-0094 D4\" -- packages/", "total_hits": 20, "genuine_D3_correct_untouched": [ "plugin-security/src/permission-set-projection.ts:861 — banner `// Data-door write-through (ADR-0094 D3)`", "plugin-security/src/permission-set-projection.ts:959 — docblock of the redirect middleware", "plugin-security/src/permission-set-projection.ts:1140 — log string INSIDE createPermissionSetWriteThrough (declared :975); enclosing function verified, not inferred from the sentence", "plugin-security/src/permission-set-projection.test.ts:566 — banner over the write-through tests" ], "genuine_D4_correct_untouched": [ "plugin-security/src/permission-set-projection.ts:300, :1299, :1438, :1465, :1481, :1497", "plugin-security/src/permission-set-drift.ts:22", "plugin-security/src/permission-set-overlay-discard.ts:18", "plugin-security/src/security-plugin.ts:3562", "plugin-security/src/permission-set-projection.test.ts:253, :913, :1111", "plugin-security/CHANGELOG.md:5864, :9491 (historic, generated)" ], "the_two_outliers_changed": [ "packages/metadata-protocol/src/protocol.ts:20024", "packages/metadata-protocol/src/protocol.recovery-doors-mutation-projector.test.ts:20" ], "arithmetic": "4 genuine D3 + 14 genuine D4 + 2 outliers = 20; post-edit the same census returns 4 D3 + 16 D4 = 20, so nothing was added or dropped and exactly two were re-pointed", "firing_control": "Pathspec trap fires on this very query: `packages/*/src/**/*.ts` returns 0 (git grep applies no :(glob) magic), `packages/**/*.ts` returns 18 (misses the two CHANGELOG.md rows), `-- packages/` returns 20. Positive control inside the chosen set at both depths the population spans: 2 files at packages/<pkg>/src/, 6 at packages/plugins/<pkg>/src/. Second control: the `boot reconcil` pattern fires on this PR's own two sites plus 11 more in metadata-protocol.", "extended_beyond_packages": "Per the PM relay. Every ADR-0094 D<n> citation repo-wide on origin/main f7ffbd65e, any spelling incl. possessive and §: D5-R 35, D4 14, D5 11, D3 9, D2 3, R1/R2 2. The 3 D3 hits outside packages/ are docs/adr/0086:379, docs/adr/0131:260 and docs/adr/0131:301 — all cite D3 for the write-through redirect, all CORRECT, governed surface, untouched. Every `boot reconcil` / `reconciliation pass` / `kernel:ready` convergence mention in the tree was read for a section citation: outside my two sites NOT ONE cites ADR-0094 D3. content/docs hits are system-context.mdx:8 (no section), authorization.mdx:239/:244/:246 (no section, then D5 and D5-R correctly), releases/v17.mdx:2614 (ADR-0119's migration-journal boot reconciliation, a different mechanism). .changeset/** has ZERO ADR-0094 mentions, control: 190 files there, 189 matching a control term. NOTHING found outside the two authorised sites, so nothing to file; nothing in content/docs/releases/** touched." }, "tests": "All exit codes captured redirect-then-read, never through a pipe; gate results quoted from the gates' own verdict lines. UNION AT FINAL COMMIT 2c904e9c4 (working tree clean at the time of the run), 15 runs all REAL_EXIT=0: check-system-context-census.mjs + --self-test, check:doc-anchors, check:adr-anchors, check:adr-symbol-anchors, check:scripts-symbol-anchors, check-keyed-text-bounds.mjs + --self-test, check:nul-bytes, check:doc-authoring, check:cross-package-test-inputs, check:durability-log-level, check:single-claim-paths, check-comment-mask-adoption.mjs, check-comment-mask-corpus.mjs. The anchor/census family was NOT narrowed on the grounds that the diff is only comments. Family derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (its stderr names objectstack at 932acc3df; 102 families; CI runs the farm). POPULATION PROOF rather than bare exit codes: check:cross-package-test-inputs names metadata-protocol in its output; check-system-context-census sweeps metadata-protocol (it anchors metadata-protocol/src/seed-loader.ts:2032) and carries 0 anchors into protocol.ts. PACKAGE: `pnpm --filter @objectstack/metadata-protocol typecheck` exit 0, and `tsc --noEmit --listFiles` confirms BOTH edited files are in the swept set (tsconfig includes src/**/* with no test exclusion), so this is not a NOT-MEASURED green. `vitest run --maxWorkers=2 src/protocol.recovery-doors-mutation-projector.test.ts` — 10 passed, exit 0. Deps built first via `pnpm --filter '@objectstack/metadata-protocol...' build` (suffix ellipsis = the package + its upstream deps). Heavy runs went through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-15247-engine set before the first attempt; verdict lines read, never a bare $?; one queue wait of 199s was spent in-round, never by ending a turn. ABLATION (clause ②), run against a COMMITTED tree, with a `trap ... EXIT INT TERM` restore on an ABSOLUTE path: built at head, swapped protocol.ts back to origin/main, rebuilt, diffed ALL 24 files that `files: [\"dist\"]` publishes. Mutation proved on disk BEFORE measuring — `boot reconciliation (ADR-0094 D4)` count 1->0, D3 0->1, blob 426728d2a->89436302d, byte-identical to origin/main's blob — and proved to reach dist/ via `ablation-dist-preflight --absent 'ADR-0094 D4'` exit 0 (\"marker absent from all 24 built files\"). RESULT: 22 of 24 byte-identical; only dist/index.js.map and dist/index.cjs.map differ. index.d.ts, index.d.cts, index.js and index.cjs are byte-identical either side. UNTOUCHED-TEXT CONTROL: a pre-existing sentence from the same docblock this diff does not touch — `registry to the target version` — occurs in exactly those two .map files and in none of the other 22, the same distribution as the changed text, so the sourcemap delta is ordinary sourcesContent embedding and not something this diff introduced. RESTORE LEG, the one usually skipped, done and proved: whole-tree `git status --porcelain` empty (per the preflight's own instruction, not a per-path diff), blob back to 426728d2a, `git diff HEAD` empty, and the rebuilt dist/ byte-identical to the pre-ablation snapshot across all 24 files. LINE-NUMBER NEUTRALITY, proved not assumed: byte length unchanged (protocol.ts 1235907 both sides, test file 24258); line count unchanged (21625 and 511); comparing `cat -n` of base against head, exactly one line differs per file AT THE SAME LINE NUMBER. 14 line-numbered anchors point into protocol.ts from elsewhere (:106, :1580, :2938, :6764, :8082 and nine rows in scripts/check-durability-degradation-log-level.mjs); none names :20024, none names :20 in the test file. MERGED-TREE RE-RUN, because origin/main moved 4 commits to f7ffbd65e while this was open (incl. #16087, which hit the line-rot mechanism in packages/objectql/src/engine.ts and repaired the system-context.mdx anchors with --fix): in a scratch worktree cut at f7ffbd65e the patch applies cleanly, line counts are unchanged, the sites are still at :20024 and :20, and the anchor family re-ran green — 8 runs all REAL_EXIT=0, same 105 read sites / 140 anchors. Scratch worktree removed after reading its `git status` and proving its only uncommitted content was my own already-committed patch. CLOSING KEYWORD: the real posted body carries exactly one, `Fixes #15247`; the other five card numbers (#15985, #16103, #16117, #16123, #16125) carry none, and #16125 is phrased without any negation-adjacent keyword. `check-partof-closing-keyword` run with the REAL posted body in PR_BODY (not the vacuous empty-env pass) — REAL_EXIT=0. The commit message carries no card-relation trailer, so a squash cannot produce a self-contradicting concatenation.", "clause_2": { "verdict": "no", "carrier": "the card's claim comment, https://github.com/objectstack-ai/objectstack/issues/15247#issuecomment-5556547141, bare line `Clause-②: no`, read back and confirmed present exactly once and undecorated", "check_clause2_carriers": "node scripts/pm/check-clause2-carriers.mjs --pair 16153 — REAL_EXIT=0, '✓ the clause-② declaration is readable in the fixed spelling and both carriers agree'", "checker_freshness": "scripts/pm/check-clause2-carriers.mjs blob 751b4a6e4fbdec025f597303164d6c2ff7c5e94a == origin/main's blob — not a stale checker", "first_attempt_exit_4": "REPORTABLE FINDING. My first claim comment opened `**Claim:` and the checker returned exit 4, 'the declaration is MISPLACED ... on the thread but NOT in the card's claim comment'. Cause: CLAIM_COMMENT_MARKER is /^\\s*>?\\s*Claim(?:ed)?\\s*:/mi, so bold decoration on the CLAIM marker itself makes the whole comment invisible as a claim carrier — the exact failure the boilerplate documents for the `Clause-②` line, one level up and not documented there. governingClaim() additionally requires a `Branch:` line. Fixed by rewriting the comment with an undecorated `Claim:` first line and a `Branch:` line; re-run is green. Worth adding to the boilerplate: 'no bold' applies to the `Claim:` marker too, and a claim needs a `Branch:` line to govern." }, "changeset_decision": "`skip-changeset` label, no changeset file — applied additively via REST POST .../issues/16153/labels and read back. Measured, not recalled: AGENTS.md line ~1019 says the label 'is for a diff that publishes nothing from any released package', and the ablation above measured exactly that case (no declaration, no runtime output, no behaviour; the only published bytes that move are sourcemap sourcesContent). Merged precedents of the same shape, both carrying skip-changeset with no changeset: #16103 (comment-only in packages/drivers/driver-memory/src/memory-matcher.ts) and #15985 (comment-only in a service-cluster-redis test header). Final read-back after the size labeler's PUT: ['size/xs', 'tests', 'skip-changeset'] — the label survived.", "mcp_calls": "0 — every read and write went through REST via curl (probe: GET /repos/objectstack-ai/objectstack returned 200). No MCP GitHub call was made for the whole run.", "open_questions": [], "out_of_scope_findings": [ "None filed. The extended census found no wrong ADR-0094 section citation anywhere outside the two authorised sites, so there was nothing to file — reported rather than silently dropped." ], "pm_or_triage_statements_measured_false": [ "Zone 2 item 1 — `protocol.ts:20062`. On my base 932acc3df the sentence is at :20024. Triage measured :20062 on 1bc3c092a, so this is line drift between shas rather than a wrong reading at the time, but as handed to me it was false. The test-file site :20 matched exactly. This is the card's own mechanism biting the card: re-locating by text is what made it harmless.", "Zone 2 item 4 — 'PR #16117 was in the merge queue at dispatch time'. Measured: #16117 is still OPEN and unmerged, with merged_at null. It also mis-states the file population: a SECOND open PR, #16123, also edits protocol.ts (+8 -3, hunk at @@ -7290,9 +7290,14 @@), which the dispatch did not mention. Neither is adjacent to :20024 and neither conflicts — the patch applies cleanly to current main.", "PM relay — 'since your base is f7ffbd65e'. My base is 932acc3df. f7ffbd65e is current origin/main, i.e. the base the drift bot merged my head INTO, not this branch's base. The branch is 4 commits behind main; that is why the merged-tree re-run above was done rather than assumed.", "NOT measured either way, flagged rather than asserted: the card body attributes both comments to PR #14982. I did not verify that attribution — it is not load-bearing for the fix and re-locating by text made it unnecessary." ], "left_undone": "Nothing on this card. The PR is a draft as instructed — not merged, auto-merge not enabled, no approving review submitted. CI convergence is the PM's per the dispatch contract, so no CI wait was performed; the platform's own PR-subscription posture was not adopted, per the 2026-08-11 ruling that this dispatch contract wins. The branch is 4 commits behind origin/main and was deliberately NOT merged forward: the patch applies cleanly and the merged tree was verified in a scratch worktree instead, so the PR history stays a clean 1-commit branch." }Generated by Claude Code
Generated by Claude Code
PM record · THREE statements of mine measured false on this card, and the round's own mechanism is what made them harmless
PR #16153 is delivered. Recording the corrections first, because they are the useful part.
⛔ 1. "PR #16117 was in the merge queue at dispatch time" — FALSE
Measured by the round: #16117 is still OPEN and unmerged,
merged_atnull. I wrote it as settled fact. ⛔ It was a stale reading restated as a current one — the same failure I recorded against myself twice already tonight (the13-vs-15count, the "pending changeset" that had shipped 39 hours earlier).⚠️ And the same Zone 2 item mis-stated the file population: a second open PR, #16123, also editsprotocol.ts(+8 −3, hunk at@@ -7290,9 +7290,14 @@) — which my dispatch did not mention at all, despite my having read #16123's own site list an hour earlier. Neither PR is adjacent to:20024and neither conflicts; the patch applies cleanly to currentmain. ⇒ The conclusion held; the census behind it did not.⛔ 2. "Since your base is
f7ffbd65e" — FALSEThat is current
origin/main, i.e. the base the drift bot merged the head into — ⛔ not this branch's base, which is932acc3df. The branch is 4 commits behind. ⭐ The round did not simply accept my framing: it verified the merged tree in a scratch worktree instead of assuming, which is exactly the right response to a PM statement it could not confirm.⛔ 3.
protocol.ts:20062— false as handed overThe sentence is at
:20024on the round's base. Triage measured:20062on1bc3c092a, so this is line drift between shas rather than a wrong reading at the time — ⭐ but as handed to the round it was false. This is the card's own mechanism biting the card, and re-locating by text is what made it harmless.⇒ Three for three, and every one caught because the round re-derived instead of inheriting. That is what Zone 2 is for.
⭐⭐ The census, and the pathspec control done properly
git grep -n "ADR-0094 D3\|ADR-0094 D4" -- packages/→ 20 hits, classified: 4 genuine D3 (all inplugin-security, all the data-door write-through, ⛔ untouched) + 14 genuine D4 + the 2 outliers. Post-edit the same census returns 4 D3 + 16 D4 = 20 ⇒ nothing added, nothing dropped, exactly two re-pointed. ⭐ An arithmetic identity is a much stronger claim than "I changed two lines."⚠️ One reading inside it is worth naming: atpermission-set-projection.ts:1140the D3 citation is a log string insidecreatePermissionSetWriteThrough— and the round verified the enclosing function rather than inferring it from the sentence.The pathspec trap, run as a deliberate control on this very query:
packages/*/src/**/*.ts→ 0;packages/**/*.ts→ 18 (misses the twoCHANGELOG.mdrows);-- packages/→ 20. Plus a positive control at both depths the population spans (2 files atpackages/<pkg>/src/, 6 atpackages/plugins/<pkg>/src/). ⇒ Third independent confirmation tonight, and the only one where the trap was demonstrated on purpose.Extended past
packages/as the relay asked: everyADR-0094 D<n>citation repo-wide, any spelling including possessive and§— D5-R 35, D4 14, D5 11, D3 9, D2 3, R1/R2 2. The 3D3hits outsidepackages/are indocs/adr/0086anddocs/adr/0131and all cite D3 for the write-through redirect: correct, governed surface, untouched. Everyboot reconcil/reconciliation pass/kernel:readymention was read for a section citation — outside the two authorised sites, not one citesADR-0094 D3..changeset/**has zeroADR-0094mentions (control: 190 files, 189 matching a control term). ⇒ Nothing to file, reported rather than silently dropped.⭐⭐⭐ A boilerplate gap the round found one level above the one I had just fixed
CLAIM_COMMENT_MARKERis/^\s*>?\s*Claim(?:ed)?\s*:/mi, so bold decoration on theClaim:marker itself makes the whole comment invisible as a claim carrier — the exact failure the boilerplate documents for theClause-②line, one level up and not documented there.governingClaim()additionally requires aBranch:line.Its first attempt opened
**Claim:and returned exit 4. ⇒ Both rules are now in the boilerplate: theClaim:marker must be undecorated, and a claim needs aBranch:line to govern. That is three PRs blocked on claim-comment shape tonight (#16117, #16131, #16139, and this one's first attempt) — the gap was mine and it is closed.Line-number neutrality, proved rather than assumed
Byte length unchanged (
protocol.ts1235907 both sides), line count unchanged (21625 and 511), and comparingcat -noutput exactly one line differs per file at the same line number. 14 line-numbered anchors point intoprotocol.tsfrom elsewhere; none names:20024. Then re-run on the merged tree (main had moved 4 commits, including #16087 which hit the line-rot mechanism): patch applies cleanly, sites unmoved, anchor family 8/8REAL_EXIT=0, same 105 read sites / 140 anchors.Clause-②:
no, with the checker's own freshness proved — script blob751b4a6e…equalsorigin/main's blob, so ⛔ not a stale checker.skip-changesetdecided by measurement (the ablation showed the only published bytes that move are sourcemapsourcesContent, with an untouched-text control showing the same distribution) and by two merged precedents of the same shape, then read back after the size labeler's PUT.⚠️ One thing the round flagged rather than asserted: it did not verify the card's attribution of both comments to PR #14982 — not load-bearing, and re-locating by text made it unnecessary. ⭐ Saying so is better than a silent assumption.PM dispatch seat · session
session_01ARYe3yQTQCUFm5qPYNgKaJ
Generated by Claude Code
Found while amending ADR-0094 for #15244 (docs-only, governed surface), so it was not fixed there.
The defect
Two comments introduced by PR #14982 point the reader at the wrong section of ADR-0094 for boot reconciliation:
packages/metadata-protocol/src/protocol.ts, in therollbackMetaItemprojector comment:... not only after the next unrelated write or boot reconciliation (ADR-0094 D3) eventually heals it.packages/metadata-protocol/src/protocol.recovery-doors-mutation-projector.test.ts, in the file header:... or a boot reconciliation (ADR-0094 D3), re-derived it.In ADR-0094, boot reconciliation is D4 (
### D4 — Boot reconciliation and the migration/backfill path). D3 is a different decision entirely:### D3 — Data-door writes are redirected into metadata (write-through).Why it is worth a card rather than a shrug
Every other citation of this mechanism in the tree already spells it D4, so these two are the outliers, not a naming convention:
git grep -n "ADR-0094 D3\|ADR-0094 D4" -- packages/The D4 spellings are in
packages/plugins/plugin-security/src/permission-set-projection.ts(several, including the log stringsreconciled (ADR-0094 D4)andbackfill into metadata FAILED (ADR-0094 D4)),permission-set-drift.ts,permission-set-overlay-discard.ts,security-plugin.tsandpermission-set-projection.test.ts. The genuine D3 spellings in that same file set all refer correctly to the data-door write-through.Prime Directive #13's whole mechanism is that a code comment naming an ADR section sends the next author to the decision they are standing on. A comment that names the wrong section sends them to the write-through redirect table when they were looking for the
kernel:readyconvergence pass — a plausible-looking wrong answer, which is worse than no citation.Scope
Comment text only, two files, no behaviour. Suggested fix:
D3toD4at both sites.Measured on
origin/mainat1bc3c092a.