Skip to content

fix(subagents): reconcile native Codex host events with Turns - #5455

Open
jackie-cqz wants to merge 13 commits into
loopx-project:mainfrom
jackie-cqz:codex/fix-native-child-host-receipts
Open

jackie-cqz wants to merge 13 commits into
loopx-project:mainfrom
jackie-cqz:codex/fix-native-child-host-receipts

Conversation

@jackie-cqz

@jackie-cqz jackie-cqz commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Goal and delivered boundary

Refs #5051. Enabled, owned Codex CLI/app-server Turns record native decisions and results through the existing multi_subagent receipt owner. CLI, Lark status and the dashboard Goal drawer distinguish host observations, coordinator reports, mixed provenance and unknown activity. Parent adoption remains independent.

Review and CI repairs

  • Resume restores the latest admitted host-observed spawn or followup under the exact Goal instance, agent and Turn. Compact hashed child bindings use the existing scalar event details; private correlation does not enter public activity rows.
  • A followup without a same-Turn spawn, repeated same-child followups, completed/errored waits and old-spawn replay preserve the correct operation and parent result. Conflict checks remain enabled. Canonical log order replaces the transient correlation dictionary.
  • Reset item IDs retain durable CLI attempt/native app-server Turn bindings and exact replay semantics.
  • Move the unchanged Codex transport adapter to loopx/extensions/codex_native_child.py; active callers use that provider seam. Typed admission/settlement retain authority. Architecture exceptions were not added.
  • Reuse the portable authority directory-sync owner for Windows archive publication; regular-file fsync, verified readback and no-replace publication remain intact. Update the stale Todo overview fixture to the existing typed 420-codepoint budget without changing that budget.

Qualification

Head: 43db8d07c140c499e432859e348a2f890a9f18dd. Base/merge base: 12d60f13fe1fae6848e2bc806688f26031c8869a, PR base main. All 13 commits carry DCO sign-off.

  • Final source-installed Linux/Python 3.11: 504 passed, 2 skipped, including all demonstrated architecture, maintainability, digest, source-notice, Turn CLI, Todo recovery and vision-wait failures plus native CLI/executor/app-server regressions. Two existing gated live-host cases remain skipped.
  • The five new real-CLI subprocess recovery scenarios failed before the repair. Current Windows/Python 3.13.5 adapter suite: 22 passed, including those scenarios, exact replay and authority-negative cases. Host protocol is synthetic; actual subprocess transport, session restoration, typed admission and durable event storage are production paths.
  • Exact CI mypy 1.20.2 (19 sources), CI Ruff, TS typecheck and full semantic smoke passed; focused typed admission/context/digest tests: 55 passed.
  • Shared archive qualification: Linux File/SQLite conformance, migration and crash suites passed; actual Windows/Node 24.15.0: 373 passed, zero skipped. Isolated real PostgreSQL 16.15 store/archive suites: 335 passed, zero skipped; real service admission suite: 10 passed. This storage code is identical across all three repaired PRs and unchanged by the final rebase.
  • Rebuilt actual Chat assets and passed the packaged native-child desktop/mobile scenario. Source/build identity is current; rendering uses synthetic fixtures, paired with the real receipt backend qualification above. Existing Goal details show provenance without adding a configuration step or claiming host completion is parent acceptance.

Earlier authenticated native-host evidence retains its earlier source scope. No new paid host qualification was claimed. No private logs, sessions, credentials or local paths are included.

Remaining boundary

Feature-off preserves existing behavior. A Codex failed item does not identify a capacity subtype; unobserved external hosts remain unknown/coordinator-reported. This is the owned-host observation slice, not overall multi-host lifecycle completion. The CLI output-budget regression smoke passed on both the same latest base and this head; no budget changed. Hosted CI and maintainer re-review/merge remain required.

@jackie-cqz
jackie-cqz force-pushed the codex/fix-native-child-host-receipts branch 2 times, most recently from 5bc9078 to 9d18a1e Compare October 2, 2026 11:51
@mergify

mergify Bot commented Oct 2, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @jackie-cqz.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 2, 2026
@jackie-cqz
jackie-cqz force-pushed the codex/fix-native-child-host-receipts branch from 9d18a1e to 09e3983 Compare October 2, 2026 12:33
@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 2, 2026
@jackie-cqz
jackie-cqz force-pushed the codex/fix-native-child-host-receipts branch 2 times, most recently from 34aef42 to 00643fc Compare October 2, 2026 13:53

@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-5 | OpenAI

动机

结论:REQUEST_CHANGES。这里评的是 00643fc,而不是配置了几个子 Agent 就推断执行成功。#5051 的实际问题是原生宿主的尝试、结果与父 Agent 采纳缺少可追溯回执;这份 PR 的方向正确,但恢复路径仍丢失完成事实、合并不同跟进操作,尚未完成稳定身份和持续回读的承诺。

改动思路

