OmX 近期缺陷回归加固实战:从 planning 门控、Stop 钩子状态权威到 tmux 启动与团队启动证据的四个回归防线
2026/9/11 5:57:56 网站建设 项目流程

OmX 近期缺陷回归加固实战:从 planning 门控、Stop 钩子状态权威到 tmux 启动与团队启动证据的四个回归防线

【免费下载链接】oh-my-codexOmX - Oh My codeX: Your codex is not alone. Add hooks, agent teams, HUDs, and so much more.项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-codex

导读

OmX(Oh My codeX)在 2026-04-11 提交了一组聚焦的编译版 recent-bug 回归加固,覆盖四个真实故障面:已批准短任务被错误重新门控回 ralplan 规划、Stop 钩子被 stale 根状态误导而抑制 auto-nudge、不支持的环境变量 SHELL 值导致 detached tmux 启动丢失目标目录、以及团队 worker 启动证据对异常状态文件的容错。本文基于 docs/qa/recent-bug-regression-hardening-2026-04-11.md 及其对应源码与测试,逐项拆解每个回归的成因、修复断言与可复跑的编译验证命令,帮助读者掌握 OmX 关键词路由、native 钩子分发、启动回退与团队运行时四大模块的加固方法论。

一、背景:编译版 recent-bug 套件与四项加固概览

OmX 用一套“编译产物优先”的回归测试策略来防止已修复缺陷复发:测试先经npm run build编译到dist/,再直接对编译后的 JS 运行node --test,从而保证 CI 验证的是用户实际运行的产物而非源码路径。本次加固在该套件上新增四组断言,分别命中四个不同的运行时子系统:

#加固方向涉及模块核心目标
1Planning-precedence follow-ups关键词路由 / ralplan 门控已批准短ralph后续任务在规划工件已存在后不被重新门控回ralplan
2Stop-hook stale-root vs current-sessionnative 钩子 / 会话状态显式非活跃的 session-scoped deep-interview 状态优先于活跃的根回退,auto-nudge 不被 stale 根状态抑制
3Detached tmux launch shell drift fallbackCLI 启动不支持的SHELL值触发回退时仍保留请求的 cwd
4Team startup worker-state evidence团队运行时容忍格式错误的 worker 状态输入;blocked状态视为真实启动进度

四个方向的测试文件与验证命令均记录在原文档中,下面逐一展开。

二、加固一:Planning-precedence——已批准后续任务不被重新门控回 ralplan

2.1 问题本质:后续任务被“旧门控”拦截

当一次会话已经完成规划(planning artifacts 已存在)时,用户后续发起的短任务(short follow-ups,源自已被弃用的$ralph流程线)不应再被强制拉回ralplan的共识规划门控。若路由层只看残留的ralplan-state.jsonskill-active-state.json,就会把已批准的后续执行重新拦截回规划阶段,造成死循环式的“规划—批准—再规划”。

2.2 源码机制:仅路由激活的中和(neutralization)

这一防线落在 src/ralplan/documented-leader-preflight.ts 的neutralizeOwnedRoutingRalplanreadNeutralizedRoutingOverlay

  • neutralizeOwnedRoutingRalplan(cwd)只对“纯路由激活”的 ralplan 状态生效:它要求ralplan-state.jsonskill-active-state.json构成一对严格匹配的routingOnlyPair(模式为ralplan、阶段为planning、会话号一致、字段白名单RALPLAN_KEYS/SKILL_KEYS约束),并通过collectOwners校验当前OMX_SESSION_ID确实持有该会话的所有权,避免误中和他人状态;
  • 命中后,以.ralplan-neutralization-<digest>-<token>.json+ 对应.commit.json的“数据—提交”两段式文件(GENERATION_PREFIXCOMMIT_SUFFIX)记录中和结果,写入过程使用writeExclusiveO_EXCL)+ 目录sync()保证幂等与崩溃安全;
  • readNeutralizedRoutingOverlay读取该 overlay 后返回{ active: false, phase: 'cancelled', current_phase: 'cancelled' }的中和形态,路由层据此判定该 ralplan 激活已“退役”,不再重新门控。

2.3 测试证据

对应测试位于 src/hooks/tests/keyword-detector.test.ts(该文件同样导入neutralizeOwnedRoutingRalplangetRemovedSkillInfo)。其中:

  • does not activate a workflow for the sunset $ralph token:断言$ralph是已声明移除的技能(getRemovedSkillInfo('ralph')replacement$ultragoal),因此不再激活任何工作流,只产生非激活诊断;
  • prefers ralplan over ralph follow-up language when both implicit routes are presentkeep going but do consensus plan first这类仍带明确规划意图的输入才路由到ralplan,避免误中和真正需要规划的请求。

