Conversation
…ipts/ablation-replace.mjs beside its sibling preflight The two documents that route an agent to `scripts/ablation-dist-preflight.mjs` now also route it to `scripts/ablation-replace.mjs`, in the order an ablation runs them: mutate on disk through the anchor-verifying helper, then prove the mutation reached `dist/` with the preflight, then read the run. `.claude/agents/os-dev.md` stays line-neutral (403 / 403): the new pointer sits under the mutate-then-build line of the ablation step; it is paid for by deleting the 干净收尾 opener that restated the header's two-delivery rule and the following bullet's ordering. `packages/qa/dogfood/README.md` gains one sentence in step 4 of "Adding a golden test", beside the existing preflight sentence. Adoption-style pointer only: not a mandatory path, no gate, no migration of existing ablation scripts. Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu
📓 Docs Drift Check
What this run could not see
Coarse fallback — 2 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
维护者速读(终稿)skills 席 改了什么 — 两处把 agent 指向姊妹工具 为什么改 — 新工具若无人被指向,只有碰巧 grep 过 风险与代价(含回滚) — 两行指向,不设必经路径、不加门禁、不迁移旧脚本(迁移集实测为空);行数中性、线宽 ≤120 B、line ratchet 绿;门禁 48 族绿、5 族需构建产物留给 CI。回滚 = revert 一个提交。顺带一件已结的:#18226 的选项 A(在字节纪律里点名 席位意见 — 荐合。把已落地的正确形态写进 dev 每次都读的那份定义,是最小改动。 你要做的(一个动作) — Approve 本 PR(或直接人工合并);席位随后按裁定 C 落地。 Generated by Claude Code |
Fixes #18599
Clause-②: no
Governed surface (
.claude/**): draft,skip-changeset, an authorized approval lands it and thedomain:skillsseat lands it from there. File surface:.claude/agents/os-dev.md+packages/qa/dogfood/README.mdonly. Headfa55c9d0ad, basef6189a43f9(origin/mainat worktree creation; the card's readings were taken onab1d35925and re-read here on the tip). Line-neutral on the governed file: 403 / 403, widest line 120 B before and after, zero lines over the ratchet's 120-byte cap.The defect
PR #18598 (card #18226) landed
scripts/ablation-replace.mjs— the on-disk mutation step of an ablation: replace through an anchor that must hit, with the write and the restore verified against the disk rather than an exit code, in place of thesed -i/perl -ifamily that silently failed in two recorded ablations (2026-08-20, a-0run whose$/interpolated into a NUL byte; 2026-09-14, an argument swallowed and nothing written, exit 0). No instruction surface pointed at it, while the two that route an agent to its siblingscripts/ablation-dist-preflight.mjsdo exist — so the helper could only be found by greppingscripts/, which is the memory-dependent shape #18226 was filed against. This PR adds the pointer to exactly those two surfaces, in the order an ablation runs the two tools: mutate on disk through the replace helper, then prove the mutation reacheddist/with the preflight, then read the run. Adoption-style only: not a mandatory path, no gate, no migration of existing ablation scripts (#18226's triage 5707288884 set that floor; the migration set measured empty in #18598's census)..claude/agents/os-dev.md— one line in, one true duplicate outInserted, new :254 (119 B), directly under the mutate-then-build line of the ablation step (:253 「每一腿(变异与还原)都是:改动 → 证明它真落到了磁盘 → …」, 108 B) and above the preflight line (old :254, now :255, 113 B):
「
-i家族」 is the name the file's existing :258 already gives the trap (sed、perl -i、str.replace、re.sub零命中也 exit 0). The line is a routing line in the register of the preflight line beside it: one instrument, the reason in the same breath, no 「必须」, no gate.Paid by deleting old :319 (72 B), the opening bullet of 「干净收尾」:
What it lost: nothing the file does not state elsewhere, twice. Its three claims — two deliveries, GitHub first, comment before terminal message — are the header's :17 (「报告交付两次,GitHub 优先:先作 issue 评论,…」) and :18 (「…再作为终报消息…」), and the very next bullet of the same section (now :320, 「终报消息之前,把同一段 JSON 发成 issue 评论,…」) restates the ordering together with the marker. The section now opens on that bullet.
Why a payment and not a fold: measured on this tree, of the file's 284 adjacent bullet pairs ZERO merge under the 120-byte cap (smallest merged 133 B), and in the ablation block :253–:264 ZERO of 11 (smallest 162 B); the block's total slack is 249 B spread over lines holding 0–61 B each, none of which fits a 35-byte script path plus its reason. Re-wrap funding is refused by the ratchet rule in any case.
Whole file: 403 → 403 lines; widest line 120 B before and after; control-byte scan (
grep -naPover the C0/DEL range) on both files: clean.packages/qa/dogfood/README.md— one sentenceStep 4 of 「Adding a golden test」, placed before the existing preflight sentence (mutate, then prove
dist/); the helper's usage placeholders are written as words here because the platform sanitizer eats tag-shaped fragments in a PR body — in the file they are the helper's own spellings:Non-governed, no line budget, the README's English register. Net +4 lines in that paragraph.
Verification by the card's own instrument (tree
objectstack-ai/objectstack)ab1d35925f6189a43f9fa55c9d0adgit grep -lI 'ablation-replace'd0b8ec2aafafter it).claude/agents/os-dev.md,packages/qa/dogfood/README.md,scripts/ablation-replace.mjsgit grep -lI 'ablation-dist-preflight'git grep -cI 'dogfood'os-dev.md / README.mdgit grep -cI 'ablation'on.claude/skills/dogfood-verification/SKILL.mdPer-file hits at head:
ablation-replace— os-dev.md 1, README.md 1, the helper 14;ablation-dist-preflight— os-dev.md 1, README.md 1.#18226 option A — a reading, not implemented here
Option A (「在字节纪律里加一条具名陷阱」: name the
perl -0+$/-interpolates-to-NUL trap in the byte-discipline rules) was routed, not ruled, and has not landed. #18226's triage 5707288884 routed it to the skills seat (「选项 A(在字节纪律里加一条具名陷阱)要走 skills 席,⛔ 不在本卡内落地」), the claim 5710594253 repeated the boundary, and PR #18598 landed option C (the helper) only. On this tree:AGENTS.mdcarries no control-character orcheck:nul-bytessentence at all (its onlyperl -imention is :224, the Bash-guard write shapes);os-dev.md:387–:390 (字节与 sanitizer 纪律) covers writing control characters as escapes and the harm of a raw NUL, and :258 covers mode ② (nothing written, exit 0) — neither names mode ① (-0+$/). Left untouched here (this card is the pointer only) and reported inopen_questionsfor the seat to queue.Gates (worktree at
fa55c9d0ad; every exit code captured by redirect-then-$?, never through a pipe)Derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom the worktree, no hand-fed paths (change set vs merge basef6189a43f: the two files; committed 2, working tree 0, untracked 0). 53 commands; reconciled with--rancarrying:: exit Nper line: 53 derived, 48 run, 5 NOT-MEASURED, 0 UNRUN.Named by the dispatch:
pnpm check:pm-skill-ratchet:: exit 0 — 「.claude/agents/os-dev.md is 403 lines (ceiling 403; headroom 0)」 · 「widest table row is 0 bytes (pin 0; headroom 0)」pnpm check:nul-bytes:: exit 0 — 「OK (scanned 8814 text file(s) … no raw ASCII control bytes)」pnpm check:agent-model-declared:: exit 0 — 「1 agent definition(s) under .claude/agents/ all declare a model」pnpm check:pm-governed-merges:: exit 0 (the post-merge audit).node scripts/pm/check-governed-merges.mjs --pr NUMBERneeds this PR's number, so it runs after creation; its verdict (expected GOVERNED, exit 3, which is a verdict and not a failure) is recorded in the report comment on the card.pnpm lint(repo-wide,eslint . --no-inline-config, as PR pm(half-states): H19 founds every verdict on the set it judges #18654 ran it) :: exit 0, 100 s, onfa55c9d0adThe other 43 that ran, all exit 0:
check-ci-filter-parity,check-closing-keyword-parity(+--self-test),check-comment-mask-adoption(+--self-test),check-comment-mask-corpus,check-keyed-text-bounds(+--self-test),check-platform-object-tenancy-census(+--self-test),check-plugin-teardown-shape(+--self-test),check-registry-log-declared(+--self-test),check-rest-log-spy-declared(+--self-test),check-system-context-census(+--self-test),check-undeclared-dep-imports(+--self-test),docs-audit/check-affected-docs,docs-audit/check-drift-comment,pm/check-governed-queue-guard --self-test,pm/check-harness-current --self-test, speccheck:empty-state·check:liveness·check:strictness-ledger·check:variant-docs,check:agent-test-spelling,check:commit-card-trailers,check:cross-package-test-inputs,check:doc-authoring,check:driver-memory-census,check:org-identifier,check:page-declaration-shape,check:pm-skill-id-lint,check:published-files,check:refd-timer-probe,check:skill-frame-sync,check:slot-lookup,check:test-source-alias,check:tier-file-adoption,check:type-source-resolution,check:watch-hint-literal.NOT MEASURED (exit 3,
PREREQUISITE NOT MET— each loads BUILT artifacts and refuses on this unbuilt worktree; the diff touches no source, config or manifest, so their verdict is CI's on its correctly built tree):pnpm --filter @objectstack/lint run check:doc-formula-expressions(@objectstack/formulaand@objectstack/lintnot built),pnpm check:dts-closure,pnpm check:dual-build-cjs-loads(101 packages withoutdist/),pnpm check:lean-entry-closure(packages/objectql/distabsent),pnpm check:sourcemap-no-sources-content. Their only remedy is a whole-repopnpm build, not proportionate to a prose-only change; declared, not hidden.① / ②: the only package touched is
@objectstack/dogfood(private, nofiles[], scriptstypecheck+testonly); the README is an input to neither (the soleREADMEmention underpackages/qa/dogfood/testis a comment inrls-fixture.dogfood.test.ts:29), so no closure build and no package test is owed — a declared narrowing.skip-changeset:.claude/**is on the fast lane and@objectstack/dogfoodis private with nofiles[]— nothing published moves.Acceptance notes
git grep -lI 'ablation-replace'→ 1」 toab1d35925, but that sha itself answers 0 — the helper landed ind0b8ec2aaf(feat(scripts): an anchor-verifying ablation replacement helper, and the census that shaped it #18598) after it; the reading was evidently taken on a tree that already carried the merge. The premise is unaffected: basef6189a43f9answers 1 (the helper alone). 承接者:无 — recorded here and in the report.ablation-dist-preflightanswers 8 on the tip, not the card's 7 — the eighth is the helper's own header cross-referencing its sibling, which is the intended composition (the two tools prove different halves and say so). 承接者:无.tail --pidrider in 干净收尾 (named by PR docs(agents): the PR body is the dev's one body write — a later correction is the seat's PATCH, and the Clause-② line rides the create #18659) stays for the next os-dev.md PR; this PR's deletion in that block is the duplicate opener, not a slot for it.维护者速读(草稿)
改了什么 — 只动两处文档。
.claude/agents/os-dev.md(行数不变 403 / 403)在消融步骤里加一行,把 dev 指向 PR #18598 新落地的锚点核验替换助手scripts/ablation-replace.mjs,与已有的ablation-dist-preflight.mjs指向并排、按消融实际执行顺序(先落盘变异、再证明到达dist/、再读结果);付账是删掉「干净收尾」节开头一条与文件头部及同节下一条重复的「报告落两次」句。packages/qa/dogfood/README.md的「Adding a golden test」第 4 步加一句同样的指向。为什么改 — 这个助手落地了,却没有任何一份指令文档指向它;而指向其姊妹工具的文档有两份。一个采纳式工具若无人被指向,只有碰巧 grep 过
scripts/的人会用到 —— 这正是卡 #18226 要消灭的「靠记性」。⛔ 不做成必经路径、不加门禁、不批量迁移旧消融脚本(#18226 分诊已定这条地板)。风险与代价(含回滚) — 零代码、零 changeset、零门禁改动;唯一的内容损失是被删的那条重复句,它的三个主张在文件头部(:17–:18)与同节下一条(:320)各有原文。回滚 = revert 本 PR,无其它文件牵连。
席位意见 — (留空,席位定稿)
你要做的 — 读新 :254 一行与被删 :319 一行;批准即由席位落地。若不同意付账形态,点名另一条重复句,席位代改。
Generated by Claude Code