CLI 与 managed app-server 的已归属连接向一个 Codex provider seam 送原生完成事件,再复用既有 native-child 事件流和 TS settlement 准入。随后同一读模型进入 agent-context、状态 Markdown、Lark 使用的状态展示及 Goal drawer。host_observed 说明决策来源,绝不说明父 Agent 已采纳;配置上限也不等于空槽或启动义务。Python 适配原生传输,TS 继续拥有准入与共享投影;没有新增调度器、peer 权限或配额消费。

具体改动

  • 「CodexNativeChildObserver.observe」(loopx/control_plane/turn_driver/codex_native_child.py:58):按 sender、terminal status 和原生工具枚举过滤,再构造稳定操作号和完成结果。正路是同一进程 spawn→wait,失败路是宿主失败或无关 sender;我通过真正的进程 stdout 传输和临时文件事件流验证,并未只 mock observer。
  • 「run_codex_cli_host」(loopx/control_plane/turn_driver/codex_cli.py:848):消费 item.completed 并在已有 Goal admission fence 内登记;恢复调用重新创建 observer。父结果原样保留,但这也是下面两个恢复缺口的真实入口。app-server 的 chat_agent 与 operation-host 回调按当前 thread/Turn 过滤,未启用时没有该回调。
  • 「native_child_activity」(loopx/capabilities/multi_subagent/native_child_receipts.py:69):从决策来源归并 host_observed/coordinator_reported/mixed/unknown,保留结果和独立 parent review。状态渲染、subagent_context、dashboard status/model 类型、drawer 及 i18n 跟随同一读模型;新 browser fixture 覆盖四态,但本轮没有完成它的浏览器复验。

完整差异为 25 文件、+493/-47:上述生产路径与类型、双语宿主契约、native/Chat/TS/browser 验证,以及 UTF-8、interrupted-Turn read-only、Windows archive/update 和安装技能集合的五个共享测试修正均已读过。它们不是启动更多 children 的授权。

P1:恢复后已有子任务完成事件被静默丢弃。 第一进程写入 child-1 的 started;同一 LoopX Turn 的 resume 进程收到 parent-1 的 wait(completed, child-1=completed),父结果正常返回,但 canonical activity 的原 spawn 没有 result。构造函数把 children 置空(:47),结果分支只查这个内存映射(:90-92),没有恢复已登记关系。原有“restart”测试重放了完整 spawn+wait 历史,不覆盖只收到新 wait 的正常恢复。最小修复是在既有回执归属下恢复可验证的 child→operation 关系,让迟到结果关联原 started 操作,而不是补造新决策或扫描任意外部历史。回归需两次真实 CLI host 调用,第二次仅 wait,完成后独立读取原 operation 的 completed,并验证未多记 launch/配额。

P1:CLI display item 编号不足以区分恢复后的 followup。 :79-80 用 parent session + item ID 哈希;真实 Codex exec 的编号是每进程从零开始,不是稳定 tool-call 身份。独立复现:两次同 Turn/同 parent 的 host 调用分别对 child-1、child-2 完成 send_input(item_0),两个父结果均正常,却只有一个 durable followup。spawn 的 receiver 哈希修复没有覆盖 followup/failed 决策。请使用可区分调用且可重放的原生身份/调用绑定,不能仅加 receiver(同 child 的不同 followup 仍会冲突),也不能每次随机号破坏重放幂等。补充真实进程 resume、相同计数器不同调用、精确重放三组回归。

本次采用改动前契约:spec_ref = docs/integrations/host-native-child-receipts.md;spec_revision = 4fc30f1。规范没有单独编号,以下以原文条款开头作为 criterion_id:

criterion_id 判定
The admitted Turn guard must already have a settlement binding 既有 TS admission 与 recorder 验证已复用;没有变成新权限源。
Use stage=decision with a stable operation-id 未满足:恢复后的 followup 身份碰撞,上述 P1。
A started operation may get a typed result 同进程正路通过;恢复仅 wait 丢结果,上述 P1。
Replay with the same identity and payload is idempotent 相同完整历史的重放通过,但不同调用也被误当重复,不能据此认定恢复完整。
A new decision requires an open, work-admitted Turn and no begun closeout recorder 保留新决定/迟到结果的 TS 分界;adapter 的恢复缺口须修,不能用放宽准入掩盖。

对主干的风险

140 项 Python 通过、2 项跳过(既有 explicit live-host release qualification,未调用付费模型);15 项 TS 通过,diff check 和语义 advisory 通过。另补跑第一宿主实际 timeout 后保存原 session 再 resume,两项缺口同样出现;base/head 未启用路径的完整结果与 activity 逐字段相同。额外真实子进程验证同进程正路、feature-off 不写原生事件、父结果保留、无原始内容保留,同时独立复现以上两项 P1。fixture 只使用合成临时状态;没有在活动 Goal 上试错。原生协议编号依据固定的 OpenAI Codex 源码 event processor,而不是从 PR 自己的输出倒推 oracle。

