From c65486ef2af5e5d46ce31517bd284507a0b8888a Mon Sep 17 00:00:00 2001 From: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> Date: Sat, 7 Nov 2026 14:21:43 +0800 Subject: [PATCH 1/2] perf(turn): defer optional modules on read-only previews Keep process-tree cleanup and semantic preference recall on their selected paths. Exercise the normal Turn plan entrypoint in fresh File and SQLite fixture processes and preserve bounded Git and validation cleanup. Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> --- .../semantic_preference/__init__.py | 41 ++++++++++--- loopx/contract.py | 3 +- .../runtime/validation_command.py | 5 +- tests/test_loopx_turn_driver.py | 60 +++++++++++-------- 4 files changed, 71 insertions(+), 38 deletions(-) diff --git a/loopx/capabilities/semantic_preference/__init__.py b/loopx/capabilities/semantic_preference/__init__.py index 2a6134d134..50694762ee 100644 --- a/loopx/capabilities/semantic_preference/__init__.py +++ b/loopx/capabilities/semantic_preference/__init__.py @@ -1,12 +1,35 @@ """Optional provider-neutral semantic preference recall.""" +from __future__ import annotations -from .contract import application_receipt, maintenance_receipt, provider_doctor, recall -from .reward_memory import run_semantic_preference_reward_memory +from importlib import import_module +from typing import TYPE_CHECKING, Any -__all__ = [ - "application_receipt", - "maintenance_receipt", - "provider_doctor", - "recall", - "run_semantic_preference_reward_memory", -] +if TYPE_CHECKING: + from .contract import application_receipt as application_receipt + from .contract import maintenance_receipt as maintenance_receipt + from .contract import provider_doctor as provider_doctor + from .contract import recall as recall + from .reward_memory import run_semantic_preference_reward_memory as run_semantic_preference_reward_memory + +# The Turn start hook reads local preferences without selecting a recall provider. +_EXPORTS = { + "application_receipt": "contract", + "maintenance_receipt": "contract", + "provider_doctor": "contract", + "recall": "contract", + "run_semantic_preference_reward_memory": "reward_memory", +} +__all__ = list(_EXPORTS) + + +def __getattr__(name: str) -> Any: + module = _EXPORTS.get(name) + if module is None: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + value = getattr(import_module(f".{module}", __name__), name) + globals()[name] = value + return value + + +def __dir__() -> list[str]: + return sorted(set(globals()) | set(__all__)) diff --git a/loopx/contract.py b/loopx/contract.py index b310687f6e..d94e87faf6 100644 --- a/loopx/contract.py +++ b/loopx/contract.py @@ -36,7 +36,6 @@ from .control_plane.todos.active_state_editing import COMPLETED_WORK_ARCHIVE_HEADING from .control_plane.todos.active_state_todo_parser import active_state_incomplete_warning from .control_plane.todos.authoring_scope import todo_contract_diagnostics -from .extensions.process_runtime import terminate_process_tree from .history import ( RunHistoryAudit, build_run_history_audit, @@ -350,6 +349,8 @@ def _retire_owned_probe(process: subprocess.Popen[str]) -> None: """ try: + from .extensions.process_runtime import terminate_process_tree + terminate_process_tree(process, grace_seconds=0.2) except (OSError, RuntimeError): pass diff --git a/loopx/control_plane/runtime/validation_command.py b/loopx/control_plane/runtime/validation_command.py index 1e896e9b5b..85dafb390c 100644 --- a/loopx/control_plane/runtime/validation_command.py +++ b/loopx/control_plane/runtime/validation_command.py @@ -9,8 +9,6 @@ from pathlib import Path from typing import Any -from ...extensions.process_runtime import terminate_process_tree - # Frozen wire id shared with capabilities/issue_fix. Kept verbatim for wire # compatibility with existing caller-repo-branch receipts. CALLER_VALIDATION_RECEIPT_SCHEMA_VERSION = "issue_fix_validation_command_v0" @@ -63,6 +61,9 @@ def run_caller_validation( ) if not argv: raise ValueError("validation command must not be empty") + + from ...extensions.process_runtime import terminate_process_tree + with subprocess.Popen( argv, cwd=workspace, diff --git a/tests/test_loopx_turn_driver.py b/tests/test_loopx_turn_driver.py index e5c1047393..6844239adb 100644 --- a/tests/test_loopx_turn_driver.py +++ b/tests/test_loopx_turn_driver.py @@ -1821,35 +1821,43 @@ def recording_collect_status(*args: Any, **kwargs: Any) -> dict[str, Any]: ) +@pytest.mark.parametrize("provider", ("file", "sqlite")) def test_turn_cli_projects_explicit_fresh_iteration_context( - tmp_path: Path, + tmp_path: Path, provider: str, ) -> None: - project, runtime, registry = _write_live_fixture(tmp_path) - output = io.StringIO() - - with contextlib.redirect_stdout(output): - exit_code = cli_main( - [ - "--registry", - str(registry), - "--runtime-root", - str(runtime), - "--format", - "json", - "turn", - "plan", - "--goal-id", - "loopx-turn-fixture", - "--agent-id", - "codex-fixture", - "--iteration-context", - "fresh", - "--include-transaction-detail", - ] - ) + _, runtime, registry = _write_live_fixture(tmp_path, provider=provider) + # Use the CLI entrypoint in a fresh process. In-process + # callers and test collection may already have selected these providers. + process = subprocess.run( + [ + sys.executable, "-c", "\n".join(( + "import sys", + "from loopx.entrypoint import main", + "status = main(sys.argv[1:])", + "unselected = {'loopx.extensions.process_runtime',", + " 'loopx.capabilities.semantic_preference.contract',", + " 'loopx.capabilities.semantic_preference.reward_memory'}", + "assert not unselected & sys.modules.keys(), unselected & sys.modules.keys()", + "raise SystemExit(status)", + )), + "--registry", str(registry), + "--runtime-root", str(runtime), + "--format", "json", + "turn", "plan", + "--goal-id", "loopx-turn-fixture", + "--agent-id", "codex-fixture", + "--iteration-context", "fresh", + "--include-transaction-detail", + ], + cwd=Path(__file__).resolve().parents[1], + env={**os.environ, "LOOPX_USAGE_PING": "0"}, + capture_output=True, + text=True, + timeout=60, + ) - payload = json.loads(output.getvalue()) - assert exit_code == 0, payload + assert process.returncode == 0, process.stdout + process.stderr + payload = json.loads(process.stdout) assert payload["session"]["action"] == "start_new" assert payload["session"]["context_policy"] == { "schema_version": "loopx_iteration_context_policy_v0", From 98dfeea0a222e004c956de73a59a28d7443846e9 Mon Sep 17 00:00:00 2001 From: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> Date: Sat, 7 Nov 2026 15:38:50 +0800 Subject: [PATCH 2/2] Scope Turn preview to deferred preference recall Keep the distinct recall import seam and its real CLI regression. The process transport proposal owns the shared cleanup callers. Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> --- loopx/contract.py | 3 +-- loopx/control_plane/runtime/validation_command.py | 5 ++--- tests/test_loopx_turn_driver.py | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/loopx/contract.py b/loopx/contract.py index d94e87faf6..b310687f6e 100644 --- a/loopx/contract.py +++ b/loopx/contract.py @@ -36,6 +36,7 @@ from .control_plane.todos.active_state_editing import COMPLETED_WORK_ARCHIVE_HEADING from .control_plane.todos.active_state_todo_parser import active_state_incomplete_warning from .control_plane.todos.authoring_scope import todo_contract_diagnostics +from .extensions.process_runtime import terminate_process_tree from .history import ( RunHistoryAudit, build_run_history_audit, @@ -349,8 +350,6 @@ def _retire_owned_probe(process: subprocess.Popen[str]) -> None: """ try: - from .extensions.process_runtime import terminate_process_tree - terminate_process_tree(process, grace_seconds=0.2) except (OSError, RuntimeError): pass diff --git a/loopx/control_plane/runtime/validation_command.py b/loopx/control_plane/runtime/validation_command.py index 85dafb390c..1e896e9b5b 100644 --- a/loopx/control_plane/runtime/validation_command.py +++ b/loopx/control_plane/runtime/validation_command.py @@ -9,6 +9,8 @@ from pathlib import Path from typing import Any +from ...extensions.process_runtime import terminate_process_tree + # Frozen wire id shared with capabilities/issue_fix. Kept verbatim for wire # compatibility with existing caller-repo-branch receipts. CALLER_VALIDATION_RECEIPT_SCHEMA_VERSION = "issue_fix_validation_command_v0" @@ -61,9 +63,6 @@ def run_caller_validation( ) if not argv: raise ValueError("validation command must not be empty") - - from ...extensions.process_runtime import terminate_process_tree - with subprocess.Popen( argv, cwd=workspace, diff --git a/tests/test_loopx_turn_driver.py b/tests/test_loopx_turn_driver.py index 6844239adb..8527b5637a 100644 --- a/tests/test_loopx_turn_driver.py +++ b/tests/test_loopx_turn_driver.py @@ -1834,8 +1834,7 @@ def test_turn_cli_projects_explicit_fresh_iteration_context( "import sys", "from loopx.entrypoint import main", "status = main(sys.argv[1:])", - "unselected = {'loopx.extensions.process_runtime',", - " 'loopx.capabilities.semantic_preference.contract',", + "unselected = {'loopx.capabilities.semantic_preference.contract',", " 'loopx.capabilities.semantic_preference.reward_memory'}", "assert not unselected & sys.modules.keys(), unselected & sys.modules.keys()", "raise SystemExit(status)",