From c2d962af1f801925d14896a36de55932036ec20a Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 16:29:35 +0000 Subject: [PATCH 1/4] =?UTF-8?q?pm-dispatch:=20two-tier=20triage=20inventor?= =?UTF-8?q?y=20=E2=80=94=20hourly=20since-window=20rounds,=20one=20daily?= =?UTF-8?q?=20full=20four-repo=20reconciliation=20fire?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The triage round's four-repo FULL open-issue inventory becomes a daily reconciliation backstop; hourly fires run on since windows anchored to the previous round-close brief's timestamp (read from the seat post — the same reading the round-open mutex already takes). The daily tier is picked by fire-time-of-day, never a counter, and the brief states which tier ran. SKILL.md carries the principle; the since-equivalent readings, cost targets and daily-duty clustering live in references/dispatch-runbook.md. Both ratcheted files stay at their ceilings (682/682, 243/243), additions paid by in-file trims. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01MsbKEG4LtERSLaDrbehM3e --- .claude/skills/pm-dispatch/SKILL.md | 10 +-- .../references/dispatch-runbook.md | 62 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index 0887aa5762..75a4a0f0fd 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -139,9 +139,8 @@ session 的 `Claim:` 评论(拼写见「认领」,车道盘点已取)—— 标 产品横跨三仓,依赖方向固定:`objectstack`(后端;`packages/spec` 是唯一契约)→ `objectui`(前端,构 建产物经 `pnpm objectui:refresh` 回流)与 `cloud`。链外两仓不入依赖链:分诊照扫(分诊座位保持五仓唯 一),各归同名 `repo:*` 执行座位,纪律即规则 4 姊妹仓执行座位一套(⛔ 此处不另抄)。第四仓 `objectos` -(纯文档与站点,执行已自 `domain:devx` 迁出):座位由维护者 2026-08-18 亲自提前行使规则 4 预登记的升 -格开设(「objectos 是新开的项目经理,是不是少了座位帖。」);无 changeset 流、无 `packages/`;合并队 -列 + required `build` + `merge_group` 自 2026-08-18 起已上线 —— 派发预期照实设,⛔ 不要求不存在的机制。 +(纯文档与站点,执行已自 `domain:devx` 迁出):座位由维护者 2026-08-18 开设(「objectos 是新开的项目 +经理,是不是少了座位帖。」);无 changeset 流、无 `packages/`;合并队列 + required `build` + `merge_group` 已上线 —— 派发预期照实设,⛔ 不要求不存在的机制。 第五仓 `hotcrm`(样板工程:元数据开发的 CRM 示例应用;岗位说明与裁决原文在 `references/lanes/hotcrm.md`):平台相关的功能在平台中实现 —— 建设 hotcrm 时发现的平台缺口按规则 1 落平台仓**普通卡**(非缝卡,⛔ 不在样板内绕行);`repo:hotcrm` 缝标签只给真协调卡。 **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 宪章同款纪律)。 @@ -248,6 +247,8 @@ 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)。 + **Backlog sweep(常设职责,不等请求)。** 每轮扫任一析取命中的卡:① 全裸(无`pm:*`、 无 `needs-user-decision`、无 `domain:*`);② 有 `pm:queue` 无 `domain:*`(**凡有车道标签的仓皆扫**, 今日为主仓与 objectui —— 三流拆分见多仓协调;豁免仅余真无车道标签的仓 cloud、objectos,该形状在那里才是队列卡常态);③ 有 `domain:*` 无 pm-state。②③ 只取 `updated_at` @@ -423,8 +424,7 @@ dev 侧推分支要早 —— 远程分支是在飞工作最硬的证据。**死 draft-only、tier 推导引用、棘轮实况、释义纪律)。无条件条款只住角色文件(冲突时它胜、错了修那里, ⛔ 不靠派发词临时覆盖)。**终报要求随派发词带一句**:只收机器可核字段(gates/line_budget/ deviations/files_changed),⛔ 复述 PR body 叙事。**清单、路径、行号在派发那一刻从树上取**,⛔ 不 - 从卡片/上次派发/记忆抄(`node scripts/pm/dispatch-gates.mjs`,取数的是 PM 不是 dev —— dev 只跑 - 被点名的族,全 farm 归 CI;点名单是线索不是规格,dev 同脚本对实际改动重取、补跑漏点名的族并报告,条款在 os-dev 定义);行级断言转述前必须自己重验。 + 从卡片/上次派发/记忆抄(`node scripts/pm/dispatch-gates.mjs`,取数的是 PM;点名单是线索不是规格,dev 对实际改动重取补跑 —— 条款在 os-dev 定义,补遗见 runbook);行级断言转述前必须自己重验。 - **触 `skills/**`(对外发布的技能包)的卡,派发词必带 PM 定的净增行数预算**(按 feature 大小定,小功能给小数);dev 装不下 ⇒ 停手回报,⛔ 不自行扩写、不自行抬预算(抬预算是维护者裁决)。 **原则:对外发布的技能包是平台最大的对外价值,评估恒整包整体**(维护者 2026-08-21:「对外发布的 skills 是整个平台的最大价值,尤其要整体考虑和评估。」)。 - **文件面写两句**(预期落点 + 生产者在别包时报备后按生产者侧修,⛔ 不在消费者侧打补丁 diff --git a/.claude/skills/pm-dispatch/references/dispatch-runbook.md b/.claude/skills/pm-dispatch/references/dispatch-runbook.md index ddaf614157..1b8a645b5c 100644 --- a/.claude/skills/pm-dispatch/references/dispatch-runbook.md +++ b/.claude/skills/pm-dispatch/references/dispatch-runbook.md @@ -18,10 +18,9 @@ 发);单一生产者纪律照旧(与「代扫」同界)—— 分诊座位在班且已在处理同卡即让行; 紧急通道改的是节奏,不是生产者数目。**半状态治愈积压排序**(维护者 2026-08-19, 原话:「项目经理等分诊,但是没有切换 label,导致挂了很久。」「我刚和他说了他才处 -理。」):sweep 半状态析取②③**最老优先、P0 嫌疑先行**,「优先最新」只适用新入卡 -①,⛔ 永不适用治愈积压 —— 限量 + 最新优先令最老半状态结构性饿死,活过一个 sweep -周期的半状态是治愈环自身的缺陷,不是库存;正文自报 P0/data-integrity 的命中即走 -本节紧急通道;机械年龄告警在半状态巡查脚本(细节以脚本头为权威)。 +理。」;排序规则本体在主文件):限量 + 最新优先会令最老半状态结构性饿死,活过一 +个 sweep 周期的半状态是治愈环自身的缺陷,不是库存;正文自报 P0/data-integrity 的 +命中即走本节紧急通道;机械年龄告警在半状态巡查脚本(细节以脚本头为权威)。 ## 发现分诊轮细则(维护者 2026-08-13) @@ -33,8 +32,8 @@ - **状态转换机制**(「finding 恒 = 待首次定级」在主文件):定级出 hold ⇒ 同笔 `finding` → `pm:on-hold`(域标签保留;hold 评论照既有纪律带日期/理由/具名重启 条件,维护者裁 vs 座位定级的出处写进评论,⛔ 不设第二个标签区分);修法是**状态 - 转换,不是豁免评论** —— 双态混编曾让健康 hold 顶红裸计数、藏住未定级堆、重验吃 - 预算;曾提议的逐卡豁免评论机制已废弃,⛔ 不复活。 + 转换,不是豁免评论**(双态混编曾让健康 hold 顶红裸计数、藏住未定级堆;逐卡豁免 + 评论机制已废弃,⛔ 不复活)。 - **首触定级补遗**:零定级评论的卡优先 —— 未定级卡前提准确性半衰期以天计,首触延 迟是单卡最大成本;旧 hold 重验不占预算;关闭 not planned 附理由并列入轮次报 告;立单 dev 只有局部视野,照实立单不压级。 @@ -47,8 +46,8 @@ 出处:反复撞的限流墙经维护者确认为「GitHub API 池」。同一趟派发/定级覆盖多张成员 卡时,**锚卡承载全量认领(或定级)评论**(会话、分支、文件面、交付物、串行约束全 -量),成员卡各留一行指针指向锚卡;标签翻转照旧逐卡执行 —— 省的是评论正文写量(实 -测一个班次约省 2/3),不是状态写入;验收与解锁扫描的读侧不变,仍逐卡读。 +量),成员卡各留一行指针指向锚卡;标签翻转照旧逐卡执行 —— 省的是评论正文写量,不 +是状态写入;验收与解锁扫描的读侧不变,仍逐卡读。 ## 座位贴活性巡查(分诊轮常设项;维护者 2026-08-14) @@ -57,19 +56,16 @@ Routine 每 fire 附带一次: - **扫描面**:`label:pm:seat` 列表页上标题挂 `🟢 ` 的贴; `🟢 Routine` 座位以调度器读数为准,不入本巡查。 -- **判据只认在任者自己的产出**(自有评论/认领/贴正文编辑 —— 作者与时间戳是平台盖 - 章的硬读数),⛔ 不算别人发给它的跨座位通知 —— 收到消息不是活着的证据。 +- **判据只认在任者自己的产出**(自有评论/认领/正文编辑,作者与时间戳是平台盖章的硬读数),⛔ 不算发给它的跨座位通知 —— 收到消息不是活着的证据。 - **>24h 无自有产出(与既有回收线同一条)⇒ 当场降级**:标题改 `⏳ vacant` + 摘 assignee **同笔**,留证据评论(最后自有产出的时间戳与链接);在飞认领照认领协议 由原认领者跟完。 -- 惰性判定(接管冲突时)照旧,本巡查是其常设出口,把「标题挂 🟢 而人已下班」的窗 - 口压到一个班次以内(三元同笔与回收细则见 `seat-post-protocol.md`)。 +- 惰性判定(接管冲突时)照旧,本巡查是其常设出口(细则见 `seat-post-protocol.md`)。 ## 分诊席读数成本三则(维护者 2026-08-20) -出处:三方讨论后维护者「立卡」;实测:数百评论座位贴每轮全文重读数千 token。 -耐久修法两层只交叉引用 —— 巡逻量具读评论级边(已落地,冻结)+ 席位恢复「读正文 -一次拿到现行状态」(被 sanitizer 转义陷阱挡住,另线);本三则是席内读数对价。 +出处:三方讨论后维护者「立卡」;实测:数百评论座位贴每轮全文重读数千 token;耐久 +修法(量具读评论级边已落地;正文单读恢复被 sanitizer 陷阱挡住,另线)外的席内对价。 - **收班简报索引化**:模板固定四段 —— 首行机器判据(「分诊轮收尾」起始标记, **逐字不动**,互斥守卫靠 grep 它)+ 索引表(卡号 | 一行判决)+ 健康指标 + 接 @@ -86,11 +82,20 @@ Routine 每 fire 附带一次: 可)返回结构化摘录,尾部优先。**裁决级阅读(契约复审、放行判定、代裁)不可外 包** —— 省这部分是拿放行质量换 token,禁止。 +## 分诊两级盘点细则(维护者 2026-08-20) + +出处(逐字,未译):「每次都需要 四仓全量 open issue 盘点 … 吗?建议分诊多久执行一 +次」→「立卡」。实测全量四仓 ~50k token/轮,`since` 等价 ~8k。小时层三读法:sweep +析取①②③ = `list_issues` + `since`(标签变更刷新 `updated_at`,半标注照样入窗); +解锁扫描反演 = 逐仓 `state=CLOSED` + `since` 与 `Blocked-by:` 反向索引求交,命中走 +既有回队双查;健康指标 = 逐标签 `perPage: 1` 只读 `totalCount`。每日层(当日首 +fire)= 四仓全量对账 + 归集本就日频的职责(finding 集中轮、`Restart-when:` 判据批 +扫、决策箱回填)。成本靶:干活轮 ≤50k,空转轮守既有探针预算;守小时 fire 的硬理由是契约复审时延(条款② PR 等复审清标,拉长节拍翻倍落地等待)。 + ## 落卡与裁决记录细则(维护者 2026-08-13) 出处(逐字,未译):「还有很多我发现分诊或者决裁后没有改状态,这个也是问题」…「这 -个也需要更新项目经理技能」。实测:一张决策卡三个叠加半状态(推荐已被证伪而正文未 -调和、换标 `pm:blocked` 指着已解除的阻塞、激活条件已可判而无人判)。 +个也需要更新项目经理技能」。实测:一张决策卡三个叠加半状态。 - **裁决记录四件补遗**(四件本体在主文件;原子、记录座位全责、维护者裁与代裁同 规):① 鲜度门可内联声明分歧代替调和正文,对过期正文记录的裁决按过期论;② 结果 @@ -120,11 +125,10 @@ Routine 每 fire 附带一次: ## 云卡(`mode:cloud`)四课 -**适用面论证**(裁定与 S/M/L 分配在主文件「资源与后端」):云有归档债(实测一个座 -位积欠 11 个遗忘容器)、create/poke/subscribe/collect 派发收集管线、逐卡容器+ -clone 启动三项固定税;subagent 唯一实成本「随 PM 会话死」已由 branch-early、 -draft-PR 时点交报、transcript 复活与接手协议兜底;共享容器争用只来自 build+test, -docs/指令类 M 卡碰不到 —— 归档义务因此只落云卡。 +**适用面论证**(裁定与 S/M/L 分配在主文件「资源与后端」):云有归档债、派发收集管 +线、逐卡容器+clone 启动三项固定税;subagent 唯一实成本「随 PM 会话死」已由 +branch-early、draft-PR 时点交报、transcript 复活与接手协议兜底;共享容器争用只来 +自 build+test,docs/指令类 M 卡碰不到 —— 归档义务因此只落云卡。 1. **授权面随 source,不随环境**:trigger 拉起的会话无仓库授权(只读勘察); `create_session` 带 `source_url` 出生即持推送授权。同时带 `outcome_branch` @@ -143,8 +147,7 @@ docs/指令类 M 卡碰不到 —— 归档义务因此只落云卡。 监控与转向:`get_session` 读实时状态(IDLE + 分支未推送 = 停摆待 poke);投递消息 用绑定会话的 poke 触发器(`create_trigger` 带 `persistent_session_id` + `fire_trigger`,用后即 `delete_trigger`);巡检退为兜底心跳,只补订阅盲区(会话停 -摆、未开 PR 的分支、姊妹仓动静)。roster 不可达是设计而非故障(维护者 2026-08-11 -裁定:事件驱动架构即长期方案;⛔ 不复测,`ListAgents` 同样列不到)。会话句柄是**账 +摆、未开 PR 的分支、姊妹仓动静)。roster 不可达与 SendMessage 一款同裁(`ListAgents` 同列不到,⛔ 不复测)。会话句柄是**账 号作用域**的:`get_session` / `archive_session` / 绑会话 poke 触发器对另一账号建 的会话一律答 `not found`,与「从不存在」不可区分 —— **⛔ 永不读作死亡信号**(实测 判 not found 的会话数十分钟前还 RUNNING;误判死会往活 worktree 塞第二个 agent); @@ -155,17 +158,15 @@ docs/指令类 M 卡碰不到 —— 归档义务因此只落云卡。 subagent 在 PM 容器内运行,agent 定义与技能文本读**本地检出**,不是 `origin/main`。 派发 subagent 批之前先快进:`git -C pull --ff-only origin main`(或核 -对 `HEAD` 等于 `origin/main`);检出过期则整批拿到过期定义(实测:os-dev 定义重写 -合入当天,容器检出仍停在重写前,首批加载了旧定义)。用 `--ff-only` 让脏或分叉的检 -出大声失败,不静默合并。 +对 `HEAD` 等于 `origin/main`);检出过期则整批拿到过期定义(实测发生过)。用 +`--ff-only` 让脏或分叉的检出大声失败,不静默合并。 ## 接手中断的 dev(worktree 接手协议) 先试复活、不可用才接手与 ⛔ 不重跑原派发词在主文件;四条增量: - worktree 已存在,⛔ 不要新建,`cd` 进去接着做(第二个 worktree 会劈开工作); -- 先读全部既有提交与未提交改动,逐 hunk 决定保留或修正 —— 既不推倒重来也不盲信 - (死 agent 从未回报,它的一切都未经验证); +- 先读全部既有提交与未提交改动,逐 hunk 决定保留或修正 —— 既不推倒重来也不盲信(死 agent 的一切都未经验证); - 把死 agent 没跑完的验证**完整重跑**并报真实输出(中断的运行没留下测试证据); - assignee、认领评论、分支**全部不动** —— 既有认领的延续,不是新认领;认领评论记 录接手,不被替换。 @@ -190,8 +191,7 @@ unreliable,按接手协议重派到该分支。自己挂的定时器不会唤醒 原则在主文件;细则:重放形态可以完全正常、报告完整正确 —— monitor 按自己的 deadline 触发;身份 = 三元组 `(issue, 分支, PR head sha)` + 通知自报的守护对象 -(自报是「变便宜」不是前提,没自报就用三元组自己算);判定重放 ⇒ 台账记「重放, -首达时间 T」即结束。 +(自报缺席就用三元组自己算);判定重放 ⇒ 台账记「重放,首达时间 T」即结束。 ## 直接验收兜底(报告丢失 ≠ 验收停摆) From ad9c80fe2612b3c222d32d51531f004a8e4008dd Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 16:29:49 +0000 Subject: [PATCH 2/4] pm-dispatch: decision re-read before writing a brief, symmetrical to the race re-read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before writing a dispatch brief, read the card's comments to the last page and quote any maintainer ruling verbatim into the brief's ruling partition as binding — or state that none exists. The race re-read answers 'is this card taken?'; it cannot answer 'has this been ruled?' (a ruling comment carries no session ID, and a ruled card put back in the queue is label- identical to a never-ruled one), and a brief written without it re-opens a closed fork and drops the ruling's own dispatch constraints. Nets -2 lines on the ratcheted SKILL.md (680/682 after this commit). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01MsbKEG4LtERSLaDrbehM3e --- .claude/skills/pm-dispatch/SKILL.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index 75a4a0f0fd..e0bc2ff8b3 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -327,13 +327,11 @@ hold 评论纪律见状态模型,hold 重验只在 `Restart-when:` 命中时发 **整车道一次读全,本地求交**(维护者 2026-08-11 接受):`list_issues` 带 `labels: [domain:X]` + 最小字段一次拿回全车道 open 集,各状态本地求交 —— 按单一 pm 状态切片的查询看不见其它状态,是结 构性盲区。候选 = open、未 assign、无`needs-user-decision`、无 `pm:retriage`;已排队父单的 open sub-issue 自动是 -候选(`pm:epic` 父单的子树除外)。**每张候选读全文 + 全部评论**(裁决落在评论区,跳过评论就是跳 -过裁决;评论还可能记着一半工作已交付);**派发前做前提过时检查(stale-premise check)—— 裁决同 +候选(`pm:epic` 父单的子树除外)。**每张候选读全文 + 全部评论,写派发词前补一次决策复读(decision re-read),与认领的竞态复读对称**:评论读到最后一页,凡维护者裁决**逐字引入派发词裁决分区**作约束,无则写明「无裁决」—— 竞态复读只答「被谁认领」答不了「已被裁过」(裁决评论不带 session ID,裁后回队的标签状态与从未裁过的卡同形,队列列表分不出),漏读的派发词把已闭分叉当开放问题重开、并丢掉裁决自带的实施约束;评论还可能记着一半工作已交付。**派发前做前提过时检查(stale-premise check)—— 裁决同 罪**(裁决描述的也是当时的仓,写得权威、日期又近,恰恰更容易被当成现成事实),两半都查:**动作 面** —— `git log --oneline -20 -- ` 之外,裁决实施卡再核被点名的动作在 `origin/main` 上 还没被做掉;**卡引用面** —— 裁决/卡片点名为阻塞、认领面、协调对象或「落地即启用」依赖的每张 -issue,逐个读当前 open/closed/assignee,引用读到的现状 ⛔ 不引用裁决写作时的描述(树答不了「那 -张卡还开着吗」;过时动作断言 dev 动手即自纠,过时卡引用不变红)。花几分钟,不查则赔一次 agent 运行。 +issue,逐个读当前 open/closed/assignee,引用读到的现状 ⛔ 不引用裁决写作时的描述(过时动作断言 dev 动手即自纠,过时卡引用不变红)。花几分钟,不查则赔一次 agent 运行。 **批次独立性。** 一批内任两单不得可能碰同一个包/registry/barrel/spec schema;拿不准就串行。**同 文件单跨轮硬串行;延后不是搁置**(被延后那一刻就把已知的坑记到该 issue 上)。**家族派发(family dispatch)是本条的范围澄清,不是豁免**:独立性防的是两个 agent 相撞同一区域, From 9857ead3d81f4093514c95ff6d2d626a5167bc87 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 16:29:58 +0000 Subject: [PATCH 3/4] =?UTF-8?q?pm-dispatch:=20the=20tier=20fuse=20is=20val?= =?UTF-8?q?id=20only=20for=20seat=20sessions=20=E2=80=94=20a=20subagent=20?= =?UTF-8?q?get=5Fsession=20reading=20measures=20the=20dispatching=20sessio?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit State plainly in the contract-review chain that a mode:subagent get_session reading reports the DISPATCHING session's model (the two fields agreeing is one source quoted twice, not corroboration), so a subagent cannot attest the tier it actually ran at. Clause-② subagent dispatches therefore always keep needs:contract-review, and the dispatched-at-the-floor review skip is seat-session-only. SKILL.md at 681/682 after this commit. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01MsbKEG4LtERSLaDrbehM3e --- .claude/skills/pm-dispatch/SKILL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index e0bc2ff8b3..37e87edce4 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -519,7 +519,8 @@ os-zhuang 审核。我的手机github 应该会收到推送消息吧」;当日 肢**由声明行承载。档位以 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` ⇒ 该子轮整体跳过、标签原样留置 —— 卡在队列外等待是安全态;契约复审 ⛔ 不适用额度耗尽豁免降档(豁免的对象是派发;复审的存在意义就是补偿一次低于地板的派发)。**载体不迁移**(维护者 2026-08-18,原话:「中期把闸门迁到 PR review 的 Request Changes 上 我觉得没必要」):闸门载体保持本标签,⛔ 不迁 PR review / Request Changes、不为迁移留门;挂与清皆按标签纪律的 read-modify-write 硬步骤写。 + 子轮开场**必调一次 `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 的实际服役档位现无法自证,条款②的 `mode:subagent` 派发因此恒保留 `needs:contract-review` 走复审链,「派发已在地板」的免审跳过仅座位自会话成立。契约复审 ⛔ 不适用额度耗尽豁免降档(豁免的对象是派发;复审的存在意义就是补偿一次低于地板的派发)。**载体不迁移**(维护者 2026-08-18,原话:「中期把闸门迁到 PR review 的 Request Changes 上 我觉得没必要」):闸门载体保持本标签,⛔ 不迁 PR review / Request Changes、不为迁移留门;挂与清皆按标签纪律的 read-modify-write 硬步骤写。 - **碰生成物的 PR,入队前先同步 + 整体重生成**(os-regen 驱动零冲突标记地**静默丢掉一侧改动**): 四步序已机械化 `bash scripts/pm/os-regen-merge.sh`;陷阱、断言措辞与锚点禁令见 landing-operations A。 - **跟到 MERGED 为止;入队后的看护同归车道 PM 的落地窗口**:验收、首次入队 flip 定点、MERGED 两读 From 9e58b7d8af8f5bc4d5a2d5b68cbfc6f5e146bd5a Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 16:30:09 +0000 Subject: [PATCH 4/4] =?UTF-8?q?docs(agents):=20point=20seats=20at=20script?= =?UTF-8?q?s/pm/git-history.mjs=20=E2=80=94=20guard-index=20row=20in=20the?= =?UTF-8?q?=20dispatch=20skill,=20windowed-history=20rule=20in=20AGENTS.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prescribed shallow-history remedy was named in no instruction file, so a seat asking a windowed churn question had no way to find it: a shallow clone answers windowed git log/rev-list at exit 0 with no warning. AGENTS.md gains the rule (answer, or REFUSE; historyHorizon() is the read-only predicate), the pm-dispatch 机械守卫索引 gains the ratchet-paid row. Both files stay at their ceilings (961/961, 682/682), additions paid by in-file content trims. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01MsbKEG4LtERSLaDrbehM3e --- .claude/skills/pm-dispatch/SKILL.md | 1 + AGENTS.md | 38 ++++++++++++++--------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index 37e87edce4..b1312dfb5b 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -675,6 +675,7 @@ grep `),复升级时逐条**跑**一遍,零命中/变形的就地改写 | `scripts/pm/check-half-states.mjs` | label/assignee/PR 半状态的 report-only 巡查(含已复核就绪却无人落地的孤儿 PR 检测) | | `scripts/pm/check-governed-merges.mjs` | governed 面合并清单的 report-only 审计(事后防线;轮报载体,本地枚举零 API,仅归因走查询) | | `scripts/pm/dispatch-gates.mjs` | 文件面 → 该跑的门禁族(派发令取数) | +| `scripts/pm/git-history.mjs` | 窗口化 commit 计数:回答或 REFUSE —— 浅 clone 对窗口化 `git log`/`rev-list` 以 exit 0 无警告答错;`historyHorizon()` 是自答工具的只读谓词 | | `scripts/pm/os-regen-merge.sh` | 碰生成物 PR 的 merge 四步序(防静默吞并与锚点倒退) | | `scripts/pm/ensure-pm-labels.sh` | pm 标签词表的幂等一次性创建;退役车道刻意不在 ⛔ 不加回,理由与对象清理以脚本头为权威 | | `check:skill-frame-sync` / `-freshness` | 四维决策框架四份拷贝的同构与新鲜度 | diff --git a/AGENTS.md b/AGENTS.md index 327f159dac..4f225ef262 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,10 +31,8 @@ the script's own header is the authority on detail. 就是改写裁决。上面那段引用即是一例:它是维护者的原话,一个字未动。 - 代码、标识符、提交信息(commit messages)、ADR/文档正文等仓库产物保持现有语言惯例(以英文为主),不要因本节而改写。 -The rules are split per channel because a merged rule was measured to fail: an agent -holding one instruction that claimed explanatory PR text for Chinese and another -demanding English produced half-Chinese, half-English PR bodies on the same day. One -rule per channel, no overlap. +The rules are split per channel because a merged rule was measured to fail (it produced +half-Chinese, half-English PR bodies in one day). One rule per channel, no overlap. --- @@ -216,9 +214,8 @@ every linked worktree pushes onto and pops off **one shared LIFO stack**. Two ag stashing at the same time swap entries — your `pop` restores the other agent's changes, your own work stays on the stack for them to take, and **`pop` reports success**; the only symptom is another agent's files in your `git status`, after which a `git add -A` -commits their half-finished work into your PR. It has really happened to two parallel -agents mid reverse-verification, both changesets recoverable only as unreachable -commits. A PreToolUse hook (`.claude/hooks/guard-shared-stash.sh`; details and the +commits their half-finished work into your PR. It has really happened, mid reverse- +verification. A PreToolUse hook (`.claude/hooks/guard-shared-stash.sh`; details and the `OS_ALLOW_STASH=1` escape in its header, self-test alongside) blocks the mutating forms — including `stash@{N}`, a *position* in a stack you don't own — and allows `list`/`show`/`create` and `apply`/`store` pinned to a literal hex object id. It fails @@ -260,6 +257,12 @@ stage it at all: `git restore --source= -- ` (no `--staged`) writes t only — porcelain shows a lone unstaged `M`, not `MM` — so prefer it when standing another ref's version up for a counterfactual. +**A windowed history question ("how many commits on `` in ``") goes through +`scripts/pm/git-history.mjs` — answer, or REFUSE.** A shallow clone answers windowed +`git log`/`rev-list` questions from truncated history at exit 0 with no warning; the tool +proves the window is covered first. `historyHorizon()` is the read-only predicate for +tools that answer their own question. + **Claim the issue BEFORE you write any code.** Assign it to yourself (`gh issue edit --add-assignee @me`, or `issue_write` with `assignees`) as the *first* action of the task — before the worktree, before the first read. An unassigned @@ -320,8 +323,7 @@ Even inside your own worktree, operate defensively: `claude/issue--`. The issue number in the name is what makes in-flight work *discoverable* — `git ls-remote --heads origin | grep issue-` is a one-command pre-check, and the Duplicate Fix Guard workflow warns on fix PRs whose branch names - no declared issue. A duplicated implementation once stayed invisible partly because - one branch carried the issue number and the other didn't. + no declared issue (how one implementation once got duplicated). 3. **Never `git push --force` / `--force-with-lease`, and never push `main`.** A force-push can clobber a parallel agent's work; `main` is shared — land everything via PR. @@ -658,8 +660,7 @@ their output is current; the wrapper reports that each run rather than staying s Two roots; **the filesystem is the catalog**. Consult the matching `SKILL.md` when working in its domain — browse the directory, never a hand-written list here (two -such lists drifted stale as skills landed; a reader who trusts a list cannot see -what it is missing): +such lists drifted stale as skills landed): - `skills/` — the **published** catalog (it ships to customer projects). - `.claude/skills/` — repo-internal agent playbooks; every entry must carry @@ -897,14 +898,13 @@ legal**: `AutomationEngine.getUnknownNodeTypeAudit()` reads the executor registr every call, records nothing, and is correct. **Why this is a rule and not a preference.** One showcase cold start produced three -instances in three unrelated subsystems, written by three people at three times: an -auth plugin froze an `undefined` cache handle into its config for the life of the -process (the printed warning sent operators to provision Redis for a problem they did -not have); the automation service asserted eight flows "will fail at execution time" -0.8s before their executor registered — indistinguishable from a deployment that -genuinely lacked the plugin; and the query engine persisted a schema attestation the -same boot was still contradicting, so the next restart rejected its predecessor's -data. +instances in three unrelated subsystems: an auth plugin froze an `undefined` cache +handle into its config for the life of the process (the printed warning sent operators +to provision Redis for a problem they did not have); the automation service asserted +eight flows "will fail at execution time" 0.8s before their executor registered — +indistinguishable from a deployment that genuinely lacked the plugin; and the query +engine persisted a schema attestation the same boot was still contradicting, so the +next restart rejected its predecessor's data. **The three cures, in preference order:**