恢复错账会让“已完成”和“可采纳”长期不一致,或把不同任务证据挂到同一操作;配置和绿色单次 smoke 都看不出它。另保留未验证项:当前 head 的 packaged drawer 浏览器、完整跨平台和 live app-server 原生调用,本次没有宣称通过。无 CI 查询/等待,无合并。

我的整体评价

归属位置合理、体量适中,统一 CLI/app-server casing 的 seam 是有价值的有界重构;无需把这次修复扩大为通用 actor 框架或整个 TS 迁移。但 provider 必须把 transient correlation 与 durable operation identity 分清。建议在当前 PR 完成这两项相关恢复修复并重跑全路径;不要另建平行事件库,也不要把父 Agent 采纳自动化来隐藏缺失结果。修复前保留 REQUEST_CHANGES,#5051 的整体验收不关闭。

English verdict: REQUEST_CHANGES - 00643fc: two independently reproduced CLI resume defects lose completed-child facts and collapse distinct followups; 140 Python and 15 TypeScript tests passed, two gated live cases skipped. No merge.

@mergify

mergify Bot commented Oct 2, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @jackie-cqz.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 2, 2026
@huangruiteng

Copy link
Copy Markdown
Collaborator

Reviewer: model_agent | GPT-5 | OpenAI

动机

结论:REQUEST_CHANGES。这里评的是 00643fc,而不是配置了几个子 Agent 就推断执行成功。#5051 的实际问题是原生宿主的尝试、结果与父 Agent 采纳缺少可追溯回执;这份 PR 的方向正确,但恢复路径仍丢失完成事实、合并不同跟进操作,尚未完成稳定身份和持续回读的承诺。

改动思路

CLI 与 managed app-server 的已归属连接向一个 Codex provider seam 送原生完成事件,再复用既有 native-child 事件流和 TS settlement 准入。随后同一读模型进入 agent-context、状态 Markdown、Lark 使用的状态展示及 Goal drawer。host_observed 说明决策来源,绝不说明父 Agent 已采纳;配置上限也不等于空槽或启动义务。Python 适配原生传输,TS 继续拥有准入与共享投影;没有新增调度器、peer 权限或配额消费。

具体改动

  • 「CodexNativeChildObserver.observe」(loopx/control_plane/turn_driver/codex_native_child.py:58):按 sender、terminal status 和原生工具枚举过滤,再构造稳定操作号和完成结果。正路是同一进程 spawn→wait,失败路是宿主失败或无关 sender;我通过真正的进程 stdout 传输和临时文件事件流验证,并未只 mock observer。
  • 「run_codex_cli_host」(loopx/control_plane/turn_driver/codex_cli.py:848):消费 item.completed 并在已有 Goal admission fence 内登记;恢复调用重新创建 observer。父结果原样保留,但这也是下面两个恢复缺口的真实入口。app-server 的 chat_agent 与 operation-host 回调按当前 thread/Turn 过滤,未启用时没有该回调。
  • 「native_child_activity」(loopx/capabilities/multi_subagent/native_child_receipts.py:69):从决策来源归并 host_observed/coordinator_reported/mixed/unknown,保留结果和独立 parent review。状态渲染、subagent_context、dashboard status/model 类型、drawer 及 i18n 跟随同一读模型;新 browser fixture 覆盖四态,但本轮没有完成它的浏览器复验。

完整差异为 25 文件、+493/-47:上述生产路径与类型、双语宿主契约、native/Chat/TS/browser 验证,以及 UTF-8、interrupted-Turn read-only、Windows archive/update 和安装技能集合的五个共享测试修正均已读过。它们不是启动更多 children 的授权。

P1:恢复后已有子任务完成事件被静默丢弃。 第一进程写入 child-1 的 started;同一 LoopX Turn 的 resume 进程收到 parent-1 的 wait(completed, child-1=completed),父结果正常返回,但 canonical activity 的原 spawn 没有 result。构造函数把 children 置空(:47),结果分支只查这个内存映射(:90-92),没有恢复已登记关系。原有“restart”测试重放了完整 spawn+wait 历史,不覆盖只收到新 wait 的正常恢复。最小修复是在既有回执归属下恢复可验证的 child→operation 关系,让迟到结果关联原 started 操作,而不是补造新决策或扫描任意外部历史。回归需两次真实 CLI host 调用,第二次仅 wait,完成后独立读取原 operation 的 completed,并验证未多记 launch/配额。

P1:CLI display item 编号不足以区分恢复后的 followup。 :79-80 用 parent session + item ID 哈希;真实 Codex exec 的编号是每进程从零开始,不是稳定 tool-call 身份。独立复现:两次同 Turn/同 parent 的 host 调用分别对 child-1、child-2 完成 send_input(item_0),两个父结果均正常,却只有一个 durable followup。spawn 的 receiver 哈希修复没有覆盖 followup/failed 决策。请使用可区分调用且可重放的原生身份/调用绑定,不能仅加 receiver(同 child 的不同 followup 仍会冲突),也不能每次随机号破坏重放幂等。补充真实进程 resume、相同计数器不同调用、精确重放三组回归。

