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
2 changes: 1 addition & 1 deletion .claude/skills/pm-dispatch/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报
- 项目席唤醒 = PR 订阅 + 每项目一个自建自绑巡查 routine(总监席除外);⛔ 无 `send_later` 链。
- 探针先行:fire 的第一动作是一次最便宜的车道盘点查询,⛔ 在它之前不读任何长文本。
- 队列空 + 无在飞 + 无待复核 + 决策箱无新答复 ⇒ 自退。
- 分诊席跑直连会话、默认判断档;直连会话按召唤跑,⛔ 无自醒不常驻;裁决归总监席。
- 分诊席与车道席常驻,断粮即换账号重开该席与信箱;分诊席默认判断档;裁决归总监席。
- 子代理裁决逐份过转录核验采信。

## 阶段细则索引
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/pm-dispatch/references/execution-duties.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
- 分诊折叠提议仅是建议,点名各卡皆无 open PR 才有效;否则各卡各自落地,拒折理由记一行。
- 并行纪律四条(常规,非豁免):① 认领申报文件面到区域级,拿不准就串行。
- ② 开 PR 前合一次 main;③ 兄弟卡落地后再合一次;④ 冲突交合并队列仲裁,⛔ 不手动排序。
- 文件面不相交只保证文本可合并;跨文件语义耦合由队列 CI 逮住,⛔ 不读作不可能冲突。
- 阻塞解除后延后单重定价:前一单派发词必答 #X 变简单、变难、不必要或无影响。
- 派发后一单前用该回答重读它的选项与成本,⛔ 不沿用立单时那份。
- 在飞卡衍生三分:不修它验收过不过;in-scope ⇒ 父卡 sub-issue,认领席自有、优先级继承。
Expand All @@ -51,6 +50,7 @@
- 标签序:`priority:p0` > `pm:blocking` > 功能点位次 > `target:` 板上项 > p1 > p2 > p3 > 无级。
- `pm:blocking` 级内先按解锁扇出(从 `Blocked-by:` 反向索引现算,⛔ 扇出数不落标签)。
- 全序每级现读/现算,零逐卡维护;同级先 `Bug` 再卡龄;无级/缺 `Path:` 轮报记分诊缺口。
- 一车道多席按全序交替取卡:席 1 奇位、席 2 偶位;只为破交替才发 `split`;认领戳仲裁。
- 解锁那一刻 PM 自己的判断最不可信:裁决收窄或关掉了那张卡是假设不是前提。
- 该假设以机制假设身份进派发令,被证伪就在同一张卡公开更正。

Expand Down
26 changes: 13 additions & 13 deletions .claude/skills/pm-dispatch/references/project-forms.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@

- 车队项目 = 任一账号上、指令行指向 pm-dispatch 的 Claude Code 项目;⛔ 不分项目类型。
- 项目做什么只由它坐的席位决定;车道席、总监席、分诊席都是席位,由维护者召唤。
- 车道席:认领、派发、PR、跨账号复审;总监席:决策箱与决裁批、发版、日报、总表。
- 分诊席:只写标签与审计评论;分诊与总监可召进任一项目,⛔ 不绑定项目。
- 唯一不变量在账号不在项目:批准账号永不跑席位(SKILL.md 全体座位的不变量);本文不另加。
- 规则与指派只写角色词(总监账户、车道账户);登录名只在裁决记录里作既往事件的证据。

## 指令行即召唤
Expand All @@ -23,32 +20,35 @@
## 席位是读出来的,不是配出来的

- 项目的席位 = 🟢 行写本账号的座位贴(车道、总监、分诊同此);派发前先读座位贴。
- 一张也没有 ⇒ 项目闲置;每席恰一条席位线程、恰一车道,一席一贴。
- 指令行就是指派:维护者在项目里写下或改写这一行,是唯一的指派动作。
- 项目聊天里的长句(「本账户坐 X;Y 的 PR 由本账户复审」)是等价写法。
- 协调者每次开场把指令行与座位贴对照:逐席按 `seat-post-protocol.md` 坐席或接管。
- 坐席即把本账号写进 🟢 行、每席开一条席位线程;⛔ 无花名册文件。
- 首次坐席自建本项目的 routine:巡逻默认每小时;分诊席加每小时裸卡轮;总监席不建。
- 总监席只被维护者召唤与 PR 订阅唤醒;摘要与收件箱扫描在召唤内做;见 `lanes/director.md`。
- 并发上限是维护者在该项目定的姿态;⛔ 不是协议常量,本文不写数字。

