Commit 7d07814
pm-dispatch: a triage fold proposal binds only before any named card has an open PR; a foreseen follow-up is a card (#21676)
Fixes #21467
Clause-②: no
Two protocol lines in the execution seat's playbook, as the card's
triage grade directs (comment 5962064937). Opened as a draft that is
**red on `check:pm-skill-ratchet`**: the file sits at its line ceiling,
so the seat has to pick how the two lines are paid before this can land.
See "Open: the line ceiling" below.
## What changed
`.claude/skills/pm-dispatch/references/execution-duties.md`, section
〈候选与批次〉. Two lines inserted; no other line moved or changed.
| line | text | bytes |
|---|---|---|
| 34 | `- 分诊折叠提议仅是建议,点名各卡皆无 open PR 才有效;否则各卡各自落地,拒折理由记一行。` | 119 |
| 43 | `- 分诊预见的后续工作是一张卡,触发条件落地时立卡;⛔ 分诊一句话永不授权无卡编辑。` | 116 |
How each clause of the direction maps to the text:
- Fold. "advisory" maps to 仅是建议. "binds only while none of the cards it
names has an open PR" maps to 点名各卡皆无 open PR 才有效. "once one does, each
card lands on its own" maps to 否则各卡各自落地. "the execution seat records the
decline in one line" maps to 拒折理由记一行.
- Follow-up. "a follow-up that a grade foresees is a card, filed when
its trigger lands" maps to 分诊预见的后续工作是一张卡,触发条件落地时立卡. "a triage line never
authorises an edit without a card" maps to ⛔ 分诊一句话永不授权无卡编辑.
Why both lines are in 〈候选与批次〉:
- The direction says "the seat picks the section", singular, so both
lines go into one section.
- The fold decision is made in this section: family dispatch, the five
admission gates and the fold-or-serial answer are lines 27 to 33. Line
33 also names where that answer is written (the serial-queue entry
and/or the chain-head claim), so the one-line decline goes there too.
Line 34 sits directly under it.
- This section also decides what counts as a card before anything is
claimed. Line 43 sits under the rules for work derived from in-flight
cards (lines 40 to 42: in-scope work becomes a sub-issue, and an
escalated card says which half it carries).
- The dispatch suggested putting the follow-up line near the claim rules
(〈认领〉). Its ⛔ half would read the same there. I did not take that
suggestion because the direction names a single section.
## Reading 1: placement and size
- The new lines are 34 and 43 (numbered after the insert). The file goes
from 183 to 185 lines (+2 / -0). `git diff --stat origin/main...HEAD`
shows 1 file changed, 2 insertions(+).
- Both lines are under the ratchet's 120-byte line cap (119 B and 116
B). Neither cites an issue or PR number.
## Reading 2: the two pm-skill gates, at head 0583520
`pnpm check:pm-skill-id-lint`, exit 0:
```text
✓ check-skill-id-lint self-test: 14 cases pass.
✓ check-skill-id-lint: 34 file(s) clean (pattern /#[0-9]{3,}/g).
```
`pnpm check:pm-skill-ratchet`, exit 1. Its self-test passes (234
checks); the failing line from the run is:
```text
✗ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/execution-duties.md is 185 lines; the ratchet ceiling is 183. Keep the surface compressed: principles in SKILL.md, on-demand detail in .claude/skills/pm-dispatch/references/ — provenance is one line, stories live on cards, not in operational text. Raising a ceiling requires a maintainer ruling quoted in the PR.
```
That is the run's only failure. Neither new line trips the
max-line-length rule.
## Open: the line ceiling
The dispatch assumed `check:pm-skill-ratchet` only measures `SKILL.md`.
That turned out to be wrong. The `CEILINGS` map in
`scripts/pm/check-skill-line-ratchet.mjs` lists
`references/execution-duties.md` at 183 lines with zero headroom, and
the gate's own message says a raise needs a maintainer ruling quoted in
the PR. So any net added line turns `Lint & Repo Gates` red.
This PR does neither of the things that would fix it. It does not raise
the ceiling: `scripts/**` is outside the declared file surface, and the
dev contract forbids raising it. It does not delete other lines either:
the dispatch fenced every other line. The seat has two options:
- **A: a ruled raise from 183 to 185.** Quote a maintainer ruling in
this PR body and edit the one `CEILINGS` row. Every existing line stays
where it is.
- **B: pay in place, net 0.** Delete two lines whose content already
reaches the same reader by another route:
- Line 60, ``- 释放是显式动作:让卡离手者同笔清 assignee + `Release:`
行(会话/因/去向);下一任重新认领。`` The same rule appears in
`references/state-machine.md` line 41 (same fields, same same-write
rule), in the assignee row of SKILL.md 〈状态模型〉 (离手恒走释放), and in the claim
paragraph of AGENTS.md ("Release is an explicit act").
- Line 165, `- 复位走梯度,每次比上一次更具体;第三次停摆判 unreliable,按接手协议重派。` The same rule
appears in `references/dispatch-runbook.md` 〈停摆复位梯度〉 (梯度逐级; ③ 第三次停摆判
unreliable,按接手协议重派到该分支). A seat already has to open that section to get
the 姿态句 text that line 164 tells it to send.
The report comment on the card compares A and B along the four axes.
## Gates, at head 0583520 (after merging origin/main at 417443e)
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`, run with no paths, derived 17 commands.
That is the same list as the dispatch. I also ran `pnpm
check:pm-settings-deny-roster`, because its roster lives under
`.claude`. Every command went through `scripts/pm/os-verify-lock.sh`,
and each exit code was captured before any pipe.
`doc-formula-expressions` first refused with exit 3 (PREREQUISITE NOT
MET). I built its prerequisites with `turbo run build
--filter=@objectstack/formula --filter=@objectstack/lint` (exit 0) and
re-ran it.
| exit | command |
|---|---|
| 0 | `node scripts/check-closing-keyword-parity.mjs` |
| 0 | `node scripts/check-closing-keyword-parity.mjs --self-test` |
| 0 | `node scripts/check-comment-mask-corpus.mjs` |
| 0 | `node scripts/pm/check-harness-current.mjs --self-test` |
| 0 | `pnpm --filter @objectstack/lint run
check:doc-formula-expressions` |
| 0 | `pnpm check:agent-test-spelling` |
| 0 | `pnpm check:cross-package-test-inputs` |
| 0 | `pnpm check:doc-authoring` |
| 0 | `pnpm check:driver-memory-census` |
| 0 | `pnpm check:gitlink-declared` |
| 0 | `pnpm check:nul-bytes` |
| 0 | `pnpm check:pm-governed-merges` |
| 0 | `pnpm check:pm-skill-id-lint` |
| 1 | `pnpm check:pm-skill-ratchet` |
| 0 | `pnpm check:refd-timer-probe` |
| 0 | `pnpm check:skill-frame-sync` |
| 0 | `pnpm check:watch-hint-literal` |
| 0 | `pnpm check:pm-settings-deny-roster` |
`node scripts/pm/dispatch-gates.mjs --ran`: `✓ dispatch-gates --ran: 17
derived famil(ies) accounted for — 17 run, 0 NOT-MEASURED (a DERIVED
zero — all 17 recorded an exit code and none of them is 3).`
Left to CI and not measured here: the type-check lanes, and the
wide-population and roster families that dispatch-gates lists outside
its derived set. This diff touches no TypeScript and no package.
No changeset: `.claude/**` publishes nothing, so `skip-changeset`
applies.
## Acceptance notes
- One dispatch assumption turned out to be false: `execution-duties.md`
is under the line ratchet at 183 lines with zero headroom. Details are
in "Open: the line ceiling".
- The two overlaps named in option B (lines 60 and 165) are density
observations, not defects. They are noted here and not filed. Carrier:
the seat, if it picks B; otherwise none.
- The ratchet also printed a hint unrelated to this diff:
`.claude/skills/spec-property-retirement/SKILL.md` has table-row pin
headroom 2 ("lower the pin to 324"). Noted, not filed. Carrier: none.
- The first gate derivation read a tree two commits behind origin/main
(it flagged STALE TREE because an unrelated baseline JSON had changed).
I merged origin/main at 417443e and re-ran every gate on the merged
head.
- The follow-up line is not where the dispatch suggested (〈认领〉). The
reason is under "What changed".
## 维护者速读(草稿)
- **改了什么**:在执行席手册 `execution-duties.md` 的〈候选与批次〉加两行规则。第一行:分诊提出的"把几张卡并进一个
PR"只是建议,只要其中任一张已经开了
PR,就各卡各自落地,执行席记一行拒绝理由。第二行:分诊预见的后续工作必须是一张卡,等触发条件落地时再立卡;分诊的一句话不能授权任何无卡的改动。
-
**为什么改**:分诊曾在同一张卡上同时给出这两种指示,执行席当时只能凭判断拒绝。协议里没有对应规则,下一个席位可能做出相反判断,例如重开已验收的
PR,或者做一次没有认领、没有文件面、没有验收锚点的改动。
- **风险与代价(含回滚)**:纯协议文本,不加门禁,不影响运行时。代价是该文件从 183 行变成 185 行,超出行数棘轮上限(183,余量
0),所以本 PR 目前 `check:pm-skill-ratchet`
是红的。需要在"维护者裁决抬上限"和"删两行重复规则抵账"之间选一个。回滚方式:revert 本 PR。
- **席位意见**:
- **你要做的**:席位选 A(抬上限)时,需要你给一句裁决原话;选 B 时你不用做任何事。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01CB6W87z22K2yjUCDyVrJRk)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent eed2dee commit 7d07814
1 file changed
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
34 | 35 | | |
35 | 36 | | |
36 | 37 | | |
| |||
39 | 40 | | |
40 | 41 | | |
41 | 42 | | |
| 43 | + | |
42 | 44 | | |
43 | 45 | | |
44 | 46 | | |
| |||
55 | 57 | | |
56 | 58 | | |
57 | 59 | | |
58 | | - | |
59 | 60 | | |
60 | 61 | | |
61 | 62 | | |
| |||
160 | 161 | | |
161 | 162 | | |
162 | 163 | | |
163 | | - | |
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
| |||
0 commit comments