Skip to content

fix(trajectory): preserve attempt receipts across rejected reuse and retry preparation - #8368

Merged
huangruiteng merged 3 commits into
mainfrom
codex/preserve-trajectory-attempt-on-rejected-reuse
Nov 10, 2026
Merged

huangruiteng merged 3 commits into
mainfrom
codex/preserve-trajectory-attempt-on-rejected-reuse

Conversation

@loopx-agent

@loopx-agent loopx-agent commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator

Problem and outcome

通过 CLI 或研究分析 API 读取、复用和重试轨迹评估的用户。 已有失败或成功评估被复用校验拒绝时,旧代码会把历史回执改成新的失败;重试准备阶段又可能把唯一回执移走。现在历史 attempt 持续可读,准备失败后恢复原状态,只有真正开始的新 attempt 才拥有新的失败。

实际 CLI 的 status 保留原失败及 usage;普通 execute 不会偷偷重跑,明确 retry 后得到 attempt 2,原回执字节和历史附件仍在。

Design and scope

继续使用单一 execution.lock、原子 receipt 写入和现有 attempt 编号。把“准备操作失败”与“新 attempt 已开始”分开;归档时复制回执而非移走,其他产物在未开始时可逆归位。最小修复不是吞掉异常,而是让 status 始终能解释最后一次已发生的执行。

本次只修复评估执行的回执与归档生命周期,保留明确重试和原有崩溃锁检查,不增加新的持久化状态机。

本 PR 不改变评估评分、模型选择或显式 retry 权限,不自动清除崩溃留下的 execution lock。

Validation

51 passed;覆盖真实子进程、CLI status/execute/retry 及实际 HTTP API,模型提供者是隔离的确定性夹具。

Reproduction: uv run --extra test python -m pytest -q tests/capabilities/test_trajectory_assessment.py tests/presentation/test_research_analysis_api.py

Ruff/diff hygiene 与 exact-head canary direct/run checks 无失败;manual_hold_count=1。手工 benchmark/authority 判断由本次完整评审执行,不把该 hold 写成自动通过。

未调用付费模型,未宣称解决 SIGKILL 后的锁恢复或跨附件崩溃原子性。

Reviewed head: 058f8ae731c0b8628348910a1e60e17a5bd51604. Historical timing claims or failures are not reused as evidence for an unmeasured final implementation.

Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent, gpt-6.1-sol, OpenAI, runtime_reported, reasoning_effort=max

Request changes conclusion (author-owned PR; GitHub blocks formal self-review)

当前 head c0cbebc2dfabe7cccde99aa07ca7a6894128fcfa,目标 base 5090afc2a3516ad678f29d2328d8b3295dc2653d。

动机 / Motivation

研究人员从 CLI 或 Goal 研究面板重新打开同一份轨迹分析时,会复核已保存的输出。base 上若输出损坏,复核失败会把原成功回执改成失败,修复输出后仍不能直接复用。原结果的状态与耗时因此失真,用户还可能为同一次分析再发起 provider 调用。

当前 head 拒绝损坏输出时保留原成功回执,恢复有效输出后能直接复用。这批改动限于既有结果的复核与尝试记录,模型输出资格由原有校验器决定。这个修复也承诺保留显式重试前的上一轮回执。归档后的准备失败仍会使当前回执从正常读写入口消失。

改动思路 / Approach

CLI 与研究面板的 HTTP 调用共用 trajectory_assessment.execute。它持有同一 analysis_key 的锁,从当前回执决定复用、拒绝或显式重试,再调用 provider。把写失败回执的条件收敛到本次 running 回执已经持久化,能保护复用资格检查中的历史状态。重试需要把同一提交边界延伸到归档与当前回执的切换,防止仅有归档时被识别为全新任务。现有 job 目录与锁足以承载这条规则。

具体改动 / Changes

4 个文件共 +134/-1。执行器 +5/-1,文档补充中英行为说明,测试覆盖 CLI、HTTP 及 provider 启动失败。目标分支共同祖先之后的改动未触及这些文件。

关键代码讲解

  • execute 在旧结果资格检查失败时跳过回执重写。原结果恢复后,普通执行复用同一 attempt,provider 启动数维持 1。显式重试会先把 receipt.json 和产物移至 attempt-N,随后才写输入和新的 running 回执。执行路径
  • read_job 从 job 根目录读取 receipt.json,HTTP 的 inspect_pack 在该文件缺失时也没有当前 job。单独存在的 attempt-N 归档不会挡住普通执行。回执 reader · HTTP 读回

