diff --git a/.claude/agents/os-dev.md b/.claude/agents/os-dev.md index a62c962550..016caf1896 100644 --- a/.claude/agents/os-dev.md +++ b/.claude/agents/os-dev.md @@ -160,8 +160,7 @@ JSON,所以终报消息就是 JSON 本身,别无其它。 **门禁结果的读法:退出码在任何管道之前捕获,报告里引门禁自己印的判定行。** `EXIT=$?` 跟在 `cmd 2>&1 | tail -40` 之后,读到的是 **`tail` 的**状态:`tail` 基本永不失败,绿门 禁与红门禁读出来都是 `0`(实测:一次 typecheck 印着 `Exit status 2`,旁边的 `EXIT` 行 -写 `0`)。这不是「不可靠」而是**不可证伪** —— 不稳的仪器至少偶尔自相矛盾,而它对两种结 -局返回同一个值,重跑多少次都翻不出来,却在报告里读作一次测量。三种安全写法任选:先重定 +写 `0`)。这不只是不可靠,是**不可证伪**:对两种结局返回同一个值,重跑也翻不出来,却在报告里读作一次测量。三种安全写法任选:先重定 向再捕获(`cmd > /tmp/out 2>&1; EXIT=$?; tail -40 /tmp/out`)·`set -o pipefail`· `${PIPESTATUS[0]}`。另一半在报告侧:**引用某个门禁结果时,点名它自己印出的判定行**,永 不引裸 `$?` —— 判定行由门禁写,`$?` 由你的管道写。⛔ 别等机械强制:陷阱在 agent 的 @@ -242,10 +241,9 @@ dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分 消融、以及每个**还原腿**,用 `--absent`)。⛔ 还原腿最常被跳过 —— 留在 `dist/` 里的 marker 会让变异代码对该树之后的每次运行继续生效,后面的测量量的是错的树。 ⛔ **落盘那一步的证据永远不是编辑工具的退出码** —— `sed`、`perl -i`、`str.replace`、 - `re.sub` 零命中时照样 exit 0,于是未改动的文件配上健康输出,读作一次成功的消融(实测同 - 一下午两起:一次 `str.replace` 锚点没中,自测照报 `51 case(s) passed` 而夹具根本不在; - 一次 `perl -0pi` 零命中,靠另跑的一步 `git diff --stat` 才逮到)。这一步无条件成立,没 - 有 build/dist 的消融同样要做 —— 两起都落在那儿。观察要**锚定你打算改的那处文本**:注 + `re.sub` 零命中时照样 exit 0,于是未改动的文件配上健康输出,读作一次成功的消融(实测 + 同一下午两起:锚点没中/零命中,自测照报全数通过,只有另跑的 `git diff --stat` 逮到)。 + 这一步无条件成立,没有 build/dist 的消融同样要做 —— 两起都落在那儿。观察要**锚定你打算改的那处文本**:注 入文本与被删文本各 `grep -c` 一次;裸 `git diff --stat` 非空或字节数变化只证明*有*改动 —— 同轮的其它编辑会替它变绿,等长替换的字节差本就是零。确认没过 ⇒ **这次消融没跑**, 读数作废:改锚点重来,并在报告里说明第一次是空操作 —— 悄悄重跑到有东西落地,是把同一 @@ -268,7 +266,9 @@ dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分 `resolve/resolves/resolved` + `#`,并无视前面的任何否定。让关单关键词远离其它卡 号;写 `# is not addressed here`、`out of scope: #` 或 `# remains open`。PR 正文与 commit message 是**分开**解析的两个源 —— commit message 干净不能证明正文干净。 - 标题与散文用**英文**(维护者 2026-08-08 裁决,见 AGENTS.md;引用的中文裁决保持原文不 + **会 squash 的分支,卡片关系在 PR 正文声明一次**,分支内各 commit ⛔ 不带卡片关系 + trailer —— squash 把全部 commit message 连成一条落地,首 commit `Fixes` + 后续 + `Part of` 逐条诚实,拼成的一条自相矛盾。标题与散文用**英文**(维护者 2026-08-08 裁决,见 AGENTS.md;引用的中文裁决保持原文不 译 —— 改写引文就是改写裁决)。正文以 **session-URL** 形式的署名页脚收尾(见「字节与 sanitizer 纪律」)。 - **触 `skills/**`(对外发布的技能包)的 diff:PR 正文报两个读数,并默认拒绝「小功能大扩 diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index f26fa4ea7e..27e89c24c1 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -77,6 +77,7 @@ session 的 `Claim:` 评论(拼写见「认领」,车道盘点已取)—— 标 | `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:blocking` | 有 open 下游依赖者(分诊 sweep 自 `Blocked-by:` 索引推导的缓存,⛔ 不手工挂);进选择优先级全序 | | `pm:retriage` | 等分诊改判(维护者 2026-08-19/20 裁定:「同意 并存」)—— 与现行 `pm:*` 标签**并存,⛔ 不摘原标**:原定级在改判前仍是权威,并存让「排队但有异议」在列表上可见;挂标者 = 提出异议的席位,挂标与**异议评论同笔**(证据 + 建议定级),无证据评论的裸挂标不合法;摘标者 = 分诊 Routine,每 fire 高优先重判、重判后摘标 —— 挂/摘分属两方、各自的转换不相交,这是本行的安全性;带本标签的 `pm:queue` 卡**跳过派发**(异议未决不派,即可派发行的除外项);标签须五仓存在(分诊五仓统一职责,首次应用时创建);老化兜底归半状态巡查(年龄谓词随巡查另行落地) | | `finding` | 观察类记录,恒 = **待首次定级**(定级即离标:晋级换 `pm:queue` / 关闭 / hold 换 `pm:on-hold`;裸标签数即健康读数)—— 不占队列不进收件箱 | @@ -160,7 +161,7 @@ session 的 `Claim:` 评论(拼写见「认领」,车道盘点已取)—— 标 4. **纵向拆分:一个分诊 PM + N 个执行 PM,一人一车道双射**(维护者 2026-08-05 拍板;2026-08-16 裁 定分诊统一收归一座)。分诊座位**五仓唯一**(仓单即多仓协调首段的五仓):全部 backlog 的分诊/ 定级/路由/type 由它一座生产,只扫/分类/打标签/拆分/查重/转仓,⛔ 永不认领、永不派发、永不写代 - 码。执行座位信任标签、只在本车道认领,误标**不自行改**、留言上报;姊妹仓 `repo:*` 座位收窄为** + 码。执行座位信任标签、只在本车道认领,误标**不自行改**、挂 `pm:retriage` + 异议评论同笔;姊妹仓 `repo:*` 座位收窄为** 执行座位**(在本仓认领/派发/复核/落地,同一套执行座位纪律,⛔ 不产 `domain:*`/type/定级;skills 车道 finding 自分诊例外照旧)。**拆分触发条件预登记**:单轮时长逼近 fire 周期,或某仓在优先级 全序下持续断粮 ⇒ 按仓拆回多席 —— 扩容是记录在案的出口,不是重设计。⛔ 借调已删除:突发积压调 @@ -503,11 +504,11 @@ issue 上(不能合 ≠ 不复核;技能面 PR 的复核席须跑在契约复审 draft PR 上 **request review `os-zhuang`**(维护者 2026-08-19:「还是应该在 pr 的审核流程,发给 os-zhuang 审核。我的手机github 应该会收到推送消息吧」;当日实测 draft 可点名审核且推送到达手机, 维护者确认「推送到了」;推送通道仅此一条,同日裁定:「只有需要我审核的pr 推给我。」)—— 「等人 -合」清单从此活在 GitHub 的 Review-requested 队列,合并自动消项;④ 轮次报 +合」清单从此活在 GitHub 的 Review-requested 队列,合并自动消项。**能请审则请审;PR 作者身份即 os-zhuang 的席位,请审必失败**(GitHub 拒绝向 PR 作者请审,author-identity 422)—— 改为把 PR **assign 给 os-zhuang** 替代通知,并在轮次报告点名说明走了 assignee 兜底;④ 轮次报 告单列「awaiting a human merge」(「等人来合」与「被忘了」在 GitHub 上长得一模一样)。混 合 diff 一条命中就分叉,⛔ 不按比例判;要拆就让 dev 单独开 PR;已入队才读到本条 ⇒ 撤回只有 转 draft。路径面干净的才转 ready → 入队(队列是唯一被认可的落地路径,⛔ 永不队列 -外 `--auto` 合并)。本段只适用本循环派发的 dev PR;PM 自己的工具 PR 留维护者。 +外 `--auto` 合并)。**入队资格 = PR 上每一个 check 全绿,⛔ 不是 required 子集** —— required 集是队列强制的地板,不是 PM 放行的门槛;非必查门的红要么是真缺陷要么是坏门,两者都归 PM 入队前处置(实测:一张 required 全绿、非必查类型门与一个测试分片红着的 PR 经队列落地,该仓 main 红了约一小时,逐 PR 连环红到 fix-forward 才止)。本段只适用本循环派发的 dev PR;PM 自己的工具 PR 留维护者。 **入队与落地(细则见 `references/landing-operations.md`,落地窗口查阅)。** 原则: @@ -553,9 +554,8 @@ os-zhuang 审核。我的手机github 应该会收到推送消息吧」;当日 停:队列空或 `rounds` 用尽(**仅一次性调用适用**);一轮 ≥ 半数派发失败或升级(系统性问题,继续 烧 backlog 是浪费);维护者打断。**常设座位队列清空 ≠ 退场**,是切换待命姿态:巡检放宽 60–70 分 -钟(有在飞收紧回 ≤45),待命五项 —— findings 配合(附证据/前提重验,⛔ 不定级不改标)、`pm:blocked`/`pm:on-hold` 解锁扫描(含回 -队前 ref 重验与扇出索引更新;hold 侧读 `Restart-when:`)、在飞/已入队 PR 跟到 MERGED、决策箱仅在报告中列出 ⛔ 不 nag、跨 -车道备忘跟进。退场只有两个入口:维护者交接令(走交接收尾清单),或被惰性回收。 +钟(有在飞收紧回 ≤45),待命五项(各项纪律以其主节为准,⛔ 此处不另抄)—— findings 配合、`pm:blocked`/`pm:on-hold` +解锁扫描、在飞/已入队 PR 跟到 MERGED、决策箱仅在报告中列出 ⛔ 不 nag、跨车道备忘跟进。退场只有两个入口:维护者交接令(走交接收尾清单),或被惰性回收。 ## 断粮与跨墙恢复(5 小时用量墙) @@ -641,7 +641,7 @@ grep `),复升级时逐条**跑**一遍,零命中/变形的就地改写 与其置信门重合,不得更宽);**永不派发 assignee 是别人的 issue;永不派发带 `needs-user-decision` 的 issue**。 - 每个 dev agent 都在**每仓专属的自有 worktree** 里干活(hook 强制;os-dev 定义重申);并行度 以 `batch` 封顶,同批**按构造文件面不相交**;**分诊座位永不认领、永不派发、永不写代码;执行 - 座位只在自己那一个车道认领、不改标签只上报误标;`domain:*` 只有一个生产者**(豁免、例外两条与全部条件见「多仓协调 4」「域车道」「候选与批次」,⛔ 不另抄第二份)。 + 座位只在自己那一个车道认领、不改标签,误标挂 `pm:retriage` + 异议评论同笔;`domain:*` 只有一个生产者**(豁免、例外两条与全部条件见「多仓协调 4」「域车道」「候选与批次」,⛔ 不另抄第二份)。 ## 报告契约(Report contract,os-dev 返回什么) diff --git a/.claude/skills/pm-dispatch/references/review-checklist.md b/.claude/skills/pm-dispatch/references/review-checklist.md index 7d69fc1bdd..3c9eae341d 100644 --- a/.claude/skills/pm-dispatch/references/review-checklist.md +++ b/.claude/skills/pm-dispatch/references/review-checklist.md @@ -35,7 +35,7 @@ - **CI 收敛读数只属于复核侧**(维护者 2026-08-10 裁定;dev 的契约是草稿 PR 时点交 报,报告里 gate `in_progress` 是诚实读数、预期内常态):翻 ready / 挂 auto-merge / 入队前亲核 Lint & Repo Gates 与 TypeScript Type Check 两个 job 的 `conclusion` 已为 - `success`(门禁族跑在其内),⛔ 不因报告写了「本地绿」跳过。收敛期转红走补丁轮 + `success`(门禁族跑在其内),⛔ 不因报告写了「本地绿」跳过;两 job 只是 required 地板,入队资格另要求 PR 全部 check 全绿(主文件条款),各仓真绿跑法与 CI 日志看不见的门禁见 `true-green.md`。收敛期转红走补丁轮 (SendMessage 续派原 dev —— 那是这笔交换已付过的价钱,不是 REWORK 的理由;红着 合并才是)。重量级卡可在派发令显式写「本单等 CI」。 - **每个门禁读数先钉到 PR 的当前 head**:先读 PR 的 `head.sha`,再比对 run 的 diff --git a/.claude/skills/pm-dispatch/references/true-green.md b/.claude/skills/pm-dispatch/references/true-green.md new file mode 100644 index 0000000000..97271c915c --- /dev/null +++ b/.claude/skills/pm-dispatch/references/true-green.md @@ -0,0 +1,32 @@ +# 各仓「真绿」跑法索引(references —— 按需加载) + +出处:主文件「复核 / 入队与落地」的入队资格条款(全 check 绿,非 required 子集)。 +每仓一节:正典测试跑法、CI 日志 grep 看不见的门禁、本地 preflight —— 一行一事实。 +与编译面清单同一维护纪律:**这张表由 PR 维护**,踩到新形态的那个 PR 顺手改这里; +⛔ 不引用 issue 编号。 + +## objectstack(后端主仓) + +- 重活(build/test)一律走共享验证锁入口 `bash scripts/pm/os-verify-lock.sh -c ''` + —— 结论读它印的 VERDICT 行,⛔ 不读裸 `$?`(排队语义与预算见 os-dev 定义)。 +- 门禁族派生:`node scripts/pm/dispatch-gates.mjs` **不传路径**,脚本自己从 merge-base + 取变更集;⛔ 不自己 `git diff` 喂清单 —— 两点差按此刻的 `origin/main` 求值,姊妹 + PR 的文件会被算进来,而退出码照样 0。 +- 该脚本只住本仓,答案只关于它所在的树:喂姊妹仓路径得到的是**本仓**的门禁族 —— + 形态完整、退出码 0、全错;`--repo /` 申报归属可机械拒错。 + +## objectui(前端) + +- 正典跑法:**仅仓根 `pnpm test`**。vitest 守卫拒绝 package 目录内的运行 —— 那种跑法 + 曾假绿(无关 console 文件通过、目标用例 0 个在跑,被计为通过);守卫的拒绝是保护, + ⛔ 不绕。 +- typecheck 脚本拼作 `type-check`(连字符);拼错脚本名的 `pnpm --filter` 匹配零脚本、 + **退出码 0**、静默假绿 —— 核对输出确实回显了脚本名再信绿。 + +## cloud + +- 本地 preflight:`preflight-workspace-dist`(workspace 依赖的 dist 新鲜度守卫)—— + 按其自身输出的提示跑,先建再测。 +- 严格区 `check-test-typecheck` 的失败**不以 `error TS` 行出现在 CI 日志**:turbo 汇总 + 只写 `#typecheck` failed —— 要看到台账消息必须本地跑该包自己的 `typecheck` 脚本; + 对 CI 日志 grep `error TS` 的阴性读数在这一族上不成立。