Skip to content

Commit 2ea0fc8

Browse files
pm-dispatch(contract-review): triage takes no contract reviews — a hand-off names a review seat or a sibling lane seat (#29686)
domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J <!-- claude-projects-attribution: {"github_login":"huangyiirene"} --> _Requested by **Irene** · [project thread](https://claude.ai/code/project/chan_01TJXtQ1tVD26ecLDZxFS67x?thread=cmsg_01TJXtQ1tVD26ecLDZxFS67x6DWPLkX4BaiYjvPnKJWmgg)_ Fixes #29667 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:分诊不再接契约复审。派发席在本席达档审;429 时交接行点名复审席 `review#N`,未设复审席时点名本车道兄弟席 `domain:<lane>#N`,⛔ 永不点分诊。`check-owed-reviews` 的 TAKE 行给出接手者(交接行所点席,或车道席/复审席),不再指向分诊。信箱 `Request: contract-review` 与回程 `Notify: contract-review` 改为车道 ↔ 复审席或兄弟席。分诊轮次只按车道计欠审 head 数。 - 为什么改:维护者裁决「目前各车道都有fable,应该不需要你契约复审」。 - 风险与回滚:只改规则文本、两个只读报表的读法与它们的自测;无新门禁、标签或巡检行。回滚即 revert。 - 先看:`contract-review.md` L21–28、L53;`check-owed-reviews.mjs` 的 `takerOf`;`record-recognisers.mjs` 的 `HANDOFF_TARGET`。 - 两分钟验证:`pnpm check:pm-record-recognisers`,预期四个自测全过。 - 需要你做的:无,Tier S,由席位达档复审后落地。 ## What changes 1. **`references/contract-review.md` 〈复核归属与资格〉.** Triage's fallback (a)(b)(c) is gone, and so is its use in the landing-head re-review line (L53). The dispatching seat reviews in its own seat at `CONTRACT_REVIEW_TIER`. On a 429 it keeps the pending-review marker and posts the hand-off line naming a review seat `review#N`, or a sibling seat of the lane `domain:<lane>#N` while none is seated, never triage. An owed head is taken by the lane seat or a review seat. An off-duty lane's owed heads go into its hand-over brief and wait for its next seat or a review seat. The claim lines (L26, L28) name the lane seat or a review seat. When two claims are live on one head, the earliest holds and the later claimant withdraws by reply (L28). This is what `contractReviewClaims` already does, and the seat amended its ruling so the text follows the code (6593367094). 2. **`scripts/pm/check-owed-reviews.mjs`.** A TAKE row now names its taker (`takerOf`): the seat a hand-off on this head names; otherwise `the domain:<lane> seat or a review seat`; when the lane seat is gone (c), `a review seat, or the domain:<lane> seat next on duty`. The hand-off column prints the named seat. Still report-only, exit 0. 3. **`scripts/pm/record-recognisers.mjs`.** The hand-off target set changes from {`triage`} to `review#N` or `domain:<lane>#N`, with the number required. A line naming `triage` (or `director`, or a seat with no number) is unreadable, so it hands the review to nobody. `contractReviewHandoff` now reads `handed` with `to` where it read `triage`. In `MAILBOX_KEYS`, `request:contract-review` runs lane → a review seat (or a sibling lane seat while none is seated), and `notify:contract-review` runs from the seat that rendered the record → lane. `contractReviewClaims` code is untouched (seat's ruling); its doc comments now say the earliest live claim holds, and that a legacy `triage#N` claim yields to a later one. The hand-off template is exported as `CONTRACT_REVIEW_HANDOFF_TEMPLATE` and pinned verbatim against contract-review.md L22, the way the claim and hold templates are pinned. 4. **`references/project-forms.md`.** L40 carries both contract-review doorbell legs, lane → review seat or sibling seat and back. L43 carries both triage legs, `Request: triage` and `Notify: release-blocker`. "Unsubscribed only" is dropped from L40 because L47 already says a recipient subscribed to the PR is never rung. 5. **`references/triage-duties.md`** (added to the surface by the seat, comment 6592498626). The owed-review step L10 and the triage self-review rows L11–14 are replaced by two lines. The round record counts owed heads older than one round per lane and names the lane; that is a report, not a review. Delta re-reviews of triage's old records go to the lane seat or a review seat. L3 now says 定级复审 so it does not read as contract review. `lanes/triage.md` is unchanged: its only review mention (L15) already says PASS/FAIL is the lane's. ### Line budget (no ceiling row moved, no re-wrap) | file | before / after / ceiling | |:--|:--| | `contract-review.md` | 60 / 60 / 60 | | `project-forms.md` | 55 / 55 / 55 | | `triage-duties.md` | 99 / 96 / 99 | Every edited line is at most 120 bytes. The exception is the hand-off template L22, a single code span (142 bytes; the template it replaces was 122), which the ratchet treats as unbreakable. `check:pm-skill-ratchet` exits 0. ## Tests - `node scripts/pm/record-recognisers.mjs --self-test`: 355 cases pass (351 before). The hand-off battery's pin went from 13 to 17. New cases: - a `domain:ui#2` target reads, lower-cased, and hands the head to it; - a line still naming `triage` is unreadable on the thread, never `handed`; - the template is spelled verbatim in a code span in contract-review.md; - the template sent unedited is unreadable. The closed-set case now covers `triage`, `director`, `review` and `domain:ui` with no number. - `node scripts/pm/check-owed-reviews.mjs --self-test`: 68 cases pass in 9 batteries (65 before). The triggers battery's pin went from 8 to 10, and the claims battery's from 5 to 6. Every TAKE case asserts its taker. New cases: - a hand-off to a sibling lane seat names it as the taker; - a `triage` hand-off line gives no (a) and never a triage taker; - a review seat's claim posted before the lane's holds the head, with no tie printed. The report case asserts that no printed `take:` names triage. - `pnpm check:pm-record-recognisers` (record-recognisers, check-owed-reviews, mailbox-open, fleet-roster): exit 0. ## Live board `node scripts/pm/check-owed-reviews.mjs` on objectstack-ai/objectstack at 2026-11-03T01:04Z found 43 open PRs (28 drafts). 18 owe a review: 3 TAKE, 3 WAIT, 0 HELD, 12 DONE. - The three TAKE rows read `take: the domain:server seat or a review seat` (#29628, #29637) and `take: the domain:ui seat or a review seat` (#29639). - No row names triage as a taker. "triage" appears only on DONE rows #29623 and #29651, as the side of an existing `triage#1` claim on a head that already has its record. ## Acceptance notes - The contract review on cf3a139 (6593356996) was FAIL on M1: the rule text said the lane wins a tied claim, and the code gives the head to the earliest claim. The seat amended its ruling (6593367094) so the text follows the code. The delta commit 7df996e rewrites contract-review.md L28 in place (117 bytes, 60/60) and the comments that said the lane wins. It also carries S1, the pinned template. S2 (a per-lane owed count printed by the report) is left for #29242, on the seat's word. - `review#N` is not yet a `seatKey` spelling, so a doorbell cannot be addressed `To: review#1` until #29242 lands the review seat. Until then the sibling lane seat is the fallback, as the rule text says. - `TRIAGE_ROUND_MINUTES` keeps its exported name; only its doc changed. - The two WIP commits on this branch carry no `Claude-Session:` trailer pair. The branch is `claude/project-thread-*`, so AGENTS.md §3 does not allow a force-push to reword them. ## Verification <details><summary>Local gates on 7df996e: 40 derived, 40 run, all exit 0 (`dispatch-gates --ran`)</summary> - On head 7df996e, `node scripts/pm/dispatch-gates.mjs --commands` derived 40 commands. All 40 ran with a 900 s timeout each, in a tree with `pnpm install --frozen-lockfile` done and `@objectstack/formula` and `@objectstack/lint` built. Exit codes were recorded before any pipe, and all 40 exited 0. - `--ran` printed: `40 derived famil(ies) accounted for — 40 run, 0 NOT-MEASURED`. - On the first head, cf3a139, the same 40 ran. Ten of them first refused or failed in a tree with no `node_modules`: nine exited 3 and `check-self-test-workflow-commands` exited 1 because `@changesets/cli` was missing. After the install and build, all ten were re-run and exited 0. - CI on 7df996e: every check-run is `success` or skipped by path filter or opt-in. The required contexts that ran are `success`: Lint & Repo Gates, TypeScript Type Check, Test Core, Test UI and Governed Surface Queue Guard. The UI build, lint and E2E contexts were skipped by path filter. </details> 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01J8VVAka2VdDFVA5VvZmmgK --- _Generated by [Claude Code](https://claude.ai/code/session_01J8VVAka2VdDFVA5VvZmmgK)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9b4fa6c commit 2ea0fc8

5 files changed

Lines changed: 140 additions & 100 deletions

File tree

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
- 已发布面以包的 `exports` 映射为准:从入口类型图不可达、且 `exports` 不可寻址的 `.d.ts` 是
1919
出货字节,⛔ 不是已发布接受集,改它不触发 `Clause-②: yes`;legacy node10 深引用在契约之外。
2020
- 四面皆不碰 ⇒ CI 加席位自读 ⛔ 不起第二个 agent;谁跑 = 派发席,达档者席内审。
21-
- 派发席达档调用被配额拒(HTTP 429)⇒ ⛔ 不降档审;PR 落交接行、留等复核标记,交分诊席。
22-
- `Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (<HTTP status / error>, <UTC time>) · head <sha>`
23-
- 分诊只接无人在审的欠审 PR(draft 亦算):现 head 无记录、无活认领,且 (a)(b)(c) 之一成立。
24-
- (a) 交接行点名现 head 或 PR 带等复核标记,同轮接;(b) 现 head 已等满一轮分诊(约 60 分钟);
25-
- (c) 车道席已收班或不在总表;欠审清单 = `node scripts/pm/check-owed-reviews.mjs`,只读。
26-
- 车道或分诊起审前读 PR:现 head 有记录或活认领 ⇒ ⛔ 不起;否则先落认领行,一 head 一行:
21+
- 派发席席内达档审;被配额拒(HTTP 429)⇒ ⛔ 不降档,留标记落交接行,点复审席,无则兄弟席:
22+
- `Contract-review-handoff: <review#N|domain:<lane>#N> — CONTRACT_REVIEW_TIER unavailable (<HTTP status / error>, <UTC time>) · head <sha>`
23+
- 欠审 PR(含 draft)现 head 无记录、无活认领且 (a)(b)(c) 之一 ⇒ 车道或复审席接,⛔ 非分诊。
24+
- (a) 交接行点名现 head 或带等复核标记,同轮由所点席接;(b) 现 head 已等满一轮(约 60 分钟);
25+
- (c) 车道收班或离总表:欠审入交班简报待下席或复审席;清单 `scripts/pm/check-owed-reviews.mjs`。
26+
- 车道或复审席起审前读 PR:现 head 有记录或活认领 ⇒ ⛔ 不起;否则先落认领行,一 head 一行:
2727
- `Contract-review-claim: <session> · head <full sha> · <UTC>`
28-
- 认领随 head 移动或贴后 2 小时无记录失效;同 head 双认 ⇒ 车道胜,分诊回帖撤回、弃产出。
28+
- 认领随 head 移动或贴后 2 小时无记录失效;双认 ⇒ 先贴者持有,后者回帖撤回、弃产出。
2929
- 车道暂缓本 head 送审落 `Contract-review-hold: <session> · head <sha> · <reason> · until <condition>`
3030
- 新 head 即清;点名现 head 时 (b) 不起;条件满足由持有车道挂等复核标记或落交接行。
3131
- 逾 24 小时条件未满的 hold 列入分诊轮次记录(`check-owed-reviews.mjs` 标出)。
@@ -50,7 +50,7 @@
5050
而已挂 auto-merge ⇒ 派发席读到即照 AGENTS.md disarm 句撤挂,FAIL 记录点名欠撤挂;重挂照 ①。
5151
- ② PR check 全绿,⛔ 非 required 子集;例外:merge-base 同签名的红不计、按设计而红见 SKILL.md。
5252
- 签名 = 失败步 + 首错行,读 base check runs 的 API ⛔ 不凭口述;主干红止血立单不变。
53-
- 落地时仍欠复核的 PR 在落地 head 复审,车道席或分诊按 (a)(b)(c) 接;FAIL ⛔ 不修已关 PR。
53+
- 落地时仍欠复核的 PR 在落地 head 复审,车道席或复审席按 (a)(b)(c) 接;FAIL ⛔ 不修已关 PR。
5454
- 每条 must-fix 引该记录立新卡、按发现定级;回退仅限主干红(p0,main-red 约定①)或安全边界。
5555

5656
## 等复核标记 `needs:contract-review`

‎.claude/skills/pm-dispatch/references/project-forms.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@
3737
- 正文首行 `Mailbox-of: <席位> · <login>`;坐席即开(`mailbox-open.mjs`)并订阅,存根记 `Mailbox:`。
3838
- 永不合并,不欠 CI,落地与台账查询排除它;移交或换账号关旧开新;评论首行 `To: <席位>`。
3939
- 次行恒为一键,下列事件必敲;一事一行 ≤200 字节,只写键与编号;表外即半态。
40-
- 车道→分诊:复审交接行同笔 `Request: contract-review`;问卡去留、路由或定级 `Request: triage`。
40+
- 车道→复审席或兄弟席同交接行 `Request: contract-review`;反向随记录 `Notify: contract-review`。
4141
- 任一席→分诊:p0 嫌疑、main 红、确定性队列红 `Request: urgent-triage`。
4242
- 立锚卡者→分诊(缺则总监)`Request: main-red`,→破坏 PR 的席与锚卡车道 `Notify: main-red`。
43-
- 分诊→车道:未订阅者随记录 `Notify: contract-review`;p0/p1 发版阻塞定入 `Notify: release-blocker`。
43+
- 车道→分诊问卡去留路由定级 `Request: triage`;反向 p0/p1 发版阻塞定入 `Notify: release-blocker`。
4444
- 移卡入队者→车道:p0/p1 `Blocked-by` 关闭 `Notify: unblocked`;记裁决席→被改席 `Notify: ruling`。
4545
- 席→兄弟席或他车道:认领文件面相交或须先落 `Notify: serial`,先落者落地 `Notify: landed`。
4646
- 上下线→兄弟席与分诊 `Notify: seat-online`、`Notify: seat-offline`;清单变→兄弟席 `Notify: split`。

‎.claude/skills/pm-dispatch/references/triage-duties.md‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
# 分诊座位职责
22

3-
- 本文与技能他处点名分诊之条(复审、摘 `pm:retriage`、约定③ 等)即分诊座位的全部职责。
3+
- 本文与他处点名分诊之条(定级复审、摘 `pm:retriage`、约定③ 等)即分诊座位的全部职责。
44
- fire 开局只按名加载互斥检查所需工具,`ToolSearch` 用 `select:`;判定本轮有活才加载其余。
55
- ⛔ 分诊 fresh session 开局不做泛关键词 ToolSearch;可验判据:空转轮 ~4 万 token 以内。
66
- 两级盘点:小时轮以 `since` 窗口读增量,锚 = 座位贴上一份收班简报的时间戳。
77
- 查重缓存住席内:新会话全量拉,其后 `since` 增量;⛔ 不建分支、不共享、不依赖备份。
88
- 每日一 fire 跑两仓全量对账并归集日频职责;选层按 fire 时刻 ⛔ 不用计数器,简报写明层。
99
- 每条枚举比对返回数与 `totalCount`,不等 ⇒ 报 `sweep INCOMPLETE` 点名缺口,⛔ 永不报干净。
10-
- 复审每轮先跑 `check-owed-reviews.mjs`,照 contract-review.md 接;配额拒 ⇒ PR 留标,⛔ 不降档审。
11-
- 每轮比对自审记录 `Head-sha` 与现 head,越过即过期,纯重生成/只动散文面例外(判已提交树)。
12-
- 自审 FAIL 过期 ⇒ 同轮达档重审新 head,逐条复查 must-fix,delta commit 当改动审。
13-
- 自审 PASS 过期 ⇒ PR 记一条 PASS 不再管辖、欠 delta 复审,归本席或新交接行。
14-
- 轮次记录逐张自审 PR 写 `认领者 · 记录 head→现 head→状态`(现行/过期已重审/过期已记)。
10+
- 轮次记录按车道计欠审逾一轮的 head 数并点名车道(`check-owed-reviews.mjs`),只报 ⛔ 不接审。
11+
- 分诊旧记录过期:delta 复审归车道或复审席,照 contract-review.md;⛔ 分诊不再审。
1512
- Backlog sweep 是常设职责,每 fire 扫任一析取命中的卡。
1613
- 析取 ①:全裸(无 `pm:*`、无 `needs-user-decision`、无 `domain:*`)。
1714
- 析取 ②:有 `pm:queue` 无 `domain:*`(仅多车道仓);析取 ③:有 `domain:*` 无 pm-state。

0 commit comments

Comments
 (0)