e2167ab8e7
CI / lint (pull_request) Successful in 1m40s
CI / quality (pull_request) Successful in 59s
CI / typecheck (pull_request) Successful in 1m46s
CI / helm (pull_request) Successful in 39s
CI / push-validation (pull_request) Successful in 48s
CI / security (pull_request) Successful in 2m11s
CI / build (pull_request) Successful in 1m31s
CI / integration_tests (pull_request) Successful in 4m57s
CI / unit_tests (pull_request) Successful in 6m44s
CI / docker (pull_request) Successful in 1m22s
CI / coverage (pull_request) Successful in 12m7s
CI / status-check (pull_request) Successful in 4s
CI / push-validation (push) Successful in 29s
CI / helm (push) Successful in 37s
CI / lint (push) Successful in 1m14s
CI / build (push) Successful in 1m16s
CI / benchmark-publish (push) Has started running
CI / quality (push) Successful in 1m30s
CI / typecheck (push) Successful in 1m36s
CI / security (push) Successful in 2m14s
CI / benchmark-regression (push) Failing after 44s
CI / e2e_tests (push) Successful in 49s
CI / integration_tests (push) Successful in 4m46s
CI / unit_tests (push) Successful in 5m57s
CI / docker (push) Successful in 1m32s
CI / coverage (push) Successful in 13m20s
CI / status-check (push) Successful in 2s
Fixed _resolve_hot_max_tokens() to read hot_max_tokens from the correct
sub-key in context_policy_json. The value is stored under
context_policy_json["acms_config"]["hot_max_tokens"] by
'agents project context set --hot-max-tokens', not at the top level.
The previous read (config_dict.get("hot_max_tokens")) always returned
None, causing the assembler to silently use the global 16K default even
when a project-level override was configured.
Also adds two Behave regression scenarios with @tdd_issue @tdd_issue_11035
tags that exercise the real DB query code path via a mocked
NamespacedProjectModel row, verifying:
1. hot_max_tokens=32000 in acms_config is applied to CoreContextBudget
and ContextRequest (override path).
2. Missing hot_max_tokens falls back to the constructor-injected global
default of 4096 (fallback path).
Module-level import json added to steps file; redundant inline MagicMock
import removed.
ISSUES CLOSED: #11035
ISSUES CLOSED: #11215
256 lines
12 KiB
Gherkin
256 lines
12 KiB
Gherkin
@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
|
|
|
|
@tdd_issue @tdd_issue_10972
|
|
Scenario: epcov path matches absolute path against relative include glob
|
|
When epcov I check path matching for "/app/.opencode/skills/SKILL.md" with include ".opencode/**"
|
|
Then epcov the path should match
|
|
|
|
@tdd_issue @tdd_issue_10972
|
|
Scenario: epcov path matches absolute path against relative exclude glob
|
|
When epcov I check path matching for "/app/.opencode/skills/SKILL.md" with exclude ".opencode/**"
|
|
Then epcov the path should not match
|
|
|
|
@tdd_issue @tdd_issue_10972
|
|
Scenario: epcov path matches absolute path against relative include glob with wildcard
|
|
When epcov I check path matching for "/app/docs/readme.md" with include "docs/*"
|
|
Then epcov the path should match
|
|
|
|
@tdd_issue @tdd_issue_10972
|
|
Scenario: epcov path matches absolute path not matching relative include glob
|
|
When epcov I check path matching for "/app/src/main.py" with include "docs/*"
|
|
Then epcov the path should not match
|
|
|
|
@tdd_issue @tdd_issue_10972
|
|
Scenario: epcov relative path is excluded by trailing ** glob
|
|
When epcov I check path matching for "build/debug/output.log" with exclude "build/**"
|
|
Then epcov the path should not 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
|
|
|
|
# ---- _resolve_hot_max_tokens: reads context_policy_json from DB ----
|
|
|
|
@tdd_issue @tdd_issue_11035
|
|
Scenario: epcov assemble uses project-level hot_max_tokens from context_policy_json
|
|
Given epcov an assembler with context_policy_json hot_max_tokens 32000
|
|
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 pipeline received budget max_tokens of 32000
|
|
|
|
@tdd_issue @tdd_issue_11035
|
|
Scenario: epcov assemble falls back to global hot_max_tokens when context_policy_json has no override
|
|
Given epcov an assembler with no hot_max_tokens in context_policy_json
|
|
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 pipeline received budget max_tokens of 4096
|