Repository navigation
fix(ci): isolate optional stack writers from test subprocess doubles - #6677
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval). APPROVE — exact head b7ff6f0fd42ce45a48781d18dc872859bd73d516.
动机
运行仓库测试的开发者,需要在启用长测试诊断后仍能收到真实的测试结果。
原来测试替换公共子进程函数时,诊断线程可能进入测试替身,测试主体执行后仍无法完成报告;现在诊断使用自己保留的构造入口,并在回收前终止仍存活的子进程。
相同八例在基线得到四次关闭路径通过、四次启用路径超时,在本头全部通过;完整模块65项通过,原生成功、失败和计时读回保持。
不修改测试选择、分片、coverage门槛或测试结论;不认定已经找到历史 hosted 卡顿根因。
原间歇卡顿、native Windows、完整六分片和持续运行资格仍由现有 CI 运行资格工作另行验证。
改动思路
Python 保留既有 pytest hook、文件描述符和子进程传输职责,TypeScript 继续解释原生计时记录;一个私有构造引用和一个清理边界足以修复,不引入新框架。
本 PR 完成可重现的可选诊断传输修复、真实进程回归和双语深层开发说明;不改变控制面决策 owner。
实际入口为:pytest 显式加载 observer → pytest_runtest_protocol → 默认关闭直接 yield / 启用 timer → 原线程栈 → 私有 Popen + communicate → kill/reap → 原生报告 → 原 TS reader。关闭路径不增加准备、澄清或确认步骤。与增加超时、关闭诊断或复制整个父目录相比,这个修复直接处理已复现的传输边界,并保留原本必须存在的结果、权限和恢复检查。最强反对理由是局部成功不足以证明更广运行资格,故本评价不以测试数或恢复文件数替代该验收。
具体改动
完整三路径相对真实 merge-base d80a38e5f2e874231fbd8c241456ab5a58a31686 审阅:+113/-18。规格先读的是 docs/development/testing-and-quality.md,不可变修订 d80a38e5f2e874231fbd8c241456ab5a58a31686,不是以本次新增说明验证本次实现。
规格逐项:Optional diagnostics preserve native test results = implemented; Bounded owned writer = implemented; Default-off isolation = implemented。这些分别由下述实际调用、负例与当前测试验证;更广平台/研究资格不在本次合同的完成声明内。
关键代码讲解
_STACK_POPEN固定模块加载时的构造入口。只把run保存到别名不足以隔离,因为它仍会动态查询被替换的Popen。pytest_runtest_protocol保持原 timer 与结束顺序;通信异常也先 kill 存活 writer,再由 context manager reap,避免异常路径的无限等待。test_test_owned_subprocess_doubles_cannot_capture_diagnostic_writers以原生 pass/fail 和资源存活状态为 oracle,覆盖 run/Popen、开关与 worker 的交叉。
完整模块 65 passed,0 skipped,包含真实 serial/xdist、verbose/quiet、原生 subtests、失败/中断读回、满 stderr 管道、两个期限、父进程死亡、取消、spawn 和活子进程通信失败。另用同一份当前八例 fixture、同一 Python3.13.16,在两个不可变源码树运行:base 四次关闭路径通过、四次启用路径5秒超时;head 八例全过。没有修改测试预期或产品期限。
对主干的风险
Spawn OSError and live-child communication OSError preserve test results; full stderr, parent timeout, helper deadline, parent death, invalid delay, cancellation and incomplete/malformed logs remain covered.
Ruff、真实 merge-base diff hygiene、开发时 semantic inventory advisory 后的完整 semantic drift 检查均通过。advisory 在这些 provider 路径未发现支持的新增词汇载体;空结果不是语义等价证明,判断还依赖完整代码和调用链。维护性 smoke 在两个 PR 各自不可变 base/head 上用同一解释器执行,四次均 exit0,配对输出逐字相同;Canary 预览中的 inherited-failure 注记不符合这次新实测,也没有被当作当前失败或完整 gate 通过。完整14/19所选 Canary 集合仅做了预览,未声称执行通过。
本轮按当前 scoped wait_for_ci=false,没有查询、等待、重跑或取消远端 CI。公开边界扫描没有新增凭据、私人链接、机器路径或原始日志;已有通用开发输出目录示例和标准 guest 路径按其语义核对。原间歇卡顿、native Windows、完整六分片和持续运行资格仍由现有 CI 运行资格工作另行验证。 本轮没有安装升级、改活跃运行、调用模型或执行新 benchmark。
我的整体评价
本精确头没有阻塞发现,结论 APPROVE;problem_context=goal_achieved 只关闭本次具名传输缺陷,不关闭父项目资格。long_horizon=preserved,user_experience=improved:原有结果/预算/权威继续由原 owner 保持,受影响的开发或恢复任务可以完成,不增加人的交互轮次。
Python 保留既有 pytest hook、文件描述符和子进程传输职责,TypeScript 继续解释原生计时记录;一个私有构造引用和一个清理边界足以修复,不引入新框架。
本 PR 完成可重现的可选诊断传输修复、真实进程回归和双语深层开发说明;不改变控制面决策 owner。
future-facing pass 已应用在同一 provider 边界:保留局部共享构造/选择和既有清理 owner,不为小修复新增状态机、包装层或通用框架。新状态词汇保持 local_only / reuse_existing;现有共享语义 owner 没有迁移。头部变化须重新核验;本 COMMENTED 结论不构成正式自批准,也不授予 merge/admin bypass 或旧 review 处置权。
English verdict: APPROVE — the exact head isolates optional diagnostic writers from test-owned subprocess doubles and reaps live children on IO errors. Independent real-process parity rejects the old hang and preserves native results. Hosted/Windows/sustained qualification is not claimed. Reviewed head b7ff6f0fd42ce45a48781d18dc872859bd73d516.
Goal And Delivered Outcome
A test that replaces public
subprocess.runorsubprocess.Popencan capture the optional stack writer. The native test phases finish, but the diagnostic thread remains inside the test double andtimer.join()prevents pytest from reporting completion.Capture the observer-owned process constructor and retain bounded communication plus kill-before-reap on every exit, including non-timeout IO errors. Default-off behavior, whole-protocol observation, timing identities, test results and existing diagnostic deadlines stay unchanged. This is a self-contained reproduced CI-adapter defect; intended base:
main.Author Declaration
Implemented against
Specification: CI observation boundary, revision
d80a38e5f2e874231fbd8c241456ab5a58a31686.pytest_runtest_protocol0starts no timer/writer; strict observation readback stays authoritativeSelf-check: read repository instructions, reviewed the complete diff, exercised actual pytest and OS child processes, and ran source validators. No independent PR review or native Windows/full hosted qualification is claimed.
Scope And Continuation
Complete within this adapter repair: existing Python pytest transport, its real-process regressions, and matching English/Chinese developer guidance. Python remains the provider-owned hook/FD/process boundary; the TS timing reader and control-plane owners are reused.
The related refactor pins one owned constructor and keeps one cleanup boundary. A new process framework or module would add indirection. Broader CI, original intermittent-stall causality and sustained qualification remain separate; this fix does not establish a historical hosted hang's cause. No new follow-up issue is needed for the completed repair.
Validation
b7ff6f0fd42ce45a48781d18dc872859bd73d516(committed files match the validated bytes).finished.synthetic.tests/test_ci_pytest_timing.py: 65 passed, 0 skipped on each Python version, Node 24.21. Python 3.11 used an outer two-worker run with the CI observer and coverage; subjects exercise serial/two-worker, verbose/quiet, subtests, blocked stderr, both deadlines, parent death, cancellation and IO failure.The focused coverage-enabled run proves instrumentation compatibility; it does not establish the six-shard aggregate coverage floor. No active Goal, private runtime snapshot or model service was used as a fixture.
Frontend / Visual Evidence
UI impact:
none; before/after/viewports/attention/craft review: N/A. This changes the existing pytest observer and developer guidance. Source data:nonefor UI.Type of Change
LoopX Area
Technical Direction
S10/S12: observable failure and regression prevention for the existing developer CI path; this does not close broader operational qualification.
Shared-authority RFC fixture impact
N/A: no shared-authority provider, promotion, runtime-routing or compatibility-projection change.
Boundary Checklist
none.