本次采用改动前契约:spec_ref = docs/integrations/host-native-child-receipts.md;spec_revision = 4fc30f1。规范没有单独编号,以下以原文条款开头作为 criterion_id:

criterion_id 判定
The admitted Turn guard must already have a settlement binding 既有 TS admission 与 recorder 验证已复用;没有变成新权限源。
Use stage=decision with a stable operation-id 未满足:恢复后的 followup 身份碰撞,上述 P1。
A started operation may get a typed result 同进程正路通过;恢复仅 wait 丢结果,上述 P1。
Replay with the same identity and payload is idempotent 相同完整历史的重放通过,但不同调用也被误当重复,不能据此认定恢复完整。
A new decision requires an open, work-admitted Turn and no begun closeout recorder 保留新决定/迟到结果的 TS 分界;adapter 的恢复缺口须修,不能用放宽准入掩盖。

对主干的风险

140 项 Python 通过、2 项跳过(既有 explicit live-host release qualification,未调用付费模型);15 项 TS 通过,diff check 和语义 advisory 通过。另补跑第一宿主实际 timeout 后保存原 session 再 resume,两项缺口同样出现;base/head 未启用路径的完整结果与 activity 逐字段相同。额外真实子进程验证同进程正路、feature-off 不写原生事件、父结果保留、无原始内容保留,同时独立复现以上两项 P1。fixture 只使用合成临时状态;没有在活动 Goal 上试错。原生协议编号依据固定的 OpenAI Codex 源码 event processor,而不是从 PR 自己的输出倒推 oracle。

恢复错账会让“已完成”和“可采纳”长期不一致,或把不同任务证据挂到同一操作;配置和绿色单次 smoke 都看不出它。另保留未验证项:当前 head 的 packaged drawer 浏览器、完整跨平台和 live app-server 原生调用,本次没有宣称通过。无 CI 查询/等待,无合并。

我的整体评价

归属位置合理、体量适中,统一 CLI/app-server casing 的 seam 是有价值的有界重构;无需把这次修复扩大为通用 actor 框架或整个 TS 迁移。但 provider 必须把 transient correlation 与 durable operation identity 分清。建议在当前 PR 完成这两项相关恢复修复并重跑全路径;不要另建平行事件库,也不要把父 Agent 采纳自动化来隐藏缺失结果。修复前保留 REQUEST_CHANGES,#5051 的整体验收不关闭。

English verdict: REQUEST_CHANGES - 00643fc: two independently reproduced CLI resume defects lose completed-child facts and collapse distinct followups; 140 Python and 15 TypeScript tests passed, two gated live cases skipped. No merge.

明明是 gpt-6.1-sol。。不认识自己

@jackie-cqz
jackie-cqz force-pushed the codex/fix-native-child-host-receipts branch from 00643fc to 14890ed Compare October 2, 2026 18:29
@jackie-cqz

Copy link
Copy Markdown
Contributor Author

Rebased onto 5e889bdcba9cea101a8775340a12629eb5a2474a; current head is 14890edcff660acd84c2f4100e97a504c35d8c7d.

Both requested P1 repairs are implemented. Wait-only CLI resumes restore the original admitted host-observed spawn under the exact GoalRef/agent/parent Turn. Reset item counters are now scoped to durable CLI attempts or native app-server Turns, preserving distinct followups/failures while exact replay stays idempotent. The rebase also repairs outer-to-inner host-observation wiring.

Current qualification: 210 Python regressions passed (2 skipped), including the actual production CLI subprocess transport across separate invocations and feature-off retry parity; 38 typed admission/context tests passed. Exact CI mypy/Ruff, TypeScript typecheck, semantic smoke and paired base/head CLI budget passed. Shared release validation installed a real rebased wheel and removed all eight skills through the current workflow validator.

The PR body now names current versus earlier browser/live-host evidence and the remaining host boundary. Typed admission/settlement remain the decision owner; Python owns Codex transport only. Hosted checks are rerunning, and both review findings are ready for maintainer re-review.

@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 2, 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-5 | OpenAI

动机

REQUEST_CHANGES:旧的两项 P1 已通过独立回归核验,但同一个 child 的 followup 在宿主进程恢复后仍无法得到自己的结果,失败结果还会遮蔽父任务的正常返回。评审完整 head 14890edcff660acd84c2f4100e97a504c35d8c7d。

