From a1213edced421a0b979f36491675191131a2d6a9 Mon Sep 17 00:00:00 2001 From: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Date: Tue, 15 Sep 2026 19:53:15 +0800 Subject: [PATCH] refactor(turn): bind the advisory primary through the shared decision owner `run-once` duplicated the controller advisory-primary rebinding that `turn_decision.apply_controller_advisory_primary` already owns for `managed-step`. The two copies had to stay step-identical by inspection: resolve the advisory primary, re-resolve the decision with it requested, fail closed when it is no longer eligible, record selected_by, and keep the advisory portfolio on the decision. Call the shared owner instead. Behavior is unchanged; the fail-closed rule now has one home, so the two Turn subcommands cannot drift. This also brings loopx/cli_commands/turn.py back under its frozen size baseline: the managed host-selection wiring took it to 1123 lines against a budget of 1114, which left full-public-smokes red on main. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> --- loopx/cli_commands/turn.py | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/loopx/cli_commands/turn.py b/loopx/cli_commands/turn.py index f95247bff0..72b3ad56ef 100644 --- a/loopx/cli_commands/turn.py +++ b/loopx/cli_commands/turn.py @@ -64,6 +64,7 @@ build_lark_operator_inbox_urgency_projector, dispatch_goal_lark_turn_start_hooks, ) +from .turn_decision import apply_controller_advisory_primary from .turn_dsh_host import build_dsh_host_runner from .turn_registration import register_turn_commands as register_turn_commands from .turn_inspection import handle_turn_journal_inspection @@ -71,7 +72,6 @@ render_loopx_turn_execution_markdown as _render_loopx_turn_execution_markdown, render_loopx_turn_plan_markdown as _render_loopx_turn_plan_markdown, ) -from .turn_selection import turn_controller_advisory_primary from .turn_todo_writeback import ( write_turn_repair_update, write_turn_validated_completion, @@ -183,22 +183,10 @@ def build_turn_decision( goal_id=args.goal_id, agent_id=args.agent_id),), ) - decision = build_turn_decision() - controller_default = turn_controller_advisory_primary(decision) - if controller_default is not None: - primary_todo_id, advisory_portfolio = controller_default - decision = build_turn_decision( - requested_action_todo_id=primary_todo_id, - ) - selected_todo = decision.get("selected_todo") - if not isinstance(selected_todo, dict) or ( - selected_todo.get("todo_id") != primary_todo_id - ): - raise ValueError( - "Turn controller advisory primary failed current eligibility" - ) - selected_todo["selected_by"] = "turn_controller_advisory_primary" - decision["action_portfolio"] = advisory_portfolio + # `run-once` and `managed-step` must resolve the same governing decision, + # so the advisory-primary rebinding lives in the shared decision owner + # instead of being repeated per subcommand. + decision = apply_controller_advisory_primary(build_turn_decision) resume_identity = { "goal_id": args.resume_goal_id, "agent_id": args.resume_agent_id,