Skip to content

fix(host): contain Windows Host descendants in an owned Job - #7602

Open
xyx2002OvO wants to merge 3 commits into
mainfrom
codex/pr5677-windows-host
Open

xyx2002OvO wants to merge 3 commits into
mainfrom
codex/pr5677-windows-host

Conversation

@xyx2002OvO

Copy link
Copy Markdown
Contributor

Goal And Delivered Outcome

Windows cannot prove managed Host descendant cleanup through POSIX process groups. Assign the bridge to an owned Job before sending its first request, retain the Job identity for drain observation, and terminate descendants when the owner closes or dies. This is the independent Host prerequisite split from #5677; it does not grant task, Stop, lease or sandbox authority.

Author Declaration

  • Written by: model_agent, OpenAI Codex.
  • Implemented against: the scope/prerequisite review on #5677 and the existing Host supervision contract.
Criterion Disposition Owner / decisive evidence
Descendants stop after leader exit, timeout, consumer failure and owner loss implemented windows_host_job.py, host_process_transport.py; real native Windows processes
Preserve existing attribution and unknown drain states implemented Existing transport owner and test_windows_host_process.py

Scope And Continuation

Complete within this prerequisite scope. #5677 retains its dependency until this proposal lands; the freshness behavior is reviewed there. The small local refactor extracts the bridge record input so containment wraps the existing transport without duplicating its supervision loop. Maintainer review/merge remains required.

Validation

  • Tested revision: implementation e44f90e0c; submitted head b1d3dd8a188f3e3bba98f64387164a7fa5f92c09 adds current main without changing these three files.
  • Run state: finished. Input classes: synthetic.
Check kind Result Evidence / limitation
real_entrypoint passed python -m pytest tests/control_plane/test_windows_host_process.py tests/control_plane/test_validation_process_cleanup.py -q: 14 passed, 5 POSIX-only skips; actual descendants and owner termination exercised.
regression_parity failed The broader tests/test_codex_operation_host.py Windows fake app-server entrypoint reports WinError 193; a focused reproduction also fails on target main fb331f45c. No native app-server qualification is claimed.
static passed Ruff on changed Python, semantic-vocabulary advisory, explicit-path public-boundary scan (3 files), diff whitespace and DCO sign-off.
integration not_run Linux/CI and exact-head maintainer review are pending. No merge or complete sandbox claim.

Signed-off-by: Tartar <xiaoyx67@mail2.sysu.edu.cn>
Signed-off-by: Tartar <xiaoyx67@mail2.sysu.edu.cn>

@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: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max

当前完整精确 head b1d3dd8a188f3e3bba98f64387164a7fa5f92c09 有一项 P2 异常清理问题,结论为 REQUEST_CHANGES。Windows Job前置有独立价值;本次不要求它完成整个#5677。

动机 / Motivation

通过 managed Host 执行任务、需要中止和回收子进程的 Windows 操作者。

原Windows路径仅尽力结束进程树,不能凭leader退出证明后代已停;本PR在桥收到Host请求前分配Job,并以kernel计数读回整组退出。

Job IO接入原监督路径且POSIX配对验证通过;新增清理报错会跳过launch guard与输出流释放,当前仍需修复,Windows原生资格也未独立建立。

本次只审Host进程生命周期前置,不审完#5677,不授予Stop、lease、任务完成、sandbox或外部效果权限。 Job容器只负责一执行及其后代,不能把进程退出提升为任务验收或once-only settlement。

改动思路 / Approach

Windows Job属于平台kernel IO,复用现有TS监督决策和Python transport较合适;不应新建控制面或把此次修复扩成整个freshness方案。

本PR保留Windows Job平台前置和原transport集成;最小修复是在Job finish报错时也执行launch_scope及output的finally清理,并补对应失败用例。

已先读#5677的范围/前置评审:平台保护应按自己的生命周期独立验收,不能为缩小父PR而删除保护。本PR的拆分方向符合这个边界;当前问题在自己的错误清理链。

路径 进入与退出
POSIX 保持原专用进程组、TS监督和既有drain事实。
Windows 创建不继承Job handle → assign原bridge handle → 原guard/record → 首个Host请求 → 原监督循环 → Job终止/计数读回。
本次缺陷 guard进入后setup出错 → bridge取消 → finish()又抛错 → 原guard/output清理被跳过。

这张表是源码路径说明,不是Windows执行证据。Microsoft Job Objects文档支持默认子进程关联及最后handle关闭时终止的机制说明;它不能证明本实现的kernel调用已经在本轮通过。

具体改动 / Changes

