OmO codex-ulw-loop 验证批次(validation-batch)强制机制落地实录:checkpoint 关闭门禁与 steering 成员一致性保障
【免费下载链接】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
导读
本文基于仓库中 .omo/evidence/20260721-ulw-loop-gajae-adoption/task-4.md 这份 TDD 证据文档,完整还原 OmO 项目omo-codex插件组件ulw-loop中**验证批次(validation-batch)**功能的落地过程:先以两条失败测试定义问题(RED),再通过组件门禁(GREEN),最后在真实构建的 CLI 上做场景化 QA。读者将掌握验证批次的 schema 定义、checkpoint 关闭时的四类强制门禁(open 成员、批次 gate 必需、criteria 全 pass、coverage 计数一致)、steering split 后的批次成员同步更新,以及如何在本地复现这一整套验证。
背景:validation-batch 在 ulw-loop 中的角色
ulw-loop是 OmO 仓库中omo-codex插件的核心组件,用于"durable repo-native 多目标编排":把一次复杂任务拆成多个 goal(目标),每个 goal 带嵌入式 success criteria(成功标准)与可观测证据审计,状态存放在仓库内的.omo/ulw-loop/目录,全部状态变更经由omo-agent-toolkit ulw-loopCLI 完成。组件能力总览见 packages/omo-codex/plugin/components/ulw-loop/README.md。
验证批次是"评审边界(review boundary)":当若干 goal 必须作为一个整体接受最终评审、不能单独放行时,就在计划创建时用--validation-batch-json声明一个批次,指定成员(memberIds)与批次最终目标(finalGoalId)。批次最终目标只有在"所有其他成员都已完结或经 supersede 解析、所有成员 criteria 全部 pass、且提交的 quality gate 覆盖率与重算结果一致"的前提下才允许 checkpoint 完成——这就是 task-4 中"batch-final checkpoint 拒绝开放成员 / 要求批次 gate / gate criteria 与 coverage 校验"三项 RED 失败点背后的诉求。
task-4 所属的采纳计划(.omo/evidence/20260721-ulw-loop-gajae-adoption/README.md)共覆盖七项内容,本文聚焦第 4 项:validation-batch 的 checkpoint/steering 强制。
RED:先用失败定义行为契约
task-4 的 RED 阶段使用两条精确命中的测试命令:
npm test -- validation-batch-checkpoint npm test -- steering-batch实现前观察到的失败行为有三条,它们共同构成了本功能的验收契约:
- 批次最终 checkpoint 未拒绝开放成员、也未要求批次 gate:即
G002(finalGoalId)可以在G001仍 pending 时直接完成,也没有强制要求提交--quality-gate-json。 - 批次 gate 的 criteria/coverage 校验缺失:提交的 quality gate 中
criteriaCoverage的totalCriteria/passCount可以随意填,系统不与批次成员的真实 criteria 状态比对。 - 拆分批次成员不更新 validation-batch 成员、也不发
batch_updated:对批次成员执行steer --proposals-json的 split 后,批次成员列表仍指向被拆分的旧 goal,账本(ledger)里也没有对应记录。
对应的测试文件与用例位于 packages/omo-codex/plugin/components/ulw-loop/test/validation-batch-checkpoint.test.ts(validation-batch checkpoint enforcementdescribe 块)与 packages/omo-codex/plugin/components/ulw-loop/test/steering-batch.test.ts。测试采用"given/when/then"注释风格,例如首个用例:"#given an open batch member #when completing the batch final goal #then rejects with batch open"。
GREEN:组件门禁与实现落点
GREEN 阶段执行更宽的门禁命令:
npm test -- validation-batch-checkpoint steering-batch steering plan-io checkpoint npm run typecheck npm run build观察到的结果(task-4 原始记录):
- 14 个测试文件、143 个测试全部通过;
- TypeScript strict 检查通过(
npm run typecheck执行tsc --noEmit); - 构建通过;
- 纯 LOC(pure LOC)审计:
checkpoint.ts249 行、steering.ts203 行、steering-mutations.ts52 行、validation-batch.ts104 行——四个文件顶部都带biome-ignore-all format注释,表明受纯 LOC 预算约束刻意保持紧凑。
实现落点集中在omo-codex插件组件的ulw-loop/src目录下四个模块,职责划分清晰:
| 模块 | 职责 |
|---|---|
| validation-batch.ts | 批次解析、schema 校验、批次查询、批次强制门禁 |
| checkpoint.ts | checkpoint 流程编排,串起批次关闭门禁与 quality gate |
| steering.ts | steering 提案校验与原子应用,追加batch_updated账本 |
| steering-mutations.ts | 具体变更原语,含 split/supersede 后批次成员同步 |
核心机制一:批次 schema 与解析校验
批次通过--validation-batch-json以 JSON 数组形式传入,例如 README 中的声明方式:
omo-agent-toolkit ulw-loop create-goals \ --validation-batch-json '[{"batchId":"VB001","memberIds":["G001","G002"],"finalGoalId":"G002"}]'validation-batch.ts 中的parseValidationBatches逐项做结构化解析,违反任一规则即抛出带类型码的UlwLoopError:
- 必须是 JSON 数组,否则报
--validation-batch-json must be a JSON array.; - 每个条目必须是对象,且三个字段齐全:
batchId、memberIds(至少两个成员)、finalGoalId; batchId全局唯一,重复报duplicate validation batch id;- 同一批次内
memberIds不得重复; finalGoalId必须是本批次成员,否则报ULW_LOOP_VALIDATION_BATCH_FINAL_NOT_MEMBER;- 成员必须存在于计划 goal 中,否则报
ULW_LOOP_VALIDATION_BATCH_MEMBER_UNKNOWN; - 同一 goal 不得出现在多个批次中,否则报
ULW_LOOP_VALIDATION_BATCH_OVERLAP。
这些校验在计划创建(create-goals)时即完成,保证后续 checkpoint/steering 阶段拿到的批次结构是合法、无重叠、可闭合的。
核心机制二:checkpoint 关闭时的批次强制
checkpoint命令的完整执行路径在 checkpoint.ts 的checkpointUlwLoop。当目标 goal 是某批次的 finalGoalId(由batchClosedBy判定)时,进入强制逻辑:
1. 开放成员拒绝(batch open gate)
if (closesBatch) requireBatchFinalReady(plan, goal);requireBatchFinalReady会找出批次中除自身外所有未解析(未 complete、未被 supersede 解析)的成员,只要有任何一个开放,就抛出:
ULW_LOOP_VALIDATION_BATCH_OPEN错误详情携带batchId与开放成员列表open,方便 Agent 定位还需处理哪些 goal。
2. 批次 gate 必需(gate required)
if (closesBatch && args.qualityGateJson === undefined) throw new UlwLoopError("Validation batch final checkpoint requires --quality-gate-json.", "ULW_LOOP_VALIDATION_BATCH_GATE_REQUIRED");批次最终 checkpoint 不再接受"只交 evidence"的简化路径,必须显式提交--quality-gate-json,否则直接失败(ULW_LOOP_VALIDATION_BATCH_GATE_REQUIRED)。
3. criteria 全 pass 与 coverage 一致(gate 内容校验)
quality gate 解析成功后,requireBatchGate(plan, goal, qualityGate)做两道校验:
- 遍历批次全部成员的成功标准,只要存在
status !== "pass"的 criterion,即报ULW_LOOP_VALIDATION_BATCH_CRITERIA_PENDING,错误详情列出所有memberId:criterionId; - 将 gate 中
criteriaCoverage.totalCriteria/passCount与"批次成员真实 criteria 数量、pass 数量"逐一比对,不一致报ULW_LOOP_VALIDATION_BATCH_GATE_MISMATCH,并把expected(重算值)与actual(提交值)一并放进详情。
质量 gate 本身要求的字段(manualQa、gateReview、iteration、criteriaCoverage,lazycodex 面额外接受codeReview)在 checkpoint.ts 调用validateQualityGate时统一校验,完整 gate 示例见组件 README.md。
4. 收尾账本
通过全部门禁后,checkpoint 会额外追加一条batch_closed账本记录:
if (closedBatch !== undefined) entries.push({ at: now, kind: "batch_closed", goalId: goal.id, message: closedBatch.batchId });批次闭合与"run 最终目标闭合"(aggregate completion)可以叠加:当批次 finalGoal 同时也是整个计划的最后一个 goal 时,requireAllValidationBatchesClosed还会从全局角度拒绝任何仍开放的批次,两条路径(批内视角 + 全局视角)共同兜底。
核心机制三:steering 后的批次成员一致性
批次成员被 split 或 supersede 时,批次定义必须同步演进,否则批次关闭门禁会引用已失效的 goal id。这条链路在 steering-mutations.ts 的splitOrBlock:
target.steeringStatus = "superseded"; target.supersededBy = replacements.map((item) => item.id); // ... updateBatchesAfterSupersede(plan, target.id, replacements.map((item) => item.id));updateBatchesAfterSupersede(validation-batch.ts)的核心行为:
- 若批次成员包含被拆分的 target,用
replacementIds原位替换; - 若 target 本身就是
finalGoalId,则 finalGoalId 顺延为最后一个替换成员(replacementIds[replacementIds.length - 1]),其余成员(含非 final 成员)的 finalGoalId 保持原值; - 保持
batchId不变,批次标识稳定可追踪。
而在 steering.ts 的steerUlwLoop中,任何被接受的 steering 变更都会通过batchUpdateLedgerEntry比较变更前后的validationBatches序列化结果,只要成员发生变动,就追加一条batch_updated账本:
{ at, kind: "batch_updated", before: [...], after: [...], message: "Validation batch membership updated after steering." }这就修复了 RED 阶段的第三个失败点:split 后批次成员更新 + 账本可审计,二者缺一不可。
Real-surface QA:真实 CLI 场景复现
GREEN 门禁通过后,task-4 用真实构建产物做了黑盒验证:构建出dist/cli.js,在每个mktemp生成的全新 git 仓库中运行,避免污染真实工作区(对应 README.md 中"隔离 temp git repo、验证后清理"的要求)。
场景一:开放成员拒绝放行
- 创建含 3 个 goal 的计划,声明批次
VB001,成员为G001-goal-alpha与G002-goal-beta,其中G002为 finalGoalId; - 在
G001-goal-alpha仍 pending 时,尝试对G002-goal-beta执行 checkpoint 完成; - 观察结果:CLI 以 JSON 错误返回,错误码为
ULW_LOOP_VALIDATION_BATCH_OPEN。
场景二:split 后的批次成员同步
- 创建同样的 3-goal 计划与批次;
- 对
G001-goal-alpha执行steer --proposals-json的 split 操作; - 观察结果:批次
memberIds从G001-goal-alpha, G002-goal-beta更新为G004, G002-goal-beta(G001-goal-alpha被移除,新生成的G004顶替其位置——新 id 由steering-mutations.ts中nextId按G\d{3}规则顺延生成)。
两个场景的断言输出(transcript summary):
batch open gate ok ULW_LOOP_VALIDATION_BATCH_OPEN batch split update ok G004,G002-goal-beta本地复现与验证
在组件目录复现 task-4 全部门禁:
cd packages/omo-codex/plugin/components/ulw-loop # 1. 单元/组件测试(含 validation-batch 与 steering 全链路) npm test -- validation-batch-checkpoint steering-batch steering plan-io checkpoint # 2. TypeScript strict 检查 npm run typecheck # 3. 构建 npm run build如需观察真实 CLI 行为,可按组件 README.md 的 Local Development 流程npm install后构建dist/cli.js,在mktemp -d的临时 git 仓库中重复上面两个 QA 场景。批次 schema 的字段约束(至少两个成员、finalGoalId 必须是成员、成员不跨批次重叠等)可在 validation-batch.ts 的validateBatches中逐条核对,作为自己编写批次 JSON 的校验依据。
错误码速查
| 错误码 | 触发条件 | 位置 |
|---|---|---|
ULW_LOOP_VALIDATION_BATCH_INVALID | 批次 JSON 结构非法(非数组/非对象/字段缺失) | validation-batch.ts |
ULW_LOOP_VALIDATION_BATCH_FINAL_NOT_MEMBER | finalGoalId 不在 memberIds 中 | 同上 |
ULW_LOOP_VALIDATION_BATCH_MEMBER_UNKNOWN | 成员引用不存在的 goal | 同上 |
ULW_LOOP_VALIDATION_BATCH_OVERLAP | goal 出现在多个批次 | 同上 |
ULW_LOOP_VALIDATION_BATCH_OPEN | 批次 final 完结时仍有开放成员 / 全局仍有开放批次 | validation-batch.ts + checkpoint.ts |
ULW_LOOP_VALIDATION_BATCH_GATE_REQUIRED | 批次 final checkpoint 未传--quality-gate-json | checkpoint.ts |
ULW_LOOP_VALIDATION_BATCH_CRITERIA_PENDING | 批次成员存在未 pass 的 criterion | validation-batch.ts |
ULW_LOOP_VALIDATION_BATCH_GATE_MISMATCH | gate coverage 计数与成员 criteria 重算结果不一致 | validation-batch.ts |
小结
从 task-4 的 TDD 证据可以看到,validation-batch 强制机制是一套"声明-校验-闭合"闭环:create-goals阶段通过--validation-batch-json声明评审边界并做 schema 校验;checkpoint 阶段以四层门禁(开放成员、gate 必需、criteria 全 pass、coverage 一致)保证批次作为一个整体才能放行;steering 阶段通过updateBatchesAfterSupersede与batch_updated账本维持批次成员随拆分/替换同步演进。任何违规都会以带类型码的 JSON 错误失败,天然适合 Agent 与自动化流水线捕获并继续处理。这套机制的测试证据(validation-batch-checkpoint.test.ts、steering-batch.test.ts、validation-batch.test.ts、cli-validation-batch.test.ts)与证据文档 task-4.md 相互印证,可作为后续扩展批次语义(如多批次串行、嵌套评审边界)的基线。
【免费下载链接】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),仅供参考