#5051 要把启用后的原生子 Agent 调用变成真实、可区分来源的回执,而不是把配置上限当作实际启动数。本次独立规范是变更前的 docs/integrations/host-native-child-receipts.md,spec_ref = docs/integrations/host-native-child-receipts.md,spec_revision = 5e889bd。按原 Lifecycle 编号逐项核对:

  • criterion_id 1.:沿用 TS 的精确 Turn 准入,不由 Python 状态标签推断权限;已有准入/关闭后报告测试通过。
  • criterion_id 2.:spawn/followup 区分、独立宿主 invocation 身份和精确重放已实现;本轮两个历史缺陷探针在旧 head 失败、当前 head 通过。
  • criterion_id 3.:started 后结果归属尚未满足。恢复只找原 spawn,不能恢复当前 followup;主 Agent 验收仍必须独立发生,宿主完成不是 accepted。
  • criterion_id 4.:相同 payload 幂等和冲突拒绝保留,但错误的关联会把合法 followup 结果送到旧 spawn,导致丢失或冲突。JSON/Markdown/前端来源展示链已读;本轮未重跑包装浏览器,保留可见交互验证缺口。
  • criterion_id 5.:结果/验收的迟到报告仍交给既有事件锁和 TS 粗粒度 owner;适配器没有重开已结算 Turn 的权限。

这是有正价值的宿主观察增量,不是整个多 Agent 生命周期已经完成。持续恢复和结果返回是本切片的必要结果,不能把它推迟成另一个与本 PR 无关的能力。

改动思路

最小合理机制是在已有 exec/app-server 事件入口观察调用,转为已有 native-child 事件,再由同一 read model 给 agent-context、状态和抽屉使用。不增加 scheduler、第二套 Goal store 或自动启动路径。Python 承担宿主字段 casing、进程和 transport 适配,TS 继续拥有准入/阶段语义;不需要为了语言偏好扩大迁移。

正路是已准入的启用 Turn → 观察实际 collab item → 记 decision → 关联终态 → 投影 host_observed → 主 Agent 另行验收。原 coordinator_reported 和 unknown 保留,混合来源明确区分。生产者是实际宿主事件,不是手填活动行;配置、安装、可用槽位都不生成观察事实。相比不做观察或要求手动同步,这个 owner 选择合理;目前需要补的是既有持久事件里的 followup 关联,而不是再建一套 child registry。

具体改动

关键代码讲解

  • CodexNativeChildObserver.observe,loopx/control_plane/turn_driver/codex_native_child.py:84:校验 sender、原生 item 类型和完成状态,统一 exec/app-server 字段;spawn 由 opaque child 身份得到稳定 ID,followup 由 session、durable invocation、native item 得到独立 ID。同一调用重放不新增工作;不同 invocation 的 item_0 不再被错误合并。child→operation 关系目前只写进进程内字典。
  • CodexNativeChildObserver._restore_spawn,同文件 :60:从完整事件流而不是有界显示窗口恢复已准入、同 Goal/agent/Turn 的 host-observed spawn。这修复 wait-only spawn 恢复,但筛选条件明确排除 followup,正是下面 P1 的关联缺口。
  • _record_native_child,loopx/capabilities/multi_subagent/native_child_receipts.py:277:复用事件锁、精确准入和 typed result/review 规则;相同身份不同结果拒绝是正确保护。错误的观察关联不能靠放宽这个保护或吞掉异常来“修复”。公共上报入口不能自行选择宿主来源。
  • native_child_observer,loopx/control_plane/turn_driver/codex_native_child.py:134:只有已有 multi_subagent context 和 Turn 身份才创建适配器。run_codex_cli_host 和 operation-host 把它接在真实事件入口;chat_agent/executor 在同一 owning result 路径读取活动,不授予子 Agent 或 parent 新权限。

完整 28 文件、+710/-57 均已阅读:9 个运行时/上下文/状态源,5 个 dashboard schema/model/copy/抽屉消费者,协议文档与 self-repair 指导,浏览器入口/fixture/55 行场景,以及原生事件、replan guard、Chat、executor、技能交付测试。前端复用 Goal 信息抽屉,英文/中文区分 host、coordinator、mixed 与 unknown;没有另造开关或必须重复输入的表单。浏览器 fixture 提供活动状态,只能验证渲染,不能证明真实持久回执。

对主干的风险

P1:恢复时把 followup 的结果关联到已完成的原 spawn,丢结果或使父任务抛错。 触发顺序为同一已准入 Turn:进程一 spawn(child) 已完成;进程二 send_input(child) 已启动;进程三仅收到 wait(child) 的终态。新的 observer 字典为空,observe:126–134 调 _restore_spawn:60–82,选回旧 spawn,而不是最后的 followup。

独立探针走真实 run_codex_cli_host 子进程 stdout、session 恢复、TS 准入和持久事件后端,仅宿主可执行文件输出合成原生协议,未调用模型:wait=completed 时父任务返回,但 followup 没有 result;wait=errored 时旧 spawn 已有 completed,recorder 抛出 operation identity already has a conflicting native child report,第三次父任务结果也没有返回。若 child 没有本 Turn 的 spawn,仅 followup 后恢复,结果同样丢失。当前六个独立场景是 3 通过、3 失败;通过项是两个旧缺陷及 feature-off,不能用它们覆盖三个失败项。

