@phase3 @acms @acms_pipeline_phase3 Feature: ACMS Pipeline Phase 3 — Context Finalization and Advanced Strategies As a CleverAgents developer I want production-grade Phase 3 pipeline components and advanced strategies So that context assembly orders fragments coherently, generates provenance preambles, and supports ARCE, temporal archaeology, and plan decision context strategies # =========================================================================== # RelevanceCoherenceOrderer # =========================================================================== @orderer Scenario: Order fragments by relevance while grouping related nodes Given the following phase3 fragments: | uko_node | content | score | tokens | depth | | project://app/io.py | io module | 0.9 | 20 | 3 | | project://app/main.py | main entry | 0.5 | 15 | 3 | | project://lib/util.py | utility fn | 0.7 | 25 | 3 | | project://app/net.py | network | 0.8 | 10 | 3 | When I order the fragments with RelevanceCoherenceOrderer Then the first ordered fragment should have uko_node "project://app/io.py" And fragments from the same group should be adjacent @orderer Scenario: Order with empty fragment list Given an empty phase3 fragment list When I order the fragments with RelevanceCoherenceOrderer Then 0 fragments should remain after ordering @orderer Scenario: Order single fragment returns it unchanged Given the following phase3 fragments: | uko_node | content | score | tokens | depth | | project://app/main.py | hello | 0.5 | 10 | 3 | When I order the fragments with RelevanceCoherenceOrderer Then 1 fragment should remain after ordering @orderer Scenario: Order preserves all fragments Given the following phase3 fragments: | uko_node | content | score | tokens | depth | | project://app/a.py | alpha | 0.3 | 10 | 3 | | project://app/b.py | beta | 0.9 | 10 | 5 | | project://app/c.py | gamma | 0.6 | 10 | 1 | When I order the fragments with RelevanceCoherenceOrderer Then 3 fragments should remain after ordering @orderer Scenario: Higher-depth fragments ordered after overview in same group Given the following phase3 fragments: | uko_node | content | score | tokens | depth | | project://app/main.py | detail | 0.8 | 10 | 9 | | project://app/main.py | brief | 0.8 | 10 | 1 | When I order the fragments with RelevanceCoherenceOrderer Then 2 fragments should remain after ordering # =========================================================================== # ProvenancePreambleGenerator # =========================================================================== @preamble Scenario: Generate provenance preamble with strategy contributions Given the following phase3 fragments with strategy sources: | uko_node | content | score | tokens | depth | strategy_source | | project://app/main.py | hello | 0.8 | 100 | 3 | relevance | | project://app/io.py | world | 0.6 | 50 | 5 | relevance | | project://lib/util.py | util | 0.7 | 75 | 2 | arce | When I generate a preamble with ProvenancePreambleGenerator Then the preamble should contain "Strategy Contributions" And the preamble should contain "relevance" And the preamble should contain "arce" And the preamble should contain "Confidence" And the preamble should contain "Tier Distribution" And the preamble should contain "Depth Distribution" @preamble Scenario: Generate preamble with confidence indicators Given the following phase3 fragments: | uko_node | content | score | tokens | depth | | project://app/main.py | hello | 0.9 | 50 | 3 | | project://app/io.py | world | 0.3 | 50 | 5 | When I generate a preamble with ProvenancePreambleGenerator Then the preamble should contain "avg=0.600" And the preamble should contain "min=0.300" And the preamble should contain "max=0.900" @preamble Scenario: Generate preamble returns None for empty fragments Given an empty phase3 fragment list When I generate a preamble with ProvenancePreambleGenerator Then the preamble should be None @preamble Scenario: Preamble identifies coverage gaps for missing tiers Given the following phase3 fragments: | uko_node | content | score | tokens | depth | | project://app/main.py | hello | 0.8 | 50 | 3 | When I generate a preamble with ProvenancePreambleGenerator Then the preamble should contain "Coverage Gaps" And the preamble should contain "Missing tiers" @preamble Scenario: Preamble includes UKO node count Given the following phase3 fragments: | uko_node | content | score | tokens | depth | | project://app/a.py | alpha | 0.8 | 50 | 3 | | project://app/b.py | beta | 0.7 | 50 | 5 | | project://lib/c.py | gamma | 0.6 | 50 | 2 | When I generate a preamble with ProvenancePreambleGenerator Then the preamble should contain "UKO Nodes: 3" # =========================================================================== # DepthReductionCompressor # =========================================================================== @compressor Scenario: DepthReductionCompressor reduces Python fragments to inherited overview levels Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://src/app/main.py | def main(): return runner() | 0.9 | 120 | 7 | | python-source | | project://src/app/util.py | class Util: pass | 0.6 | 90 | 5 | uko-py: | python-source | When I compress with DepthReductionCompressor and budget 40 Then all compressed fragments should have detail depth at most 1 And compressed fragments should fit within budget 40 And the compressed fragments should include skeleton level "MODULE_GRAPH" And a compressed fragment should contain "[MODULE_GRAPH]: symbols=main" @compressor Scenario: DepthReductionCompressor uses document detail levels for markdown fragments Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://docs/specification.md | # Spec\n## Overview\n## Details | 0.8 | 100 | 8 | | markdown | When I compress with DepthReductionCompressor and budget 20 Then all compressed fragments should have detail depth at most 1 And compressed fragments should fit within budget 20 And the compressed fragments should include skeleton level "TABLE_OF_CONTENTS_L1" And a compressed fragment should contain "Overview; Details" @compressor Scenario: DepthReductionCompressor returns no fragments for zero budget Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://src/app/a.py | def alpha(): pass | 0.7 | 80 | 6 | uko-py: | python-source | When I compress with DepthReductionCompressor and budget 0 Then 0 fragments should remain after compression @compressor Scenario: DepthReductionCompressor keeps the highest-relevance fragment when budget is tight Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://src/app/main.py | def main(): return run | 0.9 | 120 | 7 | uko-py: | python-source | | project://src/app/aux.py | def aux(): return slow | 0.3 | 120 | 7 | uko-py: | python-source | When I compress with DepthReductionCompressor and budget 9 Then 1 fragments should remain after compression And compressed fragments should fit within budget 9 And a compressed fragment should contain "main.py" @compressor Scenario: DepthReductionCompressor renders data fragments with CSV-like summary Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://db/schema.sql | users, orders, products, shipments | 0.7 | 80 | 5 | uko-data: | sql | When I compress with DepthReductionCompressor and budget 30 Then all compressed fragments should have detail depth at most 1 And compressed fragments should fit within budget 30 And a compressed fragment should contain "schema.sql" @compressor Scenario: DepthReductionCompressor renders infrastructure fragments Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://deploy/main.tf | resource "aws_instance" "web" {} | 0.8 | 90 | 6 | uko-infra: | terraform | When I compress with DepthReductionCompressor and budget 30 Then all compressed fragments should have detail depth at most 1 And compressed fragments should fit within budget 30 And a compressed fragment should contain "main.tf" @compressor Scenario: DepthReductionCompressor renders generic fragments at overview depth Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | uko:some/resource | generic resource | 0.6 | 80 | 4 | uko: | unknown | When I compress with DepthReductionCompressor and budget 30 Then all compressed fragments should have detail depth at most 1 And compressed fragments should fit within budget 30 @compressor Scenario: DepthReductionCompressor preserves fragment already at target depth Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://src/app/main.py | brief view | 0.9 | 10 | 0 | uko-py: | python-source | When I compress with DepthReductionCompressor and budget 100 Then 1 fragments should remain after compression And a compressed fragment should contain "brief view" @compressor Scenario: DepthReductionCompressor clips content when all renderings exceed budget Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://src/app/main.py | def main(): return very_long_function_name_placeholder() | 0.9 | 200 | 7 | uko-py: | python-source | When I compress with DepthReductionCompressor and budget 4 Then 1 fragments should remain after compression And compressed fragments should fit within budget 4 @compressor Scenario: DepthReductionCompressor resolves detail map from provenance URI prefix Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | uko-doc:my/design-doc | # Design Overview | 0.7 | 80 | 5 | | | When I compress with DepthReductionCompressor and budget 30 Then all compressed fragments should have detail depth at most 1 @compressor Scenario: DepthReductionCompressor resolves detail map from resource_type Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://data/schema | CREATE TABLE users (id INTEGER) | 0.6 | 80 | 4 | | database | When I compress with DepthReductionCompressor and budget 30 Then all compressed fragments should have detail depth at most 1 @compressor Scenario: DepthReductionCompressor handles minimal content fragments Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://src/app/empty.py | x | 0.5 | 1 | 3 | uko-py: | python-source | When I compress with DepthReductionCompressor and budget 10 Then compressed fragments should fit within budget 10 @compressor Scenario: DepthReductionCompressor resolves TypeScript and Java from file extension Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://src/app.ts | export function main() {} | 0.8 | 80 | 6 | | | | project://src/Main.java | public class Main {} | 0.7 | 80 | 6 | | | When I compress with DepthReductionCompressor and budget 60 Then compressed fragments should fit within budget 60 @compressor Scenario: DepthReductionCompressor resolves Rust from file extension Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://src/main.rs | fn main() {} | 0.8 | 80 | 6 | | | When I compress with DepthReductionCompressor and budget 30 Then compressed fragments should fit within budget 30 @compressor Scenario: DepthReductionCompressor resolves infra from YAML extension Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://k8s/deploy.yaml | apiVersion: apps/v1 | 0.7 | 80 | 5 | | | When I compress with DepthReductionCompressor and budget 30 Then compressed fragments should fit within budget 30 @compressor Scenario: DepthReductionCompressor detects doc resource_type Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://guides/getting-started | Welcome to the docs | 0.6 | 80 | 5 | | markdown | When I compress with DepthReductionCompressor and budget 30 Then compressed fragments should fit within budget 30 @compressor Scenario: DepthReductionCompressor detects infra resource_type Given the following phase3 skeleton fragments: | uko_node | content | score | tokens | depth | domain | resource_type | | project://infra/cluster | kubernetes deployment manifest | 0.6 | 80 | 5 | | kubernetes | When I compress with DepthReductionCompressor and budget 30 Then compressed fragments should fit within budget 30 # =========================================================================== # ArceStrategy # =========================================================================== @arce Scenario: ARCE ranks fragments with iterative refinement Given an ArceStrategy with max_iterations 3 And the following strategy3 fragments: | uko_node | content | score | tokens | depth | | project://app/io.py | async IO handler | 0.7 | 20 | 5 | | project://app/main.py | main application entry | 0.5 | 15 | 3 | | project://lib/util.py | utility library | 0.3 | 25 | 2 | And a strategy3 budget with max_tokens 1000 and reserved_tokens 0 When I assemble with the ArceStrategy Then fragments should be returned by arce strategy And the arce result should respect the budget @arce Scenario: ARCE returns empty for empty input Given an ArceStrategy with max_iterations 5 And an empty strategy3 fragment list And a strategy3 budget with max_tokens 1000 and reserved_tokens 0 When I assemble with the ArceStrategy Then 0 fragments should be returned by arce strategy @arce Scenario: ARCE respects budget constraint Given an ArceStrategy with max_iterations 3 And the following strategy3 fragments: | uko_node | content | score | tokens | depth | | project://app/a.py | alpha | 0.9 | 100 | 5 | | project://app/b.py | beta | 0.7 | 100 | 3 | | project://app/c.py | gamma | 0.5 | 100 | 2 | And a strategy3 budget with max_tokens 250 and reserved_tokens 0 When I assemble with the ArceStrategy Then at most 2 fragments should be returned by arce strategy @arce Scenario: ARCE can_handle returns 0.95 Given an ArceStrategy with max_iterations 5 When I check can_handle on ArceStrategy Then the arce confidence should be 0.95 @arce Scenario: ARCE reports capabilities Given an ArceStrategy with max_iterations 5 Then the ArceStrategy name should be "arce" And the ArceStrategy should support semantic search @arce Scenario: ARCE explain returns description Given an ArceStrategy with max_iterations 5 Then the ArceStrategy explain should contain "Adaptive Recursive" @arce Scenario: ARCE iteration limit prevents unbounded refinement Given an ArceStrategy with max_iterations 2 And the following strategy3 fragments: | uko_node | content | score | tokens | depth | | project://app/a.py | alpha content | 0.9 | 50 | 5 | | project://app/b.py | beta content | 0.7 | 50 | 3 | And a strategy3 budget with max_tokens 1000 and reserved_tokens 0 When I assemble with the ArceStrategy Then fragments should be returned by arce strategy # =========================================================================== # TemporalArchaeologyStrategy # =========================================================================== @temporal Scenario: TemporalArchaeology prioritises cold-tier fragments Given a TemporalArchaeologyStrategy And the following strategy3 fragments with tiers: | uko_node | content | score | tokens | depth | tier | | project://app/old.py | archived | 0.5 | 20 | 3 | cold | | project://app/new.py | recent | 0.9 | 15 | 3 | hot | And a strategy3 budget with max_tokens 1000 and reserved_tokens 0 When I assemble with the TemporalArchaeologyStrategy Then the first temporal result fragment should have uko_node "project://app/old.py" @temporal Scenario: TemporalArchaeology returns empty for empty input Given a TemporalArchaeologyStrategy And an empty strategy3 fragment list And a strategy3 budget with max_tokens 1000 and reserved_tokens 0 When I assemble with the TemporalArchaeologyStrategy Then 0 fragments should be returned by temporal strategy @temporal Scenario: TemporalArchaeology can_handle returns 0.5 Given a TemporalArchaeologyStrategy When I check can_handle on TemporalArchaeologyStrategy Then the temporal confidence should be 0.5 @temporal Scenario: TemporalArchaeology reports capabilities Given a TemporalArchaeologyStrategy Then the TemporalArchaeologyStrategy name should be "temporal-archaeology" @temporal Scenario: TemporalArchaeology explain returns description Given a TemporalArchaeologyStrategy Then the TemporalArchaeologyStrategy explain should contain "Historical" @temporal Scenario: TemporalArchaeology respects budget Given a TemporalArchaeologyStrategy And the following strategy3 fragments with tiers: | uko_node | content | score | tokens | depth | tier | | project://app/a.py | alpha | 0.9 | 100 | 3 | cold | | project://app/b.py | beta | 0.7 | 100 | 3 | cold | | project://app/c.py | gamma | 0.5 | 100 | 3 | warm | And a strategy3 budget with max_tokens 250 and reserved_tokens 0 When I assemble with the TemporalArchaeologyStrategy Then at most 2 fragments should be returned by temporal strategy # =========================================================================== # PlanDecisionContextStrategy # =========================================================================== @plan_decision Scenario: PlanDecisionContext prioritises warm-tier fragments Given a PlanDecisionContextStrategy And the following strategy3 fragments with tiers: | uko_node | content | score | tokens | depth | tier | | project://app/plan.py | decision | 0.7 | 20 | 3 | warm | | project://app/new.py | new code | 0.9 | 15 | 3 | hot | | project://app/old.py | archived | 0.5 | 25 | 3 | cold | And a strategy3 budget with max_tokens 1000 and reserved_tokens 0 When I assemble with the PlanDecisionContextStrategy Then the first plan_decision result should have uko_node "project://app/plan.py" @plan_decision Scenario: PlanDecisionContext returns empty for empty input Given a PlanDecisionContextStrategy And an empty strategy3 fragment list And a strategy3 budget with max_tokens 1000 and reserved_tokens 0 When I assemble with the PlanDecisionContextStrategy Then 0 fragments should be returned by plan_decision strategy @plan_decision Scenario: PlanDecisionContext can_handle returns 0.7 Given a PlanDecisionContextStrategy When I check can_handle on PlanDecisionContextStrategy Then the plan_decision confidence should be 0.7 @plan_decision Scenario: PlanDecisionContext reports capabilities Given a PlanDecisionContextStrategy Then the PlanDecisionContextStrategy name should be "plan-decision-context" @plan_decision Scenario: PlanDecisionContext explain returns description Given a PlanDecisionContextStrategy Then the PlanDecisionContextStrategy explain should contain "decision" @plan_decision Scenario: PlanDecisionContext respects budget Given a PlanDecisionContextStrategy And the following strategy3 fragments with tiers: | uko_node | content | score | tokens | depth | tier | | project://app/a.py | alpha | 0.9 | 100 | 3 | warm | | project://app/b.py | beta | 0.7 | 100 | 3 | cold | | project://app/c.py | gamma | 0.5 | 100 | 3 | hot | And a strategy3 budget with max_tokens 250 and reserved_tokens 0 When I assemble with the PlanDecisionContextStrategy Then at most 2 fragments should be returned by plan_decision strategy # =========================================================================== # Pipeline Registration # =========================================================================== @registration Scenario: Register ArceStrategy with pipeline Given an ACMS pipeline for phase3 strategy tests When I register ArceStrategy with the pipeline Then the phase3 pipeline should have strategy "arce" @registration Scenario: Register all Phase 3 strategies with pipeline Given an ACMS pipeline for phase3 strategy tests When I register all phase3 strategies with the pipeline Then the phase3 pipeline should have strategy "arce" And the phase3 pipeline should have strategy "temporal-archaeology" And the phase3 pipeline should have strategy "plan-decision-context" # =========================================================================== # Pipeline Integration — DI injection of Phase 3 components # =========================================================================== @pipeline_integration Scenario: Inject RelevanceCoherenceOrderer into pipeline Given the ACMS pipeline with a RelevanceCoherenceOrderer And the following phase3 fragments: | uko_node | content | score | tokens | depth | | project://app/main.py | hello | 0.8 | 10 | 3 | | project://lib/util.py | world | 0.6 | 15 | 5 | When I assemble context through the phase3 pipeline Then the phase3 pipeline output should contain 2 fragments @pipeline_integration Scenario: Inject ProvenancePreambleGenerator into pipeline Given the ACMS pipeline with a ProvenancePreambleGenerator And the following phase3 fragments: | uko_node | content | score | tokens | depth | | project://app/main.py | hello | 0.8 | 10 | 3 | When I assemble context through the phase3 pipeline Then the phase3 pipeline output should have a preamble And the phase3 pipeline preamble should contain "Context Assembly Provenance"