从源码结构可以推断:规划工件已存在后的短后续任务,正是通过“检测到已被中和的 ralplan overlay → 跳过重新门控”来保持已批准状态不被回退。

三、加固二:Stop 钩子 stale-root 与 current-session 的权威关系

3.1 问题本质:stale 根状态抑制 auto-nudge

OmX 的会话状态同时存在“根级状态”(如.omx/state/ultragoal-state.json、根skill-active-state.json)与“会话级状态”(.omx/state/sessions/<id>/…)。当某会话已显式将 deep-interview 模式置为非活跃,但根级仍残留一个活跃的旧状态时,Stop 钩子的 auto-nudge 判断若优先读取根回退(root fallback),就会错误地认为“仍有活跃的 deep-interview 门控”而抑制本该发送的自动提示。

3.2 源码机制:session-scoped 状态优先

在 src/hooks/keyword-detector.ts 中,deep-interview 是带输入锁的状态化技能模式:

  • DEEP_INTERVIEW_STATE_FILE = 'deep-interview-state.json':会话级 deep-interview 状态文件;
  • DEEP_INTERVIEW_BLOCKED_APPROVAL_INPUTS = ['yes', 'y', 'proceed', 'continue', 'ok', 'sure', 'go ahead', 'next i should']:访谈期间被锁定的自动批准快捷输入;
  • DEEP_INTERVIEW_INPUT_LOCK_MESSAGE = 'Deep interview is active; auto-approval shortcuts are blocked until the interview finishes.'
  • persistDeepInterviewModeState:把模式状态写入stateDir/sessions/<sessionId>/会话目录(keyword-detector.test.ts 第 4115 行creates the session-scoped deep-interview state directory before persisting mode state直接验证了目录先建后写)。

加固的权威关系在测试中体现为:

  • creates the session-scoped deep-interview state directory before persisting mode state:验证会话目录内的deep-interview-state.json被正确持久化;
  • ignores stale root child mode state during session-scoped Autopilot child reconciliation(第 4485 行):在根级存在ultragoal-state.json { active: true, current_phase: 'executing' }的 stale 状态下,session-scoped Autopilot 继续以supervised_child_skill: 'deep-interview'协调子技能,根 ultragoal 保持active: true不被触碰——即“显式会话态优先,stale 根态只作回退”。

3.3 native 钩子侧的对称防线

Stop 钩子侧的同构加固位于 src/scripts/tests/codex-native-hook.test.ts:

  • does not block Stop on stale session autopilot mirror when canonical skill state is inactive(第 2670 行):构造“会话镜像autopilot-state.jsonactive: true,但 canonicalskill-active-state.jsonactive: false, phase: 'cancelled'”的对立场景,调用dispatchCodexNativeHook处理Stop事件,断言输出为{}(即不阻止、不 nudge、不产生副作用)。

这正是文档所述“显式非活跃的会话级模式状态优先于活跃根回退”的钩子级落地:当权威状态已取消时,任何镜像/根残留都不足以重新激活门控。

四、加固三:detached tmux 启动的 shell 漂移回退与 cwd 保留

4.1 问题本质:SHELL 与 rc 文件驱动的目录漂移

detached tmux 启动会借助用户 shell 的 rc 文件(.profile/.zshrc/.bashrc)初始化环境,但 rc 中的cd语句可能把工作目录“漂移”走。当SHELL环境变量指向不存在的路径(如/definitely/missing-shell)或非受支持 shell 时,OMX 必须回退到/bin/sh执行 detached leader,而此时必须保证请求的 cwd 仍然保留——否则整个 detached 会话会在错误目录下启动。

4.2 测试证据:两个互补用例

加固测试位于 src/cli/tests/launch-fallback.test.ts,通过wrapFakeTmuxWithDetachedLeader包装的假 tmux + 假 codex 完成端到端断言:

  • preserves the requested cwd through detached tmux launch when an unsupported SHELL value falls back away from rc-driven cwd drift(第 2738 行):在HOME下放置cd ...profile/.zshrc/.bashrc,以SHELL: '/definitely/missing-shell'运行omx --madmax --tmux,随后断言 tmux 日志中出现/bin/sh__detached-session-leader——回退 shell 被正确选用,且 leader 以期望的 cwd 启动;
  • falls back to /bin/sh for detached tmux launch when SHELL drifts to an unsupported path(第 2833 行):以SHELL: '/bin/not-a-real-shell'验证同一回退路径。

