Repository navigation
Commit 2ea0fc8
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
- scripts/pm
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
53 | | - | |
| 53 | + | |
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
| 40 | + | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
| 43 | + | |
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
11 | | - | |
12 | | - | |
13 | | - | |
14 | | - | |
| 10 | + | |
| 11 | + | |
15 | 12 | | |
16 | 13 | | |
17 | 14 | | |
| |||
0 commit comments