Repository navigation
Preserve the original predecessor when a saved native capture is presented twice - #8109
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
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
动机 / Motivation
通过 CLI 恢复已保存任务决策的用户和 Agent。第一次展示的通知丢失后重试同一捕获,旧实现会把当前捕获当作自己的比较基线;暖重试也不再展示相对原前驱的变化。新实现让冷重试返回完整来源,让暖重试继续使用原前驱。旧实现仍然保留当前完整文件,并未在本次对照中丢失内容;问题是重复展示的比较关系退化,无法继续解释原前驱到当前的变化。这个边界比“修复通知丢失”或“证明模型读过旧内容”窄。
同一真实 CLI 负载中,head 通过冷/暖重试、下一捕获、前驱丢失、压缩和显式关闭等 10 项检查;两个版本的全部 20 次完整恢复内容都与原输入一致。不重新准入、不扣槽、不替换 Goal 权威或证明模型读过文件;没有证明生产环境发生过通知丢失,也没有量化模型采纳或完整成本收益。当前提交仍有两项与基线相同的旧测试失败,CQR 保留 FAIL;10 个需要显式 native Codex 配置的测试未执行,已安装宿主和实际模型效果未资格化。这是可独立回滚的展示层增量,完整恢复与实际采用继续分开验收。
改动思路 / Approach
公开入口 quota context-project 先校验保存决策的 Goal、Agent、Turn 和字节摘要,再进入既有私有 session journal。Python 负责读取拥有权和摘要已校验的物理文件,TypeScript 继续负责 scope、版本、epoch、上下文摘要和完整重建的判定;不是把权威或策略搬到 Python。
当再次展示同一捕获时,适配器使用上次成功 delta 留下的原前驱引用,而不是最新 offer 自己。只有成功的 captured_file delta 才保存该引用;它只是 path/sha256/target 三元组,不复制整份上下文或递归保存历史。每次先发布当前完整 recovery,再做可选编码;前驱不可用时完整恢复,不能回到旧决策。共享 codec 的生产与恢复入口也拒绝文件自引用,旧 wire 得到同一当前完整正文。
当前边界保留现有私有 journal 和共享 TS codec,一个有界派生前驱引用已足够;没有新日志、配置、通知协议或第二权威。本次只审查这五个文件的完整 base-to-head,不把 #8100 联合试验、真实 Host 采纳或 provider cache 问题算作已交付。只加生产端自引用检查虽然更短,却会使暖重试总是完整回退,丢掉有用的原比较关系;当前边界复用既有锁和读取器,成本与问题相称。反过来,自引用 delta 在数学上仍可从完整文件恢复,不能据此宣称过去发生了数据损坏。
具体改动 / Changes
完整审查范围是 base 12803354ab13a003de8620ab496250617224ff37 到 head 9de6605602908d6258ceafaaf9a32ec15023505b,五文件 +80/-4,其中生产代码 +13/-2、测试 +67/-2。书面依据为 docs/reference/required-work-context.md,不可变版本 12803354ab13a003de8620ab496250617224ff37;它在本补丁中没有改写。以下是评审映射标签,分别对应既有条款,不创造新验收义务:
immutable-current-recovery:缺失、变化、不安全或不兼容的基线应恢复同一当前完整来源。当前恢复 owner、真实删除前驱及完整正文对照覆盖,已实现。file-comparison-not-retention:保存文件比较不要求模型完整读过旧文件,也不能证明模型保留。实际序列未提供模型读回执,仍正确展示和恢复,已实现。epoch-scope-no-new-effects:保留 consumer/epoch 隔离、原始身份和无重准入/扣槽的恢复。压缩后的新基线、后续暖比较、显式关闭和 absent registry/runtime 反例覆盖,已实现。
关键代码讲解
_native_context_request发现目标是同一捕获时改读原comparison_base;仍调用现有私有文件校验,不把 journal 字段当作模型读回执。普通下一捕获继续使用最近的完整当前来源。project_codex_context在原锁内先保存完整当前 recovery,只有成功文件 delta 才留下原前驱三元组。full/缺失前驱/新 epoch 沿原完整恢复路径,不新增日志或手动同步。encodeContextDelivery与restoreContextDelivery只对captured_file的同 capture ID 增加 guard;使用既有 full/automatic recovery,不拒绝用户的完整源内容。confirmed-input/native-hook 分支没有被这项条件扩大。- 成本测试的 observer 仅补转发已经存在的
hook_session参数;基线的该测试因 observer 签名旧而 TypeError,head 实际路径通过。这是测试接入修正,不是给 codec 伪造成功后置条件。
独立运行同一组真实 CLI 子进程,使用隔离的 POSIX journal、不可变 JSON 和实际 TS runtime;没有模型调用或模拟 codec 结果。原始输入包含完整长文本、Unicode、原 receipt、选择、null/空值、顺序和未知控制字段。十个步骤在每个版本都逐次读取当前完整 recovery,并与独立构造的原输入作全值比较;20 次均一致,原源字节未改变,也未创建 registry/runtime。夹具指纹为 5ba8ba9952d3d03062352deb5297da76377cb8ae3ddcd00eb5c9cdb6715b90f4。
| 同负载步骤 | 基线 | 当前提交 |
|---|---|---|
| 冷捕获首次/重试 | full → 自引用 delta | full → full |
| 暖捕获重试 | 比较对象变成当前自己 | 继续指向原冷前驱 |
| 下一新捕获 | 使用最近完整来源 | 同样正确推进 |
| 丢失原前驱后重试 | 仍产生自身比较 | 当前完整恢复 |
| 压缩后/后续新捕获 | full / 新 epoch delta | 相同安全行为 |
| 显式关闭 | 原正文、journal 字节不变 | 相同 |
基线五项比较关系期望失败,head 十项全部通过;这说明回归 oracle 能检出旧问题,而不是只看到 JSON 能解析。新 legacy-wire 测试通过真实 TS codec 验证同 ID 旧 delta 自动恢复完整正文;34 个直接 TS 回归也通过。
对主干的风险 / Risks
没有发现当前头的阻塞性实现问题。最强风险是失效/跨 epoch 前驱使恢复指向旧来源,或新字段逐步长成另一套状态权威;实际反例验证了当前全文、后续捕获和显式关闭,三元组保持有界,最终兼容性仍由既有 codec 判定。这里复用已有 context_delivery_v1/captured_file 词汇,新增字段属于私有派生 IO 元数据,不新增 Enum、共享状态分类器或用户义务。
验证没有被报成全绿:配置内 mypy(17 文件)、四个改动 Python 路径 Ruff、npm run typecheck:control-plane、34 个 TS codec 测试均 PASS。三个改动 Python 测试模块完整运行结果为 head 139 passed / 2 failed / 10 skipped,同命令不可变基线为 136 passed / 3 failed / 10 skipped。两项当前失败分别是省略设置时断言 runtime 绝不创建,以及省略设置却假定旧式 mode/path 返回。它们的函数/断言未被本 PR 修改,两份完整失败记录仅归一化 pytest 临时编号与对象地址后逐字一致;没有删掉断言、错误或控制字段。基线另外一个 hook_session observer TypeError 在 head 通过。
这两项继承失败仍保持 FAILED。精确范围 CQR cqr_b54cc6614fcd9fd07704 保留 FAIL,未豁免必检;quick premerge 整体 exit 1,原生 gate 为 quality_invalid_receipt;六项直接检查、语义词汇和 quota-plan 检查通过。raw maintainability ratchet 返回失败,由原生 runner 标为 advisory_inherited_failure;本评审没有独立完成它的全量 base/head 归因,不把该失败改称通过。实现批准不解除这些合并门槛。相关 #8100 已在同两个旧测试上区分 omitted/auto/off 的预期,本次只检查相关 patch,没有资格化联合分支,不要求此小修复重复承包该工作。
十个 skipped 是需要显式 native Codex 配置的 loopback 集成,本次没有执行。隔离 hook 事件与真实 CLI/文件/TS 的证据支持这一层,不能替代已安装 App、实际模型输入或自然通知丢失的资格。没有声称生产通知确实丢失,亦没有把作者与 #8100 的联合 Responses 试验当成本头的独立结果。
我的整体评价 / Verdict
批准这一完整五文件实现范围:它改善了重试时可解释的比较导航,同时保留完整当前来源、独立身份和原无副作用恢复。长期续跑在已测序列中保留正确前驱/epoch 行为;CLI 用户能继续看见相对原前驱的变化。未验证的实际模型采纳、完整 wall/CPU/内存/补读/token/费用与长期有用成果仍保持未知。
视觉检查不适用:改动仅限 native 文件展示、共享 codec 和其测试;检查了公开 CLI caller,没有渲染页面、首屏或可见 UI 文案变化。未验证范围仍包括显式 native Codex loopback 集成、已安装 App 和实际模型行为。没有默认开关变化,也没有安装、信任或新的执行权限。
两项当前红测已用真实基线独立归因,不能被追认为通过;它们不是本补丁引入的回归,因此不把修复无关旧预期作为实现批准条件。CQR/本地 merge gate 与后续正式合并资格仍单列,当前结论不授予合并或上线权限。
English verdict: APPROVE the exact-head implementation. Matched real CLI evidence supports the predecessor/recovery fix; inherited test failures and the strict CQR merge hold remain visible and unwaived.
Presenting the same immutable quota decision twice could offer a delta against itself. A saved file is not evidence that the model read it. On a warm retry it could also displace the actual predecessor and force full recovery.
Keep one verified predecessor reference for the current file-backed delta. A retry of the first capture produces a full view; a warm retry can still compare against its original predecessor. A missing predecessor or changed epoch yields the independently readable current capture. The shared codec also rejects legacy file-backed self-deltas during reconstruction. This changes presentation only: it does not run a new guard, debit quota, change capture frequency or enable eager delivery.
Validation: reproduced the cold full→self-delta on the base. The saved-capture CLI and codec regressions now cover cold/warm retries, missing predecessors, compaction, and legacy wire recovery. The native progressive integration passed on this branch; combined with #8100, a local Responses receiver completed cold and warm cases in which the fixture deliberately suppressed hook output and forced asynchronous reads with the expected original receipts and task selections. No paid model calls. Two older tests that assume an omitted setting always means off also fail on the unchanged base; #8100 updates those expectations.
The missing output was fault injection in an isolated native-client test. No production instance of a lost notification was identified. This PR neither adds a notification protocol nor explains provider cache misses.