两个用例共同锁定契约:无论SHELL如何漂移,detached tmux 启动都必须回退到受支持的/bin/sh,且不得以 rc 文件的cd副作用漂移掉请求的 cwd。测试借助buildRunOmxEnv清空所有OMX_*/CODEX_*/TMUX环境变量以隔离干扰,并依赖isRealScriptAvailable/isRealTmuxAvailable做平台跳过(Windows 或缺少script(1)时跳过,CI 上则必须提供,见skipUnlessScriptAvailable)。

五、加固四:团队启动的 worker 状态证据容错

5.1 问题本质:外部状态根下的异常输入

团队(team)模式支持OMX_TEAM_STATE_ROOT指向外部共享状态根。外部进程(如手工编辑、其他工具)可能写入格式损坏的status.json;此外,worker 在 Codex 启动早期可能尚未持久化current_task_id,仅先写入blocked状态。启动证据收集(waitForWorkerStartupEvidence)必须对这两类输入都稳健:坏 JSON 不能炸掉 hardening-e2e 覆盖,blocked不能被视为“没进展”而反复重试直至超时

5.2 源码与测试证据

  • src/team/tests/hardening-e2e.test.ts 第 87 行tolerates malformed worker status from an external team state root:在OMX_TEAM_STATE_ROOT指向的共享根下,把workers/worker-1/status.json覆盖为{not valid json,随后monitorTeam仍返回快照,且 worker 的status.state === 'unknown'——即“外部坏输入被降级为 unknown,而不是抛异常打断监控”;
  • src/team/tests/runtime.test.ts 第 1815 行waitForWorkerStartupEvidence treats blocked worker status as settled progress even without a claimed task id:写入{ state: 'blocked', reason: 'waiting on shared file', updated_at: … }(无current_task_id)后,waitForWorkerStartupEvidence返回'worker_progress',证明blocked是合法的“已开始但被外部条件阻塞”的启动证据;
  • 同一文件第 3774–3776 行还断言失败回滚场景下readWorkerStatus返回reason: 'codex_bypass_mdm_incompatible'current_task_id: undefined被如实保留——状态读取层对缺失字段不臆造。

从测试结构可以推断,waitForWorkerStartupEvidence将“已持久化current_task_id”与“明确写入blocked状态”视为同等的进展信号,避免把阻塞误判为未启动而重复派发。

六、验证目标:编译、定向运行与整包回归

原文档给出了完整的验证链路,对应 package.json 中的脚本定义:

# 1. 全量编译(同时构建 TS 产物与 runtime 产物) npm run build # 2. 对编译产物定向运行四个加固测试文件 + hardening-e2e node --test dist/hooks/__tests__/keyword-detector.test.js \ dist/scripts/__tests__/codex-native-hook.test.js \ dist/cli/__tests__/launch-fallback.test.js \ dist/team/__tests__/runtime.test.js \ dist/team/__tests__/hardening-e2e.test.js # 3. 一键整包:build -> build:runtime -> 编译套件全量运行 npm run test:recent-bug-regressions:compiled

其中test:recent-bug-regressions:compiled实际执行的清单比定向命令更全,还包含dist/hooks/__tests__/session.test.jsdist/hooks/__tests__/issue-3497-hook-simplification.test.js;而test:recent-bug-regressions是“先编译再跑”的完整入口(npm run build && npm run build:runtime && npm run test:recent-bug-regressions:compiled)。由于定向运行依赖dist/产物,任何源码修改后都必须先执行npm run build,这正是文档把npm run build列为第一验证目标的原因。

七、加固方法论小结

从四项回归中可以提炼出 OmX 的通用防线模式:

  1. 权威分层:会话级显式状态优先于根级回退;canonical 状态优先于镜像/残留(加固二、三);
  2. 幂等中和:对“已完成使命”的激活记录以数据+提交两段式文件做不可变中和,路由层据此跳过旧门控(加固一);
  3. 回退可预测:不支持的运行时输入(SHELL)走显式回退路径,并锁定关键不变式(cwd 保留、退出码透传)(加固三);
  4. 对坏输入降级而非崩溃:外部共享状态的损坏 JSON 降级为unknownblocked视为进展信号(加固四)。

如需深入实现细节,可继续阅读 src/hooks/keyword-detector.ts、src/ralplan/documented-leader-preflight.ts、src/scripts/codex-native-hook.ts 与 src/cli/index.ts 等核心模块,并对照上述四个测试文件复跑验证命令,即可在自己的改动上复现这套“编译产物 + 定向断言 + 全量回归”的防复发流程。

【免费下载链接】oh-my-codexOmX - Oh My codeX: Your codex is not alone. Add hooks, agent teams, HUDs, and so much more.项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-codex

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询