Skip to content

fix(update): publish result before terminal progress - #8065

Merged
huangruiteng merged 1 commit into
mainfrom
codex/publish-update-result-first
Nov 5, 2026
Merged

huangruiteng merged 1 commit into
mainfrom
codex/publish-update-result-first

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

Prevent background update observers from announcing completion before the authoritative result is readable.

The unchanged worker on main 886f2cdff4b2daad642f08f1b9bcffc0edf66359 writes terminal status.json before result.json. A concurrent read_operation() can therefore return failed or succeeded without a result, and observe() can falsely report interruption. This appeared in the Runtime snapshots qualification for #8064: the existing detached-upgrade refusal test reached its expected failed state but raised KeyError: result.

  • Persist the existing authoritative result atomically before publishing best-effort terminal progress.
  • Keep the existing reader, payload format, lock lifetime and CLI ownership.
  • If final progress publication fails, readers still recover the completed result. If result publication fails, the worker never advertises successful completion.
  • Add six deterministic regressions that inspect the actual worker/reader write boundaries for successful and failed updates. No sleeps, retries, weakened assertions or skipped failures.

中文:修复后台更新先写终态、后写结果导致观察者提前退出的竞态。先持久化结果,再尽力更新进度;保留原有读路径和安装所有权。

Author Declaration

Written by: model_agent, OpenAI Codex, under the user's direction. No human review is claimed.

Implemented against the existing update-operation completion contract and a reproduced CI/product race. Both affected files are byte-identical between the tested base and latest main 6a92640346051b79d08fb369354180b613c8fa46; this is independent of #8064's snapshot-layout change.

Criterion Disposition Evidence
Completed readback always includes its result implemented Real worker and read/observe functions checked before and after each actual atomic write, for success and failure
Progress failure cannot discard the completed result implemented Injected final status-write failure preserves authoritative readback
Result failure cannot announce completion implemented Injected result-write failure propagates before any terminal status write
Original installation and detach contracts remain intact preserved Existing real detached update/upgrade and activation tests retained and passed

A separate read-only review of the identical committed content tree found no blocking findings.

Validation

