Skip to content

Commit 66e34d1

Browse files
claude[bot]claude
andauthored
fix(pm): the Served-tier line names the tier constant, never a model identifier — AGENTS.md's comment rule (#18060) (#18087)
Fixes #18060 A review of record is a GitHub **comment**, and `AGENTS.md` is unqualified about that surface: > …the pre-push hook refuses a model identifier in that pair; **no model identifier lands in a PR title or body, a comment, a changeset, a doc or a code comment.** The `Served-tier:` top line the in-seat contract-review protocol mandates carried the **value** of `CONTRACT_REVIEW_TIER`, which is a literal model identifier. So a record could clear a carrier **only** by putting that identifier into the very artifact the rule names. This PR makes the identifier-free spelling the **only** one: the line's token is the constant's **NAME**. Nothing evidential is traded away — the line was never the reading. The protocol already says 「⛔ 自述档位与传参皆非读数」, and the authoritative control is the seat's own transcript grep against the constant's value, which produces **no repository artifact at all**. Direction was ruled by triage (comment 5656662371, quoted verbatim, untranslated): > ### ⭐ Direction ruled — **the convention yields to `AGENTS.md`.** ⛔ Not a decision card. > ⛔ Triage rules the direction; the exact replacement wording is the implementer's. ## Premise readings All four checked against `origin/main` at `57343f761`, in the worktree, on 2026-09-14. | # | premise | verdict | evidence | |:--|:--|:--|:--| | P1 | both readers compare the token to the constant's **VALUE**, which is a literal model identifier ⇒ a record can pass today only by carrying that identifier in a comment | **holds** | `servedTierStands()` read `served.value === CONTRACT_REVIEW_TIER`; `check-governed-queue-guard.mjs` imports that very predicate through `loadRecordRecognisers`, so both gates answered from one comparison (00:10Z) | | P2 | `contract-review.md` :29 and :56 require that value | **holds** | :29 read 「值取转录 harness `model` 盖章」 and :56 「裁决 `Served-tier:` ≠ `CONTRACT_REVIEW_TIER` ⇒ exit 4」 (00:08Z) | | P3 | `git grep -n Served-tier origin/main -- .claude AGENTS.md skills` finds ONLY those two lines | **holds** | exactly 2 hits, both `contract-review.md`; the whole-tree grep adds only the two script files, 26 + 14 hits (00:09Z) | | P4 | the card's 「no gate reads it *yet*」 is **already false** on `origin/main` | **FALSIFIED — the window the card names has closed** | `273a66501` (2026-09-13T13:12Z, #17990) and `60b99552a` (2026-09-13T15:00Z, #18036) are both ancestors of `origin/main` — `git merge-base --is-ancestor` exit **0** for each, the self-proving direction that needs no control leg (00:41Z) | P4 is why the **readers change too** rather than only the prose. The card was filed while this was a habit; it is a gate now, and 「a gate is much harder to walk back than a habit」. ## What changed 1. **`references/contract-review.md` :29 and :56** — equal-line edits, file still 60 lines, both lines inside the 120-byte CJK prose budget (110 B and 120 B). - :29 — 「值写常量名 `CONTRACT_REVIEW_TIER`,可前置 N/N;无此行不成裁决。」 - :56 — 「`Served-tier:` ≠ 常量名 ⇒ exit 4,点名 PR、评论、读数;型号串按 `AGENTS.md` 拒。」 - The evidence stays exactly where :53 already puts it — the seat's transcript grep, which lands no artifact. 2. **`check-clause2-carriers.mjs`** — new `CONTRACT_REVIEW_TIER_NAME` is the one accepted token; new `isModelIdentifierToken()` refuses the constant's value **and** the id shape (the word claude, a hyphen, a model word — a shape, never a list, so a model nobody has named yet binds). C7's remedy quotes the **new** rule lines and names `AGENTS.md`'s rule, and ⛔ never quotes an identifier token back — a refusal that echoed it would land the identifier in one more artifact. 3. **`check-governed-queue-guard.mjs`** — its references-tier record reader takes the predicate through the same lazy recogniser import (fail-closed on a rename: a missing export is `available: false`), carries the flag on the record so the renderer never re-decides it, and its merge-queue refusal prints no identifier either. Remedy 3 now spells the token as the NAME. ⛔ **Neither gate is weakened.** The line is still required, a missing line is still a refusal, the comparison is still EXACT — no family match, no prefix floor — and the accepted token is still exactly one. The only behavioural delta is *which* single token, plus one **new** refusal class. ## Tests Self-test batteries, on `57132927c`. ⛔ No case deleted — 15 cases were re-spelled and the rest are additions: | battery | before | after | delta | |:--|--:|--:|--:| | `check-clause2-carriers --self-test` | 598 | **605** | +7 | | `check-governed-queue-guard --self-test` | 229 | **233** | +4 | The 598 baseline was measured by running `origin/main`'s own copy of the file in this tree. The 229 is derived (4 added `assert(` calls, 0 removed), because that file's copy cannot be run against a modified sibling — its fixtures are the thing this PR changes. New cases include: the constant's VALUE is refused; the refusal never quotes it back; the refusal names `AGENTS.md`'s rule; a never-shipped id binds too (a SHAPE, not a list); the two refusals differ exactly on quoting; and the row is not widened. **Gate sweep** — `node scripts/pm/dispatch-gates.mjs --commands` derived 43 families from the three changed paths; all 43 run, recorded with `--ran`: ``` ✓ dispatch-gates --ran: 43 derived famil(ies) accounted for — 43 run, 0 NOT-MEASURED (a DERIVED zero — all 43 recorded an exit code and none of them is 3). ``` `pnpm --filter @objectstack/lint run check:doc-formula-expressions` first returned **exit 3 — PREREQUISITE NOT MET** (unbuilt `@objectstack/formula` / `@objectstack/lint`, ⛔ not a finding); after `turbo run build` for those two packages under the shared verify lock it returned exit 0. **Lint** — the full repository run, not a narrowed union: `pnpm exec eslint . --no-inline-config --format json` over **6741 files**, **0 errors, 0 warnings**, exit 0. ## Legacy count — a reading for the seat, ⛔ not a work item here `origin/board-archive` at `bd7bbf53b` (snapshot 2026-09-13T20:23Z), over the archived comment bodies: | probe | count | |:--|--:| | `Served-tier` | **0** | | lit control — `Reviewed-by` | 88 | | lit control — `CONTRACT_REVIEW_TIER` | 303 | ⚠️ **Read this zero narrowly.** Two corrections to how it was specified: - The prescribed path `-- archive/` does not exist on that branch — a grep there returns 0 for the wrong reason, with the lit control ALSO reading 0. The archive lives under `board/` (11,593 files). The table above is the `board/` reading, with the instrument lit. - The archive's highest card is **#17600**, while the `Served-tier:` rule landed with **#17990** on 2026-09-13. ⇒ the archive's window **predates the convention entirely**. The zero says the archive does not reach the window, ⛔ **NOT** that no live comment carries the line. The card's 「how many comments across the fleet carry the line」 stays unmeasured, and this PR migrates nothing. ## Landing note This PR's own governed surface is `.claude/skills/pm-dispatch/references/contract-review.md` — `check-governed-merges.mjs --test` confirms it hits the register, so the PR is **draft-only and human-merged**, or lands on the references tier's review of record. ⚠️ **The review of record on THIS PR must use the NEW form** — `Served-tier:` naming `CONTRACT_REVIEW_TIER`, ⛔ not its value — because the merge-group leg runs **this PR's own guard**. A record written in the old spelling is refused by the code this PR ships. ## Acceptance notes **Open question surfaced by triage, ⛔ NOT decided here, and ⛔ `AGENTS.md` untouched.** Triage named a class the rule as written does not distinguish: **a preserved verbatim maintainer ruling that happens to contain an identifier** vs. **an identifier a seat emits as its own artifact**. This PR only removes the second kind. A blanket cleanup that rewrote preserved maintainer quotes would be worse than the problem (座位制度原话照抄不译). Whoever reconciles `AGENTS.md` should decide that explicitly. Out of scope, noted and not filed: - **238** occurrences of the constant's literal value already sit in archived comment bodies under `board/`. That is a pre-existing fact about historical compliance with the `AGENTS.md` rule, not about `Served-tier:` (which reads 0 there) — and no migration rides on this PR. - The C7 battery feeds the refusal an id **nobody has shipped** to prove it binds a SHAPE. Spelling it lands no identifier because it identifies no model — the same device `check-commit-card-trailers.mjs`'s own battery uses. A comment beside the case now says so. - `scripts/pm/dispatch-gates.mjs` is untouched: it is a `Restart-touch:` trigger file of hold #14290, and the fix did not need it. The constant keeps its single value site there. No changeset: the diff publishes nothing from any released package — `.claude/**` and `scripts/pm/**` are on the fast track, and no path in the diff appears in any package's `files[]`. `Clause-②: no` ## 维护者速读(草稿) **改了什么。** 契约复核记录里那行 `Served-tier:`,原先要求写模型档位常量的**值**(一串型号标识);现在改成写常量的**名字**。两个门禁(`check-clause2-carriers.mjs` C7、`check-governed-queue-guard.mjs` 的 references 档记录读取器)同步改判,并新增一条拒绝:凡写成型号串的一律拒,且拒绝文案**不回显**那个串。 **为什么改。** `AGENTS.md` 明写「no model identifier lands in … **a comment** …」,而复核记录就是一条 GitHub 评论。优先序 `AGENTS.md` > 座位惯例,分诊已定向。关键是这笔交易**零成本**:协议本身就说自述档位不是读数,真凭据是座位的转录 grep,那个动作不落任何仓库产物 —— 所以删掉型号串不损失任何证据价值。 **风险与代价(含回滚)。** 风险低但有一个真实的过渡成本:**本 PR 自己的复核记录必须用新拼写**,因为 merge-group 那条腿跑的就是本 PR 带的守卫;用旧拼写写的记录会被拒。存量迁移不在本 PR(板存档读数 0,但那份存档的窗口早于本约定,所以「舰队里有多少条评论带旧拼写」仍未测)。回滚 = revert 两个 commit;门禁与规则文本同笔回到旧拼写,无数据迁移、无发布面。两侧门禁都**只收紧不放宽**:该行仍必填,缺行仍是拒绝。 **席位意见。** **你要做的。** 确认「预留原文维护者裁决里出现的型号串」这一边界情形该怎么定 —— 本 PR 只清理座位自己产出的那一类,⛔ 没有动 `AGENTS.md`,也⛔ 没有改写任何被原样保留的裁决引文。 --- _Generated by [Claude Code](https://claude.ai/code/session_01DAcomhvR9kKizeYgg89Vo8)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7010085 commit 66e34d1