最小修复:在已有 durable owner 保留并恢复合法、opaque 的 child→当前 operation 关联,覆盖 followup、无同 Turn spawn、同 child 连续 followup 和恢复重放;仍绑定精确 Goal/agent/Turn/宿主来源,不持久化 prompt 或 transcript,不覆写原已完成 spawn,不关闭冲突校验。回归应通过真实两/三次 CLI invocation 分别等待 completed/errored,断言结果属于 followup、父任务照常返回、相同 wait 重放幂等。可将这些序列加入 tests/capabilities/test_codex_native_child_receipts.py,复验 uv run --extra test python -m pytest tests/capabilities/test_codex_native_child_receipts.py tests/capabilities/test_native_child_receipts.py tests/test_loopx_turn_codex_cli.py -q;现有仅 spawn 恢复的测试不足。

本轮既有六文件 Python 原生/Chat/executor 验证 214 passed、2 skipped,两个 TS 文件 15 passed,kernel mypy 19 源文件通过,CI 范围 Ruff 通过,语义 advisory 未检测到支持的新 carrier。feature-off 使用同一 fixture、不可变 base 与当前 head:完整活动、父结果和错误对象相同(fixture SHA-256 454560f0264ebf2a34793a2d338ef8e1bc079e730b2be6fbda1f5a592b884bfc),都是 unknown、零 operation/启动/配额;没有仅凭“对象缺失”宣称隔离。未查询、轮询或等待 GitHub CI。包装 UI 和真实 authenticated app-server 本轮未执行,不将作者声明或合成协议冒充这些结果。

语义与 CI 对齐

这是对已有来源 vocabulary 的有理由扩展,不是扩大 peer/子 Agent 权限。typed admission/result owner 和 generic failure/capacity 用语保留,配置上限不是启动义务,也不把 enforced 准入称为建议。当前具体违反的是原 Lifecycle 的稳定操作结果归属;修复位置应是宿主关联和现有持久事件,而非修改规范以匹配错误结果。来源、默认启用边界和无法观察外部宿主的限制在双语文档中说明;UI schema 与状态同源,不新增 parallel decision owner。

我的整体评价

正价值、归属和体量合理;未来面对相邻变更,最有价值的伴随重构就是把瞬时字典所需关系归回已有 durable owner,而非扩展 Python policy 或再加 registry。历史 coordinator 回执仍是独立/持久消费者,需要保留兼容,不能为了减代码删掉。long_horizon 与 user_experience 仍有已复现回归:连续 followup 不能完成真实恢复,正常 parent 结果还可能被观察异常遮蔽。故当前 head REQUEST_CHANGES;两项旧 P1 已确认修复,新 P1 需在本切片闭合,UI 可复核交互证据仍未完成。没有撤销未解决评审、合并、扩大权限或关闭母目标。

English verdict: REQUEST_CHANGES - 14890ed: both prior P1 regressions are fixed, but restart restores only spawn correlation; followup results are lost or conflict with a completed spawn and mask the parent result. Independent real-CLI transport oracle: 3 passed / 3 failed; native suites: 214 passed / 2 skipped, TS: 15 passed, mypy: 19 sources. Synthetic host protocol, not a paid-host or fresh browser qualification. No merge.

@mergify

mergify Bot commented Oct 2, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @jackie-cqz.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 2, 2026
Signed-off-by: jackie-cqz <2557911191@qq.com>
Signed-off-by: jackie-cqz <2557911191@qq.com>
Signed-off-by: jackie-cqz <2557911191@qq.com>
Signed-off-by: jackie-cqz <2557911191@qq.com>
(cherry picked from commit 7efb0d996f8572371e368a66824c9cfb78a41cb4)
Signed-off-by: jackie-cqz <2557911191@qq.com>
(cherry picked from commit c0f7ab8010bb30a4f99555d24139c0f4934e4093)
Signed-off-by: jackie-cqz <2557911191@qq.com>
Signed-off-by: jackie-cqz <2557911191@qq.com>
Signed-off-by: jackie-cqz <2557911191@qq.com>
Signed-off-by: jackie-cqz <2557911191@qq.com>
Signed-off-by: jackie-cqz <2557911191@qq.com>
Signed-off-by: jackie-cqz <2557911191@qq.com>
Signed-off-by: jackie-cqz <2557911191@qq.com>
Signed-off-by: jackie-cqz <2557911191@qq.com>
@jackie-cqz
jackie-cqz force-pushed the codex/fix-native-child-host-receipts branch from 14890ed to 43db8d0 Compare October 3, 2026 05:52
@jackie-cqz

Copy link
Copy Markdown
Contributor Author

Repair pushed on 43db8d07c140c499e432859e348a2f890a9f18dd, rebased onto 12d60f13fe1fae6848e2bc806688f26031c8869a.

The latest P1 is addressed in the existing receipt owner: each successful host decision retains only hashed child bindings as scalar metadata. Terminal observation resolves the latest canonical host decision under the same Goal/agent/Turn, including followups without a same-Turn spawn. No transient correlation dictionary or additional store remains. Original spawn results and conflict rejection are preserved.

