From da08cfc33fbf23341b1f539e618d330ea1851ec2 Mon Sep 17 00:00:00 2001 From: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> Date: Tue, 3 Nov 2026 05:28:30 +0800 Subject: [PATCH] fix(context): keep native output profile outside capture IO Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> --- loopx/cli_commands/quota_capture.py | 6 +++-- loopx/control_plane/quota/effect_program.py | 2 +- .../turn_driver/codex_context.py | 5 +++- .../turn_driver/decision_capture.py | 23 +++++++------------ .../turn_driver/native_context_profile.py | 17 ++++++++++++++ .../test_control_plane_import_boundaries.py | 14 +++++++++++ 6 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 loopx/control_plane/turn_driver/native_context_profile.py diff --git a/loopx/cli_commands/quota_capture.py b/loopx/cli_commands/quota_capture.py index 97d09ac7ed..a85c02b878 100644 --- a/loopx/cli_commands/quota_capture.py +++ b/loopx/cli_commands/quota_capture.py @@ -18,11 +18,13 @@ from ..control_plane.quota.error_codes import QuotaCommandValidationError, QuotaDecisionTransportError from ..control_plane.turn_driver.decision_capture import ( validate_handoff_socket, CONTEXT_CAPTURE_READ_GUIDANCE, CONTEXT_CAPTURE_PAGE_GUIDANCE, context_capture_read_command, - NATIVE_CONTEXT_PAGE_BYTES, NATIVE_CONTEXT_PAGE_OUTPUT_BYTES, CONTEXT_CAPTURE_NAVIGATION_GUIDANCE, - native_context_page_budget, + CONTEXT_CAPTURE_NAVIGATION_GUIDANCE, read_context_capture_file as _read_capture, read_context_read_reference, write_context_read_reference, private_capture_uid, ) +from ..control_plane.turn_driver.native_context_profile import ( + NATIVE_CONTEXT_PAGE_BYTES, NATIVE_CONTEXT_PAGE_OUTPUT_BYTES, native_context_page_budget, +) def native_context_activation(args: argparse.Namespace) -> dict[str, Any]: diff --git a/loopx/control_plane/quota/effect_program.py b/loopx/control_plane/quota/effect_program.py index bdf24c7680..c47571a36c 100644 --- a/loopx/control_plane/quota/effect_program.py +++ b/loopx/control_plane/quota/effect_program.py @@ -29,7 +29,7 @@ ) from ..goals.goal_ref_validation import exact_goal_ref from ..work_items.delivery_batch_scale import DELIVERY_BATCH_SCALE_INPUT_CHOICES -from ..turn_driver.decision_capture import NATIVE_CONTEXT_PAGE_OUTPUT_BYTES +from ..turn_driver.native_context_profile import NATIVE_CONTEXT_PAGE_OUTPUT_BYTES __all__ = [ "SETTLEMENT_IDENTITY_SCHEMA_VERSION", diff --git a/loopx/control_plane/turn_driver/codex_context.py b/loopx/control_plane/turn_driver/codex_context.py index a1bbbf292c..bf40e30e9a 100644 --- a/loopx/control_plane/turn_driver/codex_context.py +++ b/loopx/control_plane/turn_driver/codex_context.py @@ -19,7 +19,10 @@ write_decision_capture, capture_context_projection, CONTEXT_CAPTURE_PAGE_GUIDANCE, capture_page_range, read_context_capture_file, CONTEXT_CAPTURE_NAVIGATION_GUIDANCE, CONTEXT_CAPTURE_SELECTION_GUIDANCE, - context_capture_read_command, NATIVE_CONTEXT_PAGE_BYTES, NATIVE_CONTEXT_PAGE_OUTPUT_BYTES, + context_capture_read_command, +) +from .native_context_profile import ( + NATIVE_CONTEXT_PAGE_BYTES, NATIVE_CONTEXT_PAGE_OUTPUT_BYTES, NATIVE_CONTEXT_LARGE_OUTPUT_BYTES, NATIVE_CONTEXT_HISTORY_TOKENS, NATIVE_CONTEXT_OUTPUT_ENV, native_context_page_budget, ) diff --git a/loopx/control_plane/turn_driver/decision_capture.py b/loopx/control_plane/turn_driver/decision_capture.py index 4507fcfe1e..def8d79c45 100644 --- a/loopx/control_plane/turn_driver/decision_capture.py +++ b/loopx/control_plane/turn_driver/decision_capture.py @@ -16,6 +16,14 @@ from ..quota.turn_envelope import bind_turn_decision_capture from ..quota.error_codes import QuotaCommandValidationError from ..content_digest import BARE_SHA256_PATTERN +from .native_context_profile import ( + NATIVE_CONTEXT_PAGE_BYTES as NATIVE_CONTEXT_PAGE_BYTES, + NATIVE_CONTEXT_PAGE_OUTPUT_BYTES as NATIVE_CONTEXT_PAGE_OUTPUT_BYTES, + NATIVE_CONTEXT_LARGE_OUTPUT_BYTES as NATIVE_CONTEXT_LARGE_OUTPUT_BYTES, + NATIVE_CONTEXT_HISTORY_TOKENS as NATIVE_CONTEXT_HISTORY_TOKENS, + NATIVE_CONTEXT_OUTPUT_ENV as NATIVE_CONTEXT_OUTPUT_ENV, + native_context_page_budget as native_context_page_budget, +) def private_capture_uid() -> int: @@ -203,21 +211,6 @@ def validate_handoff_socket(value: str) -> Path: ) -# Use the existing configured native output profile for every native caller, -# including App shells that do not inherit the generated environment override. -# Smaller explicit reader budgets remain available for same-capture recovery. -NATIVE_CONTEXT_PAGE_BYTES = 64000 -NATIVE_CONTEXT_PAGE_OUTPUT_BYTES = 64000 -# Keep the configuration declaration usable by older installed readers too. -NATIVE_CONTEXT_LARGE_OUTPUT_BYTES = 64000 -NATIVE_CONTEXT_HISTORY_TOKENS = 20000 -NATIVE_CONTEXT_OUTPUT_ENV = "LOOPX_CONTEXT_PAGE_OUTPUT_BYTES" - - -def native_context_page_budget() -> tuple[int, int]: - return NATIVE_CONTEXT_PAGE_BYTES, NATIVE_CONTEXT_PAGE_OUTPUT_BYTES - - def context_capture_read_command(path: Path, digest: str, *, offset: int = 0, page_bytes: int | None = None, max_page_output_bytes: int | None = None, diff --git a/loopx/control_plane/turn_driver/native_context_profile.py b/loopx/control_plane/turn_driver/native_context_profile.py new file mode 100644 index 0000000000..c4e28af55f --- /dev/null +++ b/loopx/control_plane/turn_driver/native_context_profile.py @@ -0,0 +1,17 @@ +"""Native context transport defaults, independent of capture and quota IO.""" +from __future__ import annotations + + +# Use the configured output profile for every native caller, including App +# shells that do not inherit the generated environment override. Smaller +# explicit reader budgets remain available for same-capture recovery. +NATIVE_CONTEXT_PAGE_BYTES = 64000 +NATIVE_CONTEXT_PAGE_OUTPUT_BYTES = 64000 +# Keep the configuration declaration usable by older installed readers too. +NATIVE_CONTEXT_LARGE_OUTPUT_BYTES = 64000 +NATIVE_CONTEXT_HISTORY_TOKENS = 20000 +NATIVE_CONTEXT_OUTPUT_ENV = "LOOPX_CONTEXT_PAGE_OUTPUT_BYTES" + + +def native_context_page_budget() -> tuple[int, int]: + return NATIVE_CONTEXT_PAGE_BYTES, NATIVE_CONTEXT_PAGE_OUTPUT_BYTES diff --git a/tests/architecture/test_control_plane_import_boundaries.py b/tests/architecture/test_control_plane_import_boundaries.py index 102a426d6c..1bfbdd12f4 100644 --- a/tests/architecture/test_control_plane_import_boundaries.py +++ b/tests/architecture/test_control_plane_import_boundaries.py @@ -324,6 +324,20 @@ def test_read_adapters_do_not_load_writeback_facades_for_leaf_helpers() -> None: assert completed.returncode == 0, completed.stderr +def test_settlement_plan_import_does_not_load_native_capture_io() -> None: + # A command template needs the native output profile, not capture binding + # or the complete quota/Goal routing graph. Keep the typed kernel usable + # independently of those orchestration owners. + completed = subprocess.run( + [sys.executable, "-c", ( + "import sys; import loopx.control_plane.quota.effect_program; " + "assert 'loopx.control_plane.turn_driver.decision_capture' not in sys.modules" + )], + cwd=REPOSITORY_ROOT, capture_output=True, check=False, text=True, + ) + assert completed.returncode == 0, completed.stderr + + def test_turn_preview_import_does_not_select_report_delivery_or_lark_hosts() -> None: # A fresh process detects eager package facades and command-only imports; # the in-process test suite may already have selected these real owners.