583e6b7ea2
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / build (pull_request) Successful in 16s
CI / quality (pull_request) Successful in 17s
CI / security (pull_request) Successful in 36s
CI / typecheck (pull_request) Successful in 54s
CI / unit_tests (pull_request) Successful in 2m39s
CI / integration_tests (pull_request) Successful in 3m10s
CI / docker (pull_request) Successful in 40s
CI / coverage (pull_request) Successful in 5m0s
CI / lint (push) Successful in 14s
CI / build (push) Successful in 15s
CI / quality (push) Successful in 16s
CI / security (push) Successful in 34s
CI / typecheck (push) Successful in 35s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 2m23s
CI / docker (push) Successful in 38s
CI / integration_tests (push) Successful in 3m8s
CI / coverage (push) Successful in 5m10s
CI / benchmark-publish (push) Successful in 16m26s
CI / benchmark-regression (pull_request) Successful in 30m12s
Implement spec-mandated Layer 4 Predictive Error Prevention system: - ErrorPattern domain model with pattern text, historical failures, preventive checks, frequency tracking, and keyword-based matching. - ErrorPatternRepository with in-memory CRUD + context-matching query. - ErrorPatternService with record_failure(), match_patterns(), and get_statistics() methods. - Wire into plan execution via plan_lifecycle_service pre-execution hook. - Add error pattern statistics to CLI diagnostics output. Behave BDD: 11 scenarios covering recording, matching, formatting, stats. Robot Framework: 3 integration smoke tests. ASV benchmarks: pattern matching performance. ISSUES CLOSED: #571
164 lines
5.0 KiB
Python
164 lines
5.0 KiB
Python
"""ASV benchmarks for ACMS pipeline Phase 2 — Fragment Fusion components.
|
|
|
|
Measures the performance of:
|
|
- ContentHashDeduplicator with varying fragment counts
|
|
- MaxDepthResolver with varying fragment counts
|
|
- WeightedCompositeScorer with varying fragment counts
|
|
- GreedyKnapsackPacker with varying fragment counts and budgets
|
|
- ScoredFragment creation
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import ClassVar
|
|
|
|
_SRC = str(Path(__file__).resolve().parents[1] / "src")
|
|
if _SRC not in sys.path:
|
|
sys.path.insert(0, _SRC)
|
|
|
|
import cleveragents # noqa: E402
|
|
|
|
importlib.reload(cleveragents)
|
|
|
|
from cleveragents.application.services.acms_phase2 import ( # noqa: E402
|
|
ContentHashDeduplicator,
|
|
GreedyKnapsackPacker,
|
|
MaxDepthResolver,
|
|
WeightedCompositeScorer,
|
|
)
|
|
from cleveragents.domain.models.core.context_fragment import ( # noqa: E402
|
|
ContextBudget,
|
|
ContextFragment,
|
|
FragmentProvenance,
|
|
ScoredFragment,
|
|
)
|
|
|
|
_DEFAULT_PROV = FragmentProvenance(resource_uri="bench://phase2")
|
|
|
|
|
|
def _make_fragments(n: int, *, unique_nodes: bool = True) -> list[ContextFragment]:
|
|
"""Create *n* fragments for benchmarks."""
|
|
frags: list[ContextFragment] = []
|
|
for i in range(n):
|
|
node = f"bench://file{i}" if unique_nodes else "bench://same-node"
|
|
frags.append(
|
|
ContextFragment(
|
|
uko_node=node,
|
|
content=f"content-{i}",
|
|
relevance_score=round(0.1 + (i % 10) * 0.09, 2),
|
|
token_count=50 + (i % 5) * 10,
|
|
detail_depth=i % 10,
|
|
provenance=_DEFAULT_PROV,
|
|
)
|
|
)
|
|
return frags
|
|
|
|
|
|
class ContentHashDeduplicatorSuite:
|
|
"""Benchmark ContentHashDeduplicator throughput."""
|
|
|
|
params: ClassVar[list[int]] = [10, 100, 500]
|
|
param_names: ClassVar[list[str]] = ["fragment_count"]
|
|
|
|
def setup(self, n: int) -> None:
|
|
self.dedup = ContentHashDeduplicator()
|
|
# Half the fragments are duplicates
|
|
base = _make_fragments(n // 2, unique_nodes=True)
|
|
self.fragments = base + [
|
|
ContextFragment(
|
|
uko_node=f.uko_node,
|
|
content=f.content,
|
|
relevance_score=max(0.0, f.relevance_score - 0.1),
|
|
token_count=f.token_count,
|
|
detail_depth=f.detail_depth,
|
|
provenance=_DEFAULT_PROV,
|
|
)
|
|
for f in base
|
|
]
|
|
|
|
def time_deduplicate(self, n: int) -> None:
|
|
self.dedup.deduplicate(self.fragments)
|
|
|
|
|
|
class MaxDepthResolverSuite:
|
|
"""Benchmark MaxDepthResolver throughput."""
|
|
|
|
params: ClassVar[list[int]] = [10, 100, 500]
|
|
param_names: ClassVar[list[str]] = ["fragment_count"]
|
|
|
|
def setup(self, n: int) -> None:
|
|
self.resolver = MaxDepthResolver()
|
|
# Multiple depths per node
|
|
self.fragments: list[ContextFragment] = []
|
|
for i in range(n):
|
|
node_idx = i % (n // 3 + 1)
|
|
self.fragments.append(
|
|
ContextFragment(
|
|
uko_node=f"bench://file{node_idx}",
|
|
content=f"content-{i}",
|
|
relevance_score=0.5,
|
|
token_count=50,
|
|
detail_depth=i % 10,
|
|
provenance=_DEFAULT_PROV,
|
|
)
|
|
)
|
|
|
|
def time_resolve(self, n: int) -> None:
|
|
self.resolver.resolve(self.fragments)
|
|
|
|
|
|
class WeightedCompositeScorerSuite:
|
|
"""Benchmark WeightedCompositeScorer throughput."""
|
|
|
|
params: ClassVar[list[int]] = [10, 100, 500]
|
|
param_names: ClassVar[list[str]] = ["fragment_count"]
|
|
|
|
def setup(self, n: int) -> None:
|
|
self.scorer = WeightedCompositeScorer()
|
|
self.fragments = _make_fragments(n)
|
|
|
|
def time_score(self, n: int) -> None:
|
|
self.scorer.score(self.fragments)
|
|
|
|
def time_score_detailed(self, n: int) -> None:
|
|
self.scorer.score_detailed(self.fragments)
|
|
|
|
|
|
class GreedyKnapsackPackerSuite:
|
|
"""Benchmark GreedyKnapsackPacker throughput."""
|
|
|
|
params: ClassVar[list[int]] = [10, 100, 500]
|
|
param_names: ClassVar[list[str]] = ["fragment_count"]
|
|
|
|
def setup(self, n: int) -> None:
|
|
self.packer = GreedyKnapsackPacker()
|
|
self.fragments = _make_fragments(n)
|
|
# Budget that fits about half the fragments
|
|
total = sum(f.token_count for f in self.fragments)
|
|
self.budget = ContextBudget(max_tokens=total // 2, reserved_tokens=0)
|
|
|
|
def time_pack(self, n: int) -> None:
|
|
self.packer.pack(self.fragments, self.budget)
|
|
|
|
|
|
class ScoredFragmentSuite:
|
|
"""Benchmark ScoredFragment creation."""
|
|
|
|
def setup(self) -> None:
|
|
self.fragment = ContextFragment(
|
|
uko_node="bench://file",
|
|
content="benchmark content",
|
|
token_count=10,
|
|
provenance=_DEFAULT_PROV,
|
|
)
|
|
|
|
def time_scored_fragment_creation(self) -> None:
|
|
ScoredFragment(
|
|
fragment=self.fragment,
|
|
composite_score=0.85,
|
|
score_components={"relevance": 0.9, "hierarchy": 0.8},
|
|
)
|