Skip to content

Commit fa494d0

Browse files
feat(pm): a project seat's patrol is part of seating, recorded on the stub, and its absence is a half-state reading (#28687)
<!-- claude-projects-attribution: {"github_login":"marchtian"} --> _Requested by **田騏** · [project thread](https://claude.ai/code/project/chan_01VmuUhXU9SSUzqJYyXSmYSi?thread=cmsg_01VmuUhXU9SSUzqJYyXSmYSiHXKqxUqDPJKZyNHP7BoqTb)_ Fixes #28642 Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么**:项目席坐席时同一动作自建自绑的巡查 routine,座位贴存根记 `Patrol: TRIGGER_ID · CRON` 行,收班同笔删掉;队列空是待命而非停查,「连查几次没变化就停」的习惯不适用;半状态巡查新增两行只读读数:H70(在任项目席的座位贴没有 `Patrol:` 行)、H71(有 🟢 席位的车道上,无人认领且超过 2 小时无动静的 `pm:queue` 卡)。 - **为什么改**:#28560(p1)在 spec 车道席位在任、手上 0 张卡的情况下排队 4.5 小时无人认领——该席从未建巡查,队列清空后停了定时查;规则原本写着,但建巡查不在坐席步骤里,座位贴也看不出缺巡查,也没有读数会报警。 - **风险与回滚**:规则文本只改写既有行,三个文件净行数均为 0,SKILL.md 未动;两行读数只报告、不挡落地、不写标签。首跑实测:H70 报 16 个座位贴(规则刚立,现有存根只有 #19287 写了巡查行),H71 报 3 张卡。回滚 = revert 本 PR。 - **先看**:① `.claude/skills/pm-dispatch/references/seat-lifecycle.md`〈座位贴协议〉首两行与〈停止条件与待命〉新两行;② `seat-post-protocol.md` 存根行与〈座位 Routine 创建〉末行;③ `scripts/pm/check-half-states.mjs` 的 `h70HeldSeatWithoutPatrol` / `h71UnclaimedOnDutyLane`。 - **两分钟验证**:`node scripts/pm/check-half-states.mjs --self-test`,预期 exit 0,末行电池清单含 `H70/H71 seat patrol 27/26`。 - **需要你做的**:批准本 PR。分诊裁定这是规则变更、以你的批准为裁决;卡上引的原话「为什么会停了定时巡查,skills 是否需要优化」是提问而非明令加巡查行,所以你的批准同时作为 H70/H71 两行新读数的授权(仪器纪律:新增巡查行须有维护者原话)。 ## What changes **Rules text** (`.claude/skills/pm-dispatch/references/`, every line rewritten in place; no ceiling moved): - `seat-lifecycle.md` 〈座位贴协议〉 — the rule's one home: seating creates the self-bound patrol routine, records `Patrol:` on the stub and sends `seat-online` in the same act; the sign-off deletes it in the same act as `seat-offline`. The key pointer moved to the next line. - `seat-lifecycle.md` 〈停止条件与待命〉 — an empty queue is standby: the patrol runs until sign-off, only the maintainer's order stops it, and the "stop after N quiet checks" habit does not apply. The patrol prompt claims up to the seat's `batch` limit first, then runs the five standby items listed right below it (`pm:blocked` / `pm:on-hold` unlock, in-flight PRs to MERGED, and the rest). - `seat-lifecycle.md` 〈断粮与跨墙恢复〉 — the old line 「项目席巡查 routine 默认每小时跑各车道待命项…」 is deleted; each part has a home already: hourly is `seat-post-protocol.md` 〈座位 Routine 创建〉, the standby items are the new prompt line, the wall note is the stub's line, no cron chain is SKILL.md 〈唤醒〉. - `seat-post-protocol.md` — the stub adds a `Patrol:` line; 〈座位 Routine 创建〉 names its spelling `Patrol: TRIGGER_ID · CRON` as where the current value lives (the director seat has none). - `project-forms.md` 〈席位是读出来的〉 — 「首次坐席自建」 becomes 「坐席即建巡查 routine」 with a pointer to `seat-lifecycle.md`. **Half-state rows** (`scripts/pm/check-half-states.mjs`, report-only, zero extra requests — both read listings the sweep already holds): - **H70** (`state`) — a held `pm:seat` post (🟢 a login; not `🟢 Routine`, not the director seat, not vacant or paused) whose body has no `Patrol:` line. The shared directive reader is used, so `- **Patrol:** …` counts as a line. The value is not judged. - **H71** (`stall`) — an open, unassigned `pm:queue` card (not `pm:epic`) on a lane where some seat post reads 🟢, quiet for more than `QUEUE_ON_DUTY_UNCLAIMED_HOURS` = 2. The clock is `updated_at` (H10/H30's clock), so the age is a lower bound on time in the queue. - Self-test battery `H70/H71 seat patrol`, 27 cases, floor 26: firing cases, the live decorated spelling, out-of-scope arms (Routine, director, vacant/paused, assigned, epic, closed, PR rows), the 2 h boundary, an unreadable stamp, the lane alias, and the band and push registry. ## Tests - `node scripts/pm/check-half-states.mjs --self-test` → exit 0, `5158 cases pass`, battery `H70/H71 seat patrol 27/26`. - Live sweep (read-only), tree `f4027cfe`, 2026-11-01: H70 fired on 16 seat posts (#6026 #6367 #7623 #9831 #12224 #18883 #18917 #19357 #20163 #20966 #24145 #25966 #26620 #26761 #27737 #28677). #19287 was clean because it carries a decorated `Patrol:` line. The triage Routine post and the vacant director post were not judged. H71 fired on 3 cards: #25918 (~28h, `domain:ui`), #25921 (~7h, `domain:ui`), #27890 (~58h, `domain:skills`). ## Acceptance notes - **The `Notify: seat-online` key is not extended.** The card says the `seat-online` record carries the patrol line. The mailbox key template is parsed by `record-recognisers.mjs`, so adding a field there changes the recogniser grammar, which is outside this claim's file surface and belongs to the mailbox-keys card serial behind this one. The patrol line lives on the stub only. - **H71 drops "spare concurrency".** No seat post states its cap in machine-readable form, and a cap can span several lane seats of one account. The row says so in its own text: a full seat reads the same as an idle one. - **`dispatch-runbook.md` is not edited.** Item ④ lives in `seat-lifecycle.md` 〈停止条件与待命〉, next to the standby list it points at. - **"含前提过时" is gone with the deleted 〈断粮〉 line.** No standby item carried it before either. - **No director exemption on the seating line itself (no room in the 120-byte budget).** `project-forms.md` (总监席不建), `seat-post-protocol.md` (总监席无) and SKILL.md 〈唤醒〉 each carry the exemption. - **H70 reuses `seatIsHeld`.** So a 🟢 title whose first token is not a login (`🟢 held …`, `🟢 session_…`) reads as held, as it does for H32. - **Tier.** The governed register puts `.claude/**` at Tier S. Triage's binding note makes the maintainer's approval the ruling for this rule change, so this PR waits for that approval either way. ## Verification <details><summary>Rules ratchets — head 58de368</summary> - `pnpm check:pm-skill-ratchet` → exit 0 (project-forms 54/54, seat-lifecycle 96/96, seat-post-protocol 88/88; every edited line ≤ 120 bytes) - `pnpm check:pm-skill-id-lint` → exit 0 - `pnpm check:skill-frame-sync` → exit 0 - `pnpm check:pm-governed-prose` → exit 0 </details> <details><summary>Derived gate list — head 58de368</summary> `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` gave 55 commands. All 55 ran and exited 0. `check:doc-formula-expressions` first exited 3 (PREREQUISITE NOT MET: formula/lint not built). It exited 0 after `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint`. `--ran` reconciliation: `55 derived famil(ies) accounted for — 55 run, 0 NOT-MEASURED (a DERIVED zero — all 55 recorded an exit code and none of them is 3)`. Roster families under the touched directories, run as readings: `check-published-list-mirrors`, `check:dts-closure`, `check:engine-double-contract`, `check:i18n-stale-fill`, `check:pm-label-desc-cap` and `check:pm-settings-deny-roster` all exited 0. `check:published-readme-exports` is NOT MEASURED: exit 3, PREREQUISITE NOT MET, 63 packages not built. CI runs it. </details> No published package is touched (`.claude/**` and `scripts/pm/**` only), so this PR carries `skip-changeset` and no changeset. Session: `session_017ihL2g7RyXa8ErM6GAkHyc` (os-dev for `domain:skills#2`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e1fede6 commit fa494d0

4 files changed

Lines changed: 196 additions & 8 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
- 指令行就是指派:维护者在项目里写下或改写这一行,是唯一的指派动作。
2424
- 项目聊天里的长句(「本账户坐 X;Y 的 PR 由本账户复审」)是等价写法。
2525
- 坐席即把本账号写进 🟢 行、每席开一条席位线程;⛔ 无花名册文件。
26-
- 首次坐席自建本项目的 routine:巡逻默认每小时;分诊席加每小时裸卡轮;总监席不建。
26+
- 坐席即建巡查 routine(见 `seat-lifecycle.md`);分诊席加每小时裸卡轮;总监席不建。
2727

2828
## 接管不等撞墙账号
2929

‎.claude/skills/pm-dispatch/references/seat-lifecycle.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@
3838
- ⛔ 永不从贴的 `updated_at` 或标题推死活;活性只认在任者自己的产出。
3939
- 竞态三招:动手前重 fetch 正文、审计评论时间戳先到先得、写后回读。
4040
- 收班 = 状态 flush + 在飞默认交回队列、不等落地;派发口径失效,简报 ⛔ 不列作继承裁决。
41-
- 坐席发 `seat-online`、收班简报同一动作发 `seat-offline`,键见 `project-forms.md` 〈信箱 PR〉。
42-
- 强制接管的新账号代撞墙账号发 `seat-online`;Routine 席唤不醒,读信箱靠巡查。
41+
- 坐席即建自绑巡查 routine、存根记 `Patrol:`、发 `seat-online`;收班同笔删它、发 `seat-offline`。
42+
- 强制接管者代撞墙账号发 `seat-online`,键见 `project-forms.md`;Routine 席唤不醒,读信箱靠巡查。
4343
- 离任留守只写点名的已 ACCEPT 待队列或待人批 PR,⛔ 不读队列、不新派发、不碰未点名卡。
4444
- 换班报告默认零建议,只收三类:原则错/缺、可机械化项、平台事实变化。
4545
- 原则错/缺 → 只进简报,维护者点名才立卡;可机械化项 → 门禁/脚本卡,⛔ 不是散文。
@@ -85,12 +85,12 @@
8585
## 停止条件与待命
8686

8787
- 停:队列空或 `rounds` 用尽(仅一次性调用适用);一轮 ≥ 半数派发失败或升级;维护者打断。
88-
- 常设座位队列清空不等于退场,是切换待命姿态:巡检间隔按 `execution-duties.md` 收集节②。
88+
- 队列空是待命非退场:巡查跑到收班,只维护者明令停;⛔ 不按「N 次无变化即停」的习惯。
89+
- 巡查 prompt 先认领至本席 `batch` 上限,再跑待命五项;间隔按 `execution-duties.md` 收集节②。
8990
- 待命五项各以其主节为准,⛔ 此处不另抄:findings 配合;`pm:blocked`/`pm:on-hold` 解锁扫描。
9091
- 在飞/已入队 PR 跟到 MERGED;决策箱仅在报告中列出 ⛔ 不 nag;跨车道备忘跟进。
9192

9293
## 断粮与跨墙恢复(5 小时用量墙)
9394

9495
- 权威的墙信号是失败本身:撞墙报文里的重置时刻在那一刻可得、事前查不到,记下来。
9596
- 恢复 playbook 链既有规则:逐个探在飞云卡 → 直接验收兜底或 transcript 复活 → 照常跑轮。
96-
- 项目席巡查 routine 默认每小时跑各车道待命项(含前提过时);撞墙记入存根,⛔ 无 cron 链。

‎.claude/skills/pm-dispatch/references/seat-post-protocol.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
- 审计与认领评论的作者字段是平台盖章的硬读数,接管仲裁与活性判定优先用它对账正文。
1616
- 班次叙事 ⛔ 不进贴正文:逐卡状态在卡与 PR 上必填,轮次合计走轮次报告。
1717
- 存根四项:在座账号与项目 · 上任时刻 · 热文件串行队 · 指针行「姿态台账住项目」。
18-
- 第五行可选撞墙注记(预计 HH:MM 恢复);存根只在坐席、串行队改、撞墙、移交刷新。
18+
- 加 `Patrol:` 行,可选撞墙注记(预计 HH:MM 恢复);存根只在坐席、串行队改、撞墙、移交刷新。
1919
- 接管压缩:接任 PM 把交接的有效内容按四段模板重述为新正文,编辑历史即存档。
2020
- 旧账留在上一版 body revision,审计评论带版本指针(哪一版、何时)。
2121
- 热文件串行队是跨轮跨班次的常设事实:文件 → 有序卡片清单 → 每张卡认领的区域。
@@ -63,7 +63,7 @@
6363
- ⛔ 不取会话看起来起来了;零产出即技术性失败。
6464
- 回滚 = `delete_trigger` + 清空座位登记 + 失败注记。
6565
- 档位按职责挑,⛔ 不按重要性挑;Routine 席的档位与 cron 是维护者在 UI 上的可调项。
66-
- 项目席巡查默认每小时(总监席无巡查),放宽须有理由并写座位贴;协议 ⛔ 不复制当前值。
66+
- 项目席巡查默认每小时(总监席无),现值只记存根 `Patrol: TRIGGER_ID · CRON`;放宽须写理由。
6767

6868
## Epic 车道收尾与僵尸回收
6969

0 commit comments

Comments
 (0)