Conversation
…uard refactor(turn): derive every Turn decision from one shared owner (loopx-project#4496) moved build_lark_operator_inbox_urgency_projector, collect_status, and scheduler_execution_context_for_turn out of loopx.cli_commands.turn's top-level namespace, but this test still patches all three there. The patch loop hits the first missing name and raises AttributeError before running the CLI, breaking this test on every PR built on current main. turn_inspection.handle_turn_journal_inspection never imports these three names, so the guarantee this test checks -- inspect-journal never reaches a live or write path -- already holds by construction; the stale patch targets asserted nothing real. Signed-off-by: song <liusongstep@gmail.com>
huangruiteng
left a comment
There was a problem hiding this comment.
动机
作者的问题描述在它的合并基线上是成立的:#4496 把 build_lark_operator_inbox_urgency_projector、collect_status、scheduler_execution_context_for_turn 从 loopx.cli_commands.turn 顶层搬到了 turn_decision.py,而 tests/test_loopx_turn_journal_inspection.py 的 patch 列表还写着这三个名字挂在 turn 模块上,于是 monkeypatch.setattr 直接抛 AttributeError,守卫用例在基于 75fcd5556c 的分支上必红。我在 75fcd5556c 上复现了这条:1 failed / 17 passed,报错点正是那三行 patch 目标。所以"守卫写在了错误的模块上"这个判断是对的。
改动思路
但这个 PR 选择的修法是删掉这三个 patch 目标,而在当前 main 上这条路已经被别人用更强的方式走完了:main 的 263d08e26 test(turn): keep the current-Turn owner guards on the owner 把这同样的三个名字从 turn 循环挪到第二个循环、改挂到 turn_decision,并留了一行注释说明"守卫必须打在实际解析这些符号的地方"。也就是说,同样的红测有两种修法——把守卫搬到新 owner 或 删掉守卫——main 选了前者,本 PR 选了后者。差别是实质性的:前者保住覆盖,后者让这三个 live 读路径在守卫里彻底消失(head 上 grep turn_decision 在测试文件里是 0 次命中)。
具体改动
只有一个文件、三行删除:tests/test_loopx_turn_journal_inspection.py 的第一个 guard 循环里去掉三个名字,其余 patch 列表(build_live_quota_should_run_decision、build_loopx_turn_plan、run_codex_cli_host、run_loopx_turn_once、spend_quota_slot、refresh_state_run 等)保持不动。没有生产代码变化。
关键代码讲解
tests/test_loopx_turn_journal_inspection.py:295(head 的第一个 guard 循环):删除后,整个测试文件里不再有任何地方 patch 那三个名字。loopx/cli_commands/turn_decision.py:35-38:三个符号搬迁后的实际归属地(scheduler_execution_context_for_turn、collect_status、build_lark_operator_inbox_urgency_projector的 import),并在56/186/191行被调用——这正是守卫应该挂的位置。origin/main:tests/test_loopx_turn_journal_inspection.py:306(main 的第二个 guard 循环):main 现成的等价修法,把三个名字 patch 到turn_decision上,并保留注释解释原因。- 三处对照的运行结果:
75fcd5556c→1 failed / 17 passed(AttributeError);head0ef087f870→18 passed;main67c8c6c57→18 passed且守卫在位。
对主干的风险
阻塞项(P2):本 PR 与 main 上已合并的 263d08e26 目标重叠但实现更弱。按现状合并,等于把 main 刚刚恢复的三个 owner 级守卫再删一次,覆盖从"守卫三个 live 读"退化为"完全不守卫";而这不是为了让套件变绿所必需的——main 用同样三条 patch 把它改成挂在新 owner 之后就已经全绿。分支当前是 MERGEABLE 且 BEHIND,所以"合并后到底保留 main 的 owner 守卫还是落到更弱的 head"本身就是这段改动引入的不确定性。最小修复是:rebase 到当前 main,确认那条 AttributeError 是否还复现(在 67c8c6c57 上已不复现),若不复现就作为 superseded 关闭;若仍要推进,就保留 main 的 owner 级 patch 而不是删除目标。
其余检查我都跑了/读了:head 上 pytest -q tests/test_loopx_turn_journal_inspection.py 18 项通过;grep 确认三个名字在 turn.py 为 0、在 turn_decision.py 的 35-38 行;gh pr view 4506 --json mergeable,mergeStateStatus 得到 MERGEABLE/BEHIND;未运行完整 CI 分片,本 PR 只删三行测试代码,本地模块级运行足以支撑该结论。
我的整体评价
结论是 REQUEST_CHANGES,问题不在代码质量而在时机与覆盖:作者诊断正确、改动干净,但 main 已经用"把守卫搬到新 owner"的方式修好了同一处(263d08e26),本 PR 的变体是它的弱化版——同样能让测试变绿,代价是三个 live 读路径不再被守卫拦截。这类"过时但看起来无害的小 PR"最容易被顺手合并,然后在未来某次重构里以"守卫没发现"的形式还债,所以值得退回给作者 rebase 确认。建议路径:rebase → 复现检查 → 若不再复现即关闭并说明被 263d08e26 取代;若作者认为仍有价值,就把改动改成保留 owner 级 patch。
English verdict: REQUEST_CHANGES — exact head 0ef087f870ede163dda9dffaf5de96616d18a66c of #4506. The diagnosis is correct at the branch's merge base: pytest -q tests/test_loopx_turn_journal_inspection.py fails 1 failed / 17 passed at 75fcd5556c with AttributeError on the three patch names that #4496 moved out of loopx.cli_commands.turn. But the fix is superseded and weaker on current main, which already contains 263d08e26 test(turn): keep the current-Turn owner guards on the owner: main re-points the same three names at turn_decision (where they are imported at lines 35-38 and called at 56/186/191) and keeps the coverage, while this branch deletes them, leaving zero occurrences of turn_decision in the test file. Evidence: 18 passed both at the reviewed head and at current main 67c8c6c57, so removing the guards is not required to make the suite green; gh pr view reports MERGEABLE/BEHIND, so merging now risks resolving to the coverage-reducing variant. Minimum repair: rebase onto current main, confirm whether the AttributeError still reproduces (it does not at 67c8c6c57), then close as superseded or keep main's owner-level guards instead of deleting targets. One blocking P2, no other findings; I did not run the full CI shards, which is proportionate for a three-line test-only diff.
|
Closing as superseded / 关闭:已被主干取代 English: main commit 中文: main 的 |
Summary
tests/test_loopx_turn_journal_inspection.py::test_inspect_journal_cli_branches_before_live_or_write_pathsfails on every PR built on current main withAttributeError: <module 'loopx.cli_commands.turn'> has no attribute 'build_lark_operator_inbox_urgency_projector'.collect_status,scheduler_execution_context_for_turn) out ofloopx.cli_commands.turn's top-level namespace intoturn_decision.py, but did not update this test's patch list, which still names all three on theturnmodule.turn_inspection.handle_turn_journal_inspectionnever imported these three names, so the property under test — inspect-journal never reaches a live/write path — already holds by construction; the stale patch targets asserted nothing real once refactor(turn): derive every Turn decision from one shared owner #4496 landed.Issue Or Task
Validation
unitpassedtests/test_loopx_turn_journal_inspection.py(18 tests, previously 1 failing with AttributeError)regression_paritypassedtests/test_loopx_turn_managed_step.py,tests/test_loopx_turn_executor.py,tests/extensions/test_lark_urgency_composition.py,tests/control_plane/test_scheduler_ack_current_host_binding.py(110 tests) — confirms the still-liveturn_decision.build_lark_operator_inbox_urgency_projectorpatch target elsewhere in the suite is unaffectedstaticpassedruff check tests/test_loopx_turn_journal_inspection.pyloopx.cli_commands.turn(the only other reference tobuild_lark_operator_inbox_urgency_projectortargetsturn_decision, which still exports it).See validation disclosure guidance.
Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Core control-plane hardening
Target base branch: main
Direction tracker or promotion unit:
Shared-authority RFC fixture impact
Boundary Checklist
.loopx/,.codex/goals/, and liveACTIVE_GOAL_STATE.md).none.Signed-off-bytrailer (git commit -s).