3 files changed

Lines changed: 219 additions & 70 deletions

File tree

.claude/skills/pm-dispatch/references/contract-review.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
- 逐车道:spec 席达档审契约增量;余席默认档自审加门禁、挂标;豁免仅独立性件与保险丝。
2727
- 复核记录 = 一条评论落 PR 或卡,达档与默认档同形;散文、dev 自评、`os-dev-report` 恒不算。
2828
- 同形 = `## Contract review` 题头、所审 head sha 码段、①②③ 逐项、独立性对、PASS/FAIL 判词。
29-
- 同形含首行 `Served-tier:`:值取转录 harness `model` 盖章,可前置 N/N;无此行不成裁决。
29+
- 同形含首行 `Served-tier:`:值写常量名 `CONTRACT_REVIEW_TIER`,可前置 N/N;无此行不成裁决。
3030
- ① derived judgments 逐项:diff 引出的接受集与公开面变化逐条点名判对错。
3131
- ② semver 定级:变更级别与 changeset 声明一致。
3232
- ③ 边界旗处置:dev 挂旗与 `open_questions` 逐旗答复或升级。
@@ -53,7 +53,7 @@
5353
- ⛔ 自述档位与传参皆非读数;条款②的 `mode:subagent` 派发恒保留标至席内复核完成。
5454
- 读数不达档 ⇒ 改走转录核验的复核子代理;标签原样留置,队列外等待是安全态。
5555
- 保险丝只测座位自会话:`mode:subagent``get_session` 量的是派发会话,⛔ 不作互证。
56-
- 清标前 `--pair`:裁决 `Served-tier:``CONTRACT_REVIEW_TIER` ⇒ exit 4,点名 PR、评论、读数。
56+
- 清标前 `--pair`:`Served-tier:`常量名 ⇒ exit 4,点名 PR、评论、读数;型号串按 `AGENTS.md`
5757
- 施工档只取 harness `model` 盖章或认领 Container & model 行;`Co-Authored-By` = 署名常量 ⛔ 非证据。
5858
- 产出裁决的每轮都须读到契约复审档位,见回退证据 ⇒ 裁决整体作废。
5959
- 父会话只可逐字采纳或整体作废(核验失败、越范围、格式不完整),⛔ 永不改写润色。

0 commit comments

Comments
 (0)