Repository navigation
feat(scripts): an anchor-verifying ablation replacement helper, and the census that shaped it - #18598
Merged
Merged
Conversation
`sed -i` / `perl -i` have failed silently twice in this repository, in two different modes, and neither was caught by an exit code: once a variable interpolated into a NUL byte and turned the target binary, once the in-place write swallowed its argument and wrote nothing at exit 0. Both were caught only by on-disk evidence a dev remembered to add by hand. `scripts/ablation-replace.mjs` removes the construct rather than detecting its failures: anchor and replacement are literal argv strings with no regex, shell or interpolation surface at all; the anchor must hit a declared number of times or the tool refuses and exits non-zero; and the write is verified against the disk -- occurrence counts before/after plus `git hash-object` -- so a write that did not land is the tool's own non-zero verdict. Restore is proven the same way (blob equal to HEAD's plus an empty `git diff HEAD`, with an empty hash read as FAILURE, never as a match) and is armed on EXIT / INT / TERM against an absolute path resolved from `git rev-parse --show-toplevel`. `--self-test` runs both directions: anchor missing must exit non-zero and write nothing, anchor present must land on disk and print the evidence. Adoption-style by design: no gate requires it, it is not wired into CI, and no existing ablation script is rewritten. New ablations use it; existing ones migrate when touched. Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk Co-authored-by: Claude <noreply@anthropic.com>
Dogfooding the helper on its own self-test found it: read off the WHOLE argv, a `--self-test` belonging to the WRAPPED command hijacked the dispatcher. The parent ran its own self-test, printed a green verdict and performed no ablation at all — the exact false green the tool exists to refuse, arriving through its own front door. The flag is now read only from the argv BEFORE the `--`, and a WRAP battery pins the property along with the rest of wrap mode: the child runs against the mutated file, its own exit status passes through untouched, and the file is restored with the proof printed once the child exits. Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk Co-authored-by: Claude <noreply@anthropic.com>
Collaborator
Author
席内复核(派发席
|
os-try-charles
marked this pull request as ready for review
September 17, 2026 08:32
os-try-charles
deleted the
claude/issue-18226-ablation-replace-helper
branch
September 17, 2026 08:54
This was referenced Sep 17, 2026
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Sep 28, 2026
…ipts/ablation-replace.mjs beside its sibling preflight (objectstack-ai#18725) Fixes objectstack-ai#18599 Clause-②: no Governed surface (`.claude/**`): draft, `skip-changeset`, an authorized approval lands it and the `domain:skills` seat lands it from there. File surface: `.claude/agents/os-dev.md` + `packages/qa/dogfood/README.md` only. Head `fa55c9d0ad`, base `f6189a43f9` (`origin/main` at worktree creation; the card's readings were taken on `ab1d35925` and 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 objectstack-ai#18598 (card objectstack-ai#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 the `sed -i` / `perl -i` family that silently failed in two recorded ablations (2026-08-20, a `-0` run 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 sibling `scripts/ablation-dist-preflight.mjs` do exist — so the helper could only be found by grepping `scripts/`, which is the memory-dependent shape objectstack-ai#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 reached `dist/` with the preflight, then read the run. Adoption-style only: not a mandatory path, no gate, no migration of existing ablation scripts (objectstack-ai#18226's triage 5707288884 set that floor; the migration set measured empty in objectstack-ai#18598's census). ## `.claude/agents/os-dev.md` — one line in, one true duplicate out Inserted, 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): > - 落盘走 `node scripts/ablation-replace.mjs`,不走 `-i` 家族:锚点必须命中,写入与还原按磁盘核验。 「`-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 「干净收尾」: > - 报告落两次,GitHub 优先:卡片评论在前,终报消息在后。 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 -naP` over the C0/DEL range) on both files: clean. ## `packages/qa/dogfood/README.md` — one sentence Step 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: > Make the revert itself through `node scripts/ablation-replace.mjs --file PATH --anchor TEXT --replacement TEXT -- CMD` rather than `sed -i` / `perl -i`: the anchor must hit, the write and the restore are verified against the disk, and a mutation that did not land exits non-zero instead of handing you a green run. 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`) | reading | card @ `ab1d35925` | base `f6189a43f9` | head `fa55c9d0ad` | |---|---|---|---| | `git grep -lI 'ablation-replace'` | 1 as reported (that sha itself answers 0 — the helper landed in `d0b8ec2aaf` after it) | 1 (the helper itself) | **3** — `.claude/agents/os-dev.md`, `packages/qa/dogfood/README.md`, `scripts/ablation-replace.mjs` | | `git grep -lI 'ablation-dist-preflight'` | 7 | 8 (the card's 7 plus the helper's own header, which names its sibling) | 8, unchanged | | control `git grep -cI 'dogfood'` os-dev.md / README.md | 1 / 6 | 1 / 6 | 1 / 6, unchanged | | `git grep -cI 'ablation'` on `.claude/skills/dogfood-verification/SKILL.md` | 0 | 0 | 0 — the third routing document named in objectstack-ai#18598's report does not exist; not touched | Per-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. ## objectstack-ai#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**. objectstack-ai#18226's triage 5707288884 routed it to the skills seat (「选项 A(在字节纪律里加一条具名陷阱)要走 skills 席,⛔ 不在本卡内落地」), the claim 5710594253 repeated the boundary, and PR objectstack-ai#18598 landed option C (the helper) only. On this tree: `AGENTS.md` carries no control-character or `check:nul-bytes` sentence at all (its only `perl -i` mention 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 in `open_questions` for 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/objectstack` from the worktree, no hand-fed paths (change set vs merge base `f6189a43f`: the two files; committed 2, working tree 0, untracked 0). 53 commands; reconciled with `--ran` carrying `:: exit N` per 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 NUMBER` needs 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 objectstack-ai#18654 ran it) :: exit 0, 100 s, on `fa55c9d0ad` The 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`, spec `check: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/formula` and `@objectstack/lint` not built), `pnpm check:dts-closure`, `pnpm check:dual-build-cjs-loads` (101 packages without `dist/`), `pnpm check:lean-entry-closure` (`packages/objectql/dist` absent), `pnpm check:sourcemap-no-sources-content`. Their only remedy is a whole-repo `pnpm build`, not proportionate to a prose-only change; declared, not hidden. ① / ②: the only package touched is `@objectstack/dogfood` (private, no `files[]`, scripts `typecheck` + `test` only); the README is an input to neither (the sole `README` mention under `packages/qa/dogfood/test` is a comment in `rls-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/dogfood` is private with no `files[]` — nothing published moves. ## Acceptance notes - noted, not filed: the card attributes 「`git grep -lI 'ablation-replace'` → 1」 to `ab1d35925`, but that sha itself answers 0 — the helper landed in `d0b8ec2aaf` (objectstack-ai#18598) after it; the reading was evidently taken on a tree that already carried the merge. The premise is unaffected: base `f6189a43f9` answers 1 (the helper alone). 承接者:无 — recorded here and in the report. - noted, not filed: `ablation-dist-preflight` answers 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). 承接者:无. - Rider not taken: the pending `tail --pid` rider in 干净收尾 (named by PR objectstack-ai#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 objectstack-ai#18598 新落地的锚点核验替换助手 `scripts/ablation-replace.mjs`,与已有的 `ablation-dist-preflight.mjs` 指向并排、按消融实际执行顺序(先落盘变异、再证明到达 `dist/`、再读结果);付账是删掉「干净收尾」节开头一条与文件头部及同节下一条重复的「报告落两次」句。`packages/qa/dogfood/README.md` 的「Adding a golden test」第 4 步加一句同样的指向。 **为什么改** — 这个助手落地了,却没有任何一份指令文档指向它;而指向其姊妹工具的文档有两份。一个采纳式工具若无人被指向,只有碰巧 grep 过 `scripts/` 的人会用到 —— 这正是卡 objectstack-ai#18226 要消灭的「靠记性」。⛔ 不做成必经路径、不加门禁、不批量迁移旧消融脚本(objectstack-ai#18226 分诊已定这条地板)。 **风险与代价(含回滚)** — 零代码、零 changeset、零门禁改动;唯一的内容损失是被删的那条重复句,它的三个主张在文件头部(:17–:18)与同节下一条(:320)各有原文。回滚 = revert 本 PR,无其它文件牵连。 **席位意见** — (留空,席位定稿) **你要做的** — 读新 :254 一行与被删 :319 一行;批准即由席位落地。若不同意付账形态,点名另一条重复句,席位代改。 --- _Generated by [Claude Code](https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu)_ Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #18226
Clause-②: no
sed -i/perl -ihave failed silently twice in this repository, in twodifferent modes, and neither was caught by an exit code. This adds
scripts/ablation-replace.mjs: an ablation mutation goes through an anchorthat must HIT, and the tool produces its own on-disk evidence instead of
relying on the caller to remember to add some.
Delivered in the order triage set (
5707288884) and the card's own acceptancecriterion 1 set: the census first, and the helper's shape decided by it.
Deliverable 1 — the census
Pathspec boundary, stated before the numbers
Enumerated: every one of the 8,766 tracked files of
objectstack-ai/objectstackate0d05538c0d0275728d25acfafbab259e23d0710(the merge base of this branch), via
git grep -nIwith no pathspecrestriction.
-Iskips binary files.NOT enumerated, and each for a reason that matters to the reading:
node_modules/,dist/,.turbo/. Notablation authorship surface.
../objectui,../cloud. Different trees;--repodiscipline forbids answering for them from here.git rev-parse --is-shallow-repository=true), and the card asks about「今天树上」 — today's tree. No windowed history question was asked, so
none was answered.
No tree query can reach them. This is not a gap in the method; it is the
census's main finding, below.
The counts, and what classified them
Two probes, both over the whole tracked set:
sedfollowed by an-iswitch clusterperlfollowed by an-iswitch clusterEvery hit was then classified — markdown prose / shell or JS comment / quoted
fixture string / actually-executed command — by stripping comments, then
stripping quoted segments, and re-testing:
AGENTS.md:224,.claude/agents/os-dev.md:257— the rules that name the hazardscripts/check-bash32-floor.mjs:54.claude/hooks/guard-main-checkout-bash.selftest.sh— command STRINGS fed to the guard hook as test input, never executed assedThe two EXECUTED rows, read in context:
.claude/hooks/guard-main-checkout-bash.sh:571— inside the refusalmessage's
catheredoc. Help text. The classifier does not modelheredocs; this is a known false positive, named rather than hidden.
scripts/pm/os-verify-lock.sh:453— a realperlinvocation, butperl -MTime::HiRes -e 1: a clock probe, no-i, no in-place write. ProbeB's regex matched the
iinside-MTime. The probe OVER-selects; it doesnot under-select — three of its eight raw hits are this same over-match.
⇒ The reading
Firing controls — because a zero without one is a dead probe, not a reading
Control 1 (the classifier can say EXECUTED). The identical classifier,
same code path, fed two synthetic rows:
It fires. The in-tree zero is a property of the tree, not of a broken probe.
Control 2 (the regexes themselves reach the tree). Probes A and B are not
silent: 45 and 8 raw hits respectively. A regex that matched nothing at all
would be indistinguishable from this result at the raw level, which is exactly
why the classification pass is reported separately from the match pass.
Control 3 (the second zero — no committed ablation script exists). Probing
for the ablation script shape —
traponEXIT/INT/TERM— returns 29hits, so the probe fires; every one of the 29 is a tempdir cleanup or a process
kill, and none restores a tracked source path. Probing for the restore leg
itself (
git checkout HEAD --/git restore --source=HEAD) returns 13 hits:2 inside
scripts/ablation-dist-preflight.mjs(a verifier, not a mutator), 4in rules prose, and 7 inside test-file comments narrating an ablation that
was run in a transcript. The firing control for this zero is
git checkouttaken the same way, which hits 8+ files. ⇒ Not one committed file in this
repository performs an ablation mutation.
What the census actually decided — and it is not what the card assumed
The card asked "how many ablations on the tree use the
-ifamily". The answeris zero, and the reason is structural rather than fortunate:
Ablation is heavily, routinely used here.
of an ablation performed ad hoc in a dev's shell and never committed.
So the tree was never the population. Both recorded failures — 2026-08-20's NUL
byte and 2026-09-14's silent no-op — were transcript commands, and the tree can
neither count them nor prevent the next one. Three consequences, and each is a
shape decision rather than an opinion:
shell, not a library some committed script imports. There are no committed
scripts to import it.
boundary has an EMPTY migration set. Nothing is being left un-migrated,
and
⛔ 不许把既有消融脚本一次性全改has nothing to forbid here.⛔ stop-and-report clause is not triggered. It points the other way: with the
real population living outside the tree, a required gate would have nothing
to read, and the cost would be a manual floor bought for no coverage.
Deliverable 2 — the helper
scripts/ablation-replace.mjs, one new file, the shape the census indicates.Against the card's five requirements:
3withANCHOR MISS; a count other than the declared one (default exactly3withANCHOR AMBIGUOUSand names--expect N.and replacement before and after, plus
git hash-objectbefore and after,printed on every leg — the caller does not have to remember.
git diff HEAD. An empty hash reads as FAILURE, never as a match againstanother empty. Restore is spelled
git checkout HEAD -- ABS, never the bareform, which restores from the index.
EXIT/INT/TERM(andHUP, and an uncaughtexception) against an absolute path resolved once from
git rev-parse --show-toplevel, armed before the write.--self-test, both directions — see the table below.Three properties are structural rather than checks bolted on:
word-splitting, no interpolation anywhere in the substitution path. That is
the whole of the 2026-08-20 failure removed rather than detected:
$/is fourcharacters here and cannot become anything else. A replacement carrying a
control byte is refused before any write.
blob hash that did not move is
NOTHING LANDEDand a non-zero exit — the2026-09-14 failure, which exited 0.
0ok ·1the leg ran and its evidencerefutes it ·
2usage ·3anchor ·4the restore could not be proven.In WRAP mode the wrapped command's own status passes through untouched —
a red child is the ablation's reading, not the tool's failure — which is why
the tool's own failure needs a code no child can mint.
The boundary the card and triage drew, kept verbatim
⛔ This helper is NOT a mandatory path. No gate requires it, it is not wired
into CI, and no existing ablation script was rewritten. New ablations use it;
existing ones migrate when touched. Making it mandatory would be a new required
gate — a manual floor — and that is the maintainer's call. The header says all
of this in the file itself.
⛔
AGENTS.mdwas not touched, nor was anything under.claude/. Option A(a named trap in the byte-discipline clause) belongs to the skills seat.
Scope, and what it deliberately does not do
The restore proof is per-path. The whole-tree half already exists and is
better at it:
scripts/ablation-dist-preflight.mjsreadsgit status --porcelainover the entire tree precisely because a build betweenmutate and restore writes committed artifacts beside the file you chose. The
two compose; ⛔ neither substitutes for the other, and
--holdprints thepreflight invocation alongside its restore command.
Dogfood — the helper proving itself on a real ablation of its own code
⭐ Both directions, from a committed state (
a3ec1cd30, clean tree).Failure direction — anchor missing MUST exit non-zero and write nothing:
Landing direction — ablate this helper's own zero-hit refusal and watch its
self-test go red:
Reported honestly: the ablation's reach was narrower than intended and the
reading is stated as observed. Disabling the zero-hit branch does not make a
missing anchor pass — with
--expect 1, a zero count then falls through to theanchorBefore !== expectbranch and is still refused with the same exit code.So 1 case went red (the one asserting the refusal names the anchor miss),
not five. That is a fact about the two refusals overlapping at
--expect 1, andit is the message assertion — not a bare non-zero check — that carried the
discrimination. Worth knowing before anyone reads a single red case as a weak
ablation.
⭐ The dogfood found a real defect, in the tool, before it shipped
Wrapping the helper's own
--self-testis the obvious way to dogfood it — andthe first attempt printed
ok ... all 42 cases passandEXIT=0, havingperformed no ablation whatsoever. Read off the whole argv, the
--self-testbelonging to the WRAPPED command hijacked the dispatcher: theparent ran its own self-test instead of the mutation. The exact false green
this tool exists to refuse, arriving through its own front door. The flag is
now read only from the argv before the
--, and a WRAP battery pins it (with astand-in child, because wrapping the real self-test makes the self-test spawn
itself unbounded — which is how the bug was found in the first place).
A second live instance, in the same shift
Writing this file, a control-byte character class spelled with backslash-u
escapes was materialised into the raw bytes by the editing tool.
grepreported the new source file as binary;
check:nul-byteswould have refusedthe push. That is the 2026-08-20 failure mode reproduced inside the tool
written to prevent it. The class is gone: the byte test is arithmetic on code
points, with no escape left to materialise, and the header records why.
--self-test, both directionsNOTHING LANDED, null-hash-is-FAILURE, control-byte fatality, restore verdict--splitting, bad--expect, no-op replacement, mutually exclusive flags3, names the miss, nothing on disk, blob unmoved--holdprints its restore commandgit diff HEADempty, original text back--self-testafter--does not hijackBatteries carry a pinned floor and a roster floor, so a battery that stops
running names itself rather than going quiet.
Changeset —
skip-changeset, measured with a firing controlpublished moves — each manifest's
files[]actual shipped content — and theseat named
packages/lintshippingCHANGELOG.mdprecisely so this could notrest on a reflex.
A reachability predicate was built over the 70 publishing manifests that
declare
files[](zero of which declare an entry escaping its own packagedirectory, so no
files[]can reach repo-rootscripts/), then run withcontrols:
The predicate fires on both positives, including the
packages/linttrap.Repo-root
scripts/is outside everypnpm-workspace.yamlglob. ⇒ nothingpublished moves ⇒
skip-changeset.Clause ②
Clause-②: no, re-judged from the actual diff rather than carried from thedispatch: one new file under
scripts/, no schema, no export, no accepted setwidened anywhere. The diff agrees with the declaration.
Acceptance notes
three documents that route agents to
ablation-dist-preflight.mjsare.claude/agents/os-dev.md,.claude/skills/dogfood-verification/SKILL.md(both governed surfaces) and
packages/qa/dogfood/README.md— and thisseat's dispatched file surface is
scripts/. Adding the pointer is aseparate, differently-owned edit. Noted, not filed: an adoption-style tool
nobody is routed to is adopted by whoever greps
scripts/, and the twogoverned files are the ones that would fix that.
.claude/hooks/guard-main-checkout-bash.shwrites itsrefusal help text through a heredoc, which a comment-and-quote classifier
reads as an executed command. Carrier: no PR touches it here; it cost one
hand adjudication in this census and nothing else.
Gates
Derived, not guessed, and reconciled rather than recalled:
All 28 were run to a captured exit code (redirect first, then
$?— neveracross a pipe), and the ran-list was reconciled back with
--ran. The completeper-command table, including anything the run could not measure, is in the
os-dev-reportcomment on #18226 — it is the authority, and a family the runcould not reach is recorded there as
NOT MEASUREDwith its reason rather thanas a pass.
Families
dispatch-gatesitself declares outside that set and this run doesnot claim to have covered: the 53 artifact-roster families (their
silentverdict is a fact about a list, never a clearance), the 11 wide-population
families, the 1 path-scheduled CI job, and the 14 changeset-derived families —
which do not apply, since the measured decision above is that this diff
publishes nothing.
Repo-wide scans (
pnpm lintand the fullcheck:*farm) are CI's run, not adebt of this branch.
Generated by Claude Code