docs(pm-dispatch): 增补 2026-08-03 全天运行沉淀的八条 PM 操作经验 (#4882) - #4885
Merged
Conversation
按落点融入既有结构,纯插入不重写: - step 2 分诊:「无生产者」形状(声明了、消费端有读取、gate 全绿,却无人写值) - step 3 选批:同文件跨轮串行,推迟时把已知的坑当场钉到 issue 上 - step 5 派发:同日 main 变更写进派发词;新增 worktree 接手协议(宿主中断的 dev 不可恢复但 worktree 完好) - step 7 复核:dev 证伪前提是好报告的标志;`+0/-0` 先怀疑 NUL 字节 - 新增 Operational notes(实测坑位):gh-readonly-queue 判入队、队列踢出先认签名、 GraphQL 配额与 rate_limit 轮询、核验 main 一律用 origin/main Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015Br2xsJsczFsTR9bvbh2Ny
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
os-zhuang
marked this pull request as ready for review
August 3, 2026 13:17
This was referenced Aug 3, 2026
This was referenced Aug 3, 2026
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Aug 4, 2026
…) (objectstack-ai#4893) 2026-08-03 的 v17 协议变更派发里,有四类已经付出过代价的经验,现行 skill 里 没有或只写了半截。同日另一车道的 objectstack-ai#4885 已沉淀八条,本单只补它覆盖边界之外的。 pm-dispatch —— Operational notes 由四条扩到八条: - 5:rerun_failed_jobs 复用原 run 的提交/合并 ref,不重算。红的原因若是「基上 缺一个已合并的修复」,重跑无效,只有推新提交才拿得到新的合并 ref(objectstack-ai#4852 因此 在队列外空转 100 分钟)。与 rerun-safety-nightly.yml 无关,后者查的是测试污染。 - 6:读数纪律。cd X && cmd 短路会在错的仓里执行(跨仓一律 git -C); git grep -c | wc -l 数的是文件数不是命中数;裸名 grep 会被幸存家族当子串命中, 退役核验要带引号精确名、更硬的判据是查声明式而非提及。零命中必须用确定存在的 邻近词反查。 - 7:CI 红了先取完整日志归档。completeness check 绿只说明没有 worker 静默死掉; turbo 并发输出相邻不等于因果(test 的 dependsOn 只有 ^build,spec 无 pretest); 不要只看 tail。据错误结论开的 PR 要撤回 draft 并解绑 Fixes。 - 8:共享基础设施类修复按症状复查 main。duplicate-fix-guard.yml 只覆盖「同仓 + 同一个 Fixes #N」,objectstack-ai#4864 与 objectstack-ai#4856 挂在不同 issue 号下,门禁看不到,而后者先合的 60s 会被前者降回 30s。 另在 note 1 上补:「不在 main 上」是二义读数(兼容「排队中」与「没入队」);队列 分支 base sha 串成链,可读出排第几;转 draft 会同时掉 auto-merge 与队列成员资格。 step 7 之后新增「入队与落地」小节:merge=os-regen 的七条路径(含两条文档产物)、 四步同步协议、以及跟到 MERGED 而不是跟到入队为止。 spec-property-retirement: - 新增「四张 ratchet 的可见性按路线相反」—— 枚举值收窄不可见(objectstack-ai#4391),整 def 删除必须变化(objectstack-ai#4834:-12/-23/-5);拿错对照会双向判错。 - 修好第 2 节指向 plugin-runtime.zod.ts:243-248 的先例引用,该文件已被 objectstack-ai#4878 整体删除。 Fixes objectstack-ai#4892 Claude-Session: https://claude.ai/code/session_0176qgxgCXTJCUv4YFLtusP9 Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Aug 4, 2026
…bjectstack-ai#4907) 这道门禁自己的报错文案写着它拦的是什么:一个裸 NUL 让 grep/ripgrep 把整个 文件当成二进制、静默返回零匹配。那是 grep 的行为,与文件是什么语言无关 —— 但扫描面此前是一份 JS/TS 扩展名清单,范围(用途)与理由(载体)对不上。 代价是 .claude/ 下的全部 markdown 同时落在三道门禁之外。objectstack-ai#4890 就是这么暴露 的:PR objectstack-ai#4885 要写的规则正是「不要写裸 NUL」,而写的过程中一个真的裸 NUL 落进 了 .claude/skills/pm-dispatch/SKILL.md,这道门禁报 OK。 改为扫描所有被 git 跟踪的文本文件。二进制判据是内容判断而非扩展名清单: 非常规文件(symlink / gitlink)跳过;UTF-16/32 BOM 开头跳过(那种编码里 NUL 是结构性的);其余先剔除 NUL 字节、再整文件按 UTF-8 严格解码,解不通才算 二进制。先剔除 NUL 是为了打破「有 NUL 所以是二进制所以不查 NUL」这个 git 掉 进去的循环;整文件解码而非只看前缀,是因为 git 只嗅前 8000 字节正是本文案里 记着的盲区。 同时按仓内惯例把 --self-test 接进 check:nul-bytes 脚本,自检在临时 git 仓库 里跑真实的 scan() 路径。 Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4882
把 2026-08-03 主 backlog PM 会话跑完 12 单合并 + 8 单新立后沉淀的八条操作经验写进
.claude/skills/pm-dispatch/SKILL.md,让下一个 PM 会话不用重新踩。纯插入,不重写既有章节:git diff --stat为134 insertions(+),既有行删除数为 0。落点与内容
step 2 分诊 — 新增「无生产者」形状的识别规则:声明了、消费端有读取、gate 全绿,却没有任何生产者写值;类型系统与 lint 只验消费方,所以这类洞在全绿下长期存活。当日五次命中(#4704 / #4837 / #4839 / #4862 / #4867)。遇到 declared ≠ enforced 类 issue,分诊时先问「生产者在哪」,答案通常就是根因,并会在派发前改掉 issue 的作用域与
domain:*标签。step 3 选批 — 同文件 issue 严格跨轮串行,并明确推迟 ≠ 搁置:#4820 的 dev 查出 #4821 正文建议的
JSON.stringify键法会改掉类型强制语义、引入静默新缺陷,这条警告与Blocked-by:在 #4820 复核完成的同一轮就钉到了 #4821 上 —— 被推迟的 issue 在每次 sweep(包括别的 PM 的)里看起来都是可派发的,你知道的坑不写上去就等于不存在。step 5 派发 — 两条:
phoneOtp.cooldownSeconds配成大于 1 小时会被静默截断 —— OtpSendGuard 的历史 TTL 硬编码 1 小时 #4808 派发前 fix(plugin-auth): 每号码 OTP 发送预算改用惰性解析的共享计数存储 —— 多节点下不再按节点数倍增 (#4790) #4806 刚改过同一 guard,compareTo drops every measure-scoped filter, so<measure>__comparesilently reports a different measure than the column beside it #4820 派发前 fix(service-analytics): 按聚合种类填充「查询从未报告过的分组」,并补上 compareTo 这一道接缝 (#4708) #4822 刚改过同一文件,两单都因派发词点名而避开返工。#### Handing off an interrupted dev(worktree 接手协议):/compact与宿主中断会把运行中的子 agent 连同挂起的工具调用一并杀死(@objectstack/verify的 bootStack 与 qa dogfood 同样用裸 import 解析 cloud 私有包 —— 与 cloud#1013 同一缺陷类 #4700 / hook 的condition求不出值时:全局 fail loud —— 抛错并中断该次操作(方案 B 已拍板;Blocked-by #4770) #4775 停在同一秒),agent 不可恢复但 worktree/分支/提交完好。接手 = 派新 agent + 明确「worktree 已存在,⛔ 不要新建」+ 先通读既有改动再逐块决定取舍 + 补跑从未跑过的验证 + 认领与分支不变。两单按此接手后均一次通过复核。step 7 复核 — 两条:
phoneOtp.cooldownSeconds配成大于 1 小时会被静默截断 —— OtpSendGuard 的历史 TTL 硬编码 1 小时 #4808 / 内核的插件 init/start 超时守卫定时器从不清除也不 unref —— 每个进程在工作结束后还要空转 startupTimeout(CLI 挂 ~120s 才退出) #4813 / [metadata] nextEventSeq() 把驱动读失败也当成「表还没建」,静默从 1 重新发号 —— #4632 同形,机械检查覆盖不到 #4825 / 每号码 OTP 发送预算(#2780)也只在进程内计数 —— 与 #4772 的限流洞同类,多节点下可按节点数倍增 #4790);PM 被纠正时公开认账,错误归因另立 issue(os migrate成功时退出码是随机非零值(208/171/176/163/62…),--version/--help却干净退出 0 #4873)而不是静默丢弃。+0/-0未必是空文件 —— 文件含 NUL 字节时 git 判为二进制。fix(service-analytics): compareTo 带上 measure 自己的 filter,__compare 列不再是另一个 measure (#4820) #4870 的 347 行测试文件即如此,PM 一度误判为占位空文件。判据落在 blob 不落在 diff;修法写转义\\u0000(反斜杠 + u0000),不写裸字节。新增
## Operational notes(实测坑位)(接在 State model 之后,中文,与 Domain lanes 节先例一致) — 四条队列/平台层结论,共同点是「判据取命令输出,不取 API 字段字面值,也不取本地工作树现状」:gh-readonly-queue/*分支,不看auto_merge(入队后该字段回落为 off,零信息量);spec/src/cloud/tenant.test.ts的 #4739 导出面用例贴着 5s 超时 —— 今晚已两次把不相干的 PR 踢出合并队列 #4796 连踢五个无关 PR,原样重投全过);但止血 PR fix(spec): 给 packages/spec 的 vitest 设 testTimeout 60s —— 止血,不再把无关 PR 踢出合并队列 (#4850) #4856 合入后同签名再现即新问题,禁止条件反射式重投;rate_limit的resources.graphql.remaining,复核意见先用 REST 发出不等配额;git grep ... origin/main/git show origin/main:—— 共享检出可能落后数十提交(当日 PM 与一名 dev 都在落后 63 提交的树上 grep 出假阴性),这条同时写进派发词。验收自检
生产者×2、worktree 接手×1、gh-readonly-queue×2、rate_limit×2、origin/main×9、nul×5(不区分大小写)134 insertions(+), 0 deletions,既有行删除数 grep 得 0---/---),不发布任何包 —— 与.changeset/pm-dispatch-domain-lanes.md首 12 字节逐字节一致门禁
node scripts/check-nul-bytes.mjs→check-nul-bytes: OK (2986 tracked source file(s), no raw NUL bytes).值得记一笔:写 C2 那条时编辑工具真的把转义写成了裸 NUL 字节(SKILL.md 第 626 行),先被控制字符扫描(
grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]')抓住、按字节改写为转义文本后才提交 —— 该条经验在自己身上原样复现了一次;本 PR 正文首版的同一处也被 GitHub 吃掉过一次,现已修正。eslint 不覆盖 md(配置仅**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}等 JS/TS glob),check:doc-authoring的 ROOTS 是skills/content,不含.claude/,故无其他适用门禁。改动面严格限于
.claude/skills/pm-dispatch/SKILL.md+ 一个 changeset,未碰.claude/agents/os-dev.md、packages/**、顶层skills/**、content/docs/**。🤖 Generated with Claude Code
https://claude.ai/code/session_015Br2xsJsczFsTR9bvbh2Ny