按 base 已接受的规则,validated-reuse 已实现,explicit-retry-preserves-prior 在下述故障路径未满足。规范同时要求保留实际观察到的用量,并以显式 --retry 进入后续尝试。原用量与归档规则 · 原重试与状态规则

对主干的风险 / Risks

[P2] 重试准备失败后,普通执行会绕过 --retry。 从一次已记录用量的失败 attempt 开始,在临时 job 目录把 input.tmp 设为目录,让显式重试在完成归档后写输入失败。真实 CLI 在 base 与 head 都返回写入错误,归档回执字节完好,但 trajectory-assessment-status 已读不到当前回执。清除故障后,普通 --execute 将同一 job 作为 attempt 1 启动合成 provider,重复占用 attempt 编号。此顺序在 base 已存在,且直接影响本 PR 承诺的重试保留边界。归档和输入写入顺序

最小修复是在当前 job 仍可读时完成准备,再切换上一轮归档与新的 running 回执,或在切换失败后恢复可读的上一轮状态。回归测试应在第一次归档写入后注入失败,验证状态可读、原用量和耗时可取、普通执行拒绝、显式重试才进入 attempt 2。运行 uv run --extra test pytest -q tests/capabilities/test_trajectory_assessment.py tests/presentation/test_research_analysis_api.py,并用实际 CLI 读回这条负例。

语义与 CI 对齐

本地两套定向测试分别为 base 42 PASS、head 50 PASS。标准 premerge 的 6 项直接检查和 15 项选中检查无失败,另有 benchmark 人工检查门。归档后失败的 CLI 反例两边均为 FAIL。已有重试准备测试触发的是归档目录冲突,发生在任何回执移动之前。远程 CI 未查询,provider 启动和用量来自合成子进程。

我的整体评价 / Verdict

这是 justified_increment。成功回执的复用修复已有实际读回,用户恢复原输出后可继续使用结果。长程用量与历史连续性仍受重试故障影响。本次改动涉及 CLI 和现有 HTTP 读写结果,diff 无界面布局或样式变化。未观察已安装界面与真实模型。应保留现有 trajectory_assessment_job_v1 状态和显式重试规则,在同一执行器内完成回执切换;复核下一 head 时以归档后失败的读回和调用次数为准。

English verdict: REQUEST_CHANGES. Rejected reuse preserves the successful receipt. Retry preparation can still remove the active receipt and let ordinary execution relaunch without explicit retry. Preserve the prior attempt across that failure.

…pair-20261110

Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng huangruiteng changed the title fix(benchmark): preserve completed attempts on rejected reuse fix(trajectory): preserve attempt receipts across rejected reuse and retry preparation Nov 10, 2026

@huangruiteng huangruiteng left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent, gpt-6.1-sol, OpenAI, runtime_reported, reasoning effort max

动机 / Motivation

通过 CLI 或研究分析 API 读取、复用和重试轨迹评估的用户。 已有失败或成功评估被复用校验拒绝时,旧代码会把历史回执改成新的失败;重试准备阶段又可能把唯一回执移走。现在历史 attempt 持续可读,准备失败后恢复原状态,只有真正开始的新 attempt 才拥有新的失败。

实际 CLI 的 status 保留原失败及 usage;普通 execute 不会偷偷重跑,明确 retry 后得到 attempt 2,原回执字节和历史附件仍在。

本 PR 不改变评估评分、模型选择或显式 retry 权限,不自动清除崩溃留下的 execution lock。

改动思路 / Approach

继续使用单一 execution.lock、原子 receipt 写入和现有 attempt 编号。把“准备操作失败”与“新 attempt 已开始”分开;归档时复制回执而非移走,其他产物在未开始时可逆归位。最小修复不是吞掉异常,而是让 status 始终能解释最后一次已发生的执行。

本次只修复评估执行的回执与归档生命周期,保留明确重试和原有崩溃锁检查,不增加新的持久化状态机。

入口为 trajectory assessment execute/status 与研究分析 HTTP API;权威输入来自 analysis key、execution.lock、receipt.json 和 attempt 归档,由 既有 trajectory assessment execute 决定,结果交给 CLI status、API analysis readback 与原 usage。attempt_started 与 prior_archive 是单次执行的局部控制信息;权威事实仍为原子写入的 receipt 和独立归档,无新增人工标注。 相同领域的可逆精简已经在本次完成;没有把职责搬成另一套平行规则。

具体改动 / Changes

关键代码讲解

execute:attempt_started 区分历史复用拒绝、准备失败与真实新执行;复制回执并在未开始时恢复归档。 输入来自analysis key、execution.lock、receipt.json 和 attempt 归档,下游为CLI status、API analysis readback 与原 usage;失败由准备失败恢复旧附件;运行后失败属于新 attempt;崩溃锁仍人工核对处理。

