Skip to content

Commit 30bac28

Browse files
os-justinclaude
andauthored
fix(pm): make the stamp contract quotable — Markdown code is a quotation, rendered as written (#18730)
Fixes #18543 Clause-②: no `scripts/pm/post-stamped.mjs` only. Non-governed `scripts/pm/**`; `skip-changeset` (nothing in any package's `files[]` moves). ## The defect, in one paragraph The tool substituted the act-clock token **wherever it appeared**, including inside a passage that was *quoting the token itself* — because substitution ran on bytes and a fence was treated as a rendering instruction with no meaning for it. A seat writing about the stamp contract therefore could not quote this tool's own diagnostic through this tool: the quotation came back rewritten, the write succeeded, the read-back reported clean, and the only signal was a substitution **count** that nothing compared to intent. Measured three times inside one hour, by two seats: a false quotation published on #14251; the same hit in the sentence *describing* it and again in the comment *reporting* that (5707634696); and the dispatch claim for this card refused `[quoted-not-a-stamp]` for spelling the contract's own documentation placeholder (5717851201). The triage seat carries a hand-written workaround in its standing prompt — 「⛔ 描述这个语法时不要写出令牌字面形状,会被当真令牌解析」 — which is what this change retires. ## Before-readings — this tree at `f6189a43f9`, offline, through `--dry-run` All three taken before any edit. Every token below is written in the **new** quoting spelling, so this PR body is itself a demonstration; the inputs are shown as they were typed. **(a) The card's measured instance — the token in an inline code span inside a blockquote.** Input: a blockquote quoting this tool's own status line, with the token inside backticks, plus one live token in a subscript line. ``` post-stamped: DRY RUN — nothing was written. 2 token(s) substituted with `2026-09-17T16:34Z`, 0 quoted stamp(s) rendered verbatim. ... > `post-stamped` reported it faithfully: 「*stamp: none substituted — this body carried no `2026-09-17T16:34Z`, so there is no clock to check*」 ``` ⇒ substituted **inside the quotation**; `substitutions: 2` where the author meant 1. Exit 0. A sentence this tool never printed, published as a quotation of it. **(b1) UNESTABLISHED POINT 1, now measured — the quoted-stamp form inside a quotation.** Input: `> The second spelling is ` + the quoted-stamp token in backticks, plus one live token. ``` post-stamped: DRY RUN — nothing was written. 1 token(s) substituted with `2026-09-17T16:34Z`, 1 quoted stamp(s) rendered verbatim. ... > The second spelling is `2026-09-08T14:00Z` — a reading of something else. ``` ⇒ **worse than (a)**: the braces vanish, so the quotation no longer even shows which route it was about, and the status line's `1 quoted` is byte-identical to what a *legitimate* declared reading prints. There is no count to compare against intent at all. **(b2) UNESTABLISHED POINT 2, now measured — a fenced code block.** Input: the card's own re-check recipe inside a triple-backtick block, plus one live token. ``` post-stamped: DRY RUN — nothing was written. 2 token(s) substituted with `2026-09-17T16:34Z`, 0 quoted stamp(s) rendered verbatim. ... printf 'quoting the token: 2026-09-17T16:34Z\n' | node scripts/pm/post-stamped.mjs --dry-run --comment 18543 ``` ⇒ a fence was **not** a quotation: substituted exactly like prose. So "no substitution inside fenced code" was a real behaviour change to measure, and fencing alone would not have covered (a), which was an inline span. **(c) The claim's refusal.** Input: the quoted-stamp form with an ellipsis payload, inside backticks. ``` post-stamped: REFUSED — 1 stamp-contract problem(s) in the body. Nothing was written. 1. [quoted-not-a-stamp] ... does not declare a stamp. The quoted route renders a reading of something else VERBATIM, so its contents must be one `YYYY-MM-DDThh:mmZ` and nothing else — it is a declaration, not a free-text escape from the contract. ``` Exit 2. The same refusal fires on the documentation placeholder `YYYY-MM-DDThh:mmZ`, which is the spelling **this file's own refusal text uses** — so the tool could not quote its own refusal back through itself. ## The chosen spelling: Markdown code is a quotation > **INSIDE A QUOTED SPAN THIS TOOL RENDERS TEXT, NOT TOKENS.** A quoted span is one of Markdown's two code constructs: a **fenced code block** or a **backtick code span**. Inside one, exactly three rules stand down — substitution, the opener scan, and the quoted-stamp validation. Nothing was added to the token contract: it still has exactly two spellings, and there is still no flag that turns it off. ### The four axes - **实际业务需求.** Measured, not speculative: three live hits inside one hour across two seats, a false quotation standing on a public card until someone re-read it, and a hand-written workaround living in the triage seat's standing prompt for dozens of rounds. All four measurements above are code constructs — an inline span, a fenced block, a backticked declaration — so the structural rule is the one the evidence actually points at. A fence-only rule would have missed (a), the card's own instance. - **项目长远合理性.** Contract-first and no workaround: the quoting rule is Markdown's own, not a second vocabulary this tool invents and then has to document, and the token contract is untouched. The sustainable version of "explain the contract on a card" is that the contract is quotable; the temporary version is every seat carrying its own prompt-level workaround, which is the state being retired. - **防 AI 写代码犯错.** This is the axis that decides it. A structural rule is **visible in the stored artefact**: a reader who has never heard of this tool sees backticks and knows the passage is quoted, in the spelling every other quotation on the board already uses. A magic word is invisible and has to be memorised — and would itself need quoting the first time anybody documented it. The contract also tightens rather than loosens: quoting suppresses what *renders* a token, never what *judges a stamp a human typed*, so no stamp can hide behind backticks, and the one direction that could have weakened a refusal (making the MIXED trigger quote-aware) is deliberately not taken. - **创业阶段不扩散需求.** Zero new surface: no third token, no flag, no option, no config. One predicate (`insideQuotedSpan`) and one span scanner, consumed by the four rules that already existed. No transition window and no double spelling — the old behaviour is gone in the same commit, which is what 「短期不考虑渐进」 asks for. ### Rejected, one line each - **`--expect-now=N` (the card's candidate A).** Not a quotation spelling at all — it refuses the body instead of letting the quotation be written, so the seat still cannot quote the diagnostic; and being opt-in, it protects only the author who already remembered. - **An escape spelling (candidate C).** A third spelling in a contract whose whole value is that it has exactly two, invisible to a reader who does not know the tool, and subject to the same regress the moment somebody has to quote *it*. - **An explicit opt-out flag.** The one thing this file says there is no flag for, and it leaves no trace in the artefact of why a token was not substituted — a reader cannot tell a quotation from a bug. ## What it does NOT suppress — the load-bearing asymmetry Quoting changes what is **rendered**, never what was **authored**. A stamp inside a fence is still digits on the board. | rule | inside a quoted span | why | |:---|:---|:---| | POSITIONAL | reads every line, code included | a bare stamp in a code span on the opening line is the act's own time typed by hand, backticks or not | | MIXED | triggers on the act-clock token appearing **anywhere**, quoted or not | an author who spells the token knows it exists; deliberately NOT made quote-aware, because that is the one direction this change could have weakened a refusal | | MASKING | `maskQuotedStamps` blanks a quoted-stamp token only where it IS a token | otherwise a hand-typed stamp could hide from the bare-stamp scan behind backticks — the accident this rule may never buy | **A bare stamp inside the quoting spelling is REFUSED, exactly as in prose** (pinned, both positions). One body changes direction as a consequence: the quoted-stamp form carrying **real digits** beside a live token used to be accepted and rendered as bare digits — that acceptance *was* defect (b1) — and is now MIXED-refused. Because the old remedy text would then prescribe a route that cannot work inside a quotation, the refusal gained a clause naming the quotation and pointing at the placeholder form; a stamp with even one unquoted occurrence still gets the ordinary remedy, with no such clause. ## The status line no longer leaves a count as the only signal Before, the line carried the substitution count, the token spelling and a quoted count, and stopped there — the card quotes that form. After, the same line carries a third number, and on the same body as before-reading (a) its new tail reads: ``` · verbatim: 1 opener(s) inside a quoted span, left exactly as written ``` So (a) now reports one substituted and one left verbatim, where the filed run could only say `2`. Those two numbers are what (a) had no way to produce. `--json` gains `verbatim`, and the `DRY RUN` line spells the same three counts through one renderer (`substitutionSummary`), so the three outputs cannot describe one render three ways. ## After-readings — same four inputs, same tree, after the change - (a) exit 0 — one substituted, zero quoted, `verbatim: 1`; the quotation comes back byte-identical and the act's own token, outside it, still gets the clock. - (b1) exit 2 — MIXED, with the quoted-span clause. The argued outcome: real digits inside a quotation are digits on the board. - (b2) exit 0 — one substituted, zero quoted, `verbatim: 1`; the fenced recipe survives intact. - (c) exit 0 — the ellipsis payload and the documentation placeholder are both **quoted verbatim, not refused**. The dispatch claim for this card would now pass byte-for-byte, which is the retirement of the triage seat's standing workaround. ## Pins New battery, `the quoting spelling: Markdown code is a quotation, and a quotation is rendered as written`, 51 cases, registered in `SELF_TEST_BATTERIES` with the battery floor raised 11 → 12. It covers, in order: the card's blockquote-inline-span instance rendering verbatim **and** its before-reading control (the same body with the backticks removed is still substituted, 2); the fenced block, a tilde fence, an info string, a backtick-carrying info string (not a fence), an unclosed fence, a fence inside a blockquote, the blockquote ending it, and a four-space indented block being explicitly **not** the spelling; the claim's ellipsis refusal now rendering verbatim with its prose control still refused; the quoted-stamp form inside the spelling (rendered as the token, counted verbatim, not as a quoted stamp) with its prose control still rendering from the declaration; an unknown token name and an unclosed opener inside a quotation being text, both still refused in prose; the bare-stamp asymmetry in both positions, the mask rule, the quote-unaware MIXED trigger, and the remedy clause with its one-unquoted-occurrence control; the code-span mechanics (unmatched run, double run, one-line-only search, two spans on a line, a backtick run inside a fence); and the prose control asserting byte-identical output with `verbatim: 0`. One pre-existing case was flipped rather than added — the opener-scan battery's `⛔ …and a token inside backticks is STILL substituted — a fence is not an escape`, which is precisely the sentence this card retires. **Every other existing case is untouched and green**: the first run after the implementation, before any new case existed, reported `1 of 257 case(s) failed` — that one — so the 256 others are byte-identical in behaviour. Self-test line: **257 cases across 11 batteries → 308 cases across 12 batteries.** ## Ablation Committed the fix first, then reverted the single predicate that recognises the quoting spelling — `insideQuotedSpan` made to answer `false` always, one line, with every other line of the change left in place. The mutation was proved on disk by occurrence count before the run and the restore proved by hash against the HEAD blob, under a `trap … EXIT INT TERM` holding an absolute path. The result is recorded below with both legs' numbers. (No build step is involved: this file is run directly by `node`, resolves through no package `exports`, and has no `dist/`, so `ablation-dist-preflight.mjs` has nothing to preflight.) | leg | worktree blob | on-disk proof | self-test | |:---|:---|:---|:---| | before (= `HEAD` blob) | `baba105b5625fc16` | predicate body present ×1, marker ×0 | 308 pass / 12 batteries, **exit 0** | | ABLATED — `insideQuotedSpan` answers `false` | `62cb814417c1fd1a` | predicate body ×0, marker ×1 | **24 of 308 failed**, exit 1 | | restored — `git checkout HEAD -- ABSOLUTE_PATH` | `baba105b5625fc16` (identical to the `HEAD` blob) | marker ×0, `git diff HEAD` 0 lines | 308 pass / 12 batteries, **exit 0** | **Exactly the new cases red, the old ones green.** All 24 belong to this change: 23 of the new battery's 51, plus the one flipped opener-scan case. **Zero pre-existing cases went red.** The other 28 new-battery cases are CONTROLS — prose behaviour, the before-reading controls, the prose-still-refused halves — and stay green under the ablation by design, which is what a control is for. One failure detail is worth reading on its own: the counts case fails with `sub=2 verb=0`, which is byte-for-byte the filed reading `substitutions: 2` from before-reading (a). The ablation does not merely turn the pins red; it reproduces the card's measured defect exactly. ## Gates Derived from this worktree with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no hand-fed path list; change set = 1 path, `scripts/pm/post-stamped.mjs`, three-dot against merge base `f6189a43f`). Every derived command run, exit code captured with redirect-then-`$?`, then reconciled with `--ran`. **29 derived, 29 run, every one exit 0.** - `node scripts/check-ci-filter-parity.mjs` :: **exit 0** - `node scripts/check-closing-keyword-parity.mjs` :: **exit 0** - `node scripts/check-closing-keyword-parity.mjs --self-test` :: **exit 0** - `node scripts/check-comment-mask-corpus.mjs` :: **exit 0** - `node scripts/check-declaration-mirrors.mjs` :: **exit 0** - `node scripts/check-declaration-mirrors.mjs --self-test` :: **exit 0** - `node scripts/check-scripts-symbol-anchors.mjs` :: **exit 0** - `node scripts/check-scripts-symbol-anchors.mjs --self-test` :: **exit 0** - `node scripts/check-self-test-wired.mjs` :: **exit 0** - `node scripts/check-self-test-wired.mjs --self-test` :: **exit 0** - `node scripts/check-self-test-workflow-commands.mjs` :: **exit 0** - `node scripts/check-self-test-workflow-commands.mjs --self-test` :: **exit 0** - `node scripts/check-whole-set-label-write.mjs` :: **exit 0** - `node scripts/check-whole-set-label-write.mjs --self-test` :: **exit 0** - `node scripts/pm/bare-root-worklist.mjs --self-test` :: **exit 0** - `pnpm check:agent-test-spelling` :: **exit 0** - `pnpm check:bash32-floor` :: **exit 0** - `pnpm check:cli-command-ids` :: **exit 0** - `pnpm check:cross-package-test-inputs` :: **exit 0** - `pnpm check:driver-memory-census` :: **exit 0** - `pnpm check:entry-guard` :: **exit 0** - `pnpm check:nul-bytes` :: **exit 0** - `pnpm check:parse-guard` :: **exit 0** - `pnpm check:pm-dispatch-gates` :: **exit 0** - `pnpm check:pm-post-stamped` :: **exit 0** - `pnpm check:pnpm-filter-targets` :: **exit 0** - `pnpm check:ratchet-remedy-authority` :: **exit 0** - `pnpm check:refd-timer-probe` :: **exit 0** - `pnpm check:watch-hint-literal` :: **exit 0** Reconciled: `dispatch-gates --ran` ⇒ `29 derived famil(ies) accounted for — 29 run, 0 NOT-MEASURED (a DERIVED zero — all 29 recorded an exit code and none of them is 3)`, **exit 0**. Repo-wide, as PR #18654 did: `pnpm lint` (`eslint . --no-inline-config`) **exit 0**, run at `d7dffeb045`, which is this branch's final commit — no commit has landed on the branch since. ⚠️ NOT MEASURED, declared rather than claimed: the 53 artifact-roster families, the 11 declared wide-population families, the 14 pending-changeset families, the 2 families taking a value from the workflow and the 1 path-scheduled CI job are each outside the derived 29 and are CI's. `dispatch-gates` prints every one of them under its own heading; none is read here as a clearance. ## This body passes the tool it is fixing `node scripts/pm/post-stamped.mjs --dry-run --comment=18543 --file=THIS_BODY` ⇒ **exit 0**. Its first draft did not: it quoted the act-clock token literally *and* carried the concrete stamps from the before-readings, and the MIXED refusal fired twice — correctly, and with the new quoted-span clause naming the quotation each time. That shape is the measured cost of keeping the MIXED trigger quote-unaware, and it is the rule holding rather than a gap: every quotation above is verbatim, and what changed to clear the refusal was spelling the token in words outside the quoted evidence, not editing the evidence. ## Not in scope #18693 (the header's unmeasured issue-body footer cell) and #18709 (exit 4 on the seat's own footer re-anchor) are separate cards queued on this file behind this one; both were read and neither is addressed here. `classifyReadBack`, `footerReAnchoring` and `sentBodyLanded` are untouched, and nothing about what is SENT changed except the rendering of quoted tokens. No retry logic, nothing under `.claude/**`. --- _Generated by [Claude Code](https://claude.ai/code)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent b9d5422 commit 30bac28

1 file changed

Lines changed: 514 additions & 38 deletions

File tree

0 commit comments

Comments
 (0)