Repository navigation
Commit 77df0f6
pm(tooling): move the contract-review tier off the retired ceiling, and give the fuse the case it never had (#19573)
Fixes #19544
Clause-②: no
Fable is gone. The contract-review tier moves to the opus tier the
harness actually
serves, and the downgrade fuse gains the case it never had: a tier that
is GONE is not
a tier that is EXHAUSTED, and the difference is **who may act**.
## The four parts
**1 — the constant.** `CONTRACT_REVIEW_TIER` in
`scripts/pm/dispatch-gates.mjs` now holds
the opus model id. ⛔ Not recalled and ⛔ not invented: read off the
harness itself — the
`claude-code-remote` `get_session` tool reports it for this session as
`external_metadata.last_served_model`, and `session_context.model` and
`configured_model`
agree with it. The id is still spelled as a VALUE on exactly one line in
the tree, which
the battery proves rather than promises (a landed case scans both roots
and reds on a
second site — exercised below).
**2 — the ladder.** 「ceiling fable」 was a WORD written beside the
constant, and that is
exactly how the pair drifted: the harness stopped serving the tier, the
constant kept
naming it, and the ladder went on printing its family word as a live
rule. The ceiling is
DERIVED now — `tierWordOf()` reads the family out of the model id,
`TIER_CEILING` is that
derivation — so `--tier` renders
```
The tier stays the PM's per-card judgment call (floor sonnet · default opus · ceiling opus).
```
and the next retirement moves ONE line. The rendered EXITS text and its
docblock stop
naming the retired tier too: the quota exemption now reads "the mandated
tier EXHAUSTED ⇒
opus, never lower — a tier that is RETIRED is a maintainer ruling
instead, ⛔ never a
seat's reading". `tierWordOf` hands an id it cannot read back VERBATIM
rather than
throwing: `--tier` runs on every dispatch, and a ladder printing the
whole id is louder
than one printing a family word nobody ruled.
**3 — the case the rule never had.**
`.claude/skills/pm-dispatch/references/contract-review.md`
line 60 now reads:
```
- 额度耗尽豁免只及派发 ⛔ 不及复核;档位退役 ≠ 耗尽,恒维护者裁决 ⛔ 非席位读数。
```
Paid IN PLACE — ⛔ no ceiling raised, ⛔ no ruled clause deleted. The file
is still **60
lines against a ceiling of 60 at headroom 0**, and the line is **115
bytes** against the
120-byte cap. The old line's two clauses (「豁免对象是派发」 and 「复核 ⛔ 不随派发档位免除」)
survive compressed into 「只及派发 ⛔ 不及复核」; 额度耗尽's existing treatment is
untouched,
because it was never on this line — 「队列外等档」 is line 53's and 「⛔ 不自审」 is
line 26's,
and neither moved.
**4 — the pins.** Ten new self-test cases hold the constant and the rule
text together: the
ladder line is compared against the constant (not against a remembered
word), a
retired-spelling guard (`RETIRED_TIER_WORDS`) is asserted over every
live rendering, the
rulebook root is asserted to spell no model id at all, and the fuse's
two arms are read out
of the skill file itself.
## What deliberately did NOT change
The issue is explicit that a record of what was served AT THE TIME stays
true, so every
occurrence naming the retired tier as **history** was left alone and
judged one by one —
verbatim maintainer rulings in the mandate docblocks and the `skills/**`
glob's `why` row,
the #8640 incident note in the battery, and the test LABELS that call
the mandate
"fable-mandatory" (they already assert against `CONTRACT_REVIEW_TIER`,
so they are
tier-agnostic in behaviour). The retired-word guard therefore covers the
RULE lines and
excludes the `- path ⇢ glob — why` provenance rows, with a non-vacuity
case proving the
filtered text still carries rules to search.
`check-clause2-carriers --template`'s `Served-tier:` contract is
**unchanged**: the key
still admits the constant's NAME, ⛔ never a model id. It was already
pinned (the battery
refuses a family prefix, a suffixed constant, and the constant's own
VALUE, and its refusal
never quotes an identifier back), so nothing was added there — only
re-run.
## Governance — Tier S, ALL-not-ANY
```
node scripts/pm/check-governed-merges.mjs --test scripts/pm/dispatch-gates.mjs \
.claude/skills/pm-dispatch/references/contract-review.md
```
> governed-surface predicate: 1 of 2 path(s) hit the register (6
surfaces, repo-agnostic).
> ⛔ GOVERNED — Tier S(席内达档复核落地) … `.claude/** ×1` —
> `.claude/skills/pm-dispatch/references/contract-review.md`;
> paths not on the register: `scripts/pm/dispatch-gates.mjs`
No Tier H path is touched: `AGENTS.md`, `CLAUDE.md`, `docs/adr/**`,
`docs/NORTH-STAR.md`
and the published `skills/` root are all outside this diff. This PR
lands on the owning
seat's at-tier review of record; ⛔ no maintainer click is waited for and
⛔ no seat
approves it.
## Evidence
**`node scripts/pm/dispatch-gates.mjs --self-test`** — `✓ dispatch-gates
self-test: 1893 cases pass.`, exit 0, zero reds, run to completion on
the
final commit (the battery re-spawns the tool's CLI many times, so it is
run detached per its
own header and the log read at the end).
**`node scripts/pm/check-clause2-carriers.mjs --self-test`** — `1115
cases pass`, exit 0
(it imports the constant, so this change moves its verdict even though
the path derivation
does not name it; CI runs it in `Lint & Repo Gates`).
**Derived gate families** — `node scripts/pm/dispatch-gates.mjs
--commands` derived 37
commands off the merge base; all were run and all are green, with one
NOT MEASURED:
`check:doc-formula-expressions` exits 3 `PREREQUISITE NOT MET` (two
workspace packages are
unbuilt in this worktree) — ⛔ read as not measured, never as a pass.
`check:pm-skill-ratchet`
and its self-test are green (157 cases), as are
`check:pm-governed-merges`,
`check:skill-frame-sync`, `check:watch-hint-literal`, `check:nul-bytes`
and
`check:pm-skill-id-lint`.
**Lint, narrowed and declared.** `eslint scripts/pm/dispatch-gates.mjs
--no-inline-config`
→ 1 file, 0 errors, 0 warnings. The narrowing is measured, not assumed:
① eslint's own
population is `**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}`, so the `.md` file
is outside it
entirely; ② the file count is read from `--format json` (1); ③
`eslint.config.mjs` enables
no type-aware linting anywhere (no `parserOptions.project`, no
`projectService`), so this
diff cannot move the verdict on any file it does not touch. The
repo-wide `pnpm lint` sweep
is CI's run.
**Control bytes.** `grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'` over
both changed files
prints nothing (exit 1); the control — the same `-P` class engine asked
for printable ASCII
on the same files — fires on 28,205 and 53 lines.
### The retired id is gone from every live rule, with a control
The pattern is spelled as the id's SHAPE so this body carries no model
identifier:
```
git grep -nE 'claude-[a-z]+-5-1' HEAD -- .
scripts/check-commit-card-trailers.mjs:848
git grep -nE 'claude-[a-z]+-5-1' origin/main -- . # CONTROL: same pattern, base tree
scripts/check-commit-card-trailers.mjs:848
scripts/pm/dispatch-gates.mjs:12124
```
The control proves the grep fires: on `origin/main` it finds the
constant's old
declaration; on this branch that line is gone. The one survivor is a
**rejection
vocabulary** — the list of ids `check-commit-card-trailers` must refuse
in a commit trailer
— not a tier rule, and deleting the retired entry would weaken the gate
for old history.
### Ablation — the pins are load-bearing
Each mutation was landed with `scripts/ablation-replace.mjs` (anchor
count checked, blob
hash before/after recorded) and restored with `git checkout HEAD --`,
proven by
`blob == HEAD blob` and an empty `git diff HEAD`.
**A — move the code side without the rule.** The ladder's `ceiling
${TIER_CEILING})` was
replaced by the retired family word (anchor 1 → 0, blob `e3a804cfc19f` →
`d19c861ac7ee`):
```
✗ the ladder prints a ceiling DERIVED from the contract-review constant, so the two cannot drift apart
✗ ⛔ no RETIRED tier word survives in any live RULE … (dirty: 0/fable 3/fable)
```
2 reds out of 1,506 cases decided; every other new pin stayed green,
which is the point —
they bind different halves.
**B — a second spelling of the tier's VALUE** (a fixture argument in the
battery rewritten
to the constant's own value; anchor 1 → 0, blob `e3a804cfc19f` →
`517886d4a0f9`):
```
✗ the tier constant's VALUE is spelled in exactly ONE site under .claude/skills/pm-dispatch + scripts/pm
— 25+30 files read … (found: scripts/pm/dispatch-gates.mjs:12142, scripts/pm/dispatch-gates.mjs:25317)
```
This run is why two of the cases first written here were **deleted
before review**: the
promise was already pinned, and better, by a landed case that derives
its roots from the
mandate globs and finds the definition line instead of remembering it.
One assertion, one
owner.
**C — move the rule side without the code.** Line 60 of the rulebook was
reverted to its
pre-card wording with a model id appended (anchor 1 → 0, blob
`aebe3ca8b11d` →
`906f7ea1e9d5`):
```
✓ the ladder prints a ceiling DERIVED from the contract-review constant …
✓ …in the ladder's own vocabulary — the constant's FAMILY word …
✗ .claude/skills/pm-dispatch spells NO model id at all — 25 file(s) read … (found: …/contract-review.md:60)
✗ …and its fuse keeps the quota exemption pointed at DISPATCH, never at the review
✗ …and carries the case it never had: a RETIRED tier is not an exhausted one …
✗ the tier constant's VALUE is spelled in exactly ONE site … (found: …/contract-review.md:60, …/dispatch-gates.mjs:12142)
```
4 reds out of 1,422 cases decided — the three rulebook pins plus the
landed value-site one
— while **both ladder pins stayed green**. That asymmetry is the
demonstration the card
asks for: move the rule text without the constant and the pins red; the
halves are bound,
not merely adjacent.
## Acceptance notes
Reported to the PM rather than fixed here — all outside the declared
file surface
(`scripts/pm/dispatch-gates.mjs` · `.claude/skills/pm-dispatch/`):
- `.claude/skills/checklist-test/SKILL.md:103` states 「floor sonnet ·
default opus ·
ceiling fable」 as a **live rule**, not as history. It is Tier S like
this diff, so it
could have ridden along, but it is out of surface.
- `scripts/pm/check-dispatch-gates.mjs:263` defines part of the mandated
surface as "the
fable-mandatory surface" in a live docblock — stale vocabulary, no
behaviour.
- `.claude/skills/pm-dispatch/SKILL.md:534` reads
「额度耗尽豁免仅当契约复审档实测不可用才落默认
判断档」. With the ceiling now equal to the default, that exemption has no
room left to
exempt; it is in surface but it is a rule about the DISPATCH ladder, not
the review fuse
the card names, so it was left for a ruling rather than reinterpreted
here.
- `scripts/pm/check-clause2-carriers.mjs` consumes
`CONTRACT_REVIEW_TIER` but is not
derived by `dispatch-gates --commands` for a diff that changes it — a
watch-hint blind
spot of exactly the shape that file's own docblocks describe. Run by
hand here; green.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 2aac821 commit 77df0f6
2 files changed
Lines changed: 124 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
60 | | - | |
| 60 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12119 | 12119 | | |
12120 | 12120 | | |
12121 | 12121 | | |
| 12122 | + | |
| 12123 | + | |
| 12124 | + | |
| 12125 | + | |
| 12126 | + | |
| 12127 | + | |
| 12128 | + | |
| 12129 | + | |
| 12130 | + | |
| 12131 | + | |
| 12132 | + | |
| 12133 | + | |
| 12134 | + | |
| 12135 | + | |
| 12136 | + | |
| 12137 | + | |
| 12138 | + | |
| 12139 | + | |
12122 | 12140 | | |
12123 | 12141 | | |
12124 | | - | |
| 12142 | + | |
12125 | 12143 | | |
12126 | 12144 | | |
12127 | 12145 | | |
| |||
12201 | 12219 | | |
12202 | 12220 | | |
12203 | 12221 | | |
12204 | | - | |
12205 | | - | |
12206 | | - | |
| 12222 | + | |
| 12223 | + | |
| 12224 | + | |
| 12225 | + | |
12207 | 12226 | | |
12208 | 12227 | | |
12209 | 12228 | | |
| |||
12331 | 12350 | | |
12332 | 12351 | | |
12333 | 12352 | | |
| 12353 | + | |
| 12354 | + | |
| 12355 | + | |
| 12356 | + | |
| 12357 | + | |
| 12358 | + | |
| 12359 | + | |
| 12360 | + | |
| 12361 | + | |
| 12362 | + | |
| 12363 | + | |
| 12364 | + | |
| 12365 | + | |
| 12366 | + | |
| 12367 | + | |
| 12368 | + | |
| 12369 | + | |
| 12370 | + | |
| 12371 | + | |
| 12372 | + | |
| 12373 | + | |
| 12374 | + | |
| 12375 | + | |
| 12376 | + | |
| 12377 | + | |
| 12378 | + | |
| 12379 | + | |
| 12380 | + | |
| 12381 | + | |
| 12382 | + | |
| 12383 | + | |
| 12384 | + | |
| 12385 | + | |
| 12386 | + | |
| 12387 | + | |
| 12388 | + | |
| 12389 | + | |
| 12390 | + | |
| 12391 | + | |
| 12392 | + | |
| 12393 | + | |
| 12394 | + | |
| 12395 | + | |
12334 | 12396 | | |
12335 | 12397 | | |
12336 | 12398 | | |
| |||
12394 | 12456 | | |
12395 | 12457 | | |
12396 | 12458 | | |
12397 | | - | |
| 12459 | + | |
12398 | 12460 | | |
12399 | 12461 | | |
12400 | 12462 | | |
| |||
12415 | 12477 | | |
12416 | 12478 | | |
12417 | 12479 | | |
12418 | | - | |
| 12480 | + | |
| 12481 | + | |
12419 | 12482 | | |
12420 | 12483 | | |
12421 | 12484 | | |
| |||
25232 | 25295 | | |
25233 | 25296 | | |
25234 | 25297 | | |
| 25298 | + | |
| 25299 | + | |
| 25300 | + | |
| 25301 | + | |
| 25302 | + | |
| 25303 | + | |
| 25304 | + | |
| 25305 | + | |
| 25306 | + | |
| 25307 | + | |
| 25308 | + | |
| 25309 | + | |
| 25310 | + | |
| 25311 | + | |
| 25312 | + | |
| 25313 | + | |
| 25314 | + | |
| 25315 | + | |
| 25316 | + | |
| 25317 | + | |
| 25318 | + | |
| 25319 | + | |
| 25320 | + | |
| 25321 | + | |
| 25322 | + | |
| 25323 | + | |
| 25324 | + | |
| 25325 | + | |
| 25326 | + | |
| 25327 | + | |
| 25328 | + | |
| 25329 | + | |
| 25330 | + | |
| 25331 | + | |
| 25332 | + | |
| 25333 | + | |
| 25334 | + | |
| 25335 | + | |
| 25336 | + | |
| 25337 | + | |
| 25338 | + | |
| 25339 | + | |
| 25340 | + | |
| 25341 | + | |
| 25342 | + | |
| 25343 | + | |
| 25344 | + | |
| 25345 | + | |
| 25346 | + | |
| 25347 | + | |
| 25348 | + | |
| 25349 | + | |
| 25350 | + | |
| 25351 | + | |
25235 | 25352 | | |
25236 | 25353 | | |
25237 | 25354 | | |
| |||
0 commit comments