From bca2dbb5d333adaa28b7b0723dc2590a55978f3e Mon Sep 17 00:00:00 2001 From: keoyyo85 <335569976+keoyyo85@users.noreply.github.com> Date: Thu, 5 Nov 2026 00:31:31 +0800 Subject: [PATCH] fix(quota): keep capture IO out of the settlement plan's cold import a5b742f19 imported private_capture_supported at module scope, so importing the settlement-plan builder loaded loopx.control_plane.turn_driver.decision_capture and failed the repository's own cold-import guard. A command template needs the native output profile, not the capture-binding owner. The plan builder now resolves the predicate at its owner when it builds the spend step, so decision_capture stays the single platform qualification and the plan kernel remains loadable on its own. The generated commands are unchanged: the plan payload is byte-identical before and after on a POSIX host. Signed-off-by: keoyyo85 <335569976+keoyyo85@users.noreply.github.com> --- loopx/control_plane/quota/effect_program.py | 5 ++++- tests/control_plane/test_quota_settlement.py | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/loopx/control_plane/quota/effect_program.py b/loopx/control_plane/quota/effect_program.py index c99a27974d..e0e8da4e1d 100644 --- a/loopx/control_plane/quota/effect_program.py +++ b/loopx/control_plane/quota/effect_program.py @@ -30,7 +30,6 @@ from ..goals.goal_ref_validation import exact_goal_ref from ..work_items.delivery_batch_scale import DELIVERY_BATCH_SCALE_INPUT_CHOICES from ..turn_driver.native_context_profile import NATIVE_CONTEXT_PAGE_OUTPUT_BYTES -from ..turn_driver.decision_capture import private_capture_supported _PLATFORM_IS_POSIX = os.name == "posix" @@ -268,6 +267,10 @@ def writeback_command(boundary: str) -> str: writeback_command(" --delivery-boundary semantic_closeout") + " --agent-vision-json " ) + # Imported here so the settlement-plan kernel stays loadable on its own: the + # capture-binding owner is orchestration a command template never needs. + from ..turn_driver.decision_capture import private_capture_supported + max_output_arg = ( f" --max-page-output-bytes {NATIVE_CONTEXT_PAGE_OUTPUT_BYTES}" if private_capture_supported() diff --git a/tests/control_plane/test_quota_settlement.py b/tests/control_plane/test_quota_settlement.py index 82fadb397c..076fdfd50f 100644 --- a/tests/control_plane/test_quota_settlement.py +++ b/tests/control_plane/test_quota_settlement.py @@ -826,7 +826,9 @@ def test_private_capture_support_matches_uid_boundary( def test_settlement_command_uses_private_capture_support() -> None: # The generated command and the CLI's private-capture check must share one # platform qualification; a POSIX-looking host without getuid is unsupported. - with patch.object(quota_effect_program, "private_capture_supported", return_value=False): + # The settlement kernel resolves the predicate at its owner, because keeping + # capture IO out of the plan module's cold import is itself a guard. + with patch.object(decision_capture_module, "private_capture_supported", return_value=False): plan = quota_effect_program.build_turn_scoped_cli_settlement_plan( goal_id=GOAL_ID, agent_id=AGENT_ID, todo_id=TODO_ID, turn_instance_id=TURN_ID, scoped_cli_args="", lifecycle_actor_args="", @@ -835,7 +837,7 @@ def test_settlement_command_uses_private_capture_support() -> None: assert command is not None assert "--max-page-output-bytes" not in command - with patch.object(quota_effect_program, "private_capture_supported", return_value=True): + with patch.object(decision_capture_module, "private_capture_supported", return_value=True): plan = quota_effect_program.build_turn_scoped_cli_settlement_plan( goal_id=GOAL_ID, agent_id=AGENT_ID, todo_id=TODO_ID, turn_instance_id=TURN_ID, scoped_cli_args="", lifecycle_actor_args="",