From b02c25a36ab3117acf2418d79ad631e45b15bfb9 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Aug 2026 14:09:38 +0000 Subject: [PATCH] =?UTF-8?q?docs(pm-dispatch):=20whole-text=20restructuring?= =?UTF-8?q?=20PR-1=20=E2=80=94=20state-machine=20and=20contract-review=20d?= =?UTF-8?q?etail=20sink=20to=20references,=20report=20JSON=20single-source?= =?UTF-8?q?d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopted digest (maintainer 2026-08-23 「接受你的重构提案」, Q1-Q4 = A): - NEW references/state-machine.md: mechanism detail of the four long state-table rows (pm:on-hold restart/release, pm:blocked Unlock-action, pm:awaiting-maintainer exclusivity, pm:retriage two-party mechanics); the table rows shrink to one-line semantics + pointer. - NEW references/contract-review.md: clause-② review-chain operational detail (carrier discipline, eligibility, downgrade fuse); ownership text converged to current reality (standing owner = the skills seat's self-bound hourly cron, maintainer 2026-08-23 「要不还是你挂个定时处理审核吧」). - Report-contract JSON single-sourced from .claude/agents/os-dev.md (Q4=A). - Routines connector fact corrected (credentials ride attached repo sources; no GitHub connector entry in the Routines UI — measured 2026-08-23). - Q2=A: two superseded-ruling narratives removed; guarded tombstones kept. - Dedups: patrol-interval numbers, hourly-fire rationale, 借调 tombstone, decision-digest retirement, hotcrm intake criteria (one home each). - Hoisted the per-lane patrol-anchor first-duty sentence into 执行座位职责 (lane-file copies are PR-2's deletion). - Ratchet: SKILL.md 682 → 666, dispatch-runbook 243 → 242, new files at 43/44 — all headroom 0. Part of #11086 (PR-1 of 2; PR-2 handles lanes/seat-post/platform-readings). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01RMTpSRF5CjMmQBFfPtPCwJ --- .claude/skills/pm-dispatch/SKILL.md | 58 +++++++------------ .../pm-dispatch/references/contract-review.md | 44 ++++++++++++++ .../references/dispatch-runbook.md | 9 ++- .../pm-dispatch/references/state-machine.md | 43 ++++++++++++++ scripts/pm/check-skill-line-ratchet.mjs | 18 +++++- 5 files changed, 128 insertions(+), 44 deletions(-) create mode 100644 .claude/skills/pm-dispatch/references/contract-review.md create mode 100644 .claude/skills/pm-dispatch/references/state-machine.md diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index 25148ad1f9..9249e580a6 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -47,8 +47,8 @@ metadata: 答复 ⇒ **自退**,不再读任何长文本 ——空转座位的成本上界就是这一次查询。 **座位 Routine 三原则**(创建细则见 `references/seat-post-protocol.md`):① 由维护者在 Routines -UI 创建并勾 GitHub 连接器、UI 钉模型(会话内 create_trigger 建的是静默零产出陷阱,细节在 -references);② 创建后手动 fire 一轮烟测,判据取**GitHub 上的产出**;③ 每 fire 一轮:读座位 +UI 创建、UI 钉模型 —— 凭据随 Routine 所挂 repo sources 走,Routines UI 并无 GitHub 连接器入口 +(2026-08-23 实测;会话内 create_trigger 建的是静默零产出陷阱,细节在 references);② 创建后手动 fire 一轮烟测,判据取**GitHub 上的产出**;③ 每 fire 一轮:读座位 贴 → 从 labels 重建状态 → 跑一轮 → 结束,不继承上下文。**开轮互斥读法**(宁少跑,不让两个同座位 会话并行写标签):fire 开始、首个写动作之前读三个读数,任一未满一个轮次 ⇒ 自退 —— 最近收班简 报;晚于它的最新「开轮」标记(轮中会话在座位贴上唯一的痕迹);本车道 `pm:dispatched` 卡最新非本 @@ -75,11 +75,11 @@ session 的 `Claim:` 评论(拼写见「认领」,车道盘点已取)—— 标 | **assignee 已设** | 已认领/在飞 —— 不是你的就永不碰 | | `pm:dispatched` | 已派发(派发评论记轮次);与摘 `pm:queue` **同一次标签写入**成对落地 | | `needs-user-decision` | 决定**待做** —— 永不派发、除已裁代裁通道外永不代答;维护者的收件箱 | -| `pm:on-hold` | 决定**已做**且答案是「不是现在」—— 不派发也不催;**仅当正文或评论带机器可读行 `Restart-when: closed #N`(由 `Blocked-by:` 的同一遍解锁扫描点火、同双通道契约 —— 正文或评论任一即为行,评论停靠的出口曾静默过期两天)或 `Restart-when: <一行可执行判据>` 时才合法**;hold 评论带日期、理由、出处(维护者裁或座位定级,⛔ 不设第二个标签区分);机会主义重启的触发文件走同族正典行 **`Restart-touch: <仓内相对路径>`**(一行一路径,大小写敏感、行锚定,与 `Blocked-by:`/`Restart-when:` 同双通道 —— 正文或评论任一,H17 兼读 hold 评论;反引号/bullet 可容忍、值须为 tracked 文件)—— 喂半状态巡查 H17 的 on-hold 触发文件索引,抽取器已随巡查落地、采用即零代码;存量 hold ⛔ 不迁移、不产 finding,散文锚词抽取兜底旧卡;**放行双查(两查皆机械、零判断)**:① 只对**最近一次** `pm:on-hold`/`pm:blocked` 转换评论所载条件放行,⛔ 永不对线程里更早的 blocker —— 已放行过的条件是花掉的,再点火就把过期前提立成现行;② 该转换评论之后卡上有**更新的 merged PR** ⇒ 拒绝放行 —— 那是条件写下后卡已前进的信号(引用的事实可以为真而不再是现行条件) | -| `pm:blocked` + 正文行 `Blocked-by: #N` | 等上游 —— 选择期跳过,#N 关闭时由解锁扫描放回。**工已完、PR 被外部门禁缺陷卡住的卡同用本态,⛔ 不设新标签**:`Blocked-by:` 指向门禁缺陷卡,正文另加机器可读行 `Unlock-action: re-check PR #M` —— 解锁扫描读到它就把解锁动作从「回队重派」换成「重查该 PR 的落地」(回队前提检查见到已完工的 open PR 即按落地工作处理,⛔ 永不给完工卡重派 dev);停放的 PR 正文必须点名门禁卡,让链路从任一端可读、不依赖会被整篇改写的座位贴 | -| `pm:awaiting-maintainer` | 决定**已做**,剩余动作是一次 GitHub 之外的人工维护者操作(如 Routines UI 变更)—— 不派发、不催;与 `pm:queue`/`pm:dispatched`/`pm:blocked`/`pm:on-hold`/`needs-user-decision` **互斥**(并存即误标);出口 = 维护者完成该操作、座位摘标 + 证据评论同笔 —— **无机器出口,by construction**,在飞视图按停放库存计(强制与巡查细节以 `check-half-states.mjs` 为权威) | +| `pm:on-hold` | 决定**已做**且答案是「不是现在」—— 不派发也不催;**仅当带机器可读 `Restart-when:` 行(closed 形或一行可执行判据)才合法**,重启放行须过**放行双查** —— 行契约、双通道、`Restart-touch:` 触发文件与双查细则见 `references/state-machine.md` | +| `pm:blocked` + 正文行 `Blocked-by: #N` | 等上游 —— 选择期跳过,#N 关闭时由解锁扫描放回。工已完、PR 被外部门禁缺陷卡住的卡**同用本态,⛔ 不设新标签**(`Unlock-action:` 行改写解锁动作,细则见 `references/state-machine.md`) | +| `pm:awaiting-maintainer` | 决定**已做**,剩余动作是一次 GitHub 之外的人工维护者操作(如 Routines UI 变更)—— 不派发、不催;与其它 pm 状态标签**互斥**;互斥面、出口与巡查细则见 `references/state-machine.md` | | `pm:blocking` | 有 open 下游依赖者(分诊 sweep 自 `Blocked-by:` 索引推导的缓存,⛔ 不手工挂);进选择优先级全序 | -| `pm:retriage` | 等分诊改判(维护者 2026-08-19/20 裁定:「同意 并存」)—— 与现行 `pm:*` 标签**并存,⛔ 不摘原标**:原定级在改判前仍是权威,并存让「排队但有异议」在列表上可见;挂标者 = 提出异议的席位,挂标与**异议评论同笔**(证据 + 建议定级),无证据评论的裸挂标不合法;摘标者 = 分诊 Routine,每 fire 高优先重判、重判后摘标 —— 挂/摘分属两方、各自的转换不相交,这是本行的安全性;带本标签的 `pm:queue` 卡**跳过派发**(异议未决不派,即可派发行的除外项);标签须五仓存在(分诊五仓统一职责,首次应用时创建);老化兜底归半状态巡查(年龄谓词随巡查另行落地) | +| `pm:retriage` | 等分诊改判(维护者 2026-08-19/20 裁定:「同意 并存」)—— 与现行 `pm:*` 标签**并存,⛔ 不摘原标**;带本标签的 `pm:queue` 卡**跳过派发**(异议未决不派,即可派发行的除外项);挂/摘两方机制见 `references/state-machine.md` | | `finding` | 观察类记录,恒 = **待首次定级**(定级即离标:晋级换 `pm:queue` / 关闭 / hold 换 `pm:on-hold`;裸标签数即健康读数)—— 不占队列不进收件箱 | | `target:` | 发版阻塞 —— 每个 backlog 恰好一个生产者,见「发版板」 | | `pm:epic`(父单) | 子树已委托 epic PM(会话与领地在父单正文;`label:pm:epic` 即全量索引)—— 其它 PM 不把其 sub-issue 当候选 | @@ -97,10 +97,10 @@ session 的 `Claim:` 评论(拼写见「认领」,车道盘点已取)—— 标 `type:Bug` 的 hold**,三分支:可复现且用户可达 ⇒ 回 `pm:queue`(Bug 优先只作用于队列卡,被 hold 的 Bug 就 是被藏起的缺陷);declared≠enforced 观察类 ⇒ 转 enforce-or-remove 通道(其真实解决路径,不 hold 不裸 关);真 won't-fix 候选 ⇒ 逐卡进决策箱 —— 座位永不自行关闭真实缺陷。**机会主义重启条件必须点名触发文 - 件**(维护者 2026-08-11 接受):写侧即状态模型的 `Restart-touch:` 行;派发前必查收敛为一件事 —— 派发/折叠检查时读半状态巡查锚(`half-state-patrol.yml` 的 `ANCHOR_ISSUE` 置顶 issue)的 H17 on-hold 触发文件索引、与本次派发文件面相交,命中 ⇒ 按该 hold 评论的 rider/restart 条款处置(点名该单、顺手活列为申报过的增项)。 + 件**(维护者 2026-08-11 接受):写侧即 `Restart-touch:` 行(行契约见 `references/state-machine.md`);派发前必查收敛为一件事 —— 派发/折叠检查时读半状态巡查锚(`half-state-patrol.yml` 的 `ANCHOR_ISSUE` 置顶 issue)的 H17 on-hold 触发文件索引、与本次派发文件面相交,命中 ⇒ 按该 hold 评论的 rider/restart 条款处置(点名该单、顺手活列为申报过的增项)。 - **`Blocked-by:` 行是机器可 grep 的反向索引**,一遍读喂三个职责:上游关单时放回被解锁的、按解 锁扇出排序选择、**在合并后的 ref 上重验每张回队卡的文件面**(⛔ 只做第一件)。**一个标签存在 - ,当且仅当有具名读者**;`pm:blocking` 即其推导缓存(语义见状态模型行,读者以词表脚本注为权威;2026-08-11「⛔ 不落存储标签」已被维护者 2026-08-13 意见取代,原话见 runbook 全序节)。 + ,当且仅当有具名读者**;`pm:blocking` 即其推导缓存(语义见状态模型行,读者以词表脚本注为权威;裁决原话见 runbook 全序节)。 - **状态变更不过夜**:标签挂了评论没跟上、assignee 设了没认领评论、结论只在 chat ——都是半状态 ,结束会话(含限流悬挂)前补齐成对或回滚半边(report-only 巡查见机械守卫索引)。**等待他座位也是状态,写在卡上才存在**(等谁、自何时,⛔ 不留在会话记忆);P0 嫌疑的等待 ⇒ 紧急直接分诊通道是义务不是选项(维护者 2026-08-19)。**代执行他人指令 的关闭/作废,评论带出处三件(谁的指令、原话、在哪说的)** —— 无出处的关闭与误操作在证据上不可区 @@ -143,7 +143,7 @@ session 的 `Claim:` 评论(拼写见「认领」,车道盘点已取)—— 标 一),各归同名 `repo:*` 执行座位,纪律即规则 4 姊妹仓执行座位一套(⛔ 此处不另抄)。第四仓 `objectos` (纯文档与站点,执行已自 `domain:devx` 迁出):座位由维护者 2026-08-18 开设(「objectos 是新开的项目 经理,是不是少了座位帖。」);无 changeset 流、无 `packages/`;合并队列 + required `build` + `merge_group` 已上线 —— 派发预期照实设,⛔ 不要求不存在的机制。 -第五仓 `hotcrm`(样板工程:元数据开发的 CRM 示例应用;岗位说明与裁决原文在 `references/lanes/hotcrm.md`):平台相关的功能在平台中实现 —— 建设 hotcrm 时发现的平台缺口按规则 1 落平台仓**普通卡**(非缝卡,⛔ 不在样板内绕行);`repo:hotcrm` 缝标签只给真协调卡。 +第五仓 `hotcrm`(样板工程:元数据开发的 CRM 示例应用):收卡判据、宪章原文与边界全在 `references/lanes/hotcrm.md`。 **objectui 卡按修复落点分流三流**(维护者 2026-08-21 裁定,`domain:ui` 唯一新增标签,命名定稿原话:「按 domain:ui 定稿」):`domain:devx`(工程面)/`domain:spec`(契约面)跨仓归各自车道,其余 —— 发布库与 apps —— `domain:ui` 归 objectui 执行席;症状位置不改流向,docs 随所记录的面走,落点不明留分诊首触 ⛔ 不猜。 **车道可按仓分席(域×仓)**:忙时一个 domain 车道开多个按仓席位(如 devx@objectstack / devx@objectui;触发即规则 4 预登记的拆分条件),各席独立座位贴与 claim 互斥,闲时收归一席 —— 名册状态,不改协议文本;seam 卡单一归属:归修复落地仓的席,双仓皆动 objectstack 侧主导;`scripts/pm/**` 等住 objectstack 的全板工具链单写手恒为 objectstack 侧席,他侧上游立卡回链(hotcrm 宪章同款纪律)。 @@ -249,7 +249,7 @@ skills,类似分诊」)—— 贴内指针指向其车道文件,升级走技能 **代裁权限唯一归本座位**,任何执行座位(含姊妹仓 `repo:*`)⛔ 不代裁。 **工具加载纪律(fire 开局)**:互斥检查/自退判断只按名加载所需工具 —— `ToolSearch` 用 `select:mcp__github__list_issues,mcp__github__issue_read` 形式,判定「本轮有活」之后才加载其余;⛔ 开局不做泛关键词 ToolSearch(一次注入全家桶 schema —— 分诊席 2026-08-20 自测:空转轮 ~12 万 token,~8 万是这张门票);可验判据:空转轮 ~4 万以内,分诊下轮自测读数回报。只约束分诊 fresh session 的开局;执行座位(常驻会话)与 dev(需全工具面)不受此约束。 -**两级盘点(two-tier inventory;维护者 2026-08-20:「每次都需要 四仓全量 open issue 盘点 … 吗?建议分诊多久执行一次」→「立卡」)**:小时轮以 `since` 窗口读增量 —— 锚 = 座位贴上一份收班简报的时间戳(互斥守卫同一读数,零新状态;标签写入刷新 `updated_at`,窗口锚在简报而非上次 fire,漏 fire 积压自动入窗);每日一 fire 跑四仓全量对账并归集日频职责;选层按 fire 时刻 ⛔ 不用计数器(fresh session 无计数器);简报写明本轮跑的层(下轮读者靠它知道窗口盖了什么)。从不更新的卡不入窗是设计:它上次变更时已被扫过,老化欠账归半状态巡查不归小时轮;守住小时 fire 的硬理由是契约复审时延(`since` 读法与成本对价见 runbook)。 +**两级盘点(two-tier inventory;维护者 2026-08-20:「每次都需要 四仓全量 open issue 盘点 … 吗?建议分诊多久执行一次」→「立卡」)**:小时轮以 `since` 窗口读增量 —— 锚 = 座位贴上一份收班简报的时间戳(互斥守卫同一读数,零新状态;标签写入刷新 `updated_at`,窗口锚在简报而非上次 fire,漏 fire 积压自动入窗);每日一 fire 跑四仓全量对账并归集日频职责;选层按 fire 时刻 ⛔ 不用计数器(fresh session 无计数器);简报写明本轮跑的层(下轮读者靠它知道窗口盖了什么)。从不更新的卡不入窗是设计:它上次变更时已被扫过,老化欠账归半状态巡查不归小时轮(`since` 读法与成本对价见 runbook)。 **Backlog sweep(常设职责,不等请求)。** 每轮扫任一析取命中的卡:① 全裸(无`pm:*`、 无 `needs-user-decision`、无 `domain:*`);② 有 `pm:queue` 无 `domain:*`(**凡有车道标签的仓皆扫**, @@ -324,6 +324,8 @@ hold 评论纪律见状态模型,hold 重验只在 `Restart-when:` 命中时发 ## 执行座位职责 +**每轮巡检第一判据**:先读半状态巡查锚(`half-state-patrol.yml` 置顶 issue)点名本道卡/PR/座位贴的 H 行,逐行认领或处置,再做其余判据;锚行未处置 ⛔ 不开新派发。 + ### 候选与批次 **整车道一次读全,本地求交**(维护者 2026-08-11 接受):`list_issues` 带 `labels: [domain:X]` + @@ -516,11 +518,7 @@ os-zhuang 审核。我的手机github 应该会收到推送消息吧」;当日 - **条款②入队闸门(维护者 2026-08-16 批准;声明肢 2026-08-17 裁定)**:翻 ready / 入队前先取 PR **实际 diff** —— diff 是事实,卡片语义是预测;`--tier` 嫌疑行是提示不是裁定。**双肢命中 任一且派发档位低于契约复审档位 ⇒ ⛔ 禁止入队**:路径肢 = diff 触及契约面(`packages/spec/src/**`,含 error-code-ledger 与 `*.zod.ts` 契约 schema);声明肢 = 认领评论声明 `Clause-②: yes`,与路径无关(错误的 `no` 是记录在案、可审计的假申报,不再是静默缺口)。⛔ 永不把路径触发读作条款②的完整覆盖 —— 它只盖路径肢;不触契约文件而改变接受/拒绝行为或扩大公开面的**内容 - 肢**由声明行承载。档位以 dispatch-gates 常量 `CONTRACT_REVIEW_TIER` 为准(档位单源,⛔ 本文与标签不写模型名,模型升级只改一行一个文件)。派发席职责止于:卡上记一行认定、挂 `needs:contract-review`(标签命名审的对象,恒英文)——**PR 与卡双载体同笔挂**(维护者 2026-08-22:「简化一点是否可以直接挂 PR 侧」「两边都挂好」;PR 一存在即挂,报告先于 PR 到达则先挂卡侧、ACCEPT 时补齐 PR 侧),同笔在该 PR 上向复审席账号 request review(同裁决:「也可以直接要求复审」—— 仅通知,载体仍是标签)、停手;⛔ 禁止自查放行。 -- **`needs:contract-review` 复审链**:复审资格 —— ① 跑在契约复审档位,硬条件,认定只认降档保险丝的机读;② 非该卡派发席,已从资格条件放宽为路径偏好(维护者 2026-08-21,原话:「你自己就是 Fable,自己就可以审核」):经同一机读证实达档的派发席,可对自派的卡执行契约复审并清标(审的是低档实现者的契约增量,非自身产物 —— 派发席不写代码);放宽豁免的是独立席位,不是复审本身 —— 一行结论照样先落卡、后清标,上条「⛔ 禁止自查放行」禁的是免复审直放,不禁本路径;低于契约复审档位的席照旧留标等待。归属:常设 = 分诊席(Routine 模型由维护者在 Routines UI - 钉在契约复审档位),分诊轮子轮清该标签仍是默认清标路径(达档席自清仅是后备)—— 只审契约增量 diff、结论一行写在卡上、PASS 双载体同笔清标(PR 与卡各按标签纪律硬步骤)并清 review request 或留一条 review 评论,标清后卡方可入队;每小时一轮即天然攒批;过渡期(分诊 Routine 未建成前)由 skills 席代行。**降档保险丝**: - 子轮开场**必调一次 `get_session`**(claude-code-remote MCP,无参)读 `external_metadata.last_served_model`,⛔ 自述档位不是读数(静默降档腐蚀的恰是自述;实测与配置档陷阱见 platform-readings);读数 ≠ `CONTRACT_REVIEW_TIER` ⇒ 该子轮整体跳过、标签原样留置 —— 卡在队列外等待是安全态。 - **保险丝只对座位自会话有效**:`mode:subagent` 里的 `get_session` 量的是**派发会话**(实测:钉在地板档的子代理读回父会话的档位,`session_context.model` 与 `last_served_model` 一致只是同一来源引用两次,⛔ 不作互证)—— subagent 的实际服役档位现无法对 `CONTRACT_REVIEW_TIER` 自证,条款②的 `mode:subagent` 派发因此恒保留 `needs:contract-review` 走复审链,「派发已在地板」的免审跳过仅座位自会话成立。**⛔ 反模式:派更高档位子 agent 去执行契约复审** —— 看似满足档位,实为构造上不可测量(多次实测:子代理读回父会话档位并拒绝出裁决)。契约复审 ⛔ 不适用额度耗尽豁免降档(豁免的对象是派发;复审的存在意义就是补偿一次低于地板的派发)。**载体不迁移**(维护者 2026-08-18,原话:「中期把闸门迁到 PR review 的 Request Changes 上 我觉得没必要」):闸门载体保持本标签,⛔ 不迁 PR review / Request Changes、不为迁移留门;挂与清皆按标签纪律的 read-modify-write 硬步骤写。 + 肢**由声明行承载。档位以 dispatch-gates 常量 `CONTRACT_REVIEW_TIER` 为准(档位单源,⛔ 本文与标签不写模型名,模型升级只改一行一个文件)。派发席职责止于:卡上记一行认定、挂 `needs:contract-review`(标签命名审的对象,恒英文)、停手;⛔ 禁止自查放行。复审链细则 —— 载体纪律(双载体同笔挂/清、载体不迁移)、复审资格与归属、降档保险丝 —— 见 `references/contract-review.md`。 - **碰生成物的 PR,入队前先同步 + 整体重生成**(os-regen 驱动零冲突标记地**静默丢掉一侧改动**): 四步序已机械化 `bash scripts/pm/os-regen-merge.sh`;陷阱、断言措辞与锚点禁令见 landing-operations A。 - **跟到 MERGED 为止;入队后的看护同归车道 PM 的落地窗口**:验收、首次入队 flip 定点、MERGED 两读 @@ -545,8 +543,7 @@ os-zhuang 审核。我的手机github 应该会收到推送消息吧」;当日 卡 —— 从 `Blocked-by:` 反向索引现算);**finding 数与中位年龄**(裸标签数即未定级数,hold 已换标不 在内;老化 = 首触欠账);**发版阻塞**(release blockers;三仓 `target:`之和,归零 = 三张板都空)。 -**波次收工点(维护者 2026-08-09 裁定;人闸部分 2026-08-14/15 被同席质疑「为什么要等我执行压缩 -」后取代)。** ① 收工点 = 会话内在飞归零(⛔ 不在复核中途压缩;云卡不挡 —— 热移交见座位贴协议 +**波次收工点(维护者 2026-08-09 裁定)。** ① 收工点 = 会话内在飞归零(⛔ 不在复核中途压缩;云卡不挡 —— 热移交见座位贴协议 细则);② 收工存档 = 上下文里的判断 flush 到 GitHub(不过夜义务),随后**立即派下一波**, ⛔ 不等人闸。`/compact` 仍由维护者在终端会话择机执行 —— 收工点上的优化项,永远不是派发前提; ①② 令任何压缩(手动或自动)无损,前提是 GitHub 恒为唯一权威 —— 失守时压缩即丢判断。 @@ -554,8 +551,8 @@ os-zhuang 审核。我的手机github 应该会收到推送消息吧」;当日 ### 停止条件与待命 停:队列空或 `rounds` 用尽(**仅一次性调用适用**);一轮 ≥ 半数派发失败或升级(系统性问题,继续 -烧 backlog 是浪费);维护者打断。**常设座位队列清空 ≠ 退场**,是切换待命姿态:巡检放宽 60–70 分 -钟(有在飞收紧回 ≤45),待命五项(各项纪律以其主节为准,⛔ 此处不另抄)—— findings 配合、`pm:blocked`/`pm:on-hold` +烧 backlog 是浪费);维护者打断。**常设座位队列清空 ≠ 退场**,是切换待命姿态:巡检间隔按「收集」② +(待命放宽、有在飞收紧),待命五项(各项纪律以其主节为准,⛔ 此处不另抄)—— findings 配合、`pm:blocked`/`pm:on-hold` 解锁扫描、在飞/已入队 PR 跟到 MERGED、决策箱仅在报告中列出 ⛔ 不 nag、跨车道备忘跟进。退场只有两个入口:维护者交接令(走交接收尾清单),或被惰性回收。 ## 断粮与跨墙恢复(5 小时用量墙) @@ -612,8 +609,8 @@ grep `),复升级时逐条**跑**一遍,零命中/变形的就地改写 推荐意见必须基于这四条轴给出理由;四轴冲突时如实呈现权衡,交维护者拍板。**标准四棱卡面块是落卡与升级的 必备件**(四棱维护者 2026-08-11 接受;标准块 2026-08-18 裁定「同意」;同裁定的摘要视图/批量决裁通道已退 -役 —— 维护者 2026-08-19:「之前定期生成的决策汇总 issue没什么用」;收件箱由维护者定期与 AI -讨论消化,⛔ 不 assign 推送 —— 同日裁定:「我感觉决策卡推给我太麻烦了,我需要和ai讨论才能判断,这个还是维 +役,墓碑与原话见「回批入口」;收件箱由维护者定期与 AI +讨论消化,⛔ 不 assign 推送 —— 维护者 2026-08-19 裁定:「我感觉决策卡推给我太麻烦了,我需要和ai讨论才能判断,这个还是维 持之前的样子。我会定期和ai讨论。」),每张 `needs-user-decision` 卡落卡即带、⛔ 不留待维护者到场再补。**四维分析从业务的角度写**(2026-08-20 裁)—— 落卡分析模板、写法六项、适用边界与 四棱块固定形状细则连同出处原话见 `references/decision-analysis.md`;推荐是输入,永不是放行,人工地板不变。 @@ -625,7 +622,7 @@ grep `),复升级时逐条**跑**一遍,零命中/变形的就地改写 指向它,队列其余照常消化,⛔ 永不整席等答复。`AskUserQuestion` 只是**在场加速器**:仅当维护者在本会话 ~30 分钟内有过人类输入才可发,每问必带推荐项,被 Skip 或长挂即转卡通道 ⛔ 不重弹 —— 卡先于弹窗存在,弹窗怎么死盘面都诚实。**回批入口**:维护者说「处理决策卡」= 当轮扫全部 open -决策卡批量呈报清积压,即上句「定期和ai讨论」的常规触发词,⛔ 不复活已退役的汇总 issue。 +决策卡批量呈报清积压,即上句「定期和ai讨论」的常规触发词,⛔ 不复活已退役的汇总 issue(维护者 2026-08-19:「之前定期生成的决策汇总 issue没什么用」)。 ## 护栏(Guardrails,有约束力) @@ -645,21 +642,8 @@ grep `),复升级时逐条**跑**一遍,零命中/变形的就地改写 ## 报告契约(Report contract,os-dev 返回什么) -```json -{ - "issue": 123, - "status": "done | rework | blocked | needs_decision", - "branch": "claude/issue-123-short-slug", - "pr": "https://github.com/objectstack-ai/objectstack/pull/456 | null", - "premise_still_valid": true, - "summary": "what was implemented, 2-4 sentences", - "tests": "commands run + pass/fail evidence", - "open_questions": [ - { "question": "…", "options": ["A …", "B …"], "recommendation": "A, because …" } - ], - "out_of_scope_findings": ["filed as #: one-line description"] -} -``` +终报 JSON 的权威形状住 `.claude/agents/os-dev.md`「终报消息」节 —— 字段与拼写以那里为准,⛔ 本文 +不抄第二份(两份拷贝已实测漂移且无同步门禁)。PM 侧消费规则: `premise_still_valid: false` + `pr: null` 是合法终报 —— 当再分诊输入复核,永不当失败派发。 `status: needs_decision` 时 `open_questions` 必须非空。`out_of_scope_findings` 应已由 dev 立成无 assignee 的卡 diff --git a/.claude/skills/pm-dispatch/references/contract-review.md b/.claude/skills/pm-dispatch/references/contract-review.md new file mode 100644 index 0000000000..9fb811dd23 --- /dev/null +++ b/.claude/skills/pm-dispatch/references/contract-review.md @@ -0,0 +1,44 @@ +# 契约复审链细则(references —— 按需加载) + +出处:主文件「入队与落地」条款②闸门(原则、双肢定义与 `CONTRACT_REVIEW_TIER` 档位 +单源住那里);本表是 `needs:contract-review` 复审链的操作细则,挂标、复审、清标那一 +刻查阅;⛔ 不引用 issue 编号。 + +## 载体纪律(挂与清) + +- **PR 与卡双载体同笔挂**(维护者 2026-08-22:「简化一点是否可以直接挂 PR 侧」「两边都挂好」; + PR 一存在即挂,报告先于 PR 到达则先挂卡侧、ACCEPT 时补齐 PR 侧),同笔在该 PR 上 + 向复审席账号 request review(同裁决:「也可以直接要求复审」—— 仅通知,载体仍是标 + 签)、停手。 +- **载体不迁移**(维护者 2026-08-18,原话:「中期把闸门迁到 PR review 的 Request Changes 上 我觉得没必要」): + 闸门载体保持本标签,⛔ 不迁 PR review / Request Changes、不为迁移留门;挂与清皆按 + 标签纪律的 read-modify-write 硬步骤写。 + +## 复审资格与归属 + +- **资格** —— ① 跑在契约复审档位,硬条件,认定只认降档保险丝的机读;② 非该卡派发 + 席,已从资格条件放宽为路径偏好(维护者 2026-08-21,原话:「你自己就是 Fable,自己就可以审核」): + 经同一机读证实达档的派发席,可对自派的卡执行契约复审并清标(审的 + 是低档实现者的契约增量,非自身产物 —— 派发席不写代码);放宽豁免的是独立席位,不 + 是复审本身 —— 一行结论照样先落卡、后清标,主文件「⛔ 禁止自查放行」禁的是免复审直 + 放,不禁本路径;低于契约复审档位的席照旧留标等待。 +- **归属**:常设 = skills 席自绑小时钟(维护者 2026-08-23:「要不还是你挂个定时处理审核吧」), + 每小时一轮即天然攒批;分诊席达档时(经同一机读证实)照旧可清。只审契 + 约增量 diff、结论一行写在卡上、PASS 双载体同笔清标(PR 与卡各按标签纪律硬步骤)并 + 清 review request 或留一条 review 评论,标清后卡方可入队。 + +## 降档保险丝(机读) + +- 子轮开场**必调一次 `get_session`**(claude-code-remote MCP,无参)读 + `external_metadata.last_served_model`,⛔ 自述档位不是读数(静默降档腐蚀的恰是自 + 述;实测与配置档陷阱见 platform-readings);读数 ≠ `CONTRACT_REVIEW_TIER` ⇒ 该子 + 轮整体跳过、标签原样留置 —— 卡在队列外等待是安全态。 +- **保险丝只对座位自会话有效**:`mode:subagent` 里的 `get_session` 量的是**派发会 + 话**(实测:钉在地板档的子代理读回父会话的档位,`session_context.model` 与 + `last_served_model` 一致只是同一来源引用两次,⛔ 不作互证)—— subagent 的实际服役 + 档位现无法对 `CONTRACT_REVIEW_TIER` 自证,条款②的 `mode:subagent` 派发因此恒保留 + `needs:contract-review` 走复审链,「派发已在地板」的免审跳过仅座位自会话成立。 + **⛔ 反模式:派更高档位子 agent 去执行契约复审** —— 看似满足档位,实为构造上不可 + 测量(多次实测:子代理读回父会话档位并拒绝出裁决)。 +- 契约复审 ⛔ 不适用额度耗尽豁免降档(豁免的对象是派发;复审的存在意义就是补偿一次 + 低于地板的派发)。 diff --git a/.claude/skills/pm-dispatch/references/dispatch-runbook.md b/.claude/skills/pm-dispatch/references/dispatch-runbook.md index 5885c74ea3..a93b5bb1db 100644 --- a/.claude/skills/pm-dispatch/references/dispatch-runbook.md +++ b/.claude/skills/pm-dispatch/references/dispatch-runbook.md @@ -89,8 +89,7 @@ fire 附带一次: `state=CLOSED` + `since` 与 `Blocked-by:` 反向索引求交,命中走既有回队双查;健康指标 = 逐 标签 `perPage: 1` 只读 `totalCount`。每日层(当日首 fire)= 四仓全量对账 + 归集本就日频的 职责(finding 集中轮、`Restart-when:` 判据批扫、决策箱回填)。成本靶:干活轮 ≤50k,空转轮 -守既有探针预算;守小时 fire 的硬理由是契约复审时延(条款② PR 等复审清标,拉长节拍翻倍落 -地等待)。 +守既有探针预算(契约复审的常设承担已收敛为 skills 席自绑小时钟,见 `contract-review.md`)。 ## 落卡与裁决记录细则(维护者 2026-08-13) @@ -173,9 +172,9 @@ subagent 在 PM 容器内运行,agent 定义与技能文本读**本地检出**, 出处(逐字,未译):「如果当前任务依赖其他赛道的任务,如果判断简单,是否可以直接接手而不必 持续等待」。判据与认领纪律(含 `Claim:` 拼写)在主文件;补遗:只覆盖「等一周 vs 做十分钟」 -的形状;`packages/spec` 恒归 spec 座位,本条不豁免(唯一所有者规则更硬);**⛔ 不是「借 -调」回归** —— 判据是依赖形状,只做被本车道开卡 `Blocked-by:` 点名的那一个阻塞项,做完即 -回,⛔ 不顺手接第二张。 +的形状;`packages/spec` 恒归 spec 座位,本条不豁免(唯一所有者规则更硬);「借调」墓碑在 +主文件多仓协调 4 —— 判据是依赖形状,只做被本车道开卡 `Blocked-by:` 点名的那一个阻塞项,做 +完即回,⛔ 不顺手接第二张。 ## 停摆复位梯度 diff --git a/.claude/skills/pm-dispatch/references/state-machine.md b/.claude/skills/pm-dispatch/references/state-machine.md new file mode 100644 index 0000000000..350df14729 --- /dev/null +++ b/.claude/skills/pm-dispatch/references/state-machine.md @@ -0,0 +1,43 @@ +# 状态机细则(references —— 按需加载) + +出处:主文件「状态模型」表(语义一行在表上,本表承载四个长状态的机制细则),做对应 +转换、放行或巡查的那一刻查阅;⛔ 不引用 issue 编号。 + +## `pm:on-hold` —— 重启条件、触发文件与放行双查 + +- **合法性**:仅当正文或评论带机器可读行 `Restart-when: closed #N`(由 + `Blocked-by:` 的同一遍解锁扫描点火、同双通道契约 —— 正文或评论任一即为行,评论停 + 靠的出口曾静默过期两天)或 `Restart-when: <一行可执行判据>` 时才合法;hold 评论带 + 日期、理由、出处(维护者裁或座位定级,⛔ 不设第二个标签区分)。 +- **机会主义重启的触发文件**走同族正典行 **`Restart-touch: <仓内相对路径>`**(一行 + 一路径,大小写敏感、行锚定,与 `Blocked-by:`/`Restart-when:` 同双通道 —— 正文或评 + 论任一,H17 兼读 hold 评论;反引号/bullet 可容忍、值须为 tracked 文件)—— 喂半状 + 态巡查 H17 的 on-hold 触发文件索引,抽取器已随巡查落地、采用即零代码;存量 hold + ⛔ 不迁移、不产 finding,散文锚词抽取兜底旧卡。 +- **放行双查(两查皆机械、零判断)**:① 只对**最近一次** `pm:on-hold`/`pm:blocked` + 转换评论所载条件放行,⛔ 永不对线程里更早的 blocker —— 已放行过的条件是花掉的,再 + 点火就把过期前提立成现行;② 该转换评论之后卡上有**更新的 merged PR** ⇒ 拒绝放行 + —— 那是条件写下后卡已前进的信号(引用的事实可以为真而不再是现行条件)。 + +## `pm:blocked` —— 完工停放(`Unlock-action:`) + +**工已完、PR 被外部门禁缺陷卡住的卡同用本态,⛔ 不设新标签**:`Blocked-by:` 指向门 +禁缺陷卡,正文另加机器可读行 `Unlock-action: re-check PR #M` —— 解锁扫描读到它就把 +解锁动作从「回队重派」换成「重查该 PR 的落地」(回队前提检查见到已完工的 open PR 即 +按落地工作处理,⛔ 永不给完工卡重派 dev);停放的 PR 正文必须点名门禁卡,让链路从任 +一端可读、不依赖会被整篇改写的座位贴。 + +## `pm:awaiting-maintainer` —— 互斥与出口 + +与 `pm:queue`/`pm:dispatched`/`pm:blocked`/`pm:on-hold`/`needs-user-decision` **互 +斥**(并存即误标);出口 = 维护者完成该操作、座位摘标 + 证据评论同笔 —— **无机器出 +口,by construction**,在飞视图按停放库存计(强制与巡查细节以 +`check-half-states.mjs` 为权威)。 + +## `pm:retriage` —— 挂/摘两方机制 + +原定级在改判前仍是权威,并存让「排队但有异议」在列表上可见;挂标者 = 提出异议的席 +位,挂标与**异议评论同笔**(证据 + 建议定级),无证据评论的裸挂标不合法;摘标者 = +分诊 Routine,每 fire 高优先重判、重判后摘标 —— 挂/摘分属两方、各自的转换不相交,这 +是本行的安全性;标签须五仓存在(分诊五仓统一职责,首次应用时创建);老化兜底归半状 +态巡查(年龄谓词随巡查另行落地)。 diff --git a/scripts/pm/check-skill-line-ratchet.mjs b/scripts/pm/check-skill-line-ratchet.mjs index 33098d3bf9..295a68c746 100644 --- a/scripts/pm/check-skill-line-ratchet.mjs +++ b/scripts/pm/check-skill-line-ratchet.mjs @@ -85,13 +85,27 @@ const REPO_ROOT = new URL('../../', import.meta.url); // value). Shrink-only: lower freely, raise only with a maintainer ruling // quoted in the raising PR (see header). export const CEILINGS = new Map([ - ['.claude/skills/pm-dispatch/SKILL.md', 682], + // Lowered 682 → 666 by the maintainer-ordered whole-text restructuring round + // (ruling 2026-08-23, verbatim: 「接受你的重构提案」): the four long + // state-table rows and the clause-② review-chain bullets sank to the two new + // references below, and the report-contract JSON is single-sourced from the + // dev-agent definition. Landed count, headroom 0, same convention. + ['.claude/skills/pm-dispatch/SKILL.md', 666], // Raised 223 → 244 by the triage reading-cost card (maintainer ruling // 2026-08-20, quoted in the raising PR): three mandated conventions land in // the runbook's triage sections. Landed count, headroom 0, same convention. // Lowered 244 → 243: the decision-analysis template entry became a pointer // to the reference file below (lowering is always legitimate). - ['.claude/skills/pm-dispatch/references/dispatch-runbook.md', 243], + // Lowered 243 → 242 by the restructuring round: the stale hourly-fire + // rationale clause collapsed into a pointer at contract-review.md. + ['.claude/skills/pm-dispatch/references/dispatch-runbook.md', 242], + // Whole-text restructuring round (maintainer ruling 2026-08-23, Q1 = A): + // mechanism detail extracted from SKILL.md — the four long state-table rows + // (state-machine.md) and the clause-② review-chain operational detail + // (contract-review.md). Set at landed line counts (headroom 0, same + // convention as the entries above). + ['.claude/skills/pm-dispatch/references/state-machine.md', 43], + ['.claude/skills/pm-dispatch/references/contract-review.md', 44], // Business-perspective decision-analysis writing guide (maintainer ruling // 2026-08-20: the four-facet analysis must argue from the business // standpoint). Set at landed line count (headroom 0, same convention).