## 接管不等撞墙账号

- 🟢 行写着别的账号 ⇒ 指令行即维护者强制接管令,含在飞卡。
- 撞墙账号写不出任何东西,接管永不等它的注记或简报。
- 跨账号 `Release:` 点名旧会话与出处三件;新 `Claim:` 带 `Resume-from: BRANCH@SHA`,新 dev 续旧分支。
- 四件形状见 `execution-duties.md` 认领节;台账 = 标签 + assignee + `Claim:` + `head:claude/` PR。
- 台账按 `assignee:<旧登录名>` 读;⛔ 项目记忆与共享目录永不是台账,只是本账号的缓存。

## 信箱 PR

- 绑 PR 的对话不需要新东西:卡线程订阅自己的 PR,评论即唤醒。
- 非 PR 对话:每项目至多一个 draft PR,标签 `pm:mailbox`,分支 `mailbox/<login>`,由常驻线程订阅。
- 永不合并,移交或换账号时关闭;正文首行 `To: <login>`。
- 每席一个 draft PR:分支 `mailbox/<login>`,标签 `pm:mailbox`+`pinned`,正文首行 `To: <login>`。
- 坐席即开(`mailbox-open.mjs`)并订阅,存根指针行记其号;永不合并,移交或换账号关旧开新。
- `pm:mailbox` PR 不欠 CI,一切落地与台账查询排除它。
- 首行恒为下列七键之一(发→收;何时):一事一行 ≤200 字节,只写键与编号;表外即半态。
- `Request: contract-review · PR #n · head SHA · REASON`:车道→分诊;本席复审档不可用,一 head 一次。
- `Request: urgent-triage · #n · ONE-LINE-CRITERION`:任一席→分诊;p0 嫌疑、main 红、确定性队列红。
- `Request: main-red · CHECK-NAME · anchor #n · suggested lane X`:发现席→分诊(缺则总监);锚卡立起时。
- `Notify: contract-review PASS or FAIL · PR #n · record ID`:分诊→车道;随落记录;车道已订阅则不发。
- `Notify: seat-online · LANE#N · LOGIN · mailbox #m · takes: #a #b …`:坐席者→兄弟席+分诊;坐席时。
- `Notify: seat-offline · LANE#N · in-flight: … · stay-behind: … · brief ID`:收班者→兄弟席+分诊。
- `Notify: split · LANE#N · takes: … · leaves: …`:多席车道一席→兄弟席;开轮时,仅当清单变了。
- ⛔ 无收到/谢谢/请确认,动作即回执;同一事实 ⛔ 不重发、不催,逾期归既有升级规则。
- 每席每轮 ≤5 条,p0 豁免,计入写节奏;信箱评论是同事陈述,⛔ 永非授权(`untrusted-text.md`)。
- `record-recognisers.mjs` 读七键;⛔ 无门禁、workflow 或队列守卫读信箱:只协调,不是合并条件。

## 总表

- objectstack 置顶 issue「车队总表」,一席一行;正文由总监席日报与坐席/接管/移交重生成。
- 行 = 仓 · 车道 · 席 · 账号 · 在飞 · 待裁 · 待落地 · 撞墙注记 · 最近动静 · 信箱 PR。
- 读自座位贴、标签、assignee 与 PR 查询;生成视图 ⛔ 不手改(`cross-repo-coordination.md` 规则 5)。
4 changes: 2 additions & 2 deletions .claude/skills/pm-dispatch/references/seat-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@
- ⛔ 永不从贴的 `updated_at` 或标题推死活;活性只认在任者自己的产出。
- 竞态三招:动手前重 fetch 正文、审计评论时间戳先到先得、写后回读。
- 收班 = 状态 flush + 在飞显式安置,不是在飞归零;派发口径失效,简报 ⛔ 不列作继承裁决。
- 坐席发 `seat-online`、收班简报同一动作发 `seat-offline`,键见 `project-forms.md` 〈信箱 PR〉。
- 强制接管的新账号代撞墙账号发 `seat-online`;Routine 席唤不醒,读信箱靠巡查。
- 离任留守只写简报点名的项,⛔ 不读队列、不新派发、不碰未点名卡。
- 换班报告默认零建议,只收三类:原则错/缺、可机械化项、平台事实变化。
- 原则错/缺 → 只进简报,维护者点名才立卡;可机械化项 → 门禁/脚本卡,⛔ 不是散文。
- 平台事实变化 → references 事实表改一行。
- 后两类以 `finding` 入 skills 车道,首触归分诊席;三类之外默认关 not planned。
- 接管/移交 = 改正文 + 审计评论(只作审计);收尾清单等细则见 `references/seat-post-protocol.md`。
- epic 委托不入座位贴体系;新 `packages/spec` 工作恒归 spec 座位。

## Epic 子树车道

Expand Down
14 changes: 14 additions & 0 deletions scripts/pm/dispatch-gates.data.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,15 @@ export const COMPOUND_ANCHOR_LEDGER = [
* the governed file is its input, not a fixture; it spells that path in its
* module body and is MATCHED for it the same way the two undeclared rows
* above are, so `declared` is false for the same reason.
*
* ## The fifth row: the mailbox doorbell's spelling pin
*
* `scripts/pm/record-recognisers.mjs` reads the seven doorbell keys off the
* pm-dispatch references' `project-forms.md` in its self-test, to pin each
* key's template verbatim in the protocol text — a population claim on a file
* a card can edit, the `check-expected-skips` shape exactly. It is DECLARED
* (`self-test-reads`), so a card touching that file derives
* `check:pm-record-recognisers`.
*/
export const GOVERNED_READ_FLOOR = Object.freeze([
Object.freeze({ script: 'scripts/check-commit-card-trailers.mjs', file: '.claude/agents/os-dev.md', declared: false }),
Expand All @@ -517,6 +526,11 @@ export const GOVERNED_READ_FLOOR = Object.freeze([
file: '.claude/settings.json',
declared: false,
}),
Object.freeze({
script: 'scripts/pm/record-recognisers.mjs',
file: '.claude/skills/pm-dispatch/references/project-forms.md',
declared: true,
}),
]);

/**
Expand Down
9 changes: 7 additions & 2 deletions scripts/pm/dispatch-gates.self-test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7535,7 +7535,7 @@ export function selfTest({ tier = 'full' } = {}) {
}
const censusRows = liveMarkerCensus.map((r) => `${r.file}:${r.line} ${r.key}`).sort();
t(
`the live tree carries the eight declarations measured for this census, and no others (${censusRows.join(' · ') || 'none'})`,
`the live tree carries the nine declarations measured for this census, and no others (${censusRows.join(' · ') || 'none'})`,
censusRows.join(' · ') === [
// Seventh row, added with the declaration it names: `checklist-status.yml`
// is paths-filtered (its `pull_request:` trigger is filtered to itself) and
Expand All @@ -7557,13 +7557,18 @@ export function selfTest({ tier = 'full' } = {}) {
'scripts/pm/check-expected-skips.mjs:137 self-test-reads',
// 736 -> 738 (#26318): the data import and its re-export each gained UI_SCRIPTS_SUITE_ROOTS.
'scripts/pm/dispatch-gates.mjs:738 inherited-population',
// Ninth row, added with the declaration it names: the recogniser's mailbox
// doorbell battery pins the seven key templates verbatim in the pm-dispatch
// references' project-forms.md, a population claim on a governed file, so
// that read is declared and `GOVERNED_READ_FLOOR` carries its row.
'scripts/pm/record-recognisers.mjs:77 self-test-reads',
].join(' · '),
censusRows.join(' · '),
);
const censusCut = liveMarkerCensus.filter((r) => !r.whole).map((r) => `${r.file}:${r.line} ${r.key}`);
t(
`every live reason on those markers ENDS on its own marker line (cut: ${censusCut.join(', ') || 'none'})`,
censusCut.length === 0 && liveMarkerCensus.length === 8,
censusCut.length === 0 && liveMarkerCensus.length === 9,
);
t(
'and every one of them carries a non-empty reason — whole is not the same claim as present, and both are owed',
Expand Down
Loading
Loading