Uh oh!
There was an error while loading. Please reload this page.
docs(pm-dispatch,os-dev): 假引擎的 delete() 一律路由 assertEngineDeleteDispatch,并收编 run-summary 的盲区实例 (#5197) - #5630
Conversation
…ch,并收编 run-summary 的盲区实例 (#5197) 同一天三个互不相同任务的 dev agent(3/3)新写假引擎全部踩 `check:engine-double-contract` 判红,错误一模一样 —— 手抄守卫、未路由 `assertEngineDeleteDispatch`(#5173、#5191、 #5192),各花一轮 CI 往返 ≈15 分钟;#5584 的新测试是第四次同款命中(#5604)。这不是门禁 漏了,防线工作正常,代价纯粹是「新增测试 + 需要假引擎 + delete 路径」这个高频组合缺一行 提交前的提示。 os-dev 定义与 pm-dispatch 派发词模板各加一行同措辞纪律,把这轮往返省在提交前。两处都点名 手抄守卫**真有洞**这一实测事实,而不只是「风格不推荐」:#5173 的手抄副本放行了 `where: { id: { $in: [...] } }` —— 它看着像 id,是多行谓词,真引擎无 `multi` 时拒收。 引用的样板是「门禁绿跑时自己列出的 pinned 假引擎」而不是一个会过期的计数。 第三处是 `service-automation/src/run-summary.test.ts` 的盲区实例(#5197 评论定位):它的 内联假引擎 `async delete() { return false; }` 对谓词删除照单全收,而 `delete_record` 自 #5393 起转发 `multi: cfg.multi === true`,所以 `{ objectName: 'deal', filter: { stale: true } }` 这一形状真引擎是 reject。该文件既不在 pinned 也不在 DEBT 台账 —— 门禁的形参个数 判据够不到零形参的 delete(另立 #5629 记录该扫描面缺口及实测口径),所以是检测器盲区,不是 已登记的债。后果不是假设:#5225 里 showcase 的清扫流从上线起每次 `acted: 0`,单测全绿。 收编后按「补声明」处置而非重写断言:该 fixture 从来就不是契约内合法的,补 `multi: true` 声明其批量意图,于是 sweep 真的到达驱动,驱动报告匹配 0 行,用例原本的主题(计数器读 0) 完整保留。执行器侧的 reject 传播已由 `builtin/crud-bulk-intent.test.ts:153` 钉住,不在此 重复。 断言同时加强,这一步是实测逼出来的而非顺手:反向验证(假引擎已收编、`multi` 撤掉)预期红, 实际**仍然绿** —— 因为 `acted: 0` 既是「删了 0 行」也是「删除被拒」留下的痕迹,原用例唯一 的断言两种情形都满足,是为空而绿。补 `res.success` 与该节点 `runs: 1 / failures: 0` 之后 同一撤销才真的判红(`expected false to be true`),用例才在读它声称在读的那件事。 Claude-Session: https://claude.ai/code/session_01GX3sL71LFq8m2usg6VqTSE Co-authored-by: Claude <noreply@anthropic.com>
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckNo hand-written docs reference the 0 changed package(s). ✅ |
os-zhuang
commented
Aug 5, 2026
门禁口径追记 —— 正文里的「改动后仍是 1 problem」是在分支切点 把本分支与当前 即 25(切点上含本 PR 的 +1)+ 2(#5615 收编的两个)= 27 pinned;台账 34 → 32 是 #5615 顺带对账掉的两条,不是本 PR 动的(本 PR 一个字都没动 同时核过在飞重叠: Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
…objectstack-ai#5579) (objectstack-ai#5642) 该段给出的唯一理由是「One raw control byte makes grep treat the whole file as binary: zero matches, no signal」——而这条只对 NUL 成立。在容器内独立复现(样本用 printf 生成,未粘贴裸字节;GNU grep 3.11 + ripgrep 14.1.0): U+0000 grep: binary file matches rg: binary file matches (found "\0" ...) U+0001 grep: 2:searchable line rg: 2:searchable line U+007F grep: 2:searchable line rg: 2:searchable line 即门禁扫描面里除 NUL 之外的每个字节(含 objectstack-ai#5460 纳入门禁、objectstack-ai#5577 补进自扫字符类的 DEL)都不会让文件被当成二进制。危害只写这一条的后果不是文字不精确:agent 写出一枚 非 NUL 控制字节、自扫命中后去核对指令,会发现唯一被陈述的判据不成立,从而把门禁的红 判成误报。 `scripts/check-nul-bytes.mjs` 脚本头早就把两侧分开论证好了(objectstack-ai#5157 段),本次把散文 口径搬过去对齐: - binary-file / zero-matches 那条点名 NUL,并标明是实测结论; - 其余扫描面字节引脚本头写清的三条:渲染为空(代码对每个读者说谎)、两种拼写互不 命中(文件里是字节,不是你会去搜的转义文本)、事故源不挑字节值; - 补一句直接堵住上述推理:「不是 NUL、grep 还能搜到」永远不构成把门禁红或自扫命中 读成误报的理由; - 危害论证指向脚本头「引用它,不要重新推导」,不在此处再抄一遍论证细节。 顺带修同段两处陈旧: - 「this repo has paid four times」的硬编码计数改为免计数措辞——该族已多于四例, objectstack-ai#5624 刚因同样的漂移把台账里的 sibling 计数改成不含数字的表达; - 「a `0x01` that `check:nul-bytes` does not scan for (objectstack-ai#5157)」的现在时已错:objectstack-ai#5157 正是把该字节纳入扫描面的那一单,改为过去时的事实句。 未做(留档而非顺手扩面):单源化——让字符类与危害论证不再手抄多处——是 objectstack-ai#5484 正文 留下的方向,本 PR 只修散文口径,不动 `scripts/check-nul-bytes.mjs`、不动 objectstack-ai#5577 刚 补的自扫字符类、不动 objectstack-ai#5630 刚加的 Toolchain traps 条目。 纪律:全程未向任何文件写入裸控制字节,散文沿用该文件与脚本头既有的 `0x01`/`0x7f` 十六进制写法(不含反斜杠转义,不会被编辑工具 materialise)。 `node scripts/check-nul-bytes.mjs` 绿;改动文件自扫 `grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'` 无命中;`cat -A` / `od -c` 复核新增 行无意外字节。 `.claude/` 文档-only,无用户可见变更,走 skip-changeset 标签路线。 Fixesobjectstack-ai#5579 Claude-Session: https://claude.ai/code/session_01GX3sL71LFq8m2usg6VqTSE Co-authored-by: Claude <noreply@anthropic.com>
…in 滞后、死代码删除复核 (objectstack-ai#5513) (objectstack-ai#5645) 2026-08-05 跑完一整条 filter 缺陷链(objectstack-ai#5363 / objectstack-ai#5366 / objectstack-ai#5368 / objectstack-ai#5375 / objectstack-ai#5431 / objectstack-ai#5445, cloud#1117)后回看,六处在那一轮真实咬过人或真实救过场的规程,SKILL 里没有对应条目。 六条各落在 issue 指定的节内,**纯增补**:111 行插入、0 行删除,既有条目(objectstack-ai#5501 的接力 模式、objectstack-ai#5522 的座位模型、objectstack-ai#5630 的 assertEngineDeleteDispatch 条款)一字未动。 落点与要点: 1. **Multi-repo,rule 2 之后**「pin 滞后」——`Blocked-by:` 只保证上游已合并,姊妹仓还有 第二个读数:本仓 pin 是否覆盖那个 commit。cloud#1116 的裁决落于 framework objectstack-ai#5368 (`9c5abf4e9`),而 cloud 的 `.objectstack-sha` 未覆盖它,于是 `TursoDriver` 有一个 方向反了的分叉窗口(fail-closed 一侧先到)。规程:派发前核祖先关系;未覆盖则 dev 在 PR 正文留档窗口与方向,⛔ pin bump 不做 rider。 2. **step 3** 末「阻塞解除后重新定价」—— 前一单合入会改变后一单的成本模型,方向不止一个 (本轮变便宜、没变、成本估计过期各有实例)。两个动作配对:派发前一单时带必答项 「你的改动是否让 #X 变简单 / 变难 / 不必要 / 无影响」,派发被延后那单前用该回答重读 其选项与成本估计。 3. **step 5** 派发令「多面组件的测试落点」—— 同一契约 ≥2 实现面时,新用例进共享一致性 覆盖而非独立文件(原话照录)。附 objectstack-ai#5375 / objectstack-ai#5431 / objectstack-ai#5445 三条正交轴共用一条不变量。 4. **step 7 清单**「收益穿过它必经的那道边界之后还在吗」—— 判据是价值主张是否依赖下游 如实转发;实例即 objectstack-ai#5423(4xx 直通曾整条替换 ≥500 字符正文,`code` 到了正文没到)。 5. **step 7 清单**「死代码删除的复核」——「这是死代码」是断言而非能从 diff 读出的事实, PM 在 origin/main 独立核一次引用面再 ACCEPT(查法用 Operational notes 6:notes 6 说 怎么查不假阴性,本条说什么时候必须查)。 6. **step 8** 升级门槛之后「带前提的裁决」—— 分歧关键是可被代码证伪的事实时,第三档 = 裁决 + 前提验证要求 + 「前提不成立报 fork,不许硬做也不许悄悄改选」禁令,三件缺一 不可;缺第 3 条即退化为无人裁决且无读数显示。 实施时两处核实结果与 issue 正文不同,成文按核实后的事实写: - issue 的附带论断「没有任何闸门在量这个 pin 滞后」**不成立** —— cloud 的 `scripts/check-pin-staleness.sh`(test.yml 以 `continue-on-error` 跑)每次 CI 都报两个 pin 各落后 main 多少 commit,advisory 是**有意设计**(`--max-behind` 需显式传)。它答 的是「落后多少」,不是「是否覆盖我这条裁决 commit」;成文因此指向该脚本,并只把后一个 问题留给派发前的祖先判断。据此**未**另立「无闸门」的发现单。 - 第 4 条的 rest-server 缺陷本身已由 objectstack-ai#5423 按「截断而非替换」修掉,成文改用过去时并注明, 以免后来的读者去找一个已不存在的活 bug;该条要补的是**复核清单的缺口**,与代码是否已修 无关。 第 1 / 3 条按 issue「未验证的部分」的克制写入适用判据(前后单共用同一契约或数据表示; 组件对同一契约有 ≥2 实现面),形态迥异的批次(纯 UI、纯文档)明确不强加。 验证:`node scripts/check-nul-bytes.mjs --self-test` + 全仓扫描绿(48 断言 / 5537 文件); 改动文件自扫 `grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'` 零命中,并用邻近词反查证伪 「扫描器坏了」;`check:docs-audit-scope` 绿;markdown 结构核对(强调标记成对、代码围栏 16 个偶数、嵌套围栏缩进对齐)。 Claude-Session: https://claude.ai/code/session_01GX3sL71LFq8m2usg6VqTSE Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: os-zhuang <hr@objectstack.ai>
Fixes#5197
三个落点,前两个是同措辞的一行纪律,第三个是评论里已定位的盲区实例收编。
为什么值得动 agent 定义文件
同一天三个互不相同任务、互不相同包的 dev agent(3/3)新写假引擎全部踩
check:engine-double-contract判红,错误一模一样 —— 手抄守卫、未路由assertEngineDeleteDispatch(#5173、#5191、#5192),各花一轮 CI 往返 ≈15 分钟;#5584 的新测试是第四次同款命中(即当前 main 上的 #5604)。门禁没漏,防线是好的;代价纯粹是「新增测试 + 需要假引擎 + delete 路径」这个高频组合缺一行提交前的提示。两处措辞相互一致,都点名手抄守卫真有洞这一实测事实(而不是「风格不推荐」):#5173 的手抄副本放行了
where: { id: { $in: [...] } }—— 看着像 id,实为多行谓词,真引擎无multi时拒收。样板引用的是「门禁绿跑时自己列出的 pinned 假引擎」,不是一个会过期的计数。.claude/agents/os-dev.md—— 进「Toolchain traps」第 5 条(该列表的定义就是「每条都让至少一个 agent 白跑一轮红」,正好是这件事)。.claude/skills/pm-dispatch/SKILL.md—— 派发词模板的 Non-negotiables 末条。⛔ 模板其余部分未动,pm-dispatch skill 缺六条实测规程:阻塞解除后的重新定价、带前提的裁决、收益是否穿过下游边界、多面组件的测试落点、跨仓 pin 滞后、死代码删除的复核 #5513(同文件六条新规程)是另单。第三处:run-summary.test.ts 的盲区实例
packages/services/service-automation/src/run-summary.test.ts的内联假引擎async delete() { return false; }对谓词删除照单全收。而delete_record自 #5393 起转发multi: cfg.multi === true,所以{ objectName: 'deal', filter: { stale: true } }这一形状真引擎是 reject。该文件既不在 pinned 也不在 DEBT 台账:门禁的形参个数判据(
isEngineDeleteShape要求delete至少两个形参)够不到零形参的delete,所以这是检测器盲区,不是已登记的债。这个扫描面缺口连同实测口径另立 #5629(实测:只放开该判据,发现面从 59 个 double/58 文件涨到 150 个/107 文件),⛔ 本 PR 不修它。后果不是假设 —— #5225 里 showcase 的showcase_inquiry_purge从上线起每次acted: 0,单测却一路绿。收编按补声明处置,不是重写断言:该 fixture 从来就不是契约内合法的,补
multi: true声明其批量意图,于是 sweep 真的到达驱动、驱动报告匹配 0 行,用例原本的主题(计数器读 0)完整保留。执行器侧的 reject 传播已由builtin/crud-bulk-intent.test.ts:153钉住,此处不重复。@objectstack/objectql早已是本包 devDependency(#5393 加的),无需动 package.json,无 turbo 环。反向验证:预期红,实测仍然绿 —— 所以断言也得加强
先说方向,再说结果。预期是「假引擎收编 + 撤掉
multi:true→ 判红」。实测绿:原因是
acted: 0既是「删了 0 行」也是「删除被拒」留下的痕迹 —— 运行失败了,summary 照样记acted: 0,原用例唯一的断言两种情形都满足,是为空而绿(os-dev.md 里 fixture triage 那条「assertion keeps passing because nothing is produced」的活体标本)。所以只收编假引擎对这个用例买不到任何东西,断言必须同时加强。补
res.success与该节点runs: 1 / failures: 0 / acted: 0之后,同一撤销才真的判红:恢复
multi: true后全绿。这一步是实测逼出来的,不是顺手加固。验证
pnpm --filter @objectstack/service-automation test→Test Files 59 passed (59) / Tests 713 passed (713)。pnpm check:engine-double-contract—— 改动前:58 in 57 test file(s) — 24 pinned, 34 in the shrink-only baseline,1 problem;改动后:59 in 58 test file(s) — 25 pinned, 34 in the shrink-only baseline,仍是 1 problem,且仍是同一个main 全仓红:check:engine-double-contract挂在 #5584 刚落地的action-execution-calldata-not-found.test.ts(2 个 double 未接assertEngineDeleteDispatch,基线无条目)——所有新 PR 的 ESLint job 都过不去 #5604 的action-execution-calldata-not-found.test.ts。即本 PR 只让 run-summary.test.ts 进入 pinned 计数(24→25),台账 34 未动 —— 收编是钉接,没有记债。--self-test绿。node scripts/check-nul-bytes.mjs绿;三个改动文件另做了越过门禁扫描面的自扫(含 DEL 与0x01那一类),无控制字节。turbo run typecheck里没有 typecheck 任务([P2] framework: 66 个包用 tsup 构建、无人做类型检查 —— 实测 18 个包共 380 处 code-tier 错误(#4118 的 framework 侧对应) #4311 的面),直跑tsc --noEmit -p有 5 处先存报错,全部落在本 PR 未触碰的engine.test.ts与nested-region-parity.test.ts,run-summary.test.ts零报错。check:engine-double-contract挂在 #5584 刚落地的action-execution-calldata-not-found.test.ts(2 个 double 未接assertEngineDeleteDispatch,基线无条目)——所有新 PR 的 ESLint job 都过不去 #5604 签名(main 既有),非本 PR 引入,不追。变更集
.claude/文档 + 测试-only,无用户可见面 → 走skip-changeset标签路线,未写空 frontmatter changeset。请 PM 落标签。Generated by Claude Code