完整diff三文件 +390/-109:production两文件+266/-109、tests一文件+124/0,包含原循环移动;没有新增Task/Stop/quota状态机。

  • run_host_process 在发请求前assign桥,并把Job名写入原process record;guard、事件、timeout和原caller继续复用。提取的_bridge_record_scope七条作用域语句与不可变基线AST相同,不是另建决策owner。
  • WindowsHostJob 只封装Create/Assign/Query/Terminate/Close,原process HANDLE避免把assign指向复用PID。finish()仍可能因kernel读取、终止失败或观察超时抛错。
  • _host_process_drain 重新查询带有效名的Job;旧记录没有Job仍unsupported,非法或不可读事实保持unattributable。没有把leader退出视为全组退出。

规范依据:spec_ref docs/reference/protocols/loopx-turn-v0.md,spec_revision 898363635d4737f84b6a673a9a11265a121b6f57。Managed Host Process Lifetime 区分leader、管道与后代,要求错误/owner loss走监督清理;process supervision 明确其不授予任务、lease或sandbox权限。旧文档只承诺Windows尽力tree cleanup,不把POSIX等价或整个父RFC强加给本PR;新增Job路径需要自己的实际资格。

对主干的风险 / Risks

P2:Job finish失败会跳过其余已注册资源清理

位置:host_process_transport.py:405–411。

windows_job.finish()被放在launch_scope.close()和guarded.close_output()之前。同一finally里的前一条语句抛错,后两条就不会运行。外层Job的__exit__会再尝试自身finish/handle关闭,但不会替代launch guard和stdout的清理。对未实现GC补救的context manager,退出回调直接遗漏;其他调用者也不应依赖回收时机释放guard/pipe。

独立探针使用真实public run_host_process及真实Node桥;临时record目标是一个目录,使guard进入后的record setup失败,只对Windows Job IO注入QueryInformationJobObject异常,未替换桥、结果、持久后端或原清理断言。输入、fixture和断言在三次比较中相同:

revision/变体 guard退出 bridge stdout关闭 结果
基线 898363635d4737f84b6a673a9a11265a121b6f57 true true 保留原record写入错误。
提交head b1d3dd8a188f3e3bba98f64387164a7fa5f92c09 false false Job错误短路原finally;独立oracle失败。
head仅内存补finally true true 仍抛Job错误,不伪造成功/drained。

这是确定的Python异常路径反例,不是Windows内核实测。最小修复是把Job finish包在try内,以finally保证已注册的launch guard与output清理执行;如果清理仍失败,保留错误和unknown,而非返回成功。回归应在真实桥上组合record/setup失败与Job query/terminate/timeout异常,断言context退出、输出关闭;原Windows后代/owner丢失矩阵继续保留。

其他验证 结果与限制
Host、leased Host、validation、Codex operation五模块 PASS:78 passed、9 skipped;其中6项新Windows、1项既有Windows stdin与2项显式live-host未运行。
同命令不可变base/head核心模块 PASS:两端各28 passed、1既有Windows条件skip;不以总数代替上面的资源释放反例。
TS原监督器 PASS:21 cases,0 skip。
本地静态/仓库门 PASS:改动Python Ruff、配置内17文件mypy、完整control-plane TypeScript typecheck、diff/DCO/双语门通过;明确路径public scan零错误/警告。 标准source premerge四direct、Python compile、两catalog及八risk-profile通过;diff-scoped advisory先于full semantic smoke,二者通过。
Windows kernel实机 UNVERIFIED:Windows内核六项新用例和一项既有Windows stdin用例在Mac上跳过;两项显式live-host资格未运行。作者报告的e44f90e0c Windows结果保留为声明,不冒充本轮独立原生执行。

作者已经披露的Windows fake app-server WinError 193保留为作者报告,本轮未独立重现该平台签名,不将其归为本PR新缺陷,也不据此抹去当前cleanup反例。未查询或等待CI,未运行付费模型。

精确scope的CQR:cqr_e31a3ad2266870625228,FAIL / invalid_receipt;cleanup反例失败和所需Windows实机验证跳过均保留,不能作为通过资格。

我的整体评价 / Verdict

Windows Job属于平台kernel IO,复用现有TS监督决策和Python transport较合适;不应新建控制面或把此次修复扩成整个freshness方案。

本PR保留Windows Job平台前置和原transport集成;最小修复是在Job finish报错时也执行launch_scope及output的finally清理,并补对应失败用例。

改动规模与独立平台问题相称,Python模块是kernel IO placement;原typed监督决策和业务authority保持。当前long_horizon/user_experience仍 not_yet_proven:错误时遗漏guard/pipe清理会削弱后续工作恢复,不能因正常进程用例通过就批准。

