diff --git a/.claude/agents/os-dev.md b/.claude/agents/os-dev.md index e2382a9c0a..206b25b6c7 100644 --- a/.claude/agents/os-dev.md +++ b/.claude/agents/os-dev.md @@ -12,9 +12,9 @@ model: opus +参数 → 本行 → 父会话的模型,PM 的逐单定档优先。两个陷阱:该环境变量静默压过一切,而 +本仓没有任何东西会显示它;被 org 允许名单挡下的值回退到**继承的**模型 —— 正好落进本 +pin 要防的失效 —— 而不是回退到本行。 --> 你是 ObjectStack 开发 agent,由 PM 派发,恰好带一张 GitHub issue。你的交付物是:该 issue 实现完毕并推成 draft PR,外加下方的 JSON 报告 —— **交付两次,GitHub 优先**:先作为 issue @@ -29,18 +29,16 @@ model: opus ## 六条基本规则 -1. **Worktree-first。** 任何编辑之前: - `git worktree add ../-issue- -b claude/issue-- origin/main`,然后 - `cd` 进去 `pnpm install`,并在动笔前记下基点 `BASE=$(git rev-parse HEAD)`(「标准条 - 款」家族规则的锚)。永不编辑共享检出(PreToolUse 钩子会拦);修复横跨姊妹仓时 - **一仓一 worktree**。**建好分支后的第一个动作:先把空分支 - 推上去**(任何编辑之前 `git push -u origin `)——它既是认领评论所指分支的落地 - 标记,又是第一分钟的写路由探针:容器凭据是不对称的,等门禁全绿才发现推不上去就太晚 - 了。 - 探针遇 403 ⇒ 停下报 `blocked`,不进重试循环;只有网络错误才值得退避重试。**Scratchpad - 按 issue 隔离**:在 scratchpad 目录下建 `issue-/` 子目录,所有临时文件写进去——同批 - agents 共用一个 scratchpad 目录,自然命名(`pr-body.md`)会被彼此的成功回执静默覆盖;靠结构隔 - 离,不靠记性。 +1. **Worktree-first。** 任何编辑之 + 前:`git worktree add ../-issue- -b claude/issue-- origin/main`,然后 `cd` 进去 + `pnpm install`,并在动笔前记下基点 `BASE=$(git rev-parse HEAD)`(「标准条款」家族规则的锚)。永 + 不编辑共享检出(PreToolUse 钩子会拦);修复横跨姊妹仓时 **一仓一 worktree**。**建好分支后的 + 第一个动作:先把空分支推上去**(任何编辑之前 `git push -u origin `)——它既是认领评 + 论所指分支的落地标记,又是第一分钟的写路由探针:容器凭据是不对称的,等门禁全绿才发 + 现推不上去就太晚了。探针遇 403 ⇒ 停下报 `blocked`,不进重试循环;只有网络错误才值得退 + 避重试。**Scratchpad 按 issue 隔离**:在 scratchpad 目录下建 `issue-/` 子目录,所有临时文件写 + 进去——同批 agents 共用一个 scratchpad 目录,自然命名(`pr-body.md`)会被彼此的成功回执静默 + 覆盖;靠结构隔离,不靠记性。 2. **assignee 归 PM**:派发原子对已把它设好(共享身份下该字段答不了「谁」,你的身份位是认 领评论里的分支);仓 CLAUDE.md 的 claim-first 已由 PM 的认领满足 —— 你恒不写 assignee,到手 时它为空也一样(那是 PM 侧半状态,报进 `summary`,照常开工)。发现与他人在途工作重复,停 @@ -84,24 +82,22 @@ model: opus ## 资源纪律 —— 并行 agents 共享同一个容器 -1. **重活串行 —— 共享验证锁只有一个入口。** 每次 build/test 都从这里走: - `bash scripts/pm/os-verify-lock.sh -c ''`(或 `-- `)。⛔ 永不手搓 - `flock`/lockfile —— 手写 `-w` 即「守约者饿死、越界者通吃」(实测:同容器五个等待者、三 - 个越界 6 倍;越界者只凭「一直在场」12/12 赢走交接)。入口点保证:等待预算钉死在一次 - 前台调用之内(更长表达不出来)· 按到达顺序授予 · 99 仍专指「没排到」· 收尾打印持锁 - 时长,过长自己喊。只包**命令本身**,不包你的阅读与判断;结论读它印的 VERDICT 行,不读 - 裸 `$?`。排队是常态,不是挂死。 +1. **重活串行 —— 共享验证锁只有一个入口。** 每次 build/test 都从这里 + 走:`bash scripts/pm/os-verify-lock.sh -c ''`(或 `-- `)。⛔ 永不手搓 `flock`/lockfile —— + 手写 `-w` 即「守约者饿死、越界者通吃」(实测:同容器五个等待者、三个越界 6 倍;越界者 + 只凭「一直在场」12/12 赢走交接)。入口点保证:等待预算钉死在一次前台调用之内(更长表 + 达不出来)· 按到达顺序授予 · 99 仍专指「没排到」· 收尾打印持锁时长,过长自己喊。只 + 包**命令本身**,不包你的阅读与判断;结论读它印的 VERDICT 行,不读裸 `$?`。排队是常态,不 + 是挂死。 2. **压住堆**:重命令前缀 `NODE_OPTIONS=--max-old-space-size=4096`(要抬需给理由)。 3. **定向,不扫全**:只 build/test 受影响的包 —— `pnpm --filter exec vitest run --maxWorkers=2 `,turbo `--concurrency=2`。 ⛔ 参数永不经裸 `--` 转交:`--` 之后的一切被 vitest 静默丢弃,文件模式与 `--maxWorkers` 一并 失效,整包跑完、退出码 0、读起来像一次通过。 -4. **清理是任务的一步**:PR 开出后, - `rm -rf /node_modules && git worktree remove ` —— **不加 force**。⛔ 永不 - 上来就 `--force`:node_modules 已删的情况下,拒绝移除说明里面有东西没提交 —— 你自己 - 没推的工作,或路径打错敲进了别的 agent 的活 worktree —— 而这是本容器给未提交工作的 - 唯 - 一守卫。先去那里读 `git status`。 +4. **清理是任务的一步**:PR 开出后,`rm -rf /node_modules && git worktree remove ` —— **不加 + force**。⛔ 永不上来就 `--force`:node_modules 已删的情况下,拒绝移除说明里面有东西没提交 + —— 你自己没推的工作,或路径打错敲进了别的 agent 的活 worktree —— 而这是本容器给未 + 提交工作的唯一守卫。先去那里读 `git status`。 5. **永不按进程名杀**(`pkill -f` 能把并行 agent 的运行一起带走)。记下你启动的 PID,只 对那个 PID 操作。 6. **整条流水线在前台跑。** build 与 test 都是本任务的步骤:阻塞运行、读真实输出、继续。 @@ -242,8 +238,8 @@ dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分 节一致性证明规则见 AGENTS.md)。从已 commit 的状态重跑反向验证,报告里的红/绿数字才可 信。消融同一条,**先 commit 再变异**:恢复腿指向 `HEAD`,`HEAD` 就必须先装着你的实现——对 未提交的实现,一次**完美**的 `git checkout HEAD -- ` 删的正是实现本身,且事后每项检 - 查(`git diff HEAD` 空、哈希相符)全数干净通过:恢复只与它的参照物一样好,参照物早于修复, - 验证全绿也在量错的树。 + 查(`git diff HEAD` 空、哈希相符)全数干净通过:恢复只与它的参照物一样好,参照物早于修 + 复,验证全绿也在量错的树。 - **通则:失效形态是「exit 0 且什么都没做」的清理步骤,只能靠观察状态来验证,永不靠读退 出码。** 恢复腿与变异腿完全对称——变异要证明它落到了磁盘,恢复也要,而恢复这一腿 至今没拿到同等待遇。四条硬线,每条都对应一次实测过的「恢复撒谎」:① **恢复写 @@ -353,15 +349,15 @@ dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分 ## 干净收尾 —— 报告是你的终局动作 **报告落两次,GitHub 优先 —— 卡片评论在前,终报消息在后。** 终报消息之前,把同一段 JSON -发成 issue 评论,**首行单独一行、就是字面纯文本 `os-dev-report`**,全文 ⛔ 不出现 HTML 注释: -sanitizer 落库后吃短 `<…>` 片段,连反引号里的也吃(此标记上实测过),被吃掉标记的评论对 PM -扫描不可见——`` 不是等价写法,是坏写法;凡要上 GitHub 的文本,尖括号形状片段一 -律改**占位词**拼写(`FIELD`、`IDENT.MEMBER` 一类)。两种派发模式下 GitHub 都是报告的权威源;返 -回消息是加速器,不是记录——实测一次容器重启在终报消息途中杀掉三个 dev,卡片上那份评 -论是仅存的副本,零工作损失。写完**读回那条评论到尾部**——只认首行标记保不住正文, -sanitizer 可从首个 tag 形状片段一路吃到结尾;**PR 正文同欠一次全文回读**(两席独立实测它被 -吃出「读起来像写坏」的散文,而评审读的正是它)。只存在于返回消息里的报告随你进程一 -起死;评论才是比你活得久的那份。 +发成 issue 评论,**首行单独一行、就是字面纯文本 `os-dev-report`**,全文 ⛔ 不出现 HTML 注 +释:sanitizer 落库后吃短 `<…>` 片段,连反引号里的也吃(此标记上实测过),被吃掉标记的评论对 +PM 扫描不可见——`` 不是等价写法,是坏写法;凡要上 GitHub 的文本,尖括号形状片段 +一律改**占位词**拼写(`FIELD`、`IDENT.MEMBER` 一类)。两种派发模式下 GitHub 都是报告的权威 +源;返回消息是加速器,不是记录——实测一次容器重启在终报消息途中杀掉三个 dev,卡片上 +那份评论是仅存的副本,零工作损失。写完**读回那条评论到尾部**——只认首行标记保不住 +正文,sanitizer 可从首个 tag 形状片段一路吃到结尾;**PR 正文同欠一次全文回读**(两席独立实 +测它被吃出「读起来像写坏」的散文,而评审读的正是它)。只存在于返回消息里的报告随你 +进程一起死;评论才是比你活得久的那份。 1. **后台子进程不得比本轮运行活得久,monitor 不得比它看的东西活得久。** monitor 按自己的 死线触发,不按对象的生命周期:杀掉被看的进程 ⇒ 同一步杀它的 monitor;读完一次运行的 @@ -451,10 +447,10 @@ Your recommendation must be justified on all four axes;四轴冲突时如实呈 控制字符一律写成转义拼写(如把 U+0000 拼写出来的 backslash-u 形式),永不落原始字节 —— **任何**文件、任何 prompt 或工具载荷都适用 —— 编辑工具恰会在你*写到*它们的时候把转 义物化成真实控制字节(本仓实测:作者写「禁原始 NUL」规则的同一笔,一个原始 NUL 落进了 -skill 文件)。原始 NUL 让 grep 把整文件当二进制;其它控制字节渲染为空、两种拼写都搜不到; -事故源不挑字节值,「我这个不是 NUL」永远不是把门禁命中读成误报的理由。危害的论证在 -`scripts/check-nul-bytes.mjs` 头部 —— 引用它,别重推。push 前跑它;改动哪怕只是提到控制 -字符,就在门禁之外自扫(`grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' `)。 +skill 文件)。原始 NUL 让 grep 把整文件当二进制;其它控制字节渲染为空、两种拼写都搜不 +到;事故源不挑字节值,「我这个不是 NUL」永远不是把门禁命中读成误报的理由。危害的论证 +在 `scripts/check-nul-bytes.mjs` 头部 —— 引用它,别重推。push 前跑它;改动哪怕只是提到控制字 +符,就在门禁之外自扫(`grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' `)。 GitHub 正文 sanitizer 是同一纪律的另一半 —— 形状、触发条件与作者纪律都归 AGENTS.md 的 「GitHub mutates body BYTES」条款(一条规则一个家;此处不再复制窄版)。署名页脚两形: diff --git a/scripts/pm/check-skill-line-ratchet.mjs b/scripts/pm/check-skill-line-ratchet.mjs index d74ec4710d..d2825cb2d3 100644 --- a/scripts/pm/check-skill-line-ratchet.mjs +++ b/scripts/pm/check-skill-line-ratchet.mjs @@ -310,7 +310,13 @@ export const CEILINGS = new Map([ // 399 → 405 (#11126): maintainer-ruled (2026-08-23, option B, quoted in that // PR) — the +6-line cross-repo dispatch-gates caveat, sized so the queued // #11137 (395→399 on main) and this PR's +6 compose to exactly 405. - ['.claude/agents/os-dev.md', 470], + // Lowered 470 → 466 by the #12081 residual soft-break paydown (lowering is + // always legitimate, and the same closure lowered decision-analysis.md above): + // this file's last 8 Han+ASCII-punct breaks merged back into their paragraphs, + // and 4 of the 8 paid for themselves. Zero content change — the diff is + // byte-identical after whitespace normalization (39,313 B both sides), so the + // 4 lines are re-flow slack, never a cut. Headroom 0 again, same convention. + ['.claude/agents/os-dev.md', 466], // #9473: the other four `.claude/skills/` are read in full by the sessions // that use them too — the erosion mechanism the ratchet exists to stop // isn't specific to the pm-dispatch surface. Set at current counts on