Five real CLI subprocess recovery scenarios failed before this repair; final-source Linux qualification now passes 504 tests (2 existing gated live-host skips). Windows adapter qualification passes 22 tests, covering completed/errored followup waits, consecutive same-child followups, old-spawn replay, idempotency and negative admission. These use synthetic host protocol over real production subprocess/session/admission/event-store paths, not a paid-host claim.

Provider placement also resolves the architecture/maintainability CI failures without adding exceptions. Exact CI mypy/Ruff/TS typecheck, full semantic smoke, 55 focused typed tests, base/head CLI output budgets and rebuilt packaged desktop/mobile native activity readback pass. Shared storage qualification passes Windows 373, real PostgreSQL 335 plus service 10; storage bytes remain identical after the final rebase.

The PR body contains current source identities and evidence limits. English author repair verdict: READY FOR MAINTAINER RE-REVIEW; this is not an approval or merge. Hosted checks have restarted on the new head.

@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 3, 2026
@mergify

mergify Bot commented Oct 3, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @jackie-cqz.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 3, 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-5 | OpenAI

动机

这项改动影响启用原生子任务回执、并让同一个子任务连续处理后续请求的 Codex 用户。回执是宿主记录的执行事实,不代表父任务已经认可结果。

例如,第一次请求已经完成,第二次请求仍在运行,进程随后重放第一次的完成事件。旧恢复逻辑可能漏掉第二次请求自己的结果;当前修复能恢复后续结果,却把这个旧完成事件错记到了仍在运行的第二次请求上。

预期改善是重启后仍能准确看到每次请求自己的结果,重复旧事件不会改变新请求。本次已复验原恢复问题修好,但独立真实 CLI 探针证明旧事件仍会让新请求虚假完成,因此不能批准当前版本。

本 PR 不授权额外启动子任务,不扩张其他代理的权限,不让宿主完成自动等于父任务验收;本次评审也没有启动付费模型、合并代码或关闭整个交付目标。

REQUEST_CHANGES:旧的 followup 恢复问题已修,但旧 spawn 重放会把后来仍在运行的 followup 错记完成。评审完整28文件、精确 head 43db8d0;没有继承旧 head 的批准或把作者修复声明当验证。

#5051 的目标是让真实宿主调用形成可恢复、可区分来源的回执,配置上限不代表启动数,host 完成不等于父任务采纳。修改前 spec_ref=docs/integrations/host-native-child-receipts.md,spec_revision=5e889bdcba9cea101a8775340a12629eb5a2474a,原 Lifecycle criterion_id 逐项:1. 精确 Turn/准入 implemented;2. 稳定 decision identity implemented,旧计数器碰撞回归通过;3. 操作自己的 result not_met;4. 同身份/内容重放幂等 not_met;5. 迟到事实不重开 Turn implemented。3/4 的反例如下,不是依据本 PR 新增“最新操作”文字倒推期望。

改动思路

位置选择合理:内置 Codex provider 在自身 CLI/app-server 连接观察原生事件,复用 multi_subagent 的同一 durable event log、TS admission 和 shared projection。不创建第二 child registry,不从配置或 prose 推测执行,不赋予 peer/子代理写入权。Python 只适配宿主字段/transport,generic phase 与 admission 留在已有 TS owner。

删除 transient children map、持久化 compact hashed child relation,能正确恢复只收到新 wait 的 followup;CLI 用 journal durable attempt,app-server 用 native Turn identity,保留不同进程 item_0 的区分和同绑定精确重放。问题是“最新关联”只适合恢复真正新 wait 的目标,不应覆写一个已具有稳定 decision identity 的旧 spawn/followup snapshot。保留当前已有 owner、给非 wait 结果使用自身 operation,是更小且更容易回滚的修复。

具体改动

修改前规范:docs/integrations/host-native-child-receipts.md,修订 5e889bd。逐项映射:1. → implemented;2. → implemented;3. → not_met;4. → not_met;5. → implemented。

完整28文件 +781/-58:146行 built-in transport adapter、74行原 receipt 扩展、CLI/operation-host/Chat/executor 接线、TS context、JSON/Markdown/Lark display 与 Goal drawer/schema/双语 provenance,以及301行 native regression、浏览器 fixture 和共享验证修正。无新增 scheduler、provider 调用、capability switch 或父任务自动验收。transport adapter 移至 extensions 的 built-in provider 位置有明确理由;不是给 Python 再造 decision owner。

关键代码讲解

  • CodexNativeChildObserver._restore_operation(loopx/extensions/codex_native_child.py:60):从完整 canonical event 顺序恢复同 Goal/agent/Turn 的合法 host-observed spawn/followup,跨显示窗口、不采纳 coordinator report;旧恢复缺陷在当前源独立通过。
  • observe(同文件:127):非 wait 分支已有稳定 operation_id,但处理 agents_states 时无条件再取最新 child operation。这把旧 decision 的结果挂到未来 followup,违反精确重放语义。
  • _record_native_child(native_child_receipts.py:294):scalar hashed correlation 仅允许 started host decision;不存原 prompt/result,不把观察改成 parent review。现有 conflict 检查应保留,不能吞异常或覆盖旧结果来隐藏错账。
  • run_codex_cli_host(codex_cli.py:931):真实 stdout 和 session 入口绑定 durable attempt,再经原 admission 写回;未启用不创建 observer。executor 先持久化 attempt,真正重试才递增;app-server sender/Turn 过滤沿原 owner。

