Repository navigation
fix(context): keep fallback recovery bound to the current capture - #7291
Conversation
Persist current full recovery before optional projection and candidate updates. Invalidate stale native selectors on publication failure or same-session context loss, and retain the original receipt and capture in typed CLI errors. Cover oversized warm RPCs and IO/identity faults through compact and resume. Clarify the enabled recovery failure contract in the host documentation. Related to #7196. Signed-off-by: song <liusongstep@gmail.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max
APPROVE,针对 2ea61dbf37d08096cbc37d9b246b9cf00355f722。当前捕获恢复的已复现缺陷得到有界修复;无新增阻断发现。严格质量、旧 required 失败和人工合并门仍独立保留。
动机
受影响的是显式开启原生上下文传输、在压缩或续接后继续同一个任务的用户与 Agent。
同一会话先保存捕获 A,再返回带有新停止条件的捕获 B;旧版在可选呈现或写入失败后仍可能恢复 A,使后续工作丢掉已经交付的新条件。
独立同输入对照中,旧版 18 个组合有 14 个错误地重新选择 A;当前版本全部 18 个组合均恢复当前内容、拒绝旧查询,或明确报告传输失败。
本 PR 只修复现有原生适配器的捕获恢复一致性;没有安装 App、真实模型采用、完整成本或跨平台原生运行资格。
五条旧 lint 诊断和一个旧调度夹具失败仍未通过,严格质量与 benchmark 文档人工检查继续保持合并门槛。
改动思路
保留现有共享 TypeScript 编码器、不可变捕获 IO 和私有会话 journal,在可选呈现之前提交当前恢复引用;这比新增状态协议、扩大 RPC 上限或重写编码器更贴合故障边界。
本 PR 只修复现有原生适配器的捕获恢复一致性;没有安装 App、真实模型采用、完整成本或跨平台原生运行资格。
完整原件和恢复引用先提交,编码、candidate 与展示 wire 的更新随后进行。只在无法保存当前恢复时撤销本适配器拥有的旧 journal;撤销也失败就显式失败,携带当前原件和原 receipt。不能把这个错误当作没有准入而重新运行 guard。单纯去掉 baseline 重试不能处理写入失败和工作目录恢复后的旧引用复活,因此这里保留同一 owner 的两阶段顺序是必要的。
| 触发 | 旧版 | 当前头 |
|---|---|---|
| 真实 warm 请求超过 RPC 上限 | 已返回 B,压缩/续接仍选 A | 返回并恢复 B |
| 当前 recovery / candidate 写失败 | 后续选 A | 分别拒绝旧查询 / 恢复 B |
| 同会话暂失 cwd、身份或 epoch | 恢复环境后 A 复活 | 旧查询拒绝 |
| 不同原生会话 | 保留其自己的 A | 同样保留,不能冒充 B |
| recovery 与撤销同时失败 | B 成功但 A 留存 | 非零 typed failure,读当前显式原件 |
表格是实跑对照的概括。正常 full candidate 路径增加一次原子 journal 提交,完整 projection 只保存一次;本轮没有端到端耗时或完整成本收益结论。
具体改动
完整审查 7291@2ea61dbf37d08096cbc37d9b246b9cf00355f722 相对 aca16646c65076a8bbbc53086e0bff11122649da 的十文件 +504/-80:四生产文件 +138/-59、四测试 +345/-15、两文档 +21/-6。当前目标主干固定 a9a720db5ef77f52ac9a3c1e59be7df324149aa6;其后续文章与图片变更不涉及本 owner。全部 diff、当前讨论、DCO 和公开边界已核对。
按修改前的默认关闭、完整原捕获恢复合同及 7196 合并后审计判断,没有用本 PR 改写后的说明自证。原条款没有编号,下列是审查映射标签:same-capture-recovery、unsafe-publication-visible、source-receipt-integrity、default-off-isolation 均 implemented,分别由持锁当前引用、现有 typed error、真实 receipt/readback 与关闭态/跨会话对照覆盖。
关键代码讲解
-
project_codex_context:先保存当前完整捕获及恢复引用,再做可选编码和 candidate 更新;恢复写入失败时撤销旧选择器。
-
_discard_recovery:只在既有私有根锁内移除本适配器拥有的 journal,拒绝不安全文件;不跟随符号链接删除其目标。
-
capture_context_projection:复用原子完整捕获写入和摘要固定读取命令;native caller 传入已发布引用,避免再写一份投影。
-
_emit_quota_result:原始 decision 在呈现前保留;即使 Turn 外壳没有 receipt,失败输出仍带原 receipt 与当前保存路径,并返回非零。
-
project_saved_context_capture:准备失败显式返回 typed error 与当前原件;已经安全发布 recovery 后的可选 wire 写失败仍可回完整原件。
对主干的风险
同一独立 harness 在两个不可变源码根运行:18 个组合覆盖 compact/resume、journal/candidate 写入、身份与 cwd 恢复、epoch、foreign session 和真实 RPC 大小限制;原捕获 A 全字节保持。warm 案例同时验证实际 native trace 发现和完整输入 verifier,未用文件存在冒充保留证据。初版私有 harness 的 trace 目录未进入 trace-* 发现范围,其 warm 两行已排除;修正后两臂完整重跑得到上表结果,原记录仍保留。
完整 TypeScript 为 5,484 passed /75 skipped,类型检查通过。八个 Python 模块为 263 passed /53 skipped;实际 File/SQLite quota 与 Turn 入口在失败后保留同一 decision/receipt,只有一次准入、零次 spend,原件与状态字节不变,显式读取可恢复当前原件。synthetic native trace 与 IO 故障注入不等于真实 binary 或模型采用;全部条件跳过仍是未验证范围。改动的八个 Python 文件 Ruff、配置内 mypy17、required CLI 输出差分及 diff 检查通过。
required Ruff 另有五条 E701/E702,在不可变 base 与当前头的完整输出逐字节相同,全在未改的 attached-conversation 测试。调度 smoke 在两臂也以同一夹具、同一位置、同一完整错误失败:canonical_authority_required,发生在 todo_snapshot、尚未进入本次 native projection。该对照仅规范化源码根和 rollout event 的 id/时间,保留所有错误、决定及恢复字段。失败不是绿灯,也不要求本 PR 修复无关模块。
语义与 CI 对齐
当前标准 premerge 六项 direct 通过,19 项选中检查中18通过,失败仅为上述旧调度 smoke;另有一个 benchmark 文档人工检查。严格 cqr_d071dc25b93aecb3abf0 记录 FAIL,verify 为 invalid_receipt,整体 quality_invalid_receipt 保持。APPROVE 表示当前改动与有界修复通过独立判断,不能覆盖这些门或授予合并权限;未查询、等待或轮询 CI。
没有新增共享状态词汇:复用原 journal、context_delivery_v1 和既有 quota_decision_transport_failed;两个 bool 是局部已完成 IO 的派生事实。diff advisory 在其支持的四个变更源文件中未发现新词汇载体,这不证明覆盖全部语义。关闭态在全部共享改动入口保持无 native IO;显式开启后的不安全准备改为非零错误是有意变更,正文及两个调用者均明确说明。完整来源、停止条件和不得重新准入的义务没有降成可选 guidance。
我的整体评价
交付判断为 justified_increment;long_horizon 与 user_experience 均 improved,实证是后续恢复不再静默丢失新停止条件,并能在故障时沿当前原件继续或清晰停止。模型理解、实际任务成果、已安装 App、Windows 原生与完整成本仍未资格化,不能由测试数和 receipt 数推导。
代码量与故障族相称,复用 capture helper 和原 verifier 的有界重构已落实;不需要新增缓存、协议或迁移框架。新 helper 与调用者同包发布,已有 journal/capture 字段兼容,无新持久化状态。当前头未发现需要代码修复的阻断;旧 required 红项、严格质量和人工门保留给其原 owner,合并前仍须对未变精确头完成相应资格与权限检查。
English verdict: APPROVE at 2ea61dbf37d08096cbc37d9b246b9cf00355f722. The same independent base/head harness changes 14 stale-recovery failures to zero across18 cases, including real warm-RPC oversize and subsequent compact/resume. Current recovery is published before optional presentation; unsafe publication fails explicitly with the original source/receipt. Required lint and scheduler failures were independently reproduced unchanged and remain failed; strict CQR is FAIL/invalid and one manual hold remains. No installed/native model adoption, total-cost benefit or merge authority is claimed.
Goal And Delivered Outcome
修复 #7196 的合并后审查发现:显式开启 native context delivery 后,当前捕获 B 已经全文返回,但可选投影或 journal 写入失败会让 compact/resume 仍恢复旧捕获 A。
修复后的不变量:成功的全文回退只能恢复当前捕获,或明确拒绝 session lookup,不能恢复旧捕获。 无法保证这一点时,返回已有的
quota_decision_transport_failed,并保留当前原始 decision/receipt 的显式恢复路径。main,开发基线aca16646c65076a8bbbc53086e0bff11122649da。Author Declaration
Implemented against
Specification: #7196 post-merge audit,绑定原 PR head
6176a290dbc2e6d05bc2ea5089061d4080db1bce;沿用原始捕获只读恢复及不得重新准入的既有合同。codex_context.py在可选 codec 前保存 B 的不可变 projection 和 recoveryScope And Continuation
Validation
2ea61dbf37d08096cbc37d9b246b9cf00355f722,最终提交树与本地验证的代码树一致。git diff --check;canonicalpython -m mypy:17 个配置内核文件通过npm run -s typecheck:control-planecli-output-budget-regression-smoke.py;维护性检查无新增未评审债务、无幅度回退quota-scheduler-registry-route-smoke.py的canonical_authority_required,已在未修改的 mainaca1664复现。公开边界通过;benchmark 文档路径另触发既有 maintainer-review holdtests/presentation/test_codex_attached_conversation.py;同一版本工具在主分支复现这些局部通过不代表仓库全量绿色;已有失败没有被豁免,也不构成合并批准。
Frontend / Visual Evidence
UI impact: none。没有视觉界面变更;CLI 错误和恢复输出由实际入口测试覆盖。
Type of Change
LoopX Area
Shared-authority RFC fixture impact
N/A:没有 authority 存储、迁移、runtime routing 或 compatibility projection 变更。
Boundary Checklist