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
3,138 changes: 628 additions & 2,510 deletions .claude/skills/pm-dispatch/SKILL.md

Large diffs are not rendered by default.

9 changes: 4 additions & 5 deletions .claude/skills/pm-dispatch/references/compile-surfaces.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# 过滤 / 谓词语义的编译面清单(references —— 按需加载)

出处:主文件 step 5「过滤 / 谓词语义裁决」标准条款 —— 命中该条款的派发令把本清单
**逐面抄进去**,PR 逐面申报。清单正文自 SKILL.md 纯搬移(#5925 item 7),维护纪律
与派发前复核串在正文内,一并适用:**这张表由 PR 维护、派发前先跑复核串重验,⛔ 不凭
记忆抄**。
出处:主文件「派发」的过滤/谓词语义标准条款 —— 命中该条款的派发令把本清单**逐面抄
进去**,PR 逐面申报。维护纪律与派发前复核串在正文内,一并适用:**这张表由 PR 维护、
派发前先跑复核串重验,⛔ 不凭记忆抄**。

编译面清单(逐面实测 @ `main` `48f98b0`,2026-08-07):

Expand All @@ -15,7 +14,7 @@
| 4 | service-analytics filter-normalizer | `packages/services/service-analytics/src/strategies/filter-normalizer.ts:1235`(`lowerAnalyticsWhere`) | analytics / cube 侧 |
| 5 | `formula` | `packages/formula/src/matches-filter.ts:73`(`matchesFilterCondition`) | RLS 写侧 `check` 与公式求值;JS 两值语义的基准面 |
| 半面 | objectql `having-filter` | `packages/objectql/src/having-filter.ts:92` / `:98`(`applyHaving` / `matchesHaving`) | 聚合**后**过滤。算半面是因为词表是子集,**但申报义务不打折** —— 它是**唯一没有 conformance 表覆盖的面**(`FILTER_LOGIC_CASES` 不驱动 HAVING 路径),所以漏了它连门禁都不会红 |
| 冻结 | `driver-memory` / `driver-mongodb` | — | #5499 冻结投入:**pin-annotate,不翻转**。冻结面仍要申报,结论是「不在范围 + #5499」。现场注释见 `read-scope-sql.ts:176`、`having-filter.ts:41` |
| 冻结 | `driver-memory` / `driver-mongodb` | — | 维护者 2026-08-05 投入冻结:**pin-annotate,不翻转**。冻结面仍要申报,结论是「不在范围 + 冻结指令」。现场注释见 `read-scope-sql.ts:176`、`having-filter.ts:41` |

**这张表本身由 PR 维护 —— 与域表同一纪律。** 增删一面(新驱动、新求值器、某面被合并
或退役、冻结状态变化)的那个 PR 顺手改这里,不留给下一次裁决重新数。清单**会**过期是
Expand Down
125 changes: 125 additions & 0 deletions .claude/skills/pm-dispatch/references/dispatch-runbook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# 派发与收集运行细则(references —— 按需加载)

出处:主文件「派发」「收集」。原则住在主文件;本表是派发云卡、接手死 dev、处置停
摆/重放/失报那一刻查阅的操作细则。⛔ 不引用 issue 编号。

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

一次性云卡用 `create_session`,⛔ 不用 create_trigger+fire(维护者 2026-08-07 拍
板;trigger 流只留给定时/重复型)。

1. **授权面随 source,不随环境**:trigger 拉起的会话没有仓库授权(只能只读勘察);
`create_session` 带 `source_url` 的会话出生即持推送授权。同时带
`outcome_branch`(= 认领分支)、显式 `model`(trigger 流不可指模型)、`title`
(以车道名开头,⛔ 不叫 os-dev;形如 `⚡ <车道> #<单号> <短语>`)。
2. **派发词必带自驱条款**(云会话回合一结束就停摆等 poke,不写这条 dev 会停在中期
汇报或提问处):⛔ 不为提问/中期汇报结束回合;开放选择按裁决与评估轴自裁记入终报
open_questions;合法回合终点只有 (a) 推送完成 + 终报,或 (b) 硬阻塞详报。
3. **交付通道**:dev 自开 draft PR(`Fixes #<n>`,正文含验证记录)+ 终报以 issue 评
论(os-dev-report 标记)交付;未 attach 的姊妹仓够不着,跨仓跟进卡由 PM 代立。
trigger 拉起的定时会话维持降级通道:推送 outcome branch + 终报走最后一条会话消
息,PM 代开 draft PR。
4. **云卡 draft PR 一存在,立即 `subscribe_pr_activity` —— 硬步骤**:未订阅的云卡
PR 是轮询负债,订阅把感知从巡检周期缩到秒级。

监控与转向:`get_session` 读实时状态(IDLE + 分支未推送 = 停摆待 poke);投递消息
用绑定会话的 poke 触发器(`create_trigger` 带 `persistent_session_id` +
`fire_trigger` + 用后即 `delete_trigger`);巡检退为兜底心跳,每轮先核订阅已覆盖哪
些面、只补盲区(会话停摆、未开 PR 的分支、姊妹仓动静)。CCR 云会话不注册跨会话消息
roster —— `ListAgents` 列不到、`SendMessage` 直投 not-reachable 是设计而非故障(维
护者 2026-08-11 裁定:事件驱动架构即长期方案),⛔ 不复测 roster 路径。

## 接手中断的 dev(worktree 接手协议)

先试 SendMessage 复活(从 transcript 带全部上下文恢复),resume 不可用才接手。⛔
不重跑原派发词 —— 新 agent 带四条增量:

- worktree 已存在,⛔ 不要新建,`cd` 进去接着做(第二个 worktree 会劈开工作);
- 先读全部既有提交与未提交改动,逐 hunk 决定保留或修正 —— 既不推倒重来也不盲信(死
agent 从未回报,它的一切都未经验证);
- 把死 agent 没跑完的验证**完整重跑**并报真实输出(中断的运行没有留下任何测试证
据);
- assignee、认领评论、分支**全部不动** —— 这是既有认领的延续,不是新认领;认领评论
记录接手,不被替换。

## 停摆复位梯度

停摆的 subagent 永不自愈 —— 携带**任务中途状态**的完成通知本身就是停摆信号,立刻
SendMessage 附执行姿态句(「前台(阻塞)同步执行全部步骤,中途不停止、不把构建/测
试挂到后台等唤醒」),⛔ 不等任何静默阈值 —— 阈值是给「没有回答」的,不是给「回答说
我停了」的。**每次复位比上一次更具体**(原样重发同一句话不算一次复位):① 复述执行
姿态 → ② 点名下一个工具调用 + 明令禁止后台等待 → ③ 第三次停摆判 unreliable,按接手
协议重派到该分支。自己挂的定时器不会唤醒自己。长验证管线的派发/接力词写明前台姿
态。生产侧条款在 os-dev 定义 —— 这里是消费侧兜底,⛔ 不能写成「派发词写全了就可以不
探」。

## 通知重放去重

通知可以形态完全正常、报告完整正确,而只是同一份东西的第 N 次重放(monitor 按自己
的 deadline 触发)。**先算身份,再决定读不读内容**:去重三元组
`(issue, 分支, PR head sha)` + 通知自报的守护对象;与已验收那份逐项相同 ⇒ 台账记
「重放,首达时间 T」即结束,⛔ 不重新验收、不重读 diff、不重复 ACCEPT。⛔ 到达不读
作「还活着」(活着的判据只有探针回包),不到达也不读作「已死」(判死只认三类正当依
据)。对面自报守护对象是「变便宜」,不是去重的前提 —— 没自报就用三元组自己算。

## 直接验收兜底(报告丢失 ≠ 验收停摆)

同时满足 (a) draft PR 已存在且 CI 全绿、(b) 探活确认已死或 ≥2h 无任何推送、(c) 报
告未达 ⇒ PM 直接按 PR 验收:逐文件核对 diff 与认领申报的文件面,对照 `origin/main`
复核 PR 正文的前提声明与验证叙述,复核清单其余判据不减。顺序保护:agent 可能还活着
时**先探活、后翻 ready**(抢先翻会与它的收尾推送竞态)。死因可以是舰队级的(全账号
断粮同杀所有在飞 dev,探活半边同时不可用)—— 此时取 (a)+(c) 照常收口,PR body 就是
报告。「推分支 → 开 draft PR → 立即交报告」是保险不是效率优化,它住在 os-dev 定义
的 Definition of done,派发令只带增量。

## 派发词构造细则

⛔ 默认不整段粘贴 issue 正文 —— 让 dev 自己读 GitHub 全文与全部评论(premise-first
本来就要求),并**必须**要求 dev 自查正文完整性:长正文经工具读取可能被静默截断,
截断风险随「自己读」转移给 dev,这条自查是风险转移的对价,不是客套。派发词只带增
量:

- **三分区,措辞决定 dev 敢不敢证伪**:「裁决(不可重裁)」= 维护者/PM 已拍板的方
向与语义 —— dev 执行,不重开;「PM 机制假设(须实测,鼓励证伪)」= PM 对代码机制
的判断 —— dev 动手前验证,证伪了照实报告并按裁决意图换实现路径,⛔ 不许为了顺从假
设硬做;「PM 建议的路线(可选,实测优先)」= PM 顺手给的实现选项/断言写法/排除面
—— dev 有更好的就换,⛔ 不得因为「派发令写了」而照做。凡「我觉得可以这样」的一律降
到第三块 —— 不分区的派发令里,机制假设穿着裁决的衣服,两个方向都是返工。
- **标准非协商条款 ⛔ 不抄进派发词** —— 已一次性下沉进 `.claude/agents/os-dev.md`。
角色文件优先级是实测事实:派发词与角色文件冲突时角色文件胜,所以对每张卡都成立的
无条件条款只能住在角色文件、错了就修那里;逐卡变量走模板占位符与三分区,⛔ 不靠派
发词临时覆盖角色文件默认值。
- **清单、路径、行号在派发那一刻从树上取**,⛔ 不从卡片/上次派发/记忆抄(门禁清单单
班之内就会过期)。取数:`node scripts/pm/dispatch-gates.mjs <改动路径>…` 产出本卡
该跑的门禁族,填进派发令;取数的是 PM 不是 dev —— dev 只跑被点名的几族,全 farm
归 CI 跑一次,点名的准确性从此是 PM 独担的。卡片或分诊评论里的行级断言,转述进派
发令前必须自己重验一遍。
- **文件面写两句**:「预期落点是 X;若实测表明真正的生产者在别包,报备后按生产者侧
修(落点与理由写进报告和 PR 正文),⛔ 不在消费者侧打补丁」—— 只写一个路径名的派
发令,是要求 dev 在守约与修对之间二选一。跨包常常等于跨车道,PM 侧的对价是事后补
跨座位声明。
- **Same-day churn 进派发词**:派发时 `git log origin/main --oneline -20 --
<paths>` 见到当天合并 ⇒ 加一行「基于合并后的代码工作,issue 引用的片段可能已变,
先核对当前 main」(dev 的 worktree 从 origin/main 切出后不会自己更新)。**在飞重
叠也要拦截**(churn 行只覆盖派发瞬间):每轮读 main 新落 PR 与每个在飞派发的申报
文件面求交,相交立即警告四句 —— 合 main 重跑测试矩阵、读对方 diff 重划边界、只补
它没覆盖的部分、被完全覆盖就停下回报 ⛔ 不硬造 diff。晚一轮 = 一次返工。
- **翻转公开语义的裁决随卡带全仓 pin 清扫**,两句缺一不可:① grep 错误码/错误消息
**全仓扫描**同语义 pin,一轮翻完,不要只改本包(旧立场的 pin 住在被改包之外的消费
层);② 翻转后的 pin 必须继续承重 —— 断言新语义的**实质**(行数、译文、状态码),
不是「旧断言已删」;真正非法形状的拒收断言**逐字保留**,被守护的面永不缩水。丢第
二句,「全仓翻完」退化成「全仓删光」,绿而无值。
- **条件性标准条款,命中判据才抄,不命中就省掉别硬套**:
- 多实现面组件(同一契约 ≥2 个实现面)⇒ 「测试放在**未来的分叉会被抓住的地方**,
进共享一致性覆盖,不是独立测试文件」;不变量形:与 `find()` 给出相同行集,或以
`INVALID_FILTER` 拒收 —— 不允许有第三种、更安静的答案。
- 新增/改写拒收类用例 ⇒ 「最低断言错误的 `code` 与 `status`(ADR-0112 信封);
`toThrow()` / `rejects.toThrow()` 单独使用不构成拒收测试;措辞本身是契约时首句
断言**加在** `code`+`status` 之上;只约束新写/改写的用例,不回填存量」。
- 改过滤/谓词语义 ⇒ 把 `references/compile-surfaces.md` 的编译面清单**按其复核串
重验后逐面抄进派发令**(⛔ 不凭记忆),并带:「每一面都必须在 PR 正文有一个结
论:已改 / 本就合规(证据)/ 明确不在范围(理由);⛔ 静默略过 —— 评审把没提到
的面读作漏掉的面」。防的不是做错,是做对了一部分然后以为做完了。
- **Premise-first 写明**:issue 正文是线索不是规格,先对 origin/main 验前提;
`premise_still_valid: false` + 无 PR 是合法且常常有价值的交付 —— 派发词预设
issue 为真,就把好运行变成表面抗命。
Loading
Loading