已检查三个改动文件及CLI/Host消费者;没有渲染页面或交互布局改动,视觉评审不适用。 Windows内核六项新用例和一项既有Windows stdin用例在Mac上跳过;两项显式live-host资格未运行。作者报告的e44f90e0c Windows结果保留为声明,不冒充本轮独立原生执行。

修复和独立Windows资格完成后,需要重审新精确head。没有要求新控制面、新配置、额外用户确认或无关跟进任务;本轮没有修改提交源码、合并或安装。

English verdict: REQUEST_CHANGES — b1d3dd8a188f3e3bba98f64387164a7fa5f92c09 can skip launch-guard and output cleanup when WindowsHostJob.finish() raises. A real Python/Node fault probe fails at head and passes at base and with the minimal in-memory finally repair. Native Windows qualification remains unverified.

proc.kill()
proc.wait()
finally:
if windows_job is not None:

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.

[P2] Job finish 抛错时仍需执行其余 finally 清理。launch_guard 已进入、随后 record/setup 失败时,finish 内的 Query/Terminate 或观察超时可以再次抛错,使下方 launch_scope.close() 和 output cleanup 都不执行。真实 public run_host_process/Node 桥故障探针(仅 Windows Job IO 为替身)在基线释放 guard/关闭 stdout,在此 head 两者均未清理,内存中加一层 finally 后恢复。请用 finally 保证这两类资源释放,继续保留 Job 清理错误/unknown,并补 setup+finish 双失败回归;这项探针不宣称 Windows 内核资格。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

已在 exact head 86ed10c70c8395d2afe7eacda49831bc329d66d7 修复。

  • WindowsHostJob.finish() 现在位于嵌套 finally 的上层;即使 Job cleanup 再次抛错,launch_scope.close() 与 output cleanup 仍会执行,原 Job cleanup 错误不会被吞掉。
  • 新增 setup + finish 双失败回归:走公开 run_host_process 与真实 Node bridge,仅把 WindowsHostJob.finish 替换为“完成真实清理后抛错”,并验证 guard 与 stdout 均释放、Host 未启动。
  • 已合入当前本地 origin/main (8d48efabb351c9cc68f48f48dee64a49b4fc1890)。

验证环境:Windows 10.0.26200.9711、Python 3.12.3、Node 24.12.0。

pytest -q tests/control_plane/test_windows_host_process.py tests/control_plane/test_validation_process_cleanup.py -> 15 passed, 5 skipped。
ruff check(两个改动文件)、git diff --check、RFC bilingual staged check 均通过。

这仍是 Windows Host 集成故障探针,不把它表述为原生内核 containment 资格证明。请复审。

Signed-off-by: Tartar <xiaoyx67@mail2.sysu.edu.cn>

@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

本轮没有新增具体代码缺陷;旧 cleanup P2 已修复。结论暂为 REQUEST_CHANGES,原因是新增 Win32 核心行为仍缺独立原生验证。 审阅固定在 86ed10c70c8395d2afe7eacda49831bc329d66d7,完整对比 merge-base 8d48efabb351c9cc68f48f48dee64a49b4fc1890 的全部 3 个文件,不沿用旧 head 的批准或测试结论。

动机 / Motivation

受影响的是在 Windows 上运行本地 managed Host、并在取消或接替前需要确认后代已停止的 LoopX 操作者。

原先 Windows 主进程退出并不能证明它启动的工作都已停止;本PR为一次本地执行建立具名 Job,把后代纳入同一OS生命周期,并在返回前查询是否确实排空。

源代码已接通具名 Job 和冷读,先前 cleanup 异常跳过资源释放的问题也已修正;本轮 Linux 共用路径通过,但 Job 的原生 Windows 行为尚未独立验证。

本PR不提供沙箱、远端副作用回滚、provider lease续约或Todo完成权威,也不闭合 #5677 的其余功能或跨平台全套资格。

改动思路 / Approach

Win32 Job 是原 managed Host 的平台 IO 保障,TS 继续持有业务生命周期;这次切片不需要绑定 #7603 或整个 #5677。 保留三文件的独立平台边界和已经修复的嵌套清理,补当前head原生Windows验证后再判断采用,不因缺宿主虚构代码缺陷。

Job 的身份由真实 launch 自动产生,并在把请求发给 Host 前写入现有record;它不是模型填写的“已安全停止”标签。冷读检查schema、同host与supervision,再向OS查询Job;旧PID记录和不可查询状态不会获得新证明。POSIX的process group继续由原路径处理,TS仍负责timeout、output budget与取消政策。

