Ratchet AGENTS.md's published spellings list to the detector's constant - #11908
Conversation
…tant `scripts/check-cross-package-test-inputs.mjs` is a source scan: a path spelling it does not know produces no flag, so a test whose reads escape its package goes undeclared silently. That is why its recognised set is published in AGENTS.md rather than left in the implementation -- and nothing compared the two copies. The mirror drifted three times (#10163, #10854, and this one). Twice the stale line was the stated REASON FOR A PROHIBITION, so a rotting mirror does not merely misinform: it launders an obsolete rule into a live one. And one claim was already false BEFORE the PR that supposedly staled it, so a lag-only check would not have caught it either. Adds `scripts/check-published-list-mirrors.mjs`, which asserts line-for-line EQUALITY between a declared constant and the block a document publishes: - equality, not containment -- a comment-only drift is invisible to containment, and the comments are where the prohibitions live; - the block is located by heading + fence, never by line number (this card was filed against `AGENTS.md:96-106`; the block sat at `:92-104` three days later); - every unreadable state REFUSES: renamed heading, duplicate heading, re-tagged fence, unterminated fence, empty block, two candidate fences, and a constant that is missing, renamed, empty or not a string list; - it can only ever go RED. AGENTS.md is governed, human-merge-only, so the gate never repairs -- it prints the exact block to paste. Stated in its header. Repairs the published block in the same change: it was short by 13 of the constant's 24 lines, including the two `findUp` ANCHOR seeds PR #10852 added, and the lead-in prose named only two of the three seed kinds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
Two standing rulings on AGENTS.md govern what a mirror may put there, and a byte-identical copy of the whole constant breaks one of them outright: - the shrink-only line ceiling (`check-skill-line-ratchet`), and - "operative text carries lessons self-contained ... numbers go" (maintainer ruling 2026-08-12, `check-skill-id-lint`). The constant is the text of a CLI failure box: spellings (code, each with the comment that annotates it) plus free-standing NOTE PARAGRAPHS set off by blank entries, two of which carry issue-ID citations. Publishing all 24 lines put those citations into the instruction surface and check:pm-skill-id-lint went red -- the gate meant to keep the document honest would have broken the document's own prose standard. So the mirror judges a projection with no judgement in it: an entry is PUBLISHED unless it is blank, or it is a comment line that no published entry directly precedes. A comment continuing a spelling travels with that spelling; a note paragraph standing alone stays in the failure box. Every spelling is code, so no spelling can hide from it. 24 entries project to 17 published lines, zero issue-ID citations, and the published block grows 11 -> 17: the two `findUp` anchor seeds, the ⛔ manifest prohibition that qualifies them, and the `-> repo root` annotation. A self-test case now pins the citation property against the live constant, so an issue number added to a spelling line goes red HERE, naming the ruling, instead of landing in AGENTS.md. check:pm-skill-id-lint: 22 file(s) clean. check:pm-skill-ratchet is red by 8 lines (969 vs 961) and needs a maintainer ruling -- see the PR body. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
|
ACCEPT on the implementation; the ceiling is escalated, not decided here. Verified against the branch and current What I confirmedGoverned discipline held. The CEILINGS map is untouched — structurally, not by assertion. The diff is 4 files ( "It can only ever go RED" — I checked this rather than taking it. A raw grep for Structural location, confirmed in code ( The drift premise re-measured on current
The detector moved by one while this sat in review, which sharpens the card rather than weakening it. The control makes the zero a reading. On your branch The zero-headroom measurement, re-derived independently. I did not re-run your greedy rewrap; I measured the raw line widths of the five paragraphs against the 90-column target: The projection is pinned against the live constant, not against a fixture (
|
…iner ruling The one-line follow-up PR #11908's body pre-wrote: the published-spellings mirror re-sync costs +8 lines, lossless rewrap headroom measured 0, and the mirror is now mechanically enforced. Maintainer ruling 2026-08-25, verbatim: 「同意,帮我合并,然后继续」 (option A as presented in the PM-chat batch review; provenance on PR #11908). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9StxQgG2DPA26XzZZqnJB
|
Maintainer ruling, 2026-08-25 (option C1): 「我看到了,你分析过了,接受你的建议」 — the +8-line-scale content for the spellings-mirror ratchet is approved in principle, but this PR needs a rework before it can land:
Please redo on top of current Generated by Claude Code |
Resolution: TAKE MAIN as the base everywhere. The only conflict was scripts/pm/check-skill-line-ratchet.mjs, where this branch's obsolete `['AGENTS.md', 961] -> 969` edit collided with main's re-pinned `['AGENTS.md', 1150]`. Main's map wins wholesale, which dissolves commit d41ef56 -- that raise was measured against the pre-reflow layout and its 961 baseline no longer exists. AGENTS.md, lint.yml and check-cross-package-test-inputs.mjs auto-merged: the 120-byte reflow left the spellings section untouched (its first change after line 32 lands at 128), and the lint.yml rewrite left the gate step beside its sibling, "Hand-written declaration mirrors". The re-measured ceiling lands in the next commit.
…ut, 1150 -> 1158 The branch's original raise (961 -> 969) was measured against the pre-#11948 layout and was dissolved by the merge. Re-measured on current main: AGENTS.md is 1150 there and 1158 with the mirror re-sync applied, so the honest cost is again +8 -- published block 11 -> 17 lines, prose paragraph 4 -> 6. The maintainer's option-C1 ruling is quoted verbatim and untranslated beside the value, per the map's convention. Gate reads at the new value: check-skill-line-ratchet: AGENTS.md is 1158 lines (ceiling 1158; headroom 0). check-skill-line-ratchet self-test: 71 cases pass.
Fixes #10855
⛔ GOVERNED SURFACE. This PR edits
AGENTS.md, which is human-merge-only(
scripts/pm/check-governed-merges.mjs). Its ready/auto-merge state was set by the PMseat on the maintainer's merge instruction (comment 5409341735) — ⛔ I have not touched
draft state or auto-merge in this rework, and no one else should flip them back.
Status: REWORKED onto current
origin/main(2026-08-25)The maintainer ruled option C1 on this PR — verbatim and untranslated:
— approving the +8-line-scale content in principle, with a rework required because
AGENTS.mdhad since been wholesale-reflowed to the 120-byte-wrapped layout (#11948, thenedited by #12103, #11934, #11829). The branch's diff and its old
961 → 969ask were bothmeasured against a layout that no longer exists.
This branch now carries
origin/mainmerged in (⛔ never a rebase, never a force-push — itcarries other authors' commits), with the resolution taking main as the base everywhere
and this PR's semantic content re-applied on top.
What the rework changed
AGENTS.mdbaselineThe cost re-measures to the same +8 on the reflowed layout — published block 11 → 17 lines,
prose paragraph 4 → 6 — so commit
d41ef56's961 → 969is dissolved by the merge andreplaced by a
1150 → 1158entry carrying the C1 ruling verbatim, per the map's convention.⭐ The mirror gate is its own oracle here. The 00:08Z review re-measured the detector and
found the constant had already moved (22 → 23
findUpoccurrences) while this sat in review.Rather than trust the branch's copy of the block, the re-applied block is held byte-identical
to today's constant by the gate itself —
node scripts/check-published-list-mirrors.mjsgreen is the proof that the published copy matches what the detector recognises right now.
What was wrong
scripts/check-cross-package-test-inputs.mjsis a source scan: a path spelling it does notknow produces no flag, so a test whose reads escape its package goes undeclared silently.
That is why its recognised set is published in
AGENTS.mdrather than left in theimplementation — and nothing compared the two copies. The published block was short by the
two
findUpanchor seeds, the ⛔ manifest-name prohibition that qualifies them, and the-> repo rootannotation.⭐ Twice before, the stale line over there was the stated reason for a prohibition
(#10163, #10854). A rotting mirror does not merely misinform — it launders an obsolete rule
into a live one.
The card's line reference had already rotted: it names
AGENTS.md:96-106; the block sat at:92-104three days later, and at:93-109today. The gate therefore locates the blockstructurally — by its heading and fence — and never by line number.
The gate
scripts/check-published-list-mirrors.mjs, wired intolint.ymlbeside its closest sibling(Hand-written declaration mirrors — the post-#11905 rewrite left that neighbour intact),
--self-testfirst (37 cases).a spelling authors are told is recognised while the scanner is blind to it. Containment
cannot see it, and cannot see a comment-only drift either — and the comments are where the
prohibitions live.
each with its annotating comment) plus free-standing NOTE PARAGRAPHS set off by blank
entries. An entry is PUBLISHED unless it is blank, or a comment line that no published entry
directly precedes. Every spelling is code, so no spelling can hide from it.
⭐ Publishing all 24 entries verbatim would put the note paragraphs' issue-ID citations into
AGENTS.mdand turncheck:pm-skill-id-lintred — the gate meant to keep the documenthonest would have broken the document's own prose standard (maintainer ruling 2026-08-12).
A self-test case pins that property against the live constant.
fence, empty block, two candidate fences, and on the code side a constant that is missing,
renamed, empty, or not a string list.
AGENTS.mdis governed, so the gate never repairs; itprints the exact block to paste. The module imports
readFileSync, existsSyncand nowrite API at all.
Non-vacuity, re-run on the reworked tree
Every leg: mutate → prove it landed on disk (anchored
grep -c+ sha change) → run the gate→ restore → prove the sha is back, all under a
trap ... EXIT INT TERM. No build/dist stepis involved and none is needed: both gates read the source files directly
(
check-published-list-mirrorsimportsscripts/check-cross-package-test-inputs.mjsby pathand
readFileSyncsAGENTS.md), so there is nodist/copy that could go stale.AGENTS.mdprose line lengthened in place to 138B (line count held at 1158)1 line(s) over the 120-byte budget: L127 (138B)REPOfindUpseed deleted from the published blockin the constant but NOT PUBLISHED⭐ L1 is the leg that matters for the ceiling claim. The 120-byte rule prints nothing when
green, so a silent run is not evidence it judged this file. L1 makes the cap demonstrably
reach
AGENTS.mdprose, which is what turns "my re-applied lines are ≤91 bytes" into ameasurement instead of a silence.
The ceiling, now ruled
scripts/pm/check-skill-line-ratchet.mjs:66— "RAISING one requires a maintainer rulingquoted in the raising PR's body". The C1 ruling quoted at the top of this body is that
ruling; it is reproduced verbatim and untranslated beside the value in the map, per the
convention the
958 → 961and1149 → 1150entries already follow.AGENTS.mdsits at its ceiling with zero headroom by construction, and lossless rewrapheadroom across the section measures 0 — so the re-sync cannot be paid in place without
deleting load-bearing prose. From here the mirror is mechanically enforced, so any later
drift is priced at the moment it is incurred rather than accruing silently.
Verification
Derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackon thereal change set (5 paths, three-dot semantics, repo assertion held) — never a hand-built path
list. 28 of the 29 derived families green at
97d431da, exit codes captured before anypipe, each verdict line the gate's own:
pnpm lint— the whole repo,eslint . --no-inline-config— green in 75s, so therepo-wide scan is a measurement here rather than a declared narrowing.
check:type-check-debt, and it is the same environmentalrefusal this PR declared before the rework, not a regression from the diff: it refuses to
--re-measurewithout the workspace build closure on disk ("56 workspace dependenc(ies) ofthe ledgered packages have no built type entry point"), which
lint.ymlbuilds before thatstep. It is a deliberate fail-closed refusal — measuring from here would "silently measure a
DIFFERENT WORLD" — and this diff contains no TypeScript at all. Declared, not skipped.
Its sibling
check:type-check-coverageruns the same script and is green.Merge resolution re-read adversarially.
git diff origin/main...HEADis exactly the fivefiles above, and every one of its 14 deleted lines is accounted for (13 stale
AGENTS.mdlines + the old ceiling row) — nothing from the dead layout, no reversion of the sibling
AGENTS.md edits. Controls for all three, each confirmed present and absent from the removals:
#11934's
git fetch origin main &&worktree-recipe prefix, #11829's version-PR schedulesentence, and the shared-ref-namespaces bullet.
Co-tenancy
The
lint.ymlhazard the review named (#11905's 95/76-line rewrite) landed and is merged inhere; the gate step sits beside Hand-written declaration mirrors as intended.
AGENTS.mdco-tenants #11829 / #11934 / #12103 are all merged and preserved.
No changeset: this diff publishes nothing (scripts, workflow, and the instruction file) —
skip-changesetis on the PR.Generated by Claude Code