Skip to content

fix(benchmark): preserve native process evidence before cleanup - #7707

Merged
huangruiteng merged 2 commits into
mainfrom
codex/native-process-evidence-20261030
Oct 30, 2026
Merged

huangruiteng merged 2 commits into
mainfrom
codex/native-process-evidence-20261030

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

A native Codex app-server stream failure was recorded after the benchmark worker had already cleaned up its process group. The cleanup signals made it difficult to distinguish an earlier child exit from wrapper-initiated shutdown.

Record the child PID and Linux start identity, first transport failure, process status before cleanup, requested cleanup signals and final observed status. Persist each edge in an atomic owner-only native-process.json snapshot and include it in the wake receipt. The observer wraps the shared stdio transport; launch, RPC ownership, retry and cleanup policy stay with their existing owners.

A null pre-cleanup return code remains unknown. A signal observed only after cleanup does not establish a native crash, exit 0 does not prove an outstanding transaction completed, and SIGKILL does not establish OOM. No task text, arguments, environment, stderr or raw exception messages enter the snapshot. Observation write failures preserve the runtime exception and child cleanup.

Validation:

  • 8 new real-subprocess tests cover clean/nonzero EOF, signal death, a live child closing stdout, an unfinished tool turn, intentional cleanup, durable first-failure retention, privacy and persistence failure.
  • 167 related existing cases passed; 64 optional/environment cases skipped. Five fixture-import failures in the initial run passed when rerun with the existing tests directory on PYTHONPATH: 175 distinct passing cases overall.
  • Changed-file Ruff, whitespace/RFC checks, Python compilation and all 9 selected premerge canaries passed across the initial run and a targeted dependency retry. The semantic canary initially lacked TypeScript; it passed after npm dependency installation.
  • All four changed files passed the public-boundary scan. The combined local registry check still reports unrelated authority-health errors; it is not reported as wholly passing.

The new schema and cleanup-trigger strings are local process observations, not a shared fault-classification vocabulary. Runtime documentation describes the observation limits; no new independently callable capability or UI is introduced. No live model calls were made. Historical attempts remain frozen, and new experiment adoption requires independent review, an approved source/profile and real-chain qualification. The benchmark-sensitive maintainer-review hold remains.

Signed-off-by: huangruiteng <huangrt01@163.com>

@songoow songoow 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 Astra Pro | OpenAI | self_reported

REQUEST_CHANGES — 1 项 P2:真实精简分发遗漏新增模块,native Goal worker 无法启动。 审阅 head a3d3403e8bb5ccbc2ed6e0e4be3e996c0145b947,merge-base a36e01c32b0a290a96466c766629a0b01850f823;完整阅读 4 个改动文件并追踪了未改动的 source staging 调用者。

动机 / Motivation

受影响的是使用 Harbor 或共享 benchmark worker 运行 native Goal、并调查中断原因的实验操作者。

原先 native 进程关闭输出后,操作者可能只能看到清理后的退出结果;这次改动在首次传输失败和清理前后各保留结构化快照,让两类事件可区分。

完整源码环境里的新观察行为已得到真实合成子进程验证,但实际非LoopX精简归档缺少新增模块,native Goal worker会在模型调用前直接失败。

这项观察不判定 OOM、任务完成或根因,不产生重试/结算权,也不声称提高模型分数或长时实验收益。

改动思路 / Approach

现有 stdio transport 继续拥有协议,worker 继续拥有进程组清理;新增对象只在事件边沿记事实。这比在清理后从一个信号猜原始原因可靠。first_failure 不能从最终 poll() 重建,因而保留这一有限历史不是第二套任务状态;写失败只记异常类型,也不应覆盖原始事务失败。

观察属于现有runner的诊断投影,不应成为启动原生任务的新安装障碍。 保留被动观察和原cleanup owner,在同一PR修复实际分发闭包并覆盖隔离worker;无需新增控制框架。

我检查了 codex_stdio、现有 native_codex_goal receipt、child_process/_reap_child_process,以及 BenchmarkCodex._stage_source 的精简归档和独立 product/runner revision 边界。协议与cleanup都已复用;当前缺口发生在新增 helper 的部署位置。仅runner使用的观察器可以放进既有 benchmark/runtime 分发路径,或者完整补齐相应归档及overlay闭包,不需要扩成一个新的通用进程控制框架。

具体改动 / Changes

关键代码讲解

  1. NativeCodexProcessObservation 保留开始时点、Linux start ticks、首次失败、清理前状态、请求发送的信号与清理后状态;缺失数据保持 null,异常正文仅留 hash,快照通过临时文件原子替换。OSError 不替换原异常。
  2. ObservedStdioNativeGoalTransport 对 request、notify、next_event 调用原实现,只在异常处记录后原样抛出;没有新增JSON-RPC重试、重新解释完成结果或扩大权限。
  3. child_process/_reap_child_process 在原有 finally 清理链前后观察;其他调用者默认 process_observation=None。原信号与wait规则仍由worker持有,观察不能成为cleanup成功证书。
  4. run_native_goal 创建observer、把快照接入 receipt.native_process,run_once 指定wake下的文件;但这里新导入的 native_codex_process.py 没有进入 NATIVE_GOAL_SOURCE_PATHS。因此测试checkout与实际非LoopX任务环境行为不同。

总计 407 新增、8 删除,包含 149 行observer、worker接入、181行新测试和32行operator说明。新测试覆盖退出0/23、信号、仍存活的EOF、未完成工具、正常完成、首次失败不可替换、持久化失败;说明明确不追补历史证据,也不把SIGKILL认作OOM。

既有规格采用 docs/architecture/rfcs/long-horizon-harness-benchmark-research-program-v0.md,修订 0ad08b15dd7331051c93566075561a390a9cd7e2。本次标签 native-authority 对应原生runner/verifier/score保持权威,typed-observation 对应观测应来自真实事件/receipt;观察模型本身符合这两项。它们不免除既有可运行分发入口,也没有要求本PR证明模型成绩或整个研究路线图。

对主干的风险 / Risks

P2,benchmark/runtime/worker.py 第339–342行:请补齐真实source staging闭包。 BenchmarkCodex._stage_source 对非LoopX worker只打包 benchmark/runtime、native_codex_goal.py 和 codex_stdio.py。新增helper位于另一product文件,未被带入。当前archive测试只import旧的 native_codex_goal,所以无法发现 run_native_goal 执行时才触发的新依赖。

我直接调用生产 archive_source,读取源码里实际的路径清单,再用 python -I -S 从解包结果执行真正的 benchmark.runtime.worker;只有native app-server使用合成协议fixture,没有Docker、安装或模型调用。相同脚本的结果如下:

入口 merge-base 当前head
完整checkout,合成native Goal完成 exit0 / complete exit0 / complete,并新增观察
生产精简archive,同一成功任务 exit0 / complete exit1 / ModuleNotFoundError,receipt.ok=false,无普通worker stdout
普通plain worker exit0 / ok,无native_process 相同

失败明确指出缺 loopx.capabilities.benchmark_toolkit.native_codex_process,发生在任何模型交易之前。请在正确owner补齐分发,并把隔离archive回归推进到实际worker执行;也覆盖既有product/runner分离部署,不应要求操作者手工向容器补文件。

本轮pytest首组选定结果为131通过、64个可选provider案例跳过、5个fixture顶层import失败;新增8例全过。那5例在不可变base上同样缺 test_loopx_turn_codex_cli,使用仓库现有的 PYTHONPATH=.:tests 后head同5例通过,因此它们与新归档回归分开记录。git diff --check通过。远端pytest聚合job只是检查上游CHECKS_RESULT/SHARDS_RESULT,不能当成新增测试缺陷;本轮没有完整归因所有远端失败,也不把跳过当作通过。

语义与 CI 对齐

新schema是诊断词汇扩展,未赋予retry、任务完成或结算权。实际违反的是现有native worker的部署可运行性。需要修复的是新增导入触发的归档缺口,再运行隔离archive及8个进程观测案例;无须放松测试、信号策略或benchmark结果合同。

我的整体评价 / Verdict

被动观察设计具有正向价值,基本体量也合理;当前分发缺口让实际native Goal无法开始,构成长程工作与操作者体验回归,所以不能因完整checkout测试通过而批准。修复应保持同一scope、原stdio协议与cleanup owner,解决分发闭包即可。真实模型收益、长时写入成本和完整Harbor/SForge矩阵仍未验证。本次检查的 benchmark/runtime/worker.py 与 RUNTIME.md 不改变已渲染的产品页面;无需用截图证明内部行为。 未进行产品页面视觉检查,因为本次没有页面改动。

English verdict: REQUEST_CHANGES — a3d3403e8bb5ccbc2ed6e0e4be3e996c0145b947 has one P2 deployment regression: the non-LoopX native worker archive omits the newly imported observation module. The same isolated worker succeeds on the immutable baseline and fails on this head before any model call; full-checkout process tests pass. Optional provider and live-model qualification remain unverified.

Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

已在 125d132af 修复该 P2:

  • 将 native_codex_process.py 加入真实 NATIVE_GOAL_SOURCE_PATHS,非 LoopX Harbor worker 的精简归档不再遗漏新增运行时依赖。
  • 扩展隔离归档回归,在 python -I -S、无 editable checkout / site-packages 掩盖的条件下同时导入 native_codex_goal 与 native_codex_process。

验证:带 Harbor 的实际 benchmark 环境下,隔离 staging 回归与 native process evidence 共 9 项通过;扩大到三份相关测试文件为 191 通过、4 跳过,另 5 项因该外部测试环境未把 tests/ 加入顶层模块搜索路径而失败,均发生在未改的 test_codex_operation_host 辅助导入,和本次 source bundle 闭包无关。Ruff、diff check 通过;两份变更文件的 public-boundary scan 均 clean。完整 loopx check 仍被本机全局 registry 的历史 Goal 迁移欠账阻断,未把它记作本 PR 通过。

@huangruiteng
huangruiteng requested a review from songoow October 30, 2026 16:06
huangruiteng added a commit that referenced this pull request Oct 30, 2026
Signed-off-by: huangruiteng <huangrt01@163.com>

@huangruiteng huangruiteng 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 · OpenAI · self_reported

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

动机 / Motivation

Benchmark operators diagnosing a native Goal or LoopX Goal run after its app-server stream fails need to know whether the child had already exited or the wrapper later stopped it.

Before this change, an EOF followed by worker cleanup left only the cleanup signal; after this change, the receipt records the first transport failure and process status before cleanup, then records cleanup separately.

A native Goal wake now contains the same bounded native-process snapshot in receipt.json and native-process.json, without replaying a request, restarting the child or claiming a root cause.

This PR does not infer OOM, assign fault, retry work, alter scores, retrofit historical attempts or change non-native worker modes.

这项修复解决的是证据顺序,而不是为失败自动定责。当前 exact head 125d132affbe4bc44822d36826382884a5a898e2 在旧行为最容易误判的场景中,先保留 transport failure 与清理前进程状态,再单独记录 worker 发出的清理信号;因此它是一个完整且可独立采用的诊断改进。

改动思路 / Approach

现有 worker 继续拥有进程 launch/cleanup,现有 StdioNativeGoalTransport 继续拥有 JSON-RPC。新增 observer 只在这两个边界旁采样事实:transport 抛错时写入不可替换的 first_failure,进入清理前写入 before_cleanup,随后记录请求的信号与 after_cleanup。它不重放请求、不重启子进程,也不决定 retry 或 fault attribution。

架构判断是 retain:The current boundary keeps the correctness invariant in the worker, protocol IO in the shared transport and the receipt as a passive projection; it does not introduce optional policy or a second decision owner. 当前 PR 边界是:Capture and document process evidence only; fault attribution, retries, score countability and historical reconstruction stay outside this PR.

与只记最终 return code 的更小方案相比,这个设计多保留了一个关键因果边:当 stdout 已关闭而进程仍存活时,后续 SIGINT/SIGKILL 来自 wrapper cleanup,不能倒推为 native failure。observer 的持久化失败也只写入 persistence_error_type,原异常与进程回收仍由既有 owner 处理。

具体改动 / Changes

规格依据是 docs/architecture/rfcs/long-horizon-harness-benchmark-research-program-v0.md,固定修订 0ad08b15dd7331051c93566075561a390a9cd7e2。RFC-§1-native-authority 要求 benchmark-native runner/verifier/score 保持权威;RFC-§11.1-typed-runtime-observation 要求 toolkit 只提供 typed runtime observations,不获得 runner/model/verifier/score authority;RFC-E1-failure-distinction 要求 native receipt 保持 public-safe 并区分执行链各类失败。当前 head 分别通过无定责的 process schema、被动 transport wrapper 和进程/清理分边测试实现这些触及本 PR 的准则,不把整个 E1 或真实模型收益宣称为已完成。

关键代码讲解

  1. NativeCodexProcessObservation(loopx/capabilities/benchmark_toolkit/native_codex_process.py:32)维护 schema-versioned、content-free snapshot。failure() 只接受第一个失败;started() 在 Linux 上尽力读取 start ticks,读不到就保持 unknown;每一步发布 deep copy,避免后续边改写旧观察。
  2. ObservedStdioNativeGoalTransport(同文件 :106)复用共享 stdio transport。request、notify、next_event 只在异常路径记录并原样抛出,因此成功返回、request count 和 retry owner 不变。
  3. child_process(benchmark/runtime/worker.py:131)在既有 finally 回收路径中加入 before/signal/after callbacks。即使 observation write 抛 OSError,子进程仍被回收;scope exception 也继续向上传播。
  4. run_native_goal(同文件 :328)把同一 snapshot 写入 receipt.native_process 与 wake-local native-process.json,只对 execute-stage native Goal lane 安装 observer。
  5. 当前 head 把 native_codex_process.py 加入 NATIVE_GOAL_SOURCE_PATHS,并通过 python -I -S 的精简归档导入测试验证。它直接修复旧 head 中 Harbor worker 找不到新增模块、无法启动的 P2 finding。

行为披露清楚:过去 native wake 没有这份证据;现在 native-goal 与 loopx-goal 默认生成它。旧 receipts 允许缺字段,非 native modes 不安装 observer,文档也明确禁止从 snapshot 推断 OOM、评分有效性或 fault ownership。

对主干的风险 / Risks

主要回归风险是 observer 自己改变原执行:重复 RPC、吞掉原异常、在写文件失败后跳过清理,或把 cleanup signal 误记成 first native failure。当前验证逐项覆盖了这些反例:focused suite 为 8 passed / 1 platform skip;normal completion、exit 0/23、SIGKILL、live-child EOF、unfinished tool transaction、first-failure immutability 与 persistence failure 均走真实本地 subprocess/process-group 边界。隔离归档测试还证明非 LoopX Harbor 包在 python -I -S 下能同时导入 Goal 与 process modules。

扩大 affected suite 先得到 134 passed、51 expected skips 和 5 个 collection failures;这 5 个失败来自调用入口缺少 PYTHONPATH=tests,同 5 项按仓库入口重跑全部通过。Ruff 与 git diff --check 通过。这里不把它描述为 whole-repository pass,也不伪造最初失败的其它根因。

Remote packet 生成时 13 checks success、21 pending、没有 reported failure。Pending CI 继续构成独立 merge-readiness hold;它不推翻当前 changed invariants 的本地证据。测试中的 app-server 是 synthetic script,因此这些结果证明 worker/stdio ordering,不证明生产模型为何退出。

语义与 CI 对齐

native_codex_process_observation_v1 是 benchmark-local diagnostic vocabulary;它复用 subprocess/transport 的现有事实源,不进入 Goal authority、scheduler 或 scoring contract。文档把 enforced capture 与 operator interpretation 分开,缺失终态/start ticks 仍为 unknown。当前 exact head 未发现未对齐的共享语义;CI 完整性仍由 merge gate 单独核对。

我的整体评价 / Verdict

这项改动改善 long-horizon 失败诊断:它让昂贵长跑在 wrapper cleanup 之后仍保留 causal ordering,同时不改变运行、continuation、retry 或 score。对 operator journey 也有直接收益:从一个 wake receipt 即可区分“清理前已终止”“清理时仍存活”和“证据不完整”,不必依赖 stderr 猜测。视觉审查不适用,因为没有 rendered UI;未验证范围是生产模型/provider 的实际退出原因。

415 行 diff 中,330+ 行属于 adversarial tests 与公开边界文档;生产机制保持在既有 worker/transport owner 附近。旧 finding 已由 staged source path 和 isolated import regression 直接关闭。综合 exact-head source inspection、正反 real-subprocess tests、archive import、Ruff 与 diff check,我没有发现需要阻止 approval 的 current defect;远端 pending checks 仍需在 merge readiness 中完成,且本 review 不授予 merge authority。

English verdict: APPROVE 125d132affbe4bc44822d36826382884a5a898e2. The prior staged-archive blocker is fixed, the passive observer preserves first-failure/cleanup ordering without replay or new authority, and focused real-subprocess plus isolated-import validation covers the changed invariants; pending remote CI remains a separate merge-readiness hold.

@huangruiteng
huangruiteng merged commit 04c5799 into main Oct 30, 2026
29 of 38 checks passed
@huangruiteng
huangruiteng deleted the codex/native-process-evidence-20261030 branch October 30, 2026 16:55
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