相比只增加kill-tree轮询,Job提供不同的OS生命周期边界;相比重写supervisor,这个小型ctypes helper更符合平台IO定位。原流程因包入ExitStack产生的大块缩进不等于新增同量业务规则;_bridge_record_scope 是原环境/record逻辑抽取,不是第二个authority owner。

具体改动 / Changes

关键代码讲解

  1. WindowsHostJob 创建随机具名Job,拒绝名字已存在,设置kill-on-close,并以原Popen handle赋值。finish() 请求终止剩余进程并查询accounting直到active为0;超时或查询失败不能正常返回。__exit__ 独立关闭handle。
  2. run_host_process 先创建/assign Job,再写record与交付Host请求。现有TS loop及launch guard继续存在;收尾中把 finish()、launch_scope.close() 和 close_output() 放入独立嵌套finally。
  3. _host_process_drain/execution_host_drain 对有效Windows Job记录读取active count;非法名字和查询错误保留不可归因,旧无Job记录仍为unsupported,leased调用还需组合内外两份事实。

之前 review 指出的“finish() 抛错后guard/output被跳过”已经在当前head修好。我直接调用新回归的setup+finish双失败路径:真实Node bridge,只有Windows Job接口为Linux模拟,断言guard与output关闭、Host marker未产生且bridge退出。这验证了Python控制流修复,不能证明Win32 handle、Job继承或kill-on-close行为。

既有合同 docs/reference/protocols/loopx-turn-v0.md 固定于 0ad08b15dd7331051c93566075561a390a9cd7e2。本次映射标签 host-lifetime 指leader退出/输出结束/后代停止不同,以及监督不授予执行权威;failure-is-not-stop 指信号发送不能替代最终观察。原合同仍明确Windows best-effort边界;本PR增加Job能力,不因此取得完整Windows、租约或settlement资格。当前三文件也没有依赖 #7603 的private IO helper,不能机械要求两个PR必须按某个顺序合并。

对主干的风险 / Risks

最强的剩余风险是“leader或owner已退出,但某个后代仍可写入,而冷读宣称drained”。source中可以看到正确的fail-closed意图:assignment必须成功,query错误保留unknown,finish必须观察零active,旧记录不凭PID成功。但这些事实最终来自Win32,Linux通过或fake Job不能替代它。

本轮验证为:Python managed Host/leased Host/Windows test文件 32 PASS、7 SKIP;现有TS host_process及host_process_group 21 PASS;上述真实Node清理异常探针 PASS;git diff --check PASS。作者已报告Windows运行,我保留该报告,但仍需能绑定源码的执行产物,而不要求所有native测试都必须在审阅者本机重跑。

我独立读取了当前head关联的 Windows CI job 124039153826 的完整日志:运行于Windows Server2025,checkout为226dae11e,明确合入本head 86ed10c70…。该job成功,但所有pytest命令均显式选择既有文件,全文没有test_windows_host_process.py;主要Windows组的419通过、20跳过也不包含新7例。因此这盏绿灯不能验证新Job的后代停止、owner kill、cold read、assignment失败与cleanup异常。它们仍是 UNVERIFIED,这与本机恰为Linux是两个不同事实。

语义与 CI 对齐

这次复用已有drain词汇,不引入新的任务完成或peer权限。请提供可绑定当前head的 python -m pytest -q tests/control_plane/test_windows_host_process.py 原生执行日志或产物,并覆盖受影响的真实调用者;已有合格产物可以直接核验,无需重复已证明的运行。若尚无产物,将这7例加入Windows lane再执行即可;保留后代marker和查询失败观察,共用POSIX回归继续保留。这里请求的是缺失的决定性观察,不要求扩写生产框架、扩大父PR scope,或把没有Windows机器归为作者的新代码缺陷。

我的整体评价 / Verdict

独立平台切片和OS IO定位合理,旧P2修复完整,未发现新的可复现正确性问题。长程接替安全与取消体验依赖原生Job是否真的排空,当前证据尚不足以给APPROVE;剩余工作可以有界地落在这7例及调用者路径上。旧record兼容应保留unsupported,不能为了简化而抹掉未知。本次检查的 turn_driver/host_process_transport.py 与 windows_host_job.py 不改变已渲染的产品页面;无需用截图证明内部行为。 未进行产品页面视觉检查,因为本次没有页面改动。

English verdict: REQUEST_CHANGES — 86ed10c70c8395d2afe7eacda49831bc329d66d7 resolves the previous cleanup-finally defect and adds no newly reproduced code finding in this review. POSIX/common Python tests passed 32 cases, TS passed 21, and the Linux real-bridge cleanup simulation passed. The seven decisive Windows Job cases remain unverified on a native Windows host, so approval is withheld for that material evidence gap.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants