Skip to content

docs(pm-dispatch): 三条 fleet-wide hazard 写进 SKILL —— 定点文本写法纪律、sanitizer 写侧就地删除、判死门槛 (#6393) - #6460

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-6393-fleet-wide-hazards
Aug 7, 2026
Merged

docs(pm-dispatch): 三条 fleet-wide hazard 写进 SKILL —— 定点文本写法纪律、sanitizer 写侧就地删除、判死门槛 (#6393)#6460
hotlong merged 1 commit into
mainfrom
claude/issue-6393-fleet-wide-hazards

Conversation

@hotlong

@hotlong hotlong commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #6393

#6393 立单人给出的三条 fleet-wide hazard 写进 .claude/skills/pm-dispatch/SKILL.md,并按 #5451 route B 逐条核实后给发布件 skills/objectstack-pm-dispatch/SKILL.md 加机制级泛化版。三条 hazard 均为 2026-08-07 实测,且跨两个座位(domain:spec-surface 立单席 + domain:devx 认领席)独立复现。纯文档 / 内部流程纪律,不发布任何包 ⇒ skip-changeset


1. 三条落点 before / after

危险 1 —— 已删除的 send_later 定时器仍会投递,且文本可能落后现实数轮

内容
落点 Operational note 3(完整待执行状态写进 send_later 定点文本 之后新增一段)+ step 6 巡检定点条款 + step 7 flip 定点条款,共 3 处
before note 3 只要求定点文本完整(哪个 PR、哪个动作、判据是什么),抗上下文丢失;全文 0 处提到「已删除的定时器仍会投递」,0 处约束文本的祈使句形态
after 新增「定点文本的写法纪律」:文本必须以「幂等 —— 动手前先重读状态」开头;只许描述判据(若 X 则 Y),不许描述结论(现在去做 Y);⇒ 重新派发 / ⇒ 判为不可靠 / ⇒ 打回不 arm 点名为要禁的形态。step 6 / step 7 各挂一条同款约束并回指 note 3

明确写进 after 的合成关系,避免读者以为是覆写:上面第一条让文本完整,这一条让它过期时仍然安全;两条是同一枪的两面。

危险 2 —— sanitizer 就地吞掉尖括号片段,反引号不提供保护

内容
落点 Operational note 12,原地扩写第三条 bullet
before note 12 两条 bullet 全部讲读侧:双读取判据(body + body_html 在同一处断掉才算 issue 端截断)、Repair first 的停摆成本。0 处提「反引号」「HTML 实体」「就地删除」
after 新增第三条 bullet:同一个 sanitizer 的写侧就地删除形态 —— 短片段被删、正文其余完好,因此没有「断掉的位置」,双读取判据在它身上恒假;附立单人三例写后回读对照表;两条动作(写实体、写后回读逐个确认)

⚠️ 既有主张零改写,见下面第 3 节的机械证明。after 文本自己也写了这句:「上面两条…… ⚠️ 一字不改、依旧成立;这一条是新增的另一种失效形态,不是对它的修正」。

危险 3 —— 探针门槛 ≠ 判死门槛

内容
落点 step 6,五条探活 bullet 之后新增一段
before 派发后 ~45 分钟无任何远程产出即到探活门槛 给的是探针门槛;全文 0 处出现「判死」,PM 面对的「多久之后可以下『它死了』的结论」无答案
after 45 分钟原样保留为探针门槛;新增判死的三类正当依据(探针回包表明已死 / 宿主回报 stopped / 超过本车道基线且连续静默),点名 ⛔ 「探针门槛过了两次」不是依据;并把 mode:cloud 的 ~2h 静默显式定性为本轮收集边界而非判死

机械 before/after 判别(实测,非论证)

origin/main 与本分支各 grep 一次判别串,origin/main 全为 0:

判别串 origin/main 本分支
幂等 —— 动手前先重读状态 0 3
已删除的定时器 0 2
只许描述**判据** 0 1
反引号 0 3
HTML 实体 0 1
就地删除 0 1
判死 0 5

发布件同法:idempotent — re-read the state / State criteria / collection boundary, not a verdict / baseline you have actually measured / backticks do not protect / read it back and confirm —— origin/main 全 0,本分支各 1。


2. 声明 A —— 三条规则各自代入真实历史案例(论证式验证,非实测)

⚠️ 本单是纯文本纪律改动,无可执行运行时行为 ⇒ 模板式「改前红 / 改后绿」不适用,这里不伪造一个红。有判别力的验证是:把每条新规则代入一个已经发生过的案例,给出新旧文本各自会作出的判断。判别串的 grep 计数(上表)是这张表的实测支撑;表本身的推论是论证

# 历史案例 旧文本会给出的判断 新文本会给出的判断
1a #5783 那次误投:已 delete_trigger 的定时器仍投递,文本写「判为不可靠 ⇒ 重新派发一个 fresh os-dev,worktree 已存在」,而 PR #6389 早已交付并通过复核 note 3 只检查文本是否完整 —— 该文本完整(带了 issue 号、动作、worktree 路径),判定合格。全文无一条能拦住那句祈使句 该文本含未经重读即可执行的祈使句「⇒ 重新派发」⇒ 违反写法纪律,不得这样写;合规写法是「若 #5783 仍无分支且无探针回包 ⇒ 判为不可靠」,投递时重读会立刻发现 PR 已存在,规则自动失效
1b PM 22:1xZ 那次(认领评论):定时器没被删,文本「两个 dev 静默结束 ⇒ 判定失效 ⇒ 重新派发一个新 dev」被现实追上 同上 —— 文本完整,判定合格;删与没删旧文本都管不到 同样违规(祈使句),且 after 文本明写「删与没删是两条路径,终点是同一个」⇒ 两种形态一并覆盖
2 立单人的写后回读三行对照表:<!-- os-dev-report --> 存回为空;expected <n> to be 19 存回 expected to be 19;git log -- <path> 存回 git log -- note 12 的判据是「bodybody_html 在同一处断掉才算 issue 端截断」。这三例正文没有断点,双读取一致地报告「正文完整」⇒ 判定为「没有 sanitizer 问题」,而标记确实已经消失 新 bullet 明写这一判据在写侧形态上恒假,并给出可执行动作:写实体 + 写后逐片段回读 ⇒ 判定为一次真实的写侧丢失,且能在写入当时被抓到
3a #5783 的 92 分钟误判:PM 在 92 分钟处写下「将判为不可靠」,而它在基线之内、几分钟后推了分支 唯一可用的数字是 45 分钟探针门槛;「门槛过了两次」是当时的推理链条 ⇒ 支持判死 「探针门槛过了两次」被点名 ⛔ 不是判死依据;判死需三类之一,而 92 分钟落在本席 93–110 分钟基线之内判定为不得判死,继续观察
3b 本车道九单基线(#5767/#5622/#5955/#5783 + #6251/#6038/#6405/#6359) 无基线概念,任何单一数字都可被当成判死线 明确要求「先建基线再判」,并把两条基线写成出处样例、非全车队常数;九单实测跨越 ~64 分钟到近 3 小时,任何单一常数都会在这个跨度里翻车

3. 声明 B —— 既有主张未被改写(实测)

note 12 的读侧主张逐字仍在。 按内容锚点抽出 note 12 整段(从 **12. 判「正文被 sanitizer 截断」**13. MCP 工具的两个参数语义陷阱),对 origin/main 与本分支各抽一次后 diff:

before lines: 26   after lines: 51
diff 中 "^<"(即被删除的行)计数 = 0

⇒ 26 行原文一行未删、一行未改,新增 25 行。整份 diff 的删除行全仓只有 1 行:

-  「没挂」无法被本轮以外的任何机制补救。
+  「没挂」无法被本轮以外的任何机制补救。重挂的那一枪按 **notes 3 的定点
+  文本写法纪律**写:……

即原句原文照旧、仅在其后追加从句,不是替换。

step 6 的 45 分钟探针门槛仍在且未被判死门槛取代。 派发后 ~45 分钟无任何远程产出即到探活门槛批量在飞期间,主巡检间隔不得长于 45 分钟 两条均未进入 diff 的删除侧;新增段第一句即 45 分钟是发探针的门槛,⛔ 不是判死的门槛 —— 两者必须分开,并在末尾把两个既有数字的分工写死:45 分钟 = 探活门槛;mode:cloud 的 ~2h = 本轮收集边界;两者都不是判死


4. 基线的出处标注(⛔ 非全车队常数)

写进 step 6 的表带出处、标形态,并在表前一句明写「只是出处样例,⛔ 不是全车队常数 —— 卡片形态不同,区间没有理由相同,driver 或 engine-core 的重活不适用下表」:

出处(车道 / 日期) 卡片形态 实测端到端
domain:spec-surface 席,2026-08-07(#6393) 文本面卡:#5767 / #5622 / #5955 / #5783 93 / 96 / ~95 / ~110 分钟
domain:devx 席,2026-08-07(#6393 认领评论) 混合:#6251 / #6038 / #6405 / #6359 ~67 / ~64 / ~160 / ~170 分钟(后两单含长 CI 等待)

规则句是「基线是你自己车道实测的完工耗时,⛔ 不是本文里的任何常数;没有基线就先建基线再判」。


5. 发布件逐条核实结论(#5451 route B)

skills/objectstack-pm-dispatch/SKILL.md 全文后逐条判定。参照 #6405 的实测结论:发布件没有 lane / seat / domain:* 词汇,pm:* 状态也只定义了一部分 ⇒ 泛化一律写成机制描述,⛔ 不照抄本仓词汇、不引入本仓 issue 号。

hazard 发布件有无同构面 依据(file 内容,非推断) 处置
1(定点文本) step 6 Cloud mode:Arm a check-in (~15 min); on each wake, sweep … then re-arm silently —— 同一个「把文本投进未来」的机制,只是不点工具名 在其后加两条规则(以幂等重读开头 / 只写判据不写结论),含「已取消的定时器仍可能投递」的实测句
2(sanitizer 写侧) 有,且是承重面 step 4 认领评论模板本身由占位符构成(分支名是 race check 与 stale-claim reclaim 的读取键);step 5 又要求 dispatch prompt 里带 report marker;step 0 Repair first 只覆盖读侧截断 在 step 4 认领模板之后加「写后回读」段:实体写法 + 逐片段回读 + 明写这不是 Repair first 的截断形态
3(判死门槛) 有(部分) step 6 Cloud mode 的 silent for over ~2 h (count it as blocked and move on) 是唯一的时间阈值;发布件没有 45 分钟探针门槛 加「静默门槛是收集边界、不是判死」+「先量自己项目的基线」;⛔ 不引入探针门槛这套本仓机器,只用发布件已有的阈值作锚

发布件三条都有同构面 ⇒ 三条都加了泛化版,没有一条是硬塞的role 词计数核对:改后仍为 0(grep -oiE '\brole(s)?\b' | wc -l ⇒ 0),check:role-word 绿。


6. 声明 C —— 三轴决策框架逐字节未变(实测,三重取证)

按内容锚点抽出 4 份拷贝(跨 3 文件),改前改后各抽一次:

拷贝 位置 md5(改前 = 改后) 字节
1 .claude/skills/pm-dispatch/SKILL.md step 8 31b2bb67ea03b2804d32aaae4666cbcc 2181
2 skills/objectstack-pm-dispatch/SKILL.md 自有 frame 段 e35b5f9233d1761371f669f8ff4c6cfe 2896
3 同上,内嵌 dev-agent 模板拷贝 1800b99f4d111762aff5cafbcd729182 1456
4 .claude/agents/os-dev.md 0da1ba478dac2885c662ea2672694726 2048
diff frame-before.md5 frame-after.md5   ⇒ 无输出(EXIT 0)
cmp copy1 … copy4                      ⇒ 四份全部 byte-identical

check:skill-frame-sync 改前改后均 EXIT 0(4 copies … structurally isomorphic across 3 files,3 轴顺序 business-need → long-term-soundness → ai-authoring-safety)。

⚠️ 一处读数需要如实说明,不是回归:check:skill-frame-freshness 的输出行由改前的 3/3 framework files are byte-identical to the ref 变为改后的 1/3。原因是该计数比的是整份文件、不是 frame 段,而本 PR 恰好动了 3 份文件中的 2 份;该 gate 同一次输出里明写 the frame itself is unchanged — that is finewording differences are not drift,EXIT 仍为 0。frame 段本身未变的证据是上表的 cmp/md5,不是这个计数。


7. 与 #6410 的关系 —— 相邻但不合并

#6410(semantic-ruling 模板要带 compiler-face 清单)落在同一个文件step 5 派发词 区域,与本 PR 的四处落点(note 3 / note 12 / step 6 / step 7)无一行重叠;两者评审面不同(前者是语义裁决的派发清单,后者是定时器 / sanitizer / 判死门槛三条运维纪律),本座位按串行派发。⇒ 分开 commit、分开 rationale,不搭车。本 PR 未触碰 step 5 的任何一行。


8. 门禁 EXIT 表(git add 之后运行)

门禁 改前 改后 说明
pnpm check:skill-frame-sync EXIT 0 EXIT 0 4 拷贝跨 3 文件同构,3 轴顺序一致
pnpm check:skill-frame-freshness EXIT 0 EXIT 0 the frame itself is unchanged — that is fine(见第 6 节读数说明)
pnpm check:doc-authoring EXIT 0 EXIT 0 365 files clean
pnpm check:role-word EXIT 0 EXIT 0 44 baselined file(s),发布件 role 计数仍为 0
pnpm check:nul-bytes EXIT 0 EXIT 0 6087 tracked text files,no raw ASCII control bytes
控制字节自扫 grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' 无命中(grep EXIT 1) 两份改动文件逐一扫过
pnpm --filter @objectstack/spec check:skill-docs EXIT 0 动了发布件才跑;✅ Skill docs in sync

9. 本 PR 正文的自证 —— 危险 2 在本 PR 里当场复现(dogfood,实测)

本 PR 正文里所有字面尖括号一律写 HTML 实体。为了给危险 2 留一条当场可复现的证据,下表第二行故意写成裸尖括号、且放在反引号里(正是立单人测过的「反引号不保护」形态)。PR 创建后立刻读回 .body 逐段比对,危险 2 在本 PR 自己的正文里当场复现:

写法 预期 回读 .body 实测结果
HTML 实体 &amp;lt;n&amp;gt; ⇒ 渲染成 &lt;n&gt; 存活 存活 —— 回读里 &amp;lt;n&amp;gt;&lt;n&gt; 两段一字不差
裸尖括号(探针,反引号内):<probe> 被就地删除,留下一对空反引号 被就地删除 —— 回读为一对空反引号,正文其余部分完好无损

三点值得记:

  • 反引号确实不保护 —— 探针就在一对反引号里,照样被整段吃掉;
  • 写侧就地删除而非截断 —— 正文 8600+ 字符一字不少,只是少了那一个片段,note 12 既有的「两者在同一处断掉」判据在这里恒假,与新 bullet 的论断一致;
  • 失效完全静默 —— 创建 PR 的调用返回成功,渲染页看不出缺口,只有把回读的 .body 与写入原文逐段对比才看得见。本 PR 因此是这条 hazard 的第 4 个实测样本(立单人 3 例 + 本例),也是它第一次在跨座位之外被独立复现。

⚠️ 上表第二行的裸尖括号在每次正文写入时都会被重新吃掉,所以渲染页上看到的就是那对空反引号 —— 它是证据本身,不是排版错误。


10. 不在本 PR 里(边界申明)

…r 写侧就地删除、判死门槛 (#6393)

三条 hazard 均为 2026-08-07 实测,跨 domain:spec-surface 与 domain:devx 两个座位:

1. 已删除的 send_later 定时器仍会投递,且文本可能落后现实数轮(三次实测)。
   落点 Operational note 3 新增「定点文本的写法纪律」,step 6 巡检定点与 step 7
   flip 定点各加一条同款约束:文本以「幂等 —— 动手前先重读状态」开头,只描述
   判据(若 X 则 Y),不描述结论(现在去做 Y)。

2. GitHub sanitizer 就地吞掉尖括号片段,反引号不提供保护。落点 Operational
   note 12 —— 原有的「读侧截断」两条一字未改、依旧成立,新增的是同一个
   sanitizer 的第二种失效形态(写侧就地删除),附三例写后回读实测对照表。

3. 45 分钟是探针门槛,不是判死门槛。落点 step 6 —— 探针门槛保留不动,新增判死
   的三类正当依据与「先建基线再判」。两条实测基线带出处写成样例,明确标注
   不是全车队常数(两席九单跨越 ~64 分钟到近 3 小时)。

发布件 skills/objectstack-pm-dispatch/SKILL.md 三条逐条核实后加泛化版(机制描述,
不含 lane/seat/domain:* 词汇):step 6 加「check-in 写成判据」与「静默门槛是收集
边界而非判死」,step 4 加认领评论的写后回读(其占位符正是被吞的形态)。

三轴决策框架 4 份拷贝逐字节未变(diff/cmp/md5 三重取证 + frame-sync 绿)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 7, 2026 10:33pm

Request Review

@github-actions github-actions Bot added the size/m label Aug 7, 2026
@hotlong hotlong added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 7, 2026 — with Claude
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 7, 2026
@hotlong
hotlong marked this pull request as ready for review August 7, 2026 22:51
@hotlong
hotlong added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit 48f98b0 Aug 7, 2026
24 checks passed
@hotlong
hotlong deleted the claude/issue-6393-fleet-wide-hazards branch August 7, 2026 23:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants