Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 34 additions & 35 deletions .claude/skills/pm-dispatch/SKILL.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -77,6 +77,7 @@ UI 创建并勾 GitHub 连接器、UI 钉模型(会话内 create_trigger 的Rout
| `needs-user-decision` | 决定**待做** —— 永不派发、除已裁代裁通道外永不代答;维护者的收件箱 |
| `pm:on-hold` | 决定**已做**且答案是「不是现在」—— 不派发也不催;hold 评论带**日期、理由、重启条件** |
| `pm:blocked` + 正文行 `Blocked-by: #N` | 等上游 —— 选择期跳过,#N 关闭时由解锁扫描放回 |
| `pm:blocking` | 有 open 下游依赖者(分诊 sweep 自 `Blocked-by:` 索引推导的缓存,⛔ 不手工挂);进选择优先级全序 |
| `finding` | 观察类记录 —— 持有态,待发现分诊轮定级,不占队列不进收件箱 |
| `target:<major>` | 发版阻塞 —— 每个 backlog 恰好一个生产者,见「发版板」 |
| `pm:epic`(父单) | 子树已委托 epic PM(会话与领地在父单正文;`label:pm:epic` 即全量索引)—— 其它 PM 不把其 sub-issue 当候选 |
Expand All@@ -93,19 +94,17 @@ UI 创建并勾 GitHub 连接器、UI 钉模型(会话内 create_trigger 的Rout
触发文件清单,车道座位贴设「派发前必查」段,派发卡文件面与清单相交时点名该单、顺手活列为申报过的增项。
- **`Blocked-by:` 行是机器可 grep 的反向索引**,一遍读喂三个职责:上游关单时放回被解锁的、按解
锁扇出排序选择、**在合并后的 ref 上重验每张回队卡的文件面**(⛔ 只做第一件)。**一个标签存在
,当且仅当有具名读者**,无读者的标签必烂;已议已拒(维护者2026-08-11):「被依赖」是随上游关单衰
变的推导属性,从行现算,⛔ 不落存储标签。
,当且仅当有具名读者**;2026-08-11 的「⛔ 不落存储标签」已被维护者 2026-08-13 意见取代(原话
:「被依赖的卡片是不是应该通过label标注提高优先级」):`pm:blocking` = 分诊 sweep 自该索引推导写
入/摘除的**缓存**,⛔ 不手工挂 —— 变的是缓存位置,推导本性与具名读者不变量未变(读者:选择优先级全序、列表页扫描)。
- **状态变更不过夜**:标签挂了评论没跟上、assignee 设了没认领评论、结论只在 chat ——都是半状态
,结束会话(含限流悬挂)前补齐成对或回滚半边(机械辅助
:`node scripts/pm/check-half-states.mjs`,report-only 巡查)。**代执行他人指令的关闭/作废,评
论带出处三件(谁的指令、原话、在哪说的)** —— 无出处的关闭与误操作在证据上不可区分,会被兄弟
席当误扫重开;同理适用于摘标签、回收认领等不可反推理由的动作。
,结束会话(含限流悬挂)前补齐成对或回滚半边(report-only 巡查见机械守卫索引)。**代执行他人指令
的关闭/作废,评论带出处三件(谁的指令、原话、在哪说的)** —— 无出处的关闭与误操作在证据上不可区
分,会被兄弟席当误扫重开;同理适用于摘标签、回收认领等不可反推理由的动作。
- **写后回读**:每次写正文、评论、标签,发出后读回校验 —— sanitizer 会静默吞内容, label bot 的
整组 PUT 会冲掉刚打的手工标签;「API 返回 200」≠「落地内容正确」。

**一次性建标签**:`bash scripts/pm/ensure-pm-labels.sh`(幂等)。⛔ 退役的`domain:engine` /
`domain:ui` 不在脚本里也不要加回去 —— 重建退役标签就是把无主车道放回自动补全;两者存量已清零
但**标签对象仍在**,删除对象是 PM 的一步单独动作,删掉前别当它们不存在。
**一次性建标签**:`bash scripts/pm/ensure-pm-labels.sh`(幂等;退役车道刻意不在脚本里 ⛔ 不加回,理由与对象清理以脚本头为权威)。

## 平台读数纪律

Expand DownExpand Up@@ -164,9 +163,9 @@ UI 创建并勾 GitHub 连接器、UI 钉模型(会话内 create_trigger 的Rout
5. **One board, no second tracker。** pm 标签就是状态机;org Project 只是维护者的聚合视图,权
威层坚持 issue 正文 + REST。

**跨座位转移**:工作跨座位线,PM 永不跨 —— 落到对方队列(目标仓立单带 `pm:queue` +出处行),依赖
走 `Blocked-by:`;后续杂事由消费侧座位立;凡触 `packages/spec` 一律转`domain:spec` 座位(唯一所
有者),不论谁需要它。
**跨座位转移**:工作跨座位线,PM 永不跨(唯一豁免:简单阻塞项直接接手,见「候选与批次」)—— 落到
对方队列(目标仓立单带 `pm:queue` +出处行),依赖走 `Blocked-by:`;后续杂事由消费侧座位立;凡触
`packages/spec` 一律转`domain:spec` 座位(唯一所有者),不论谁需要它。

## Domain lanes(同仓多 PM 并发)

Expand DownExpand Up@@ -207,10 +206,10 @@ UI 创建并勾 GitHub 连接器、UI 钉模型(会话内 create_trigger 的Rout
**单一生产者。** `domain:*` 只由分诊座位产出;打标签 ≠ 认领;**未打标签的 issue 任何人不得认领
** —— 那意味着分诊还没走到,不是「可以自己判一下」。

**跨域例外路径(唯一的越界通道)。** 真拆不动的跨域单 PR 由**分诊座位指定**一个车道PM 认领;认
领评论**申报完整文件面**;只在这条路径上跑**定向在飞检查**(范围 = 该单文件面触及的那几个域的
在飞单,读各自认领评论的文件面申报,要求不相交,相交即让行)。日常同域批次选择不跑全局在飞检
—— 同域独立性由本域批次选择保证,跨域相交只可能从例外路径进来
**跨域例外路径(越界通道之一;另一条:简单阻塞项直接接手,见「候选与批次」)。** 真拆不动的跨域
单 PR 由**分诊座位指定**一个车道PM 认领;认领评论**申报完整文件面**;只在这条路径上跑**定向在飞
检查**(范围 = 该单文件面触及的那几个域的在飞单,读各自认领评论的文件面申报,要求不相交,相交即
让行)。日常同域批次选择不跑全局在飞检查 —— 同域独立性由本域批次选择保证,跨域相交只从这两条越界通道进来

**合并队列仍是一条共享串行资源。** 车道买到的是并行编写,不是并行落地;flaky 税随PM 数线性放大
,红队列同时挡住所有车道 —— 谁发现 flake 谁修或立单,不绕行。
Expand DownExpand Up@@ -252,7 +251,9 @@ UI 创建并勾 GitHub 连接器、UI 钉模型(会话内 create_trigger 的Rout
仓没有车道标签,这形状是它们队列卡的常态);③ 有 `domain:*` 无 pm-state。②③ 只取 `updated_at`
早于 ~2 分钟的卡且不是可选项 —— 半标注卡是协议自己按设计生产的(一次标签写入即把老卡打成半标
注),只带路由或状态机其一的卡对两个视图同时不可见。排除:`tracking`、`status:parked`(其正常形
状恰是「带域标签无 pm-state」)、全部 `pm:seat` 贴;存量大时每轮限量、优先最新。
状恰是「带域标签无 pm-state」)、全部 `pm:seat` 贴;存量大时每轮限量、优先最新。**紧急卡直接分诊**
(维护者 2026-08-13):维护者点名或 p0 嫌疑 ⇒ 立即起 `claude-fable-5` 分诊子代理,不等 Routine 班
次;授权面 = 分诊本身(定级/路由/标签/既有评论格式),⛔ 不写码不认领;产出落卡,与 Routine 分诊同格式同效力(细则见 `references/dispatch-runbook.md`)。

**分类动作**(每张三选一 + 一个修复通道):**`pm:queue`** —— 有具名落点或复现的具体缺陷、范围明
确的工具/门禁修复、恢复不变量的 finding、test-only pin,无可问之事; **`needs-user-decision`**
Expand DownExpand Up@@ -332,12 +333,14 @@ UI 创建并勾 GitHub 连接器、UI 钉模型(会话内 create_trigger 的Rout
PR 前合一次 main;③ 兄弟卡落地后再合一次;④ 冲突交合并队列仲裁,⛔ PM 不手动排序;豁免不外溢。**
阻塞解除后给延后单重新定价**:派发前一单时带必答项「你的改动让 #X 变简单/变难/变得不必要还是无
影响?」,派发后一单前用这个回答重读它的选项与成本,⛔ 不沿用立单时那份(前后单共用同一契约或数
据表示时适用)。

**选择优先级**:`priority:p0` 插队 > 解锁扇出 ≥2 的上游单 > `target:` 板上项 > 被任一开
卡 `Blocked-by:` 点名的上游单 > 普通队列项,项内 `Bug` 先于 `Feature`/`Task`(维护者 2026-08-11
与 2026-08-12 裁定)—— **平手判据,⛔ 不是优先级阶梯**(P1–P5 细粒度渐变已试已拒:没人维护必烂)
;扇出从`Blocked-by:` 反向索引现算,⛔ 不为此发明存储标签;**优先是排序,不是豁免**。**解锁那一刻两类断言同时最不可信**:
据表示时适用)。**跨车道简单阻塞项直接接手**(维护者 2026-08-13):本车道卡被他车道卡挡住且阻塞项
**机械、规格清楚、S 级** ⇒ 被挡座位直接接手做掉,⛔ 不持续等待;他车道卡上走完整认领、尊重其热文
件串行队、完工留收单注记;带设计判断/语义权衡的仍归属地车道(细则见 `references/dispatch-runbook.md`)。

**选择优先级 —— 车道取卡全序**(维护者 2026-08-13,并入 2026-08-11/2026-08-12 的 Bug 平手裁定)
:`priority:p0` 插队 > `pm:blocking` > `target:` 板上项 > type `Bug` > 其余;同级按卡龄
,`pm:blocking` 级内先按解锁扇出(照旧从 `Blocked-by:` 反向索引现算,⛔ 扇出数不落标签)。全序每级
取既有信号现读/现算,零逐卡维护 —— 与 P1–P5 已拒不矛盾(拒的是手工维护的渐变档:没人维护必烂);**优先是排序,不是豁免**。**解锁那一刻两类断言同时最不可信**:
卡内文件面要在合并后的 ref 上重验(上游已合 ≠ 卡还成立—— 关掉上游的那个合并最可能顺手把你这张
卡也修掉);PM 自己「这条裁决收窄/关掉了那张卡」的判断是假设不是前提,必须以机制假设身份进派发
令,被证伪就在同一张卡公开更正再重新分诊。
Expand DownExpand Up@@ -398,9 +401,8 @@ dev 侧推分支要早 —— 远程分支是在飞工作最硬的证据。**Sta
贴 issue 正文 —— 让 dev 自己读 GitHub 全文与全部评论,并**必须**要求 dev 自查正文完整性(截断
风险随「自己读」转移给 dev,自查是对价不是客套)。派发词只带增量:

- **三分区,措辞决定 dev 敢不敢证伪**:「裁决(不可重裁)」执行不重开;「PM 机制假设(须实测,鼓励
证伪)」dev 动手前验证,证伪了照实报告并按裁决意图换路径;「PM 建议的路线(可选,实测优先)」有
更好的就换。凡「我觉得可以这样」的一律降到第三块 —— 机制假设穿着裁决的衣服,两个方向都是返工。
- **三分区,措辞决定 dev 敢不敢证伪**:「裁决(不可重裁)」/「PM 机制假设(须实测,鼓励证伪)」/「PM
建议的路线(可选,实测优先)」;凡「我觉得可以这样」的一律降到第三块 —— 机制假设穿着裁决的衣服,两个方向都是返工(细则见 runbook)。
- **标准非协商条款 ⛔ 不抄进派发词** —— 已下沉进 `.claude/agents/os-dev.md`;无条件条款只能住
在角色文件(派发词与它冲突时它胜),错了就修那里,⛔ 不靠派发词临时覆盖。**清单、路径、行号在
派发那一刻从树上取**,⛔ 不从卡片/上次派发/记忆抄(取数 `node scripts/pm/dispatch-gates.mjs`
Expand All@@ -427,9 +429,7 @@ Model tiering 显式传参);S 级但不机械(判断面在设计不在门禁)按
create_trigger+fire —— 维护者 2026-08-07 拍板,trigger 流只留给定时/重复型):① 授权面随
source 不随环境;② 派发词必带**自驱条款**;③ 交付通道 = dev 自开 draft PR + 终报以 issue 评论
交付;④ **云卡 draft PR 一存在立即 `subscribe_pr_activity` —— 硬步骤**。云会话 `SendMessage`
not-reachable 是设计非故障(维护者 2026-08-11 裁定),⛔ 不复测。**接手中断的 dev**:先试
SendMessage 复活,resume 不可用才走接手协议 —— ⛔ 不重跑原派发词;worktree 不新建;逐 hunk 读
既有工作再决定;验证完整重跑;assignee/认领评论/分支全不动(既有认领的延续,不是新认领)。
not-reachable 是设计非故障(维护者 2026-08-11 裁定)⛔ 不复测;**接手中断的 dev**:先试 SendMessage 复活,不可用才走接手协议(四条增量见 runbook,⛔ 不重跑原派发词)。

### 收集

Expand DownExpand Up@@ -459,10 +459,9 @@ SendMessage 复活,resume 不可用才走接手协议 —— ⛔ 不重跑原派
判 unreliable 按接手协议重派。这里是消费侧兜底,⛔ 不能写成「派发词写全了就可以不探」。
- **通知重放先算身份再读内容**:去重三元组 `(issue, 分支, PR head sha)`,与已验收那份相同 ⇒ 记
「重放」即结束,⛔ 不重新验收不重复 ACCEPT;⛔ 到达不读作「还活着」,不到达也不读作「已死」。
- **直接验收兜底(报告丢失 ≠ 验收停摆)**:(a) draft PR 在且 CI 全绿 + (b) 探活确认已死
或 ≥2h 无推送 + (c) 报告未达 ⇒ 直接按 PR 验收(逐文件核对 diff 与申报文件面,对
照 `origin/main` 复核前提与验证叙述,复核判据不减);先探活后翻 ready。舰队级死因(全账号断粮)
下取 (a)+(c) 照常收口,PR body 就是报告。
- **直接验收兜底(报告丢失 ≠ 验收停摆)**:(a) draft PR 在且 CI 全绿 + (b) 探活确认已死或 ≥2h 无
推送 + (c) 报告未达 ⇒ 直接按 PR 验收(复核判据不减,细则见 runbook);先探活后翻 ready;舰队级
死因(全账号断粮)下取 (a)+(c) 照常收口,PR body 就是报告。

### 复核

Expand DownExpand Up@@ -644,8 +643,8 @@ pull(今天谁撞上;零拉动默认 defer/ remove);③ AI-agent error-resistanc
- Every dev agent works in its **own worktree per repo**(hook 强制;os-dev 定义重申);并行度
以 `batch` 封顶,同批 file-disjoint by construction(唯一松动是维护者明示豁免时的替代四条,申
报降到区域级,不是取消不相交)。**分诊座位永不认领、永不派发、永不写代码;执行座位只在自己那
一个车道认领**(唯一例外:分诊指定的跨域例外单);**`domain:*` 只有一个生产者**,执行座位不改标
签只上报误标
一个车道认领**(例外两条:分诊指定的跨域例外单、简单阻塞项直接接手);**`domain:*` 只有一个生
产者**,执行座位不改标签只上报误标
- 与 AGENTS.md 冲突时,**AGENTS.md wins**。

## Report contract(os-dev 返回什么)
Expand Down
51 changes: 49 additions & 2 deletions .claude/skills/pm-dispatch/references/dispatch-runbook.md
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,39 @@
# 派发与收集运行细则(references —— 按需加载)

出处:主文件「派发」「收集」。原则住在主文件;本表是派发云卡、接手死 dev、处置停
摆/重放/失报那一刻查阅的操作细则。⛔ 不引用 issue 编号。
出处:主文件「候选与批次」「分诊座位职责」「标签纪律」「派发」「收集」。原则住在
主文件;本表是选卡排序、紧急分诊、接手阻塞项、派发云卡、接手死 dev、处置停摆/重
放/失报那一刻查阅的操作细则。⛔ 不引用 issue 编号。

## 车道取卡全序与 `pm:blocking`(维护者 2026-08-13)

出处原话(逐字,未译):「被依赖的卡片是不是应该通过label标注提高优先级。项目经理
处理任务清单时,bug 是不是应该提高优先级。」落地在主文件「选择优先级」与「标签纪
律」;本节是排序与标签语义的细则。

- **全序**:`priority:p0` > `pm:blocking` > `target:` 板上项 > type `Bug` > 其余;
同级按卡龄,`pm:blocking` 级内先按解锁扇出(从 `Blocked-by:` 反向索引现算)。理
由:p0 是维护者显式裁定;blocking 卡住别的车道的吞吐,一张挡多张;bug 是已坏的
不变量,先于增强;卡龄防饿死。每级只读既有信号(标签、原生 type 字段、
created_at),零逐卡维护 —— 这正是「手工 P1–P5 渐变已拒(没人维护必烂)」与本全
序可行的差别:被拒的是需要有人持续赋值的档位,不是从现有信号算出来的顺序。
- **`pm:blocking`** = 「本 open 卡有 open 的下游依赖者」。⛔ 不手工维护:分诊轮
sweep 从卡身 `Blocked-by:` 引用的反向索引推导,写入与摘除都在 sweep;依赖者全关
即摘。写标签只是把决策箱指标早已在现算的结果**缓存**到列表页可见的地方 —— 推导
本性不变,「一个标签存在,当且仅当有具名读者」不变(具名读者:取卡全序、列表页
扫描)。种子与消费者注记在 `scripts/pm/ensure-pm-labels.sh`;手工挂上的按误标处
理,sweep 对着索引校正。

## 紧急卡 fable 直接分诊(维护者 2026-08-13)

出处原话(逐字,未译):「对于比较紧急的卡片,是否应该使用 fable 5 子agent直接分
诊」。紧急卡 = 维护者点名的、或 `priority:p0` 嫌疑的。座位不等分诊 Routine 的班次
节奏,立即起一个 `claude-fable-5` 分诊子代理:

- 授权面 = 分诊本身(定级/路由/标签/分诊评论既有格式),⛔ 不写码、不认领、不派发;
- 产出落在卡上,与 Routine 分诊**同格式同效力**(审计评论照既有分诊格式,原生
type / `domain:*` / pm-state 照既有纪律);
- 单一生产者纪律照旧:与「代扫」同一条边界 —— 分诊座位在班且已在处理同一张卡即让
行;紧急通道改变的是节奏,不是分类生产者的数目。

## 云卡(`mode:cloud`)四课

Expand DownExpand Up@@ -62,6 +94,21 @@ subagent 在 PM 自己的容器内运行,agent 定义与技能文本读的是**
- assignee、认领评论、分支**全部不动** —— 这是既有认领的延续,不是新认领;认领评论
记录接手,不被替换。

## 跨车道简单阻塞项直接接手(维护者 2026-08-13)

出处原话(逐字,未译):「如果当前任务依赖其他赛道的任务,如果判断简单,是否可以直
接接手而不必持续等待」。形状:本车道卡被他车道卡挡住,且该阻塞项**判断简单** ——
机械、规格清楚、S 级 ⇒ 被挡座位直接接手做掉,⛔ 不持续等待;本条只覆盖「等一周 vs
做十分钟」的形状。

- **纪律不减**:在他车道卡上走完整认领(assign + 会话 ID + 分支评论,`Claim:` 首行
拼写照旧)、尊重该车道热文件串行队(读其座位贴具名段)、完工后卡上留收单注记;
- **边界**:凡带设计判断/语义权衡的仍归属地车道;`packages/spec` 恒归 spec 座位,
本条不豁免(唯一所有者规则更硬);
- **⛔ 不是「借调」回归**:借调(按积压形状把人调去别的车道)已议已删;本条判据是依
赖形状 —— 只做被本车道开卡 `Blocked-by:` 点名的那一个阻塞项,做完即回,⛔ 不顺手
接第二张。

## 停摆复位梯度

停摆的 subagent 永不自愈 —— 携带**任务中途状态**的完成通知本身就是停摆信号,立刻
Expand Down
Loading
Loading