Commit 30bac28
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.
1 parent b9d5422 commit 30bac28
1 file changed
Lines changed: 514 additions & 38 deletions
0 commit comments