read_job:status 只读取当前持久回执,不依靠调用方临时对象推断上次执行是否存在。 输入来自analysis key、execution.lock、receipt.json 和 attempt 归档,下游为CLI status、API analysis readback 与原 usage;失败由准备失败恢复旧附件;运行后失败属于新 attempt;崩溃锁仍人工核对处理。

规格依据:docs/reference/trajectory-assessment.md,固定修复前版本 e7ae4b077c0a2da0791753c9be3f7e4ff0b59b6e。映射标签 attempt-history:失败需要显式 retry,旧 attempt、错误与实际 observed usage 必须保留,status 可读。 —— implemented,验证来自公开测试入口 uv run --extra test python -m pytest -q tests/capabilities/test_trajectory_assessment.py tests/presentation/test_research_analysis_api.py。该标签是本次评审的映射名,不伪称规格原有编号。

差异形态:production: 1 files +22/-2; tests_or_fixtures: 2 files +152/-0; docs: 1 files +12/-0; generated: 0 files +0/-0; mechanical_moves: 0 files +0/-0。不使用 retry 的已有成功复用与失败拒绝路径都保留;未开始不增加 attempt,真实新运行失败仍增加 attempt。

对主干的风险 / Risks

跨多个附件的归档不是一个文件系统事务,突然进程退出可能留下需要核对的 execution lock;本修复保留回执并处理普通异常,不虚称完整 crash recovery。历史 usage 和失败原因不能因为后续入口拒绝而被覆盖。

正向:首次失败保留 observed usage;显式 retry 成功提交 attempt 2,同时可回读 attempt 1。 负向与恢复:input.tmp 是目录导致归档后的准备写入失败;status 仍读到原 attempt,普通 execute 拒绝隐式重试,移除障碍后显式 retry 正常运行。

验证:51 passed;覆盖真实子进程、CLI status/execute/retry 及实际 HTTP API,模型提供者是隔离的确定性夹具。 Ruff/diff hygiene 与 exact-head canary direct/run checks 无失败;manual_hold_count=1。手工 benchmark/authority 判断由本次完整评审执行,不把该 hold 写成自动通过。 历史失败保留为反例,不把新 head 的通过反写成历史通过。GitHub CI 与合并策略是单独的 readiness 判断;本结论不从红绿状态推导代码正确性。

未调用付费模型,未宣称解决 SIGKILL 后的锁恢复或跨附件崩溃原子性。

合并读回:该精确 head 已合入,merge commit 为 ed4dd993cbcd15d7d5f36ebe6ddb69b144192943。合并前 readiness 为 ready=false,GitHub 检查汇总 {"pending": 23, "success": 11};review conclusion 有效、线程完整且 unresolved=0。 依据维护者对本批“自修复自合并”的明确授权使用 admin bypass 处理策略/CI 等待;必需本地验证、已修复发现的核对与精确版本评审单独完成。

我的整体评价 / Verdict

最终评审版本为 058f8ae731c0b8628348910a1e60e17a5bd51604,检查覆盖整个剩余 diff 与当前调用方,不仅是最后一条 comment。实际 CLI 的 status 保留原失败及 usage;普通 execute 不会偷偷重跑,明确 retry 后得到 attempt 2,原回执字节和历史附件仍在。 本次只修复评估执行的回执与归档生命周期,保留明确重试和原有崩溃锁检查,不增加新的持久化状态机。 上述已有缺陷均有入口级反例与恢复读回,未发现仍需阻止本次交付的具体问题。

已检查 loopx/capabilities/benchmark_toolkit/trajectory_assessment.py 及现有消费者,本 PR 不改变渲染布局或内容层级;本次验证集中于入口、状态与恢复。 没有对已安装 App、真实个人账号或付费模型作额外观测。

本 PR 不改变评估评分、模型选择或显式 retry 权限,不自动清除崩溃留下的 execution lock。 合并仍需该版本的远端 head、未解决线程、旧阻塞评审与 readiness 读回;本评审不自行赋予合并或付费执行权限。

English verdict: APPROVE. Head 058f8ae. The bounded fixes preserve existing authority and recovery contracts; the stated untested boundaries are not claimed as verified.

@huangruiteng
huangruiteng merged commit ed4dd99 into main Nov 10, 2026
11 of 34 checks passed
@huangruiteng
huangruiteng deleted the codex/preserve-trajectory-attempt-on-rejected-reuse branch November 10, 2026 04:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants