Repository navigation
fix(memory): recover validated App outcomes after refresh replay - #6735
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; model=gpt-6.1-sol; provider=OpenAI; runtime_reported; reasoning_effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
完整评审 6735@921dcbf9c5645fb7d16a5379bb263aaf7c97ec0f,实际基线 f9bdae6。当前增量 APPROVE;已有广域 strict mypy / change-quality hold 及后续原生合并门保留,不据此合并或更新共享安装。
动机
已经为指定 Goal 中的指定 Agent 启用自动记忆写入的维护者与 Codex App 调用方。
首次刷新已经记录工作结果,但反思暂存失败;旧版重试虽然验证成功,后续扣额仍只看第一次事件中的空指针,经验一直无法写入。当前头让相同身份的重试重新找到私有候选,并在两步结算均已读回后继续。
同一合成文件快照的实际 CLI 对照中,补交反思的三条旧路径都停在暂存;当前头都能到达写入钩子。启用后的受控存储对照进一步得到一次写入和精确读回,重复刷新及扣额不增加账目。
本次只修复已存在的自动钩子,不新增学习服务、配置开关或 UI,不认证共享默认安装、真实 OpenViking 持续运行、跨宿主或记忆的因果效用。
安装采用、真实服务的持续重试与净效用仍由既有 Reward Memory 验收继续;本评审也保留已有的独立 change-quality 质量门。
改动思路
精确身份和绑定比较只有一个 TypeScript owner,Python 保留现有验证子进程、私有文件与 provider IO;继续复用原有结算读回和幂等写入器,比改写历史账目或新增补偿队列更小。
当前 PR 完成原自动钩子的暂存失败和结算后补交恢复,不扩张配置、宿主覆盖或一般记忆调度。
旧事件已提交时,不应通过“修补第一次事件”补上候选指针。当前把 Goal、Agent、Todo、Turn 与结算 effect 的确定性查找键放到同一 typed owner;反思内容和目标绑定另行冻结。刷新重试重新执行当前任务声明的独立验证器,再保存其结果,较早的一次成功不覆盖当前失败。扣额钩子和结算后的刷新恢复都读回同一组原始结算凭证,再调用现有写入器。没有第二个 provider writer、配置选择器、后台任务或通用补偿框架。
下面是独立执行的同快照对照,启用组的外部 provider IO 明确使用受控替身;真实 CLI、配置摘要与 Agent 门、验证子进程、File authority 和 TypeScript 结算没有替换。
| 原始操作与恢复 | 基线写入次数 | 当前头写入次数 | 两边扣额次数 |
|---|---|---|---|
| 首次正常提交有效反思 | 1 | 1 | 1 |
| 首次暂存失败,扣额前重试 | 0 | 1 | 1 |
| 首次暂存失败,扣额后重试 | 0 | 1 | 1 |
| 首次未附反思,扣额后补交 | 0 | 1 | 1 |
当前头四例再执行相同刷新与扣额,provider 新增写入均为零,结算后的 run index 和 rollout event 字节保持不变。关闭功能的另一组五例全部没有外部写入;不附反思的普通路径也没有新 ingestion 字段。已经存在意图和授权时,恢复不要求新的设置、确认或手工 ingest;遇到真实配置变更则仍走既有的窄作用域恢复门。
具体改动
完整净提案为 9 文件、+523/-136:5 个产品文件 +231/-136,3 个测试文件 +279,1 个 README +13。已通读全部改动及未变的 outcome_lifecycle、配置/Agent selector、私有验证声明和结算消费者。新模块仅为 53 行 typed identity/binding 规则;主要 Python 变化替换原候选实现,没有据 LOC 宣称完成语言迁移。
关键代码讲解
rewardMemoryAppOutcomeIdentity:由原结算五项身份派生稳定键,查找不再依赖第一次暂存是否成功。每个身份字段变化都会改变键;内容摘要独立冻结,不能换一个反思来覆盖同一结算。bindRewardMemoryAppOutcome:复用当前选中的 Agent policy,保存目标绑定 fingerprint 与验证声明摘要。重放逐项比较;只有显式重新验证能更新验证声明,不能借此改反思或改目标。兄弟 Agent 的无关声明不会改变本候选。stage_codex_app_turn_outcome_candidate:在候选自身的跨运行时锁下读取、验证与保存私有 sidecar;总是保留当前验证结果。验证器必须证明相同反思摘要和证据引用,仅退出零不足以允许写入。候选仍是 mode 0600,原始反思不进入公开投影。run_staged_codex_app_turn_outcome_ingest:按同一个键定位私有候选,重新比较当前声明和绑定,并要求刷新、扣额两项实际读回;然后复用既有 outcome writer。精确旧指针仅是兼容查找,不给缺少绑定 stamp 的旧候选补造权限。刷新 handler 的 late-finalize 和 spend adapter 共用这条路径。
独立规范先固定为 loopx/capabilities/reward_memory/README.md,spec_revision: f9bdae6。本 PR 新增的 README 段落仅作行为披露,不反过来定义验收。
- Lifecycle completion boundary — implemented:真实、有证据的结果应幂等写回,不要求隐藏的第二开关;补交恢复和重复执行通过实际命令链验证。
- Independent Agent bindings — implemented:当前 Agent 的显式选择、禁用和无效 override 不回落;绑定变更不能复用候选,兄弟声明不使候选误失效。34 项配置/作用域测试和 typed 负例通过。
- Codex App — implemented:沿用私有候选、任务原声明的精确摘要/证据 attestation,以及刷新、扣额的相同身份读回。24 项聚焦测试与独立真实 CLI 对照共同覆盖。
- Experimental activation — implemented:已有每 Goal/Agent 的默认关闭门保留;存在 CLI、候选或成功结算不等于启用 provider,失败也不阻断普通工作。
整体路线与既有 roadmap S6/S9 的证据、记忆和权限分离相符。此次是已存在调用链的恢复修复,没有新增用户配置操作;设置页、Lark 或 App 的新交互不在 diff 中,不能因此宣布其安装采用或所有宿主记忆能力已完成。
对主干的风险
关键风险是恢复时重复扣额、覆盖原反思、转移目标或沿用旧验证成功。当前证据包括失败/缺失的原始暂存、扣额前后恢复、正常首写、重复刷新和扣额,以及九个身份/绑定字段破坏、反思篡改、缺少任一结算凭证、验证声明变更、验证器由成功变失败和 legacy unstamped 等负例。异常仍由已有 fail-open owner 返回,不把 provider 故障升级为用户执行门。
独立正常构建 wheel/sdist 并检查全部五个改动产品文件与源树逐字节一致;隔离 wheel 的 CLI 路径另外验证。没有绕过 Chat assets 的正常构建校验。受控 provider 检查证明调用链、一次写入与精确读回规则,不证明真实 OpenViking 的网络、持久化或长期运行质量;作者所报真实服务实验也没有被冒领为本次独立复现。这里没有实际共享安装升级、App 宿主唤醒或 Windows 资格。
独立源码验证为 184 项 Python 测试、8 项 TypeScript 测试、控制面 TS typecheck、仓库声明的 17 文件 mypy 通过。原生 premerge 的 6 个直接检查和 19 个选择检查中,18 个选择检查通过;唯一失败是默认 CLI 输出比较使用后来的 origin/main,基线与当前头出现完全相同的四条 heartbeat 输出增长失败:brief +4 行、compact +9 行、full JSON +1502 字符、full Markdown +1488 字符/+32 行。完整失败明细逐字相同,受影响的 heartbeat 生产路径没有被本 PR 修改。用已支持的 LOOPX_CLI_OUTPUT_BASE_REF 和 LOOPX_CLI_OUTPUT_MAIN_REF 同时固定到实际基线后,同一完整 CLI 检查通过;没有改门限、删场景或压缩指令。初次默认 gate 的失败原件仍保留,没有把整次运行改记成绿色。
另一个独立门仍需如实保留:PR 报告额外广域 strict mypy 为基线 4898、当前 4895 个错误;作者的完整对照认为三项修复、未新增错误。该完整失败签名不同,不满足 change-quality 的 identical-failure waiver。我没有将它记成通过或批准该豁免;本次独立通过的是仓库声明的 17 文件工作负载。已有质量 hold 和原生合并判断继续独立约束交付。未查询、轮询或等待远程 CI。
语义与 CI 对齐
复用已有候选、reflection、validation、settlement 与 Agent binding 词汇;新增 typed key/bind 是同能力内部规则,私有历史 stamp 不是第二配置源或新共享 actor 生命周期。开发期 advisory 在完整语义检查前运行,支持语法内检测到 0 项新词;完整 semantic/native checks 也通过,但它们不代替上面的真实恢复反例。通用控制面没有加入产品/benchmark 特定义务,也没有把机器强制校验叫作建议。
我的整体评价
当前头交付的是一个有用、完整且可回退的恢复增量。long_horizon=improved 限于同一结果不会因第一次暂存缺失而永久搁置,并能在后续相同身份重试中恢复;user_experience=improved 限于复用已知任务、配置和授权,免除手工 ingest 或额外扣额,不等于证明记忆提升了后续判断质量。
future-facing pass 已应用于相邻身份边界:删除 Python 的 key hash,stage/finalize 共用一个 typed owner;保留现有 Python 验证/文件/provider adapter,是因为仍有真实调用方。原普通 Turn writer、App 两阶段候选和历史只读兼容分别有实际用途,不为抽象而合并,也不要求无关全量迁移。
本头 APPROVE,没有发现需要本 PR 再修复的新增阻断。原始默认检查失败及归因、已有广域 strict-mypy/change-quality hold、后续 closeout/readiness、维护者合并与安装权限均保留。此处的 COMMENTED approval 是同登录账号下独立 Agent 的完整评审记录,不是 GitHub formal self-approval,也不授予合并或升级权限。
English verdict: APPROVE - 921dcbf. Real File/TypeScript CLI replay pairs recover late or failed App staging with one debit; the controlled-provider pair writes and reads back once, and repeated refresh/spend adds no effects. 184 Python tests,8 TS tests,declared mypy/typecheck and the full actual-base CLI workload pass; normal packaging is checked. Preserve the original unpinned-budget failure and its identical baseline attribution, the separate broad strict-mypy/change-quality hold,and all merge/install/host/real-provider utility gates.
An App refresh can commit while optional memory staging fails. A later refresh replay validates the reflection, but the immutable first rollout event still has an empty candidate pointer, so spend never reaches ingestion.
Resolve the private candidate by one TypeScript-owned key for the exact settlement. Serialize staging/finalization, freeze the reflection and destination binding, and check the current Todo validation declaration. A validated refresh retry can also finish ingestion after spend has already committed. Accounting and rollout receipts remain unchanged; retries reuse the existing configured writer and its deduplication.
Validation:
The additional strict mypy invocation over three CLI/adapter entrypoints and their transitive imports remains failed. Independent immutable runs at base
f9bdae67596c185cebc81dc555dd6a3e0242e9c5and head921dcbf9c5645fb7d16a5379bb263aaf7c97ec0fused the same command, lockfile, Python and package versions, with separate source checkouts and environments:The full diagnostic multiset was compared. Eight head-only diagnostic lines correspond to byte-identical source lines shifted by this diff; referenced definition positions were checked too. Three old errors are repaired by the reflection-reference list guard and the settlement-readback
Noneguard. No introduced error identities were observed in this matched workload. Full observations retain every error and its multiplicity.This is a causal diagnosis, not a passing strict check. The complete failure signatures differ by the three repaired errors, so they do not satisfy the current change-quality contract for an identical-failure baseline waiver. The failed observation and quality hold remain. The separate repository-declared 17-file mypy workload was rerun on the immutable head and passed; it does not cover this broader import graph.
This restores the existing configured automatic hook; there is no new UI, provider, configuration switch or manual ingestion path. Unstamped legacy candidates are held. Packaged/installed adoption and memory utility remain unqualified. This PR does not authorize installation or merge.