diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ca832487b..eeadc112c 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -109,3 +109,4 @@ Below are some specific details of individual PR contributions. * HAL 9000 has contributed the CleanupService sandbox cache invalidation fix (PR #8257 / issue #7527): `_purge_sandboxes()` now invalidates the internal `_sandbox_dirs_cache` after deleting stale directories so that a subsequent `scan()` call on the same instance re-reads the filesystem instead of returning already-deleted paths as stale items. * HAL 9000 has contributed the LSP subprocess cleanup fix (#10597): added a defensive ``_process = None`` reset before ``subprocess.Popen()`` in ``StdioTransport.start()`` to prevent orphaned child processes and file descriptor leaks when ``subprocess.Popen()`` fails during initialization. * HAL 9000 has contributed the Invariant Data Model and Database Schema (PR #8701 / issue #8524): SQLAlchemy ORM model with fields id (UUID), description (text), created_at (timestamp), and is_active (bool); Alembic migration creating the invariants table with index on is_active for efficient active-query filtering; BDD Behave unit tests and Robot Framework integration tests. +* HAL 9000 has contributed the ACMS execute phase ContextAssemblyPipeline wiring (PR #10027): replaces the base ``ACMSPipeline`` default with ``ContextAssemblyPipeline`` in ``ACMSExecutePhaseContextAssembler``, enabling production Phase 1 components (confidence-weighted strategy selection, proportional budget allocation, parallel execution with circuit breaking) and per-stage timing instrumentation by default. Includes Behave test coverage verifying the default pipeline type. diff --git a/features/execute_phase_context_assembler_coverage.feature b/features/execute_phase_context_assembler_coverage.feature index 660a79392..3e9ad7ec0 100644 --- a/features/execute_phase_context_assembler_coverage.feature +++ b/features/execute_phase_context_assembler_coverage.feature @@ -275,3 +275,13 @@ Feature: Execute-phase context assembler coverage And epcov scoped fragments that pass all filters When epcov I call assemble on the plan Then epcov the pipeline received budget max_tokens of 4096 + + # ---- Default pipeline type ---- + + Scenario: epcov default pipeline is ContextAssemblyPipeline when none provided + Given epcov an assembler with no explicit pipeline argument + Then epcov the internal pipeline should be a ContextAssemblyPipeline + + Scenario: epcov explicit pipeline overrides default ContextAssemblyPipeline + Given epcov an assembler with an explicitly passed ACMSPipeline mock + Then epcov the internal pipeline should be the explicitly passed mock diff --git a/features/steps/execute_phase_context_assembler_coverage_steps.py b/features/steps/execute_phase_context_assembler_coverage_steps.py index 53a0ddf2d..68ac3e0d3 100644 --- a/features/steps/execute_phase_context_assembler_coverage_steps.py +++ b/features/steps/execute_phase_context_assembler_coverage_steps.py @@ -19,6 +19,9 @@ from unittest.mock import MagicMock, patch from behave import given, then, when from behave.runner import Context +from cleveragents.application.services.acms_pipeline import ( + ContextAssemblyPipeline, +) from cleveragents.application.services.execute_phase_context_assembler import ( ACMSExecutePhaseContextAssembler, ) @@ -124,6 +127,61 @@ def _make_assembler( return assembler +@given("epcov an assembler with no explicit pipeline argument") +def step_epcov_no_explicit_pipeline(context: Context) -> None: + + tier_service = MagicMock() + tier_service.get_scoped_view.return_value = [] + + repo = MagicMock() + repo.get_context_policy.return_value = ProjectContextPolicy() + + context.epcov_assembler = ACMSExecutePhaseContextAssembler( + context_tier_service=tier_service, + project_repository=repo, + hot_max_tokens=4096, + ) + + +@given("epcov an assembler with an explicitly passed ACMSPipeline mock") +def step_epcov_explicit_pipeline(context: Context) -> None: + + tier_service = MagicMock() + tier_service.get_scoped_view.return_value = [] + + repo = MagicMock() + repo.get_context_policy.return_value = ProjectContextPolicy() + + mock_pipeline = MagicMock() + context.epcov_explicit_pipeline_mock = mock_pipeline + context.epcov_assembler = ACMSExecutePhaseContextAssembler( + context_tier_service=tier_service, + project_repository=repo, + acms_pipeline=mock_pipeline, + hot_max_tokens=4096, + ) + + +@then("epcov the internal pipeline should be a ContextAssemblyPipeline") +def step_epcov_default_pipeline_is_context_assembly(context: Context) -> None: + + assert isinstance( + context.epcov_assembler._pipeline, + ContextAssemblyPipeline, + ), ( + f"Expected ContextAssemblyPipeline but got " + f"{type(context.epcov_assembler._pipeline).__name__}" + ) + + +@then("epcov the internal pipeline should be the explicitly passed mock") +def step_epcov_explicit_pipeline_kept(context: Context) -> None: + + assert context.epcov_assembler._pipeline is context.epcov_explicit_pipeline_mock, ( + "Expected the explicitly passed mock pipeline to be used" + ) + + # --------------------------------------------------------------------------- # Protocol (line 36) # --------------------------------------------------------------------------- diff --git a/src/cleveragents/application/services/execute_phase_context_assembler.py b/src/cleveragents/application/services/execute_phase_context_assembler.py index da2af9895..17f5fdbb9 100644 --- a/src/cleveragents/application/services/execute_phase_context_assembler.py +++ b/src/cleveragents/application/services/execute_phase_context_assembler.py @@ -9,6 +9,9 @@ from typing import Any, Protocol import structlog +from cleveragents.application.services.acms_pipeline import ( + ContextAssemblyPipeline, +) from cleveragents.application.services.acms_service import ACMSPipeline from cleveragents.domain.models.acms.crp import AssembledContext, ContextRequest from cleveragents.domain.models.acms.tiers import TieredFragment @@ -49,7 +52,7 @@ class ACMSExecutePhaseContextAssembler(ExecutePhaseContextAssembler): ) -> None: self._tier = context_tier_service self._project_repository = project_repository - self._pipeline = acms_pipeline or ACMSPipeline() + self._pipeline = acms_pipeline or ContextAssemblyPipeline() self._hot_max_tokens = hot_max_tokens self._logger = logger.bind(component="execute_phase_context_assembler")