oh-my-openagent 重命名变更集代码质量审查实录:agent-command-string 审计闸门为何在 1190 个测试中唯一飘红
【免费下载链接】oh-my-openagentOmO: Just type "mass ulw" keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent
导读
本文以 oh-my-openagent(OmO)仓库内 .omo/evidence/20260809-omo-agent-toolkit-rename/F2.md 这份代码质量审查(Code-Quality Review)报告为主线,完整还原一次omo→omo-agent-toolkit重命名变更集从 typecheck、全量测试、仓库法则对照到违规项判定的全过程。你将看到:一个"上线即永久变红"的审计闸门(audit gate)如何因自我匹配(self-scan)而失效,一行代码的修复为何足以让 1190 个测试从 1 红恢复全绿,以及#given/#when/#then测试法则、无行号指纹、allowlist 分类等工程约束在 script/agent-command-string-scan.ts 等源码中的真实落地形态。
1. 审查背景:一次跨 142 个文件的重命名重构
本次审查针对的是omo-agent-toolkit重命名变更集,其元数据如下:
- Worktree:
.local-ignore/worktrees/omo-agent-toolkit-rename(分支feat/omo-agent-toolkit-rename,基于origin/dev的 7 个提交) - 审查 Diff:
git diff origin/dev...HEAD,共 142 个文件;排除.omo证据产物后,可审查源码 diff 为 3,323 行 - 审查者:senpi-task 子任务
st_019fe5d1,只读分析,所有结论均通过实际执行命令验证
审查遵循三条主线:真实命令结果(typecheck、scoped tests)、仓库法则对照(AGENTS.md 的硬性约定)、测试质量评估(AI-slop 注释与同义反复检查)。所有结果都标注为 "REAL RESULT",强调不是推理而是运行产物。
重命名的最终形态可以从当前 package.json 的bin映射看到——omo条目已被移除,omo-agent-toolkit与四个保留别名(oh-my-opencode、oh-my-openagent、lazycodex、lazycodex-ai)共同指向共享入口bin/oh-my-opencode.js:
"bin": { "oh-my-opencode": "bin/oh-my-opencode.js", "oh-my-openagent": "bin/oh-my-opencode.js", "omo-agent-toolkit": "bin/oh-my-opencode.js", "lazycodex": "bin/oh-my-opencode.js", "lazycodex-ai": "bin/oh-my-opencode.js" }2. 第一道关卡:全仓 typecheck 零诊断
审查命令:bun run typecheck(tsgo 根项目 +typecheck:script+typecheck:packages,覆盖 29 个 package 项目)
真实结果:
TYPECHECK_EXIT=0PASS。根目录、script/以及全部 package tsconfig 均零诊断通过。对一次横跨 142 个文件、涉及 bin 映射、CLI 安装参数解析、postinstall 脚本的重命名来说,类型层面的完整性是第一道必须迈过的门槛——这一关干净通过,说明重命名没有破坏任何导出签名与调用关系。
3. 第二道关卡:scoped 测试 1,190 例 1 红
审查命令:
bun test bin script packages/omo-opencode/src/cli packages/omo-senpi/src/components/ulw-loop真实结果:
TEST_EXIT=1 1189 pass 1 fail 2929 expect() calls Ran 1190 tests across 186 files. [11.83s] (fail) agent command string audit > #given tracked source files #when legacy agent and human commands are scanned #then every hit is categorizedFAIL — 唯一一条红测试,且已用bun test script/agent-command-string-audit.test.ts单独复现(0 pass / 1 fail),排除排序或偶发(flake)因素。失败 diff 如下:
@@ collectHits() vs allowlist @@ + "script/agent-command-string-audit.allowlist.json:5: omo ulw-loop", + ... (33 hits total, ALL inside script/agent-command-string-audit.allowlist.json itself) - Expected - 0 + Received + 33 at script/agent-command-string-audit.test.ts:57:273.1 根因:审计闸门自我匹配,永远无法通过
这条红测试不是代码回归,而是审计机制自身的逻辑缺陷。审计闸门会扫描每一个git ls-files追踪的文件,用正则\bomo (ulw-loop|boulder|install|...)\b等模式查找遗留命令字符串;但isExcluded()(审查时位于 script/agent-command-string-audit.test.ts 第 16-22 行)没有排除 allowlist 文件自身。
问题因此成立:allowlist 的每条目本身就是一个遗留命令字符串(例如script/agent-command-string-audit.allowlist.json:5: omo ulw-loop),于是闸门对自己扫描出了 33 次未分类命中。变更集的最后一个提交("migrate remaining agent commands … with an audit gate")因此落地了一个永久变红的闸门——这恰恰是审计闸门要防止的事情。
3.2 修复方案:一行排除
审查给出的修复只有一行,把 allowlist 加入isExcluded()排除列表:
|| filePath === "script/agent-command-string-audit.allowlist.json"(备选方案是在collectHits()中跳过ALLOWLIST_PATH;但放进isExcluded更简单,且与既有 CHANGELOG /.omo的排除模式一致。)
这一修复在当前仓库源码中已经落地:查看 script/agent-command-string-scan.ts 的isExcluded(),可以看到排除列表已包含ALLOWLIST_RELATIVE_PATH(即 allowlist 自身),与审查建议完全一致:
export function isExcluded(filePath: string): boolean { return filePath === ALLOWLIST_RELATIVE_PATH || filePath === AUDIT_TEST_RELATIVE_PATH || filePath === SCAN_MODULE_RELATIVE_PATH || filePath === SCAN_TEST_RELATIVE_PATH || filePath === "CHANGELOG.md" || filePath.endsWith("/CHANGELOG.md") || filePath === ".omo" || filePath.startsWith(".omo/") || filePath.split("/").some((part) => part === "node_modules" || part === "install-dist" || part === "dist") }3.3 审计闸门的机制设计:无行号指纹
为什么审计闸门要用"指纹"而不是直接比对行号?script/agent-command-string-scan.ts 中fingerprintSource()的注释给出了明确的安全理由:
Deliberately line-number-free: a release version stamp or a doc edit shifts every line below it, and a line-pinned fingerprint turns that shift into a red release gate. The count keeps the audit sensitive to a NEW legacy command occurrence inside an already-allowlisted file.
即:指纹刻意不携带行号——一次版本戳更新或文档编辑会把其下所有行号整体下移,行号固定的指纹会把这种行移变成一次虚假的发布闸门变红;而保留出现次数则让闸门对"已放行文件内新增一条遗留命令"仍然敏感。fingerprintSource()的实现要点:
- 三个扫描模式(script/agent-command-string-scan.ts):
AGENT_COMMAND_RE(\bomo (ulw-loop|boulder)\b)、HUMAN_COMMAND_RE(\bomo (install|uninstall|cleanup|doctor|run|get-local-version|version|mcp)\b)、BARE_BIN_RE(command -v omo、/bin/omo、=omo、$(which omo)等裸二进制引用); - 指纹键为
${filePath}: ${match[0]},出现次数大于 1 时以xN后缀标注; - 仅扫描
git ls-files追踪文件(script/agent-command-string-scan.ts),并过滤排除列表、node_modules、install-dist、dist等目录。
配套的 script/agent-command-string-scan.test.ts 用三个场景验证了这个设计契约:行移位后指纹不变、已放行文件新增一条命令后指纹变化、全新文件中的遗留命令按路径上报。
3.4 闸门的断言结构
script/agent-command-string-audit.test.ts 包含两道断言:
- 分类闸门:
collectHits(WORKSPACE_ROOT)必须恰好等于 allowlist 中四个分类(emit-migrate、test-expectation、input-compat-preserve、docs)条目的并集;其中emit-migrate与test-expectation必须保持为空数组(有意设计的"债务闸门"——任何人往这两个分类写入新条目都会触发失败)。 - 无行号 pin 约束:allowlist 条目不得携带
路径:行号:前缀,防止文档与发布戳的行位移破坏发布闸门。
当前 script/agent-command-string-audit.allowlist.json 的input-compat-preserve与docs分类展示了放行条目的形态,例如"packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts: omo ulw-loop"、"packages/omo-native/bin/lib/launcher.js: omo ulw-loop"、"AGENTS.md: omo doctor"等——每条都是"为兼容旧输入而有意保留"的遗留命令位置。
4. 第三道关卡:对照 AGENTS.md 仓库法则
审查将 diff 逐条对照 AGENTS.md 的工程法则,结果如下表(原文完整继承):
| 法则 | 结果 |
|---|---|
禁止as any | CLEAN — 零新增(一处 grep 误报:文档行中的 "alias anywhere" 散文) |
禁止@ts-ignore/@ts-expect-error | CLEAN — 零新增 |
| 禁止压制 lint | CLEAN — 零新增eslint-disable或等价物 |
| 代码中禁止 emoji | CLEAN — 无新增。packages/omo-senpi/plugin/extensions/omo.js中的⚡ ultraworking是已检入压缩构建产物中的既有内容,diff 仅重盖了 bundle 哈希并重命名了字符串 |
| kebab-case 文件命名 | CLEAN — 新文件全部为 kebab-case(bin-map.test.ts、agent-command-string-audit.test.ts、agent-command-string-audit.allowlist.json、postinstall.test.ts) |
createXXX工厂模式 | N/A — 无新增组件/工厂;resolveOmoBin/toSpawnTarget是既有导出、原地修改 |
barrelindex.ts仅导出 | NOT INTRODUCED —packages/omo-senpi/src/components/ulw-loop/index.ts承载业务逻辑,但早于本 diff(hunk 仅替换omo→omo-agent-toolkit字符串),属既有状况,不计入本次变更 |
| ~200 LOC 软性文件规模上限 | PRE-EXISTING OVERAGE WORSENED —packages/omo-codex/src/install/codex-cache-bins.ts由 229 行增至 255 行,本就超限,本次再增 26 行而未抽取。仅作观察(软性上限) |
#given/#when/#then前缀测试、禁止 AAA | ONE VIOLATION — 见下方 V2,未出现 Arrange-Act-Assert |
| 禁止空 catch 块 | CLEAN — 新增removeGeneratedRuntimeWrapper的 catch 对非 ENOENT 重新抛出;readActiveStatus为 log-and-return;压缩产物中的catch{}为既有输出 |
| 禁止万能 util/helper/service 文件 | CLEAN — 无新增 |
4.1 V1(BLOCKING):审计闸门测试在 HEAD 即为红
- 位置:script/agent-command-string-audit.test.ts 分类闸门测试(审查时约第 57 行)
- 问题:闸门未排除自身 allowlist,产生 33 次未分类自我命中,随包发布即永久失败
- 违反理由:变更集不得携带一条红测试落地;一个永远无法通过的闸门比没有闸门更糟
- 修复:在
isExcluded()中排除script/agent-command-string-audit.allowlist.json,重跑套件至全绿
4.2 V2(minor):新测试缺少#given/#when/#then前缀
- 位置:packages/omo-opencode/src/cli/install-platform-resolution.test.ts 第 170、180、190、200、208 行附近的五个
OMO_EDITION install routing测试 - 问题:使用纯英文描述名 + 裸
// when/// then注释,全程无#given/#when/#then前缀,而仓库法则要求强制前缀。同一次 diff 中新增的doctor-target.test.ts测试带有前缀,说明 diff 内部风格不一致 - 修复建议:改写为
#given OMO_EDITION=codex #when resolving install args for a non-codex invocation #then the platform defaults to codex形式
从当前源码看,这五个测试仍然存在且描述名未变(如"OMO_EDITION=codex defaults a non-codex invocation name to the codex platform",第 170 行),说明该 minor 违规在审查后尚未完全清理——这是审查结论未被完全消费的可见证据。
4.3 V3(minor):bin-map 测试头部注释是 AI-slop
- 位置:script/bin-map.test.ts 头部
- 问题:第 1 行仅复述文件名(
// script/bin-map.test.ts),第 2 行叙述变更事件("omo -> omo-agent-toolkit rename")而非陈述持久契约,均为噪音;describe字符串已经说明了被测内容 - 修复:删除这两行
当前仓库的 script/bin-map.test.ts 已从 import 直接开始、头部注释被删除,V3 修复已经落地。
4.4 被检查且未标记的实质性 WHY 注释(应保留)
审查明确指出以下注释属于"解释非显然安全理由"的实质性注释,不得删除:
- ulw-loop 组件中 "Deliberately NO PATH lookup of the bare name
omo" 块与.jsspawn 说明(避免对裸名omo做 PATH 查找的刻意设计) - postinstall.mjs 中关于 npm ≥7 隐藏生命周期输出的说明(解释为何通知是 best-effort)
.github/workflows/publish.yml中升级模拟(upgrade-simulation)契约注释(记录"标记版 vs 用户自有遗留包装器"的安全不变量)packages/omo-codex/plugin/components/bootstrap/src/setup.ts的降级路径注释(仅字符串更新)- .omo/evidence/20260809-omo-agent-toolkit-rename/ 下
lead-codex-qa.sh、lead-npm-qa.sh的 ISOLATION CONTRACT 头部(隔离契约,属安全文档,经确认不予标记)
5. 第四道关卡:同义反复评估(每个新测试逐一过筛)
"同义反复"指那种无论如何都不可能失败的测试——它不检测任何真实行为。审查对本次新增的每个测试文件逐一评估:
5.1 script/bin-map.test.ts(3 个测试,均为真实变更探测器)
…the omo bin entry is absent— 若omo被重新加回 bin map 即失败,真实有效…omo-agent-toolkit points at the shared entry— 若入口被移除或改指即失败,真实有效…the four surviving aliases keep the shared entry— 若四个别名任一漂移即失败,真实有效
5.2 script/agent-command-string-audit.test.ts(1 个测试)
…every hit is categorized—非同义反复,是实时闸门(其当前恰好失败本身就是证明);但正如 V1 所示,随包发布状态下它无法通过,当前失败模式是自扫描而非真实回归。emit-migrate/test-expectation的toEqual([])断言是有意设计的债务闸门——任何人往这两个分类登记新条目都会失败,属于设计内行为
5.3 postinstall.test.ts(审查时为 3 个测试,均执行真实 postinstall.mjs 于隔离 fixture HOME)
announces the omo-agent-toolkit rename exactly once— 通知被删除、改写或打印两次即失败,真实有效never fails the install regardless of platform binary resolution— postinstall 在 fixture 环境非零退出即失败。断言真实,但命名过度承诺:只覆盖一种环境形态,"regardless of platform binary resolution"并未做平台变化测试,属命名瑕疵而非同义反复stays idempotent across repeated runs—命名不当:它断言两次运行各打印一次通知(运行间一致性);真正的幂等(第二次运行什么都不打印)反而会让该测试失败。建议改名为prints the notice exactly once on every run
审查结论:不存在无法失败的测试。每个新测试都命名了一个可被回归击穿的行为。
从当前 postinstall.test.ts 看,该文件已演进为 4 个测试并补齐了#given/#when/#then前缀:新增了finishes when the opencode version probe never returns(用挂起 opencode shim 验证 postinstall 在版本探测永不返回时仍能在超时前正常结束),且announces … exactly once与stays idempotent across repeated runs的断言逻辑保持与审查描述一致。
6. 审查裁决与修复闭环
6.1 最终 Verdict(原文)
One blocking defect (V1: the audit-gate test is red at HEAD by self-scan, confirmed by real test runs, full-suite and standalone) plus two minor violations (V2 missing
#given/#when/#thenprefixes in the new install-platform-resolution tests, V3 slop header comments in bin-map.test.ts). Everything else — typecheck, remaining 1,189 tests, banned-pattern scan, naming, catches, comment quality, generated artifacts — is clean.REJECT — fix V1 (exclude
script/agent-command-string-audit.allowlist.jsoninisExcluded(), suite must go 1190/1190 green), V2, and V3, then re-submit.
即:拒绝合并(REJECT)。必须修复 V1(在isExcluded()中排除 allowlist 自身,套件须恢复 1190/1190 全绿)、V2、V3 后重新提交。
6.2 审查闭环的仓库现状印证
对比当前仓库 HEAD,可以观察到这次审查驱动的修复闭环:
- V1 已修复:script/agent-command-string-scan.ts 的
isExcluded()已将 allowlist 文件自身列入排除,正是审查建议的一行修复; - V3 已修复:script/bin-map.test.ts 头部两行噪音注释已删除;
- V2 残留:packages/omo-opencode/src/cli/install-platform-resolution.test.ts 的五个
OMO_EDITION路由测试仍使用裸// when/// then注释、无#given前缀,尚未按建议重命名; - postinstall 测试持续演进:由审查时的 3 个增至 4 个,并补齐前缀、新增挂起探测场景。
这正体现了 AGENTS.md 所强制的证据驱动工作流:.omo/evidence/20260809-omo-agent-toolkit-rename/目录下留存了 F1-F4 审查文档、lead-codex-qa.sh/lead-npm-qa.shQA 脚本与各任务日志,审查结论有据可查、修复进度可追溯。
7. 可复用的审查方法论要点
从这份 F2 报告可以提炼出一套可移植的变更集质量审查清单:
- 用真实命令结果说话:typecheck 与 scoped tests 必须实际执行并记录退出码与通过/失败计数,杜绝"应该能过"的推断;
- 红测试必须单独复现:
TEST_EXIT=1后先以单文件复跑(bun test script/agent-command-string-audit.test.ts),区分真实回归与排序/偶发; - 闸门类工具要审查其自指性:审计/门禁工具若扫描仓库自身文件,必须确认排除列表覆盖自身输入(allowlist、测试、扫描模块、CHANGELOG、证据目录),否则会出现"闸门对自己 33 次命中"式的永久红;
- 法则对照要逐条留痕:
as any、@ts-ignore、lint 压制、emoji、命名、空 catch、万能文件等每一条都给出 CLEAN / 违规 / N/A 的判定与证据; - 区分实质性注释与 AI-slop:复述文件名、叙述变更事件的注释是噪音;解释非显然安全理由的 WHY 注释必须保留——并明确列出"不要删"清单;
- 测试逐条做同义反复检查:每个新测试都必须能指出"哪个行为回归会让它变红",命名不得过度承诺("regardless of platform" 却没有平台变化矩阵)。
【免费下载链接】oh-my-openagentOmO: Just type "mass ulw" keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考