fix(turn): preserve effect uncertainty and original journal recovery on errors - #5142
Conversation
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Exact head: 49ac1fcccc5f372e70b99347bd25a7dc7dbf04c5; immutable base: fd96e5e2574272262b9ea604a96581a0d20e94d1。
这是作者自评审,不是独立 approval,也不单独授权合并。按当前 capability policy revision 11 完成全 PR 复核,不继承旧 head 的结论。Goal 配置不等待 CI,本次未查询或轮询远端 CI;用户指定的独立审阅仍是合并前置条件。
动机
真实执行可能已调用 Host、验证产物,甚至完成 canonical Todo 提交,随后在本地 checkpoint 失败。基线 CLI 异常 renderer 却把所有 effects 写成 false,把“没有收到成功答复”误说成“没有执行”。纠正这种反馈可以减少恢复时重复的模型调用和业务效果,同时保留原 Turn 的恢复身份,不取消验收门禁。
上一轮独立审阅还发现更具体的反例:原身份和 phase prefix 合法,但 journal 含未知 prepared step。旧 PR head 的 inspector 给出 consistent/continue/reinvoke_host=true,原 writer 却拒绝同一个 intent。因此本次不只增加 null,也要把 inspector 对齐现有 writer 契约。这里实证的是错误恢复建议,并未证明旧 writer 真的执行了重复效果。当前交付是独立可验证的恢复切片;异构发现、准入、fresh task 绑定、产品回传和父 Agent 的金融语义验收都没有按此 PR 宣布完成。
改动思路
只删除 false 更小,但会隐藏已有 checkpoint 和恢复入口。新造 provider 查询、Python 判定或另一恢复状态机会复制权威。这里复用已有 executor 的锁内只读 inspection、原 TS recovery owner 与 provider prepared-effect readback;新增 recorded_effects 每次从原 journal 派生,不维护新的持久状态。
独立审阅修复采用更小的 consolidation:把 writer 原有 prepared-attempt 校验提成同一个 TS 纯函数,writer 和 inspector 共用;不创造另一份 inspector 规则。仍使用原 settlement step、phase、status 与 effect identity。absent attempt 字段仍合法;present empty map 仍保留原 writer 的拒绝语义。unsupported step、多个 intent、错误引用和错误 phase/status 不给出可继续建议。原 writer 准入、身份、租约、quota、completion validation 和 valid replay 不放松;只有 inspector 对原 writer 已拒绝的 intent 更严格。Python 保持 I/O、严格 transport 与展示的角色。
具体改动
关键代码讲解
handle_turn_command(loopx/cli_commands/turn.py:93)区分是否已进入 executor;异常时用原 goal/agent/Turn key 只读观察一次。观察失败仍保留原错误和未知,不创建任务、不重新调用 Host。preparedAttemptViolation(loopx/control_plane/turn_driver/turn_journal_attempt_contract.ts:18)复用原 writer 的单个 prepared step、精确 effect reference、next phase 和 status 契约,返回 typed diagnostic。原 private checker 被替换为共享调用,而不是复制新规则。valid terminal-closeout 的特殊 phase 也保持原语义。interpretTurnJournalEffect(loopx/control_plane/turn_driver/turn_journal.ts:548)分别判断 lineage/phase 和 prepared intent。intent 错误追加原式诊断并令 journal_consistent=false,现有 recoveryDecision 据此 blocked、reinvoke_host=false;inspection 仍不产生 effects。recordedTurnEffects(loopx/control_plane/turn_driver/turn_journal_effect_readback.ts:16)只投影原 Turn 的 lower-bound facts。可信 lineage 中已 checkpoint 的 true 可以保留;非法 intent 下未证明的效果均为 null,包括此前保存的 scheduler acknowledged=false。foreign/corrupt lineage 不借用事实。prepared 不能当作 committed。build_turn_error_payload(loopx/cli_commands/turn_rendering.py:16)保留已知 hook effect,当前调用未确认的执行效果为 null,allowlisted 原 journal 放在 scope=original_turn。严格同包 Python adapter 与 JSON/Markdown 使用同一投影,不把原 Host 当成本次又启动。
整条 base-to-head diff 为 14 文件 +468/-53:生产 7 文件 +193/-50、测试 5 文件 +233/-3、双语协议/roadmap 2 文件 +42/-0。最后一次修复为 8 文件 +216/-60;新增共享纯校验 57 行,删除原 private 检查,派生 observation helper 55 行。不是语言迁移或配置框架扩张。测试涵盖真实 File 提交后 checkpoint 崩溃、shared writer/inspector 九种非法 intent、合法历史/准备/终结情况、不可用/异源观察、隐私 allowlist 和 CLI 渲染。
对主干的风险
最大风险是把原 Turn 的效果当成本次重新执行,或把 prepared 当成提交证明;另一风险是 observer 和 writer 再次漂移。明确 scope、nullable lower bounds、共享原谓词及真实 CLI 反例共同约束这些风险。原事实不授予新交易或新的 Host 调用,结构验证也不证明金融内容正确。只读异常路径增加一次锁/RPC;损坏或不可用观察仍可能缺失诊断,此时保留原错误和未知,不自动 fallback 执行。
语义与 CI 对齐
行为变化明确披露:基线异常 all-false 改成 nullable;旧 PR head 未知 prepared intent 的 continue 改为 blocked。后者对齐已存在 writer 拒绝,不改变其执行准入。valid success/replay 的当前调用 effects、原持久 journal/receipt schema 和默认启用配置不变。依赖异常 false 的外部脚本需要遵循双语协议识别未知,不做版本双轨或第二权限来源。
最终 head 验证:190 项 Python 回归(97.68s)、55 项 TS、typecheck:control-plane、Ruff、diff/身份/DCO 和 Goal-bound standard premerge 19/19 全通过,无 skip、warning、manual hold 或预算延长。既有真实 File oracle 在 immutable base 的 canonical 提交后准确失败于 False is None,修复路径保持一次 Host/提交。新增相同 CLI oracle blob 24b5bcfeb1b507e2dd088b3bc6dc0be75340a9c0 在旧 head 39684b7659a05d59b131d4e87a5cdf45e656faf3 失败 True is False(7.11s),新 head 通过(1.28s)。它检查 journal 字节不变,并禁止 Host、状态/业务写回与 spend 路径;不是用 mock 成功回执证明提交。
本 PR 的产品入口是现有 CLI 错误/inspection JSON 与 Markdown,已实际运行。没有 dashboard 布局、设置或配置字段变化,不需要新增 UI source;frontend/Lark 全体委派闭环仍由既有 companion 负责。本次未运行 packaged browser/Lark、外部模型或全仓测试,不以 API 或测试数量声称整体产品完成。
我的整体评价
APPROVE,限于该 exact head 的异常读回和原 journal 契约一致性修复。全 PR 判断是有价值、边界合理的 justified increment:持续工作中的恢复更可信,用户能看见真实错误及原身份;shared predicate 减少重复规则,TS 保持决策权威。独立审阅反例已修复并实际 old/new 证伪,不继承旧结论。通用 discovery/admission/task binding、跨仓库 lease namespace 与 frontend/Lark 读回仍未闭环,父 Agent 的证据语义拒绝也不能因此撤销。作者自检不替代用户指定任务的最新 head 独立批准,未批准不合并、不升级。
English verdict: APPROVE - 49ac1fc; truthful nullable error effects and original recovery now share the writer's TS prepared-attempt contract. The old-head public CLI counterexample fails and the new head passes without writes or reinvocation; 190 Python, 55 TS and 19 premerge checks pass. Author self-review is not independent approval; broader delegation/product qualification remains open.
Goal And Delivered Outcome
turn run-oncecan raise after Host execution or canonical writeback. The CLI exception renderer replaced every effect withfalse, even when the original journal already contained Host and validation checkpoints. A caller could mistake a failed reply for non-execution and start another task.null. A separate allowlistedjournal_observationprojects the original Turn checkpoints and recovery decision through the existing TS journal owner.preparedand malformed attempts remain unknown, never invented commit receipts.main. Related to the existing recovery protocol in fix(turn): recover ambiguous settlement effects without duplicate execution #3412. It does not reimplement provider recovery or loosen permission rules; the inspector now shares the original writer's prepared-intent validation.Scope And Continuation
Validation
49ac1fcccc5f372e70b99347bd25a7dc7dbf04c5unitpassedintegrationpassedreal_backendpassedreal_entrypointpassedregression_paritypassedfd96e5e2574272262b9ea604a96581a0d20e94d1and the final head. Base fails specifically atFalse is Noneafter the real canonical commit; head passes and verifies same-Turn recovery without another Host invocation. Only the independent test oracle was copied into the isolated base; its production source was unchanged.regression_paritypassed24b5bcfeb1b507e2dd088b3bc6dc0be75340a9c0fails on prior PR head39684b7659a05d59b131d4e87a5cdf45e656faf3atTrue is Falsefor journal consistency, then passes on current head. Unknown prepared intent now gives blocked/no-reinvoke/unknown, matching the original writer denial. Only the oracle was copied into the isolated old-head checkout; no production changes or journal writes.manualpassedstaticpassedgit diff --check; no private runtime artifacts in the branch.staticpassedloopx canary premerge --from-git-diff --git-diff-base fd96e5e2574272262b9ea604a96581a0d20e94d1 --tier standard: all 19 checks passed, no failures/skips/warnings/manual holds; validation is not merge authority.See validation disclosure guidance.
Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
recorded_effects; exceptional invocation effect booleans can now benull.Boundary Checklist