共享 archive 4行变化独立复用 syncAuthorityDirectory,保留 file fsync 与非替换发布,属于明确的无条件 Windows 兼容修复,不是 multi_subagent opt-in 效果。其作者 Windows/PostgreSQL 验证声明已读,本轮没有冒称实际跑过对应平台/数据库。其余 fixture 修正保留 canonical ownership、420预算和 revision-before-write,未改生产阈值来掩盖错误。

对主干的风险

P1:旧 spawn 的完成快照让当前 followup 虚假完成。 独立三次真实 production CLI 调用:第一次 spawn(child) 且 completed;第二次 send_input(child) 且 running;第三次仅重放第一次同身份同内容的 completed-spawn item,没有新 wait、更没有 followup terminal。当前 canonical readback 的 spawn 和 followup 均为 completed;不可变旧14890源在同一 fixture 保留 followup pending。三个父结果均正常返回,零 parent acceptance、零 quota,故这是 result attribution 回归,不是 launch 计数/权限问题。

对应 :127–132 对任意 snapshot 取 latest operation。新增 test_real_cli_old_spawn_replay_does_not_replace_a_later_followup 断言所有结果 completed,恰好把错误输出写成了正确期望;测试应先独立表达“旧结果不能证明未来任务完成”。最小修复是非 wait terminal 绑定自身稳定操作,真正新 wait 才按合法持久关联恢复,并断言 followup 在自己的新 terminal 前始终 pending;保留 duplicate/conflict 保护,不抹掉原 spawn。

本轮204项 native/真实CLI/Chat/executor/replan 和37项共享 fixture 通过(此选集无 skips),38项 TS context/admission 通过,Ruff、mypy19源、control-plane typecheck、advisory后 full semantic smoke 通过。独立三案例 oracle 当前1 failed/2 passed:旧重放失败、连续同 child followup completed/failed 与 off 分支通过。旧14890校正后的同一 oracle2 passed/1 failed:重放不误完成,旧连续 followup 结果冲突仍失败。首次 reviewer oracle 直接访问缺失 result 得到 KeyError,已改为 get 后重跑;那次错误保留但不算产品证据。

Replay fixture SHA-256 b2895c208e9cb7f49cf1673faec718b56916c8c6b8165093607003c9129f01cb。完整 off 三调用 parent/error/activity 观察在旧源和当前源逐字段相同,fixture SHA-256 2198c25e994d7a0fd8d51c6196498752dfbecd5a47eef83cf06e80a593f74676,没有只比较计数或删诊断来制造 parity。实验用合成宿主协议,但走真实子进程 stdout/session/TS admission/事件后端;不冒称付费模型或 authenticated app-server。当前 packaged UI 未独立重跑,Ego Lite 原任务空间恢复失败;这不是“缺新授权/浏览器不可用”的泛化。作者 renderer fixture不能单独证明真实持久回执,也不替代实际平台 qualification。未查询、轮询或等待 GitHub CI。

typed-state/domain-neutrality/behavior disclosure/guidance/default-off/authority lenses 均核对:现有 provenance vocabulary 扩展合理,精确 host status mapping 不从错误 prose 推断 capacity;cap 是 ceiling,准入是强制规则不是 guidance;host observation 不授权下一次调用。完整 UI/app-server feature-off parity仍未全部资格化,保留不确定,绝不以 unit 计数推断全覆盖。

我的整体评价

REQUEST_CHANGES。原两项身份/恢复缺陷以及后来 followup 结果丢失均已独立确认修好,但新的 stale replay 回归仍在本切片 owning boundary,不能作为无关后续工作绕过。long_horizon 和 user_experience 均受错误持久结果影响。相关 future-facing refactor pass 认可 provider move 和去 transient map;剩余最有价值的小改动就是区分自身 decision terminal 与新 wait 的恢复关联,不需增加 framework、平行 store 或宽泛迁移。

保留已有 coordinator 历史与独立 parent review。当前没有 APPROVE,不撤销仍未解决的阻塞评审,不合并,也不关闭 #5051 的整体资格验收。

English verdict: REQUEST_CHANGES - HEAD 43db8d0. Prior followup recovery defects are fixed. Independently reproduced: replaying an old completed spawn falsely completes a later running followup. Production CLI/store transport with synthetic protocol; 204 native plus37 shared and38 typed tests pass, replay oracle1 failed/2passed. No paid-host, fresh packaged UI, approval or merge claim.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-rebase Mergify: the pull request has merge conflicts with its base branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants