Skip to content

Commit c7d6ca8

Browse files
pm-dispatch: a published schema, skill or ADR PR owes a full review — item ④ design judgment in the contract-review record, brief and rule (#26514)
<!-- claude-projects-attribution: {"github_login":"os-warren"} --> _Requested by **Warren** · [project thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ8EtbiFoQ2oh3NQHXsUyoiwP)_ Fixes #25765 Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么**:契约复核在 ①②③ 之外加第 ④ 项「设计判断」:凡 PR 已提交树碰到已发布 schema(`packages/spec/src/**` 非测试)、`skills/**` 与 `.claude/skills/**`、`docs/adr/**` 三面,席位 ACCEPT 前欠的达档复核就是完整复核 —— 逐个面文件判改动对它所引的代码与验收场景是否成立(ADR 另判首个消费者与执行计划),只审面文件、被引代码读而不审,由起草者之外的 agent 在契约档跑,每个实质 head 一轮,只落发现的 commit 由同一复核者 delta 复核,无 must-fix 即止。记录仍是同一条 `## Contract review` 评论(多一个 ④ 节,⛔ 不另开第二条记录);`--template` 打出 ④ 节与说明,`--brief-template` 打出对抗性的 ④ 指令与「只审面文件」规则。 - **为什么改**:项目负责人 2026-10-25 下令 spec、skills、ADR 的改动都要在契约档做完整复核,10:20Z 补充「只针对 PR 中的重要文件」(原话逐字在卡 #25765 正文与评论 6396446237,本文不改写)。卡上实测:一张 ADR PR 两次契约复核 PASS 之后,独立完整复核仍找出三处设计缺陷,全部被负责人采纳 —— 契约复核读的是 diff 对裁决,从不问设计对首个消费者成不成立。 - **风险与回滚**:只改 `.claude/skills/pm-dispatch/` 两个文件与 `scripts/pm/record-recognisers.mjs`;无新门禁、无发布面、无 changeset。行数 49→55(上限 60)、319→319(上限 319,同行改写);脚本自测 201→215 例。风险在成本:每张三面 PR 多一轮达档复核(卡上实测每轮 10–18 分钟);以及 ④ 只挂 schema 与 governed 两面、收窄面不挂,若负责人要把收窄面也纳入需另下令。回滚 = revert 本 PR。 - **先看**:① `references/contract-review.md` 第 29–32 行(④ 定义、只审面文件、cadence)与第 40 行(独立性);② `scripts/pm/record-recognisers.mjs` `contractReviewBriefLines` 的两处 ④ 段;③ `SKILL.md` 第 190 行指针行的后半句。 - **两分钟验证**:`node scripts/pm/record-recognisers.mjs --brief-template | grep -n ④` 看到「④ judges the hits files ONLY」与「④ Design judgment」两段;`node scripts/pm/record-recognisers.mjs --brief-template --face narrowing | grep -c ④` 打印 0;`pnpm check:pm-record-recognisers` 打印 215 cases pass。 - **需要你做的**:无,席位落地(Tier S:`.claude/**` + `scripts/pm/**`,契约复核 PASS 与席位 ACCEPT 后由席位 ready → 入队)。 ## What changes Items 1–6 of the card (「What to change」 1–4 in the body, 5–6 in comment 6396446237), as one PR of three files. The tier is spelled everywhere by its constant name `CONTRACT_REVIEW_TIER`. ### Faces — measured, nothing added The card asks whether `skills/**` and `docs/adr/**` already fall under SKILL.md's governed-rules-text definition. They do: SKILL.md 〈路径分叉〉 「governed 面统一定义」 lists `docs/adr/**` + `.claude/**`(全量) + `skills/**` + `docs/NORTH-STAR.md` + `.github/workflows/**`, and the rules face in `record-recognisers.mjs` reads the governed register (`governedPathsIn`). The published-schema face is `packages/spec/src/**` minus test files (`SUSPECT_TIER_GLOBS`). Read on `origin/main` at `00a4593a` with `node scripts/pm/record-recognisers.mjs --template --paths PATH`: | path | `Served-tier:` | `Scope:` hit | |:--|:--|:--| | `docs/adr/0141-x.md` | `CONTRACT_REVIEW_TIER` | yes (rules face) | | `skills/objectstack-data/SKILL.md` | `CONTRACT_REVIEW_TIER` | yes (rules face) | | `.claude/skills/pm-dispatch/SKILL.md` | `CONTRACT_REVIEW_TIER` | yes (rules face) | | `packages/spec/src/data/x.zod.ts` | `CONTRACT_REVIEW_TIER` | yes (schema face) | | `packages/spec/src/data/x.test.ts` | `TIER_DEFAULT` | no | So all three surfaces of the order are the schema face and the rules face already; this PR adds no face and edits no definition. It adds the **depth** (item ④), the **scope** of ④ (the `hits` files only, the cited code read to judge them), the **cadence** and the **independence** clause, on those two faces. The narrowing face (at tier, but by construction free of schema and governed paths) and the declaration face carry no ④. ### `.claude/skills/pm-dispatch/references/contract-review.md` — 49 → 55 lines (ceiling 60) Record shape, before (one line): ```text - 同形 = `## Contract review` 题头、所审 head sha 独占码段、①②③ 逐项、独立性对、PASS/FAIL。 ``` After (two lines): ```text - 同形 = `## Contract review` 题头、head sha 独占码段、①②③ 逐项(schema/governed 两面加 ④)、 独立性对、PASS/FAIL。 ``` Added after the ② ③ definition line (four lines: ④'s definition and scope, then cadence): ```text - ④ 设计判断只欠 schema 与 governed 规则文本两面,spec、skills、ADR 皆已在内 ⛔ 不另立面: 逐 `hits` 文件判改动对所引代码与验收场景是否成立,ADR 另判首个消费者与执行计划; 被引代码读而不审;①–④ 合称完整复核,余面同形无 ④,⛔ 无第二条记录。 - 实质 head 各欠一轮完整复核;只落发现的 commit 由同一复核者 delta 复核;无 must-fix 即止。 ``` Added after the 独立性对 line (one line — independence): ```text - ④ 恒由起草者之外的 agent 达档跑,起草已达档不免;喂入同上,⛔ 不喂起草者的结论。 ``` The existing scope rule (混合 diff 的达档复核范围 = `reviewFace` 的 `hits` 路径 + 其 hunk 所断言的文件(读被引代码)) is the surface-file rule the owner refined the order with; ④ restates it as 「逐 `hits` 文件判 … 被引代码读而不审」 and the remainder stays the lane seat's ACCEPT (unchanged line). The regeneration / prose-only head-move exception is unchanged: those are not substantive heads. Every line ≤ 120 bytes (longest new line 116). ### `.claude/skills/pm-dispatch/SKILL.md` — 319 → 319 lines (ceiling 319, headroom 0) One line reworded, the ACCEPT pointer line in 〈路径分叉〉. Its first half — the pointer format `指针 ACCEPT → PR #n comment ID` (the placeholder for the comment id is written in angle brackets in the file; spelled out here so the body sanitizer leaves it alone) — is unchanged. The second half, after the `;`: Before: ```text 技能面 hunk 复核随面定档:席未达档起隔离达档复核。 ``` After: ```text 受管/spec 面欠完整复核 ①–④,席未达档起隔离达档复核。 ``` 111 → 118 bytes. The retired words 「随面定档」 (the tier follows the face) remain stated in `contract-review.md` 「档随面定」; the SKILL.md line now names what the governed and published-schema faces owe (the full review ①–④) and who runs it when the seat is below tier. ### `scripts/pm/record-recognisers.mjs` — 2054 → 2134 lines - `REVIEW_FACES` gains `fullReview` (`true` on `schema` and `rules`, `false` on `narrowing` and `declaration`); `recordCarriesDesignJudgment(face, tierName)` reads it (a null face is the bare template, their tier). - `contractReviewRecordLines` takes an optional `faceId` and prints the fourth section; `contractReviewTemplateLines` passes the face through and gains a ④ note; `contractReviewBriefLines` gains the ④ instruction and the surface-file scope rule. `--template`, fenced record after (the bare template, `--face schema`, `--face rules`, `--paths` over a mixed list): ```text ### ③ Boundary flags ### ④ Design judgment Implemented-by: `claude/issue-NNNN-slug` ``` `--template`, note added after the `Scope` note: ```text · ④ Design judgment on the schema and rules faces only — the published spec, skills and ADR surfaces the full-review order names; the narrowing and declaration faces carry no ④. For each `hits` file: does the change hold against the code it cites and the scenario it is accepted against — an ADR against its first consumer and its execution plan? The cited code is READ to judge it, never reviewed; a must-fix found here is a FAIL like any other. ``` `--brief-template`, scope rule added after the `ACCEPT at TIER_DEFAULT` line: ```text ④ judges the `hits` files ONLY: lockfiles, generated output, changesets and prose elsewhere in the PR are not reviewed; the cited code is READ to judge them, never reviewed. ``` `--brief-template`, judge item added after ③: ```text ④ Design judgment — for EVERY `hits` file: does the change hold against the code it cites and the scenario it is accepted against — an ADR against its first consumer and its execution plan? Read the cited code in the live tree and try to break the design; name each finding must-fix or should-fix. A must-fix is a FAIL. ⛔ Judge the tree, never the PR body's account of it. ``` `--face narrowing` and `--face declaration` print none of the four blocks (the ④ note in the template's calibration text names them as faces that carry no ④). Self-test: 14 pins added (8 in the template battery, 6 in the brief battery), floors raised 19 → 27 and 10 → 16 so a pin that stops registering reds; the battery roster count (12) is unchanged. The pins cover: ④ right after ③ in the bare record and one record shape (four `###` headings, never a second record); schema, rules and `--paths` print it; narrowing and declaration do not (fenced record checked, not the calibration text); the face table marks exactly `schema,rules`; an unknown `faceId` is refused; a record carrying ④ still reads FOUND and its tier STANDS (④ is prose to every reader); the note text; the brief's ④ instruction, its surface-file rule, per face; the brief stays free of angle brackets, model identifiers and digit-shaped card numbers. | File | Before | After | Ceiling | |:--|--:|--:|:--| | `.claude/skills/pm-dispatch/references/contract-review.md` | 49 | 55 | 60 (headroom 5) | | `.claude/skills/pm-dispatch/SKILL.md` | 319 | 319 | 319 (headroom 0) | | `scripts/pm/record-recognisers.mjs` | 2054 | 2134 | not ratcheted | ## Why The owner's order: a change on a published schema, a skill or an ADR owes a full review by an independent agent at the contract tier before the seat's ACCEPT — the floor, not a replacement for who drafts (the sibling card #25729 is untouched). Measured on the card: a contract review reads the diff against its order and never asks whether the design works for its first consumer; that question is what ④ makes mandatory. Triage (comment 6431838043) fixed the carrier: `contract-review.md` + the brief template, ⛔ no new gate — the full review is a record the seat reads, like the contract review. ## Tests - `pnpm check:pm-record-recognisers` (the script's own suite, run by `lint.yml` line 1165): `✓ record-recognisers self-test: 215 cases pass` — on `origin/main` at `00a4593a` it prints 201; +14 pins. - `node scripts/pm/check-governed-queue-guard.mjs --self-test` (loads this file through the real lazy import and drives every queue state with the printed record): exit 0. - `npx eslint scripts/pm/record-recognisers.mjs`: exit 0 (the repo-wide `pnpm lint` is CI's run). - No ablation: the diff changes printed text and a face flag, both pinned by the self-test's positive and negative cases (narrowing / declaration carry no ④); no behaviour outside the self-test's reach changed. ## Acceptance notes - **Carrier**: item ④ in the ONE `## Contract review` record (the seat's recommendation on the card), not a second record — `contract-review.md` says 「⛔ 无第二条记录」 and the self-test pins four `###` headings and one record shape. - **④ on the narrowing face: no.** The order names published spec, skills and ADRs; the narrowing face exists only when the diff has no schema and no governed path. Extending ④ there would widen the order; a one-flag change (`fullReview: true` on `narrowing`) if the owner wants it. - **Independence** was already the `Implemented-by:`/`Reviewed-by:` pair plus the feeding rule; the new line adds what the card asks: a change drafted at the contract tier still owes the review, by an agent other than its drafter, never fed the drafter's conclusions. - **Cadence** is new text: one full review per substantive head; a commit that only applies the findings gets a delta review of that commit by the same reviewer; the cycle stops at the first round with no must-fix. The existing regeneration / prose-only head-move exception stays. - **Citing the card in the skill — not done, by rule.** The dispatch order allows the skill text to cite the card's evidence; `pnpm check:pm-skill-id-lint` (pattern `#` + 3 digits) and `.claude/agents/os-dev.md` (「教训写成自含规则,⛔ 不引卡号」) forbid card numbers in `.claude/skills/pm-dispatch/**`. The rules are written self-contained; provenance lives in this body and in the script's docblock, where ruling-record citations are the file's own convention. - **Not in scope, not changed**: who drafts ADR text (#25729); re-reviewing merged PRs; `references/_index.md` does not exist for pm-dispatch (no generator owns one). - **Observation, not filed**: the bare `--template` / `--brief-template` (no `--face`, no `--paths`) print ④, because the bare template is the tier of a schema or governed-path face; a narrowing-only PR already has to be printed with `--face narrowing` (the self-test refuses `--paths` over such a list), so no new trap. ## Verification Local gates on the final head `54224ebf` — derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (41 families), each exit code captured before any pipe, reconciled with `--ran`: `✓ dispatch-gates --ran: 41 derived famil(ies) accounted for — 41 run, 0 NOT-MEASURED`. One family, `check:doc-formula-expressions`, first exited 3 (PREREQUISITE NOT MET: `@objectstack/formula` and `@objectstack/lint` dist absent in a fresh worktree); after `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` under `os-verify-lock.sh` (VERDICT command-exit 0, held 99 s) it re-ran and exited 0. `check:pm-dispatch-gates` ran detached (308.9 s). <details><summary>Exit codes (41)</summary> ```text 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-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/ci/plan-test-core-shards.mjs --self-test :: exit 0 node scripts/pm/bare-root-worklist.mjs --self-test :: exit 0 node scripts/pm/check-governed-queue-guard.mjs --self-test :: exit 0 node scripts/pm/check-harness-current.mjs --self-test :: exit 0 pnpm check:agent-test-spelling :: exit 0 pnpm check:bash32-floor :: exit 0 pnpm check:ci-filter-parity :: exit 0 pnpm check:cli-command-ids :: exit 0 pnpm check:cross-package-test-inputs :: exit 0 pnpm check:doc-authoring :: exit 0 pnpm check:driver-memory-census :: exit 0 pnpm check:entry-guard :: exit 0 pnpm check:gitlink-declared :: exit 0 pnpm check:nul-bytes :: exit 0 pnpm check:parse-guard :: exit 0 pnpm check:pm-expected-skips :: exit 0 pnpm check:pm-governed-merges :: exit 0 pnpm check:pm-governed-prose :: exit 0 pnpm check:pm-record-recognisers :: exit 0 pnpm check:pm-skill-id-lint :: exit 0 pnpm check:pm-skill-ratchet :: exit 0 pnpm check:pnpm-filter-targets :: exit 0 pnpm check:pnpm-flag-spellings :: exit 0 pnpm check:ratchet-remedy-authority :: exit 0 pnpm check:refd-timer-probe :: exit 0 pnpm check:scripts-symbol-anchors :: exit 0 pnpm check:skill-frame-sync :: exit 0 pnpm check:watch-hint-literal :: exit 0 pnpm check:pm-dispatch-gates :: exit 0 pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0 ``` </details> - `pnpm check:pm-skill-ratchet`: `contract-review.md is 55 lines (ceiling 60; headroom 5)`, `SKILL.md is 319 lines (ceiling 319; headroom 0)`, widest SKILL.md table row 341 (pin 341). - `pnpm check:pm-skill-id-lint`: 104 file(s) clean. - `pnpm check:pm-dispatch-gates`: `✓ dispatch-gates self-test (fast tier): 1935 cases pass` (308.9 s). - Control-character scan over the three files: clean. No model identifier in the diff, the commit or this body. Two-minute check: ```bash node scripts/pm/record-recognisers.mjs --template | grep -n "④" node scripts/pm/record-recognisers.mjs --brief-template | grep -n "④" node scripts/pm/record-recognisers.mjs --brief-template --face narrowing | grep -c "④" # prints 0 pnpm check:pm-record-recognisers # 215 cases pass ``` CI on the PR: the required contexts run on the head after this PR opens; this body is written before them (⛔ not waited on, per the order) and the seat's ACCEPT reads the check-runs. ## Human Minimum Each item is one rule from CONTRIBUTING.md › Human Minimum. - [x] 1. No schema touched; `packages/spec` holds no runtime logic — n/a. - [x] 2. Every name I added uses the casing for its kind (`fullReview`, `recordCarriesDesignJudgment`). - [x] 3. No formatter ran; eslint on the edited file passes (repo-wide `pnpm lint` is CI's). - [x] 4. One issue, one branch off an up-to-date `main` (`00a4593a`), one pull request — on the card thread's harness branch, the measured platform exception to `claude/issue-N-slug` named in the seat's Claim. - [x] 5. Nothing publishes: `.claude/**` and `scripts/pm/**` are the fast lane, `skip-changeset` declared at `pr_create`; both declaration lines are at the top of this body. - [x] 6. `packages/spec` untouched. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English (the 维护者速读 block and the quoted rule lines are the four Chinese channels the skill allows). - [x] The *Before Submitting* list in CONTRIBUTING.md is done. --- _Generated by [Claude Code](https://claude.ai/code/session_01JQwxbZCMuAzYCqL3RBJRdX)_ Co-authored-by: objectstack-fleet[bot] <332303061+objectstack-fleet[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent add806c commit c7d6ca8

3 files changed

Lines changed: 99 additions & 13 deletions

File tree

‎.claude/skills/pm-dispatch/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报
187187
- 改动 >3000 行(含生成物)同换终局四件套,⛔ 无 Tier S 例外;读数 = PR additions+deletions。
188188
- ① 席位记录落 PR 先于 `pr_ready`/入队且钉 head:速读六行+席位意见,其下 `## 席位核对`。
189189
- ② PR 悬着等人批,同笔挂 `needs-user-decision`;人工直合即审核记录,授权批准 ⇒ 席位落地。
190-
- 指针 `ACCEPT → PR #n comment <id>`;技能面 hunk 复核随面定档:席未达档起隔离达档复核。
190+
- 指针 `ACCEPT → PR #n comment <id>`;受管/spec 面欠完整复核 ①–④,席未达档起隔离达档复核。
191191
- 核对六项:形态/前提实测/门禁 check-runs/接受的偏差/范围外去向+`Skills-docs:`/落地条款。
192192
- 速读六行固定:改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的。
193193
- 草稿归 dev:每个 PR 正文带 `## 维护者速读` 六行,中文、业务角度,不写席位意见。

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,26 @@
1919
出货字节,⛔ 不是已发布接受集,改它不触发 `Clause-②: yes`;legacy node10 深引用在契约之外。
2020
- 四面皆不碰 ⇒ CI 加席位自读 ⛔ 不起第二个 agent;谁跑 = 派发席,达档者席内审。
2121
- 复核记录 = 一条评论落 PR 或卡,席内与子代理同形;散文、dev 自评、`os-dev-report` 恒不算。
22-
- 同形 = `## Contract review` 题头、所审 head sha 独占码段、①②③ 逐项、独立性对、PASS/FAIL。
22+
- 同形 = `## Contract review` 题头、head sha 独占码段、①②③ 逐项(schema/governed 两面加 ④)、
23+
独立性对、PASS/FAIL。
2324
- 同形含首行 `Served-tier:`:值写该面所定档的常量名 `CONTRACT_REVIEW_TIER` 或 `TIER_DEFAULT`;
2425
无此行不成裁决;模板 `node scripts/pm/record-recognisers.mjs --template`,申报面加 `--face declaration`。
2526
- 同形另带 `Local-runs:` 行:`none`,或 `probe — REASON` 具名唯一本地探针;
2627
有行必校,缺行旧记录不改判。
2728
- ① derived judgments 逐项:diff 引出的接受集与公开面变化逐条点名判对错。
2829
- ② semver 定级与 changeset 声明一致;③ 边界旗:dev 挂旗与 `open_questions` 逐旗答复或升级。
30+
- ④ 设计判断只欠 schema 与 governed 规则文本两面,spec、skills、ADR 皆已在内 ⛔ 不另立面:
31+
逐 `hits` 文件判改动对所引代码与验收场景是否成立,ADR 另判首个消费者与执行计划;
32+
被引代码读而不审;①–④ 合称完整复核,余面同形无 ④,⛔ 无第二条记录。
33+
- 实质 head 各欠一轮完整复核;只落发现的 commit 由同一复核者 delta 复核;无 must-fix 即止。
2934
- 另记作者:PR `user.login` 非 `objectstack-fleet[bot]` ⇒ ③ 注点名该 login(脱中继写),落地前读。
3035
- 复核形状:只读 diff 与卡片,check 结论取 head 的 check-runs,⛔ 永不本地重跑派生门禁族。
3136
- 只喂卡片、既有裁决与 PR 本体,⛔ 不喂派发令与派发席自己的结论;简报写成对抗性。
3237
- 简报从 `node scripts/pm/record-recognisers.mjs --brief-template` 起稿:
3338
只读条款与输入集内建,⛔ 不删 ⛔ 行。
3439
- 隔离复核子代理暂存全写按所审 PR 命名的 `<scratchpad>/pr-<n>/`,⛔ 不读非本轮自写的暂存。
3540
- 独立性对:`Implemented-by:`/`Reviewed-by:` 取值同见 `--template`;子代理记采纳它的席位。
41+
- ④ 恒由起草者之外的 agent 达档跑,起草已达档不免;喂入同上,⛔ 不喂起草者的结论。
3642
- 轮次报告设复审清单专节,与呈裁清单同为强制审计。
3743
- 落地前检两条,过则 Tier S 入队、Tier H 等人批:① 达档条款②复核 PASS 在案(同形记录)。
3844
- 例外:纯重生成或只动上列散文面的 head 后移原记录继续管;判据机读已提交树;

0 commit comments

Comments
 (0)