Published head: 966384a49c334ce8a95bc9b31cdf50ecaff6dfde.
Content tree: bf5806a2fac8b33344a2dbffac59693f23bc1d19, identical to locally reviewed/tested commit d8431eb4d068b0aa8fbddc4d48ebc168680e949c.
Input classes: synthetic, public_fixture.

  • Regression proof: all six new cases fail against the unchanged baseline and pass with the repair.
  • Focused operation module: 24 passed, repeated on the exact published remote head.
  • Update/activation scope: 261 passed, 3 existing native-Windows skips across operation, runtime activation/download, artifact resolution, update ownership, Chat and host activation.
  • Changed-file Ruff, diff checks, bilingual RFC gate and public-boundary check: passed. Public-boundary output retains existing warnings.
  • Configured mypy (python -m mypy --no-incremental) without a source PYTHONPATH override reproduces existing task_orchestration_admission.py:110 no-any-return. A run with PYTHONPATH set to the worktree returned green; that environment-dependent result is not treated as CI-equivalent qualification. No typing fix is included here.
  • Standard selected premerge: 7/8 catalog smokes passed; existing CLI output-budget probe fails for missing interaction_contract, scheduler_hint, selected_todo. Direct checks, compile and maintainability passed.
  • Full Ruff reproduces existing E731 at tests/test_manager_context_roundtrip.py:289; not included in this repair.
  • Hosted Runtime snapshots qualification associated with the published head passed (GitHub's PR merge ref into main 6a926403), including update ownership, frontend/runtime construction, clean installation and upgrade (run); publication was correctly skipped for the PR. DCO and Dependency Review passed. Python Tests stops at the existing E731 lint finding, with dependent gates not qualified. Release Artifacts is still running. Full repository pytest was not rerun for this independent two-file patch; no aggregate green result is claimed.

The scope run initially lacked the repository launcher on PATH for host activation's bare loopx subprocess. With the documented source launcher on PATH, the complete scope passed. Source import paths were verified to the tested worktree.

Scope And Continuation

This is a self-contained completion-ordering repair, not an update protocol redesign. No new state, schema, dependency, permission or retry policy. Two files only; existing tests are unchanged. It does not fix unrelated repository qualification failures or alter #8064's publication proposal.

UI impact: none; no rendered frontend changes. Shared-authority RFC fixture impact: N/A.

Boundary Checklist

  • Public-safe diff and description, with no private state or credentials.
  • No release publication, deployment, merge, paid-model run or user-machine change.
  • No unrelated baseline fixes, gate relaxation or new skips.
  • No paired RFC change.
  • DCO Signed-off-by included.

Signed-off-by: Codex <codex@openai.com>

@loopx-agent loopx-agent 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: actor_kind=model_agent; model=gpt-6.1-sol; provider=OpenAI; declaration_source=runtime_reported; reasoning_effort=max.
Exact head: 8065@966384a49c334ce8a95bc9b31cdf50ecaff6dfde

动机

通过 CLI 更新 LoopX、随后等待或重新连接进度的用户。原 worker 先写“已完成”的进度、再写最终结果,观察者可在两次写入之间误报中断;新顺序先原子保存最终结果,再尽力更新终态进度。跨进程观察者在终态窗口读到完整结果,进度写失败仍可读回,结果写失败不会先公告完成。本 PR 不改变安装执行、更新授权、跨进程锁或重试规则,也不声称修复其他 Host 提示词或全部仓库检查。

审查先读已有合同 docs/guides/installing-loopx.md,不可变 revision 886f2cdff4b2daad642f08f1b9bcffc0edf66359,条款 Stable, main and source builds。Owned update worker survives observers; final stdout/result or running descriptor is authoritative, progress is not completion, failures/interruption remain visible and status cannot replay installation. 本次落实既有“进度不是最终结果、状态读取不重放安装”的要求,没有重写合同以匹配测试。

改动思路

复用既有 worker、原子文件写入和观察器,只调整事实与进度的发布顺序;不新增锁、状态机或重试框架。本次边界为既有更新操作的最终结果先于终态进度持久化;安装权限、执行、锁和重连 owner 保留。 原 worker 先写“已完成”的进度、再写最终结果,观察者可在两次写入之间误报中断;新顺序先原子保存最终结果,再尽力更新终态进度。 既有权限和失败 owner 继续负责拒绝与恢复,本次没有增加准入、配额、Host 切换或自动重试权限。 这一不变量对原有所有更新默认生效,不是需要另设开关的可选特性;最终事实已可读后,尽力写进度仍可安全失败。

具体改动

改动共2文件,+93/-1;生产仅将原有结果写入移到终态进度之前,并增加两行解释,余下是90行回归测试。复用既有 worker、原子文件写入和观察器,只调整事实与进度的发布顺序;不新增锁、状态机或重试框架。本次边界为既有更新操作的最终结果先于终态进度持久化;安装权限、执行、锁和重连 owner 保留。 实际 CLI 的 update/upgrade 仍调用 start_or_observe 和 observe,--status 仍只读。atomic_json 继续用原临时文件、fsync 与 replace;没有引入“看到终态即可跳过结果”的第二规则。

  • worker:Own original installer and publish result。原 worker 先写“已完成”的进度、再写最终结果,观察者可在两次写入之间误报中断;新顺序先原子保存最终结果,再尽力更新终态进度。
  • read_operation:Read authoritative final result。Unchanged; final result wins status even if status write fails.
  • observe:Bounded observable operation outcome。Unchanged; now terminal cannot outrun actual result publication.
  • start_or_observe:Reattach without duplicate worker。Unchanged worker-lock exclusion applies even when result already exists.

正向路径中,原安装器返回的成功或失败 payload 先持久化,观察器立即得到同一完整结果,进度写入失败也不会遮蔽结果。反向路径中,结果写入失败会先退出,不能先把状态公告为完成。已经存在的 kernel worker lock 仍覆盖整个 worker 生命周期;在结果已可读而 worker 尚未退出时,重复更新也只重连现有操作。

独立验证使用真实子进程 worker、原子文件、内核锁、read_operation、observe 和 start_or_observe,只替换未改安装器的返回值以避免改用户安装。分别暂停在真实终态写入之后、注入终态进度 IO 失败、注入结果 IO 失败,每种覆盖成功/失败结果:head6个场景符合预期;base复现4个缺陷反例,另2个进度失败控制本来正确。锁内重连未启动第二个 worker,所有子进程已回收。

纠正测试文件清单后的6模块命令得到 head244 passed/5 failed/3 skipped、base238 passed/5 failed/3 skipped。五个失败都是未改 Traex 可见 Goal 提示词禁止 heartbeat 一词的原断言;完整37499字节规范化失败块相同,相关测试、Host renderer、配置和 lock 内容未变。最初命令误列两个不存在的测试文件,exit4且未收集用例,该记录保留;后来的实际清单命令覆盖了原本要验证的模块,并没有把整个矩阵称为通过。改动文件 Ruff 通过。

对主干的风险

此改动保证发布顺序,不会消除磁盘故障或恢复安装器本身;结果写失败仍须如实表现为中断。核心风险是错误地把 status 当最终事实,或在锁尚持有时启动第二个安装;真实跨进程窗口、两种 IO 失败和锁内重连已分别验证。未更改真实安装 provider,因此独立 worker 测试没有重复安装;不把这些结果外推为 Windows 或所有 Host 的资格。

必需验证保持失败:uv run --extra test python -m mypy 在未改 task_orchestration_admission.py:110 报 no-any-return;配置范围的完整 Ruff 在未改 test_manager_context_roundtrip.py:289 报 E731。基线与两个 exact head 的完整输出分别208字节、697字节逐字一致。标准 premerge 的6项 direct checks 通过,8项 catalog 检查7项通过;此 diff 未选 risk/public-boundary 检查。 唯一所选失败是 CLI-output-budget-regression:独立同命令固定 base/main 到 886f2cdff4b2daad642f08f1b9bcffc0edf66359,在 base measurement 阶段、尚未比较 head 前就缺 interaction_contract、scheduler_hint、selected_todo;三个 revision 的完整失败在仅规范化源/临时根路径后2688字节一致。相关因果源、测试、配置与 ignored lock 未改。归因说明本 PR 没有引入这些失败,不豁免必需门;change-quality cqr_adce16222cdc7564f7a3 仍为 FAIL。未查询、轮询或等待 CI,也未执行合并。

我的整体评价

APPROVE:当前 head 未发现需本 PR 修复的阻断性问题;独立跨进程基线反例证明了修复价值,写入失败和重连负例均保留原执行边界。 已检查实际 CLI 更新、状态与观察器调用路径;没有渲染页面或布局变化,视觉评审不适用。 unverified_scope: none。代码批准与 change-quality、必需验证及合并权限分开;不把测试数、review 或包资格当作已部署、长期效果或完整成本收益的证明。

English verdict: APPROVE. The exact-head change is supported by independent base/head boundary evidence; required quality failures remain on hold. No merge performed.

@huangruiteng
huangruiteng merged commit 7a8388f into main Nov 5, 2026
22 of 28 checks passed
@huangruiteng
huangruiteng deleted the codex/publish-update-result-first branch November 5, 2026 03:19
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