fix(pm): make the stamp contract quotable — Markdown code is a quotation, rendered as written - #18730
Merged
Merged
Conversation
…ion, rendered as written `post-stamped` substituted the act-clock token wherever it appeared, a passage QUOTING the token included, so a seat could not quote the tool's own diagnostic through the tool. Measured three times inside one hour on live artefacts: a false quotation published on #14251 (an inline code span inside a blockquote), the same hit in the sentence describing it and again in the comment reporting that, plus a dispatch claim refused `[quoted-not-a-stamp]` for spelling the contract's own documentation placeholder. The remedy is structural, not a third spelling and not a flag: inside Markdown code — a fenced block or a backtick span — this tool renders TEXT. Substitution, the opener scan and the quoted-stamp validation all stand down there; a reader of the stored artefact sees the rule without knowing the tool exists. It suppresses nothing that judges a stamp a human typed. The positional scan reads every line, code included; the MIXED trigger stays deliberately quote-unaware; and `maskQuotedStamps` blanks a quoted-stamp token only where it IS a token, so no stamp can hide from the contract behind backticks. The status line now reports how many openers were left verbatim beside how many were substituted, so the count is no longer the only signal an author has to compare against intent. Self-test: 257 cases across 11 batteries -> 308 across 12. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
os-justin
marked this pull request as ready for review
September 17, 2026 17:31
This was referenced Sep 17, 2026
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 #18543
Clause-②: no
scripts/pm/post-stamped.mjsonly. Non-governedscripts/pm/**;skip-changeset(nothing in any package'sfiles[]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-runAll 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.
⇒ substituted inside the quotation;
substitutions: 2where 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.⇒ worse than (a): the braces vanish, so the quotation no longer even shows which route it was about, and the status line's
1 quotedis 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.
⇒ 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.
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
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
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.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.
maskQuotedStampsblanks a quoted-stamp token only where it IS a tokenA 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:
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.--jsongainsverbatim, and theDRY RUNline 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
verbatim: 1; the quotation comes back byte-identical and the act's own token, outside it, still gets the clock.verbatim: 1; the fenced recipe survives intact.Pins
New battery,
the quoting spelling: Markdown code is a quotation, and a quotation is rendered as written, 51 cases, registered inSELF_TEST_BATTERIESwith 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 withverbatim: 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, reported1 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 —
insideQuotedSpanmade to answerfalsealways, 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 atrap … EXIT INT TERMholding an absolute path. The result is recorded below with both legs' numbers. (No build step is involved: this file is run directly bynode, resolves through no packageexports, and has nodist/, soablation-dist-preflight.mjshas nothing to preflight.)HEADblob)baba105b5625fc16insideQuotedSpananswersfalse62cb814417c1fd1agit checkout HEAD -- ABSOLUTE_PATHbaba105b5625fc16(identical to theHEADblob)git diff HEAD0 linesExactly 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 readingsubstitutions: 2from 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 basef6189a43f). 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 0node scripts/check-closing-keyword-parity.mjs:: exit 0node scripts/check-closing-keyword-parity.mjs --self-test:: exit 0node scripts/check-comment-mask-corpus.mjs:: exit 0node scripts/check-declaration-mirrors.mjs:: exit 0node scripts/check-declaration-mirrors.mjs --self-test:: exit 0node scripts/check-scripts-symbol-anchors.mjs:: exit 0node scripts/check-scripts-symbol-anchors.mjs --self-test:: exit 0node scripts/check-self-test-wired.mjs:: exit 0node scripts/check-self-test-wired.mjs --self-test:: exit 0node scripts/check-self-test-workflow-commands.mjs:: exit 0node scripts/check-self-test-workflow-commands.mjs --self-test:: exit 0node scripts/check-whole-set-label-write.mjs:: exit 0node scripts/check-whole-set-label-write.mjs --self-test:: exit 0node scripts/pm/bare-root-worklist.mjs --self-test:: exit 0pnpm check:agent-test-spelling:: exit 0pnpm check:bash32-floor:: exit 0pnpm check:cli-command-ids:: exit 0pnpm check:cross-package-test-inputs:: exit 0pnpm check:driver-memory-census:: exit 0pnpm check:entry-guard:: exit 0pnpm check:nul-bytes:: exit 0pnpm check:parse-guard:: exit 0pnpm check:pm-dispatch-gates:: exit 0pnpm check:pm-post-stamped:: exit 0pnpm check:pnpm-filter-targets:: exit 0pnpm check:ratchet-remedy-authority:: exit 0pnpm check:refd-timer-probe:: exit 0pnpm check:watch-hint-literal:: exit 0Reconciled:
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 atd7dffeb045, which is this branch's final commit — no commit has landed on the branch since.dispatch-gatesprints 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,footerReAnchoringandsentBodyLandedare untouched, and nothing about what is SENT changed except the rendering of quoted tokens. No retry logic, nothing under.claude/**.Generated by Claude Code