@mock_only
Feature: Execute-phase context assembler coverage
  Comprehensive tests for ACMSExecutePhaseContextAssembler covering
  _resolve_execute_view, _path_matches, _resource_matches,
  _to_context_fragment, and the full assemble() method with all
  filtering branches.

  # ---- Protocol ----

  Scenario: epcov protocol assemble method is abstract
    Given epcov a class implementing the ExecutePhaseContextAssembler protocol
    When epcov I call assemble on the protocol stub
    Then epcov the result should be None

  # ---- _resolve_execute_view ----

  Scenario: epcov resolve execute view success
    Given epcov an assembler with a project repository returning a custom policy
    When epcov I resolve the execute view for "proj-alpha"
    Then epcov the resolved view should have the custom include_resources

  Scenario: epcov resolve execute view falls back on exception
    Given epcov an assembler with a project repository that raises an exception
    When epcov I resolve the execute view for "proj-broken"
    Then epcov the resolved view should be the default empty ContextView

  # ---- _path_matches static method ----

  Scenario: epcov path matches with no rules passes all
    When epcov I check path matching for "src/foo.py" with no include or exclude
    Then epcov the path should match

  Scenario: epcov path matches with include rule matching
    When epcov I check path matching for "src/foo.py" with include "src/**/*.py"
    Then epcov the path should match

  Scenario: epcov path matches with include rule not matching
    When epcov I check path matching for "docs/readme.md" with include "src/**/*.py"
    Then epcov the path should not match

  Scenario: epcov path matches with exclude rule matching
    When epcov I check path matching for "src/secret.py" with exclude "src/secret*"
    Then epcov the path should not match

  Scenario: epcov path matches with exclude rule not matching
    When epcov I check path matching for "src/foo.py" with exclude "src/secret*"
    Then epcov the path should match

  # ---- _resource_matches static method ----

  Scenario: epcov resource matches with no rules passes all
    When epcov I check resource matching for "res:abc" with no include or exclude
    Then epcov the resource should match

  Scenario: epcov resource matches with include rule matching
    When epcov I check resource matching for "res:abc" with include "res:*"
    Then epcov the resource should match

  Scenario: epcov resource matches with include rule not matching
    When epcov I check resource matching for "other:xyz" with include "res:*"
    Then epcov the resource should not match

  Scenario: epcov resource matches with exclude rule matching
    When epcov I check resource matching for "res:secret" with exclude "res:secret"
    Then epcov the resource should not match

  Scenario: epcov resource matches with exclude rule not matching
    When epcov I check resource matching for "res:abc" with exclude "res:secret"
    Then epcov the resource should match

  # ---- _to_context_fragment ----

  Scenario: epcov converts tiered fragment with full metadata
    Given epcov an assembler instance
    When epcov I convert a tiered fragment with detail_depth 3 and relevance 0.8
    Then epcov the core fragment should have detail_depth 3 and relevance 0.8

  Scenario: epcov converts tiered fragment with missing metadata defaults
    Given epcov an assembler instance
    When epcov I convert a tiered fragment with no detail_depth or relevance
    Then epcov the core fragment should have detail_depth 1 and relevance 0.5

  Scenario: epcov converts tiered fragment with non-int detail_depth
    Given epcov an assembler instance
    When epcov I convert a tiered fragment with detail_depth "high" and relevance "bad"
    Then epcov the core fragment should have detail_depth 1 and relevance 0.5

  Scenario: epcov converts tiered fragment clamps relevance to bounds
    Given epcov an assembler instance
    When epcov I convert a tiered fragment with relevance 1.5
    Then epcov the core fragment should have clamped relevance 1.0

  Scenario: epcov converts tiered fragment with negative relevance
    Given epcov an assembler instance
    When epcov I convert a tiered fragment with relevance -0.3
    Then epcov the core fragment should have clamped relevance 0.0

  Scenario: epcov converts tiered fragment with no resource_id uses uko fallback
    Given epcov an assembler instance
    When epcov I convert a tiered fragment with empty resource_id
    Then epcov the core fragment uko_node should start with "uko:"

  Scenario: epcov converts tiered fragment with path metadata
    Given epcov an assembler instance
    When epcov I convert a tiered fragment with path "src/main.py" in metadata
    Then epcov the core fragment provenance location should be "src/main.py"

  Scenario: epcov converts tiered fragment with non-string path metadata
    Given epcov an assembler instance
    When epcov I convert a tiered fragment with non-string path in metadata
    Then epcov the core fragment provenance location should be empty

  # ---- assemble: no project links ----

  Scenario: epcov assemble returns None when plan has no project links
    Given epcov an assembler instance
    And epcov a plan with no project links
    When epcov I call assemble on the plan
    Then epcov the assembled result should be None

  # ---- assemble: empty scoped view ----

  Scenario: epcov assemble returns None when scoped view is empty
    Given epcov an assembler with scoped view returning empty list
    And epcov a plan with project links
    When epcov I call assemble on the plan
    Then epcov the assembled result should be None

  # ---- assemble: fragment excluded by missing view ----

  Scenario: epcov assemble excludes fragment whose project has no view
    Given epcov an assembler with views only for "proj-alpha"
    And epcov a plan with project links for "proj-alpha" and "proj-beta"
    And epcov scoped fragments for "proj-alpha" and "proj-beta"
    When epcov I call assemble on the plan
    Then epcov the assembled result should include only proj-alpha fragments

  # ---- assemble: resource filtering ----

  Scenario: epcov assemble excludes fragment by resource include rules
    Given epcov an assembler with resource include rule "allowed:*"
    And epcov a plan with project links
    And epcov scoped fragments with resource ids "allowed:file" and "denied:file"
    When epcov I call assemble on the plan
    Then epcov the assembled result should include only the allowed resource fragment

  Scenario: epcov assemble excludes fragment by resource exclude rules
    Given epcov an assembler with resource exclude rule "secret:*"
    And epcov a plan with project links
    And epcov scoped fragments with resource ids "public:file" and "secret:file"
    When epcov I call assemble on the plan
    Then epcov the assembled result should include only the public resource fragment

  # ---- assemble: path filtering ----

  Scenario: epcov assemble excludes fragment by path include rules
    Given epcov an assembler with path include rule "src/**"
    And epcov a plan with project links
    And epcov scoped fragments with paths "src/main.py" and "docs/readme.md"
    When epcov I call assemble on the plan
    Then epcov the assembled result should include only the src fragment

  Scenario: epcov assemble excludes fragment by path exclude rules
    Given epcov an assembler with path exclude rule "vendor/**"
    And epcov a plan with project links
    And epcov scoped fragments with paths "src/main.py" and "vendor/lib.py"
    When epcov I call assemble on the plan
    Then epcov the assembled result should include only the non-vendor fragment

  Scenario: epcov assemble excludes fragment with no path when include_paths set
    Given epcov an assembler with path include rule "src/**"
    And epcov a plan with project links
    And epcov a scoped fragment with no path metadata
    When epcov I call assemble on the plan
    Then epcov the assembled result should be None

  # ---- assemble: max_file_size filtering ----

  Scenario: epcov assemble excludes fragment exceeding max_file_size
    Given epcov an assembler with max_file_size of 10 bytes
    And epcov a plan with project links
    And epcov a scoped fragment with content exceeding 10 bytes
    When epcov I call assemble on the plan
    Then epcov the assembled result should be None

  # ---- assemble: max_total_size filtering ----

  Scenario: epcov assemble excludes fragment exceeding max_total_size
    Given epcov an assembler with max_total_size of 20 bytes
    And epcov a plan with project links
    And epcov two scoped fragments each with 15 byte content
    When epcov I call assemble on the plan
    Then epcov the assembled result should include only the first fragment

  # ---- assemble: all filtered out ----

  Scenario: epcov assemble returns None when all fragments are filtered out
    Given epcov an assembler with resource include rule "nonexistent:*"
    And epcov a plan with project links
    And epcov scoped fragments with resource ids "other:a" and "other:b"
    When epcov I call assemble on the plan
    Then epcov the assembled result should be None

  # ---- assemble: successful full pipeline ----

  Scenario: epcov assemble returns full AssembledContext on success
    Given epcov an assembler with default policy and pipeline
    And epcov a plan with project links
    And epcov scoped fragments that pass all filters
    When epcov I call assemble on the plan
    Then epcov the assembled result should be an AssembledContext
    And epcov the assembled result should have fragments and metadata
