mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
`headroom/transforms/text_compressor.py` was a regex-line-sampling fallback that nothing in the runtime called. ContentRouter routes `CompressionStrategy.TEXT` straight to the Kompress ML compressor at `content_router.py:1046` — the comment there literally says 'Prefer Kompress ML compressor for text'. The Python file was orphaned but still imported by its own test class, making it look live in the 3e queue. Drops the 3e.3 port from the queue: there's nothing to port. # Removed * `headroom/transforms/text_compressor.py` (255 LOC, unused) * `tests/test_text_compressors.py::TestTextCompressor` (3 tests) * `text_compressor` mention in `error_detection.py` shim docstring * `text_compressor` mention in `test_signals_keyword_parity.py` docstring * `TextCompressor` mention in `bench_latency.py` scenario comment # Kept (defensive) The legacy marker regex in `ccr/tool_injection.py:213` stays — it parses an even older TextCompressor output format (pre-2026), is purely defensive, and removal buys nothing. Test references to that format in `test_ccr_tool_injection.py` document the regex contract and stay too. # Test plan * `make ci-precheck` clean * `tests/test_text_compressors.py` 19 passes (was 22, dropped 3)
149 lines
6.3 KiB
Python
149 lines
6.3 KiB
Python
"""Phase 3e.1: parity contract for the Rust-backed error_detection shim.
|
|
|
|
The Python regex registry was retired in favor of recompiling regex from
|
|
the keyword tables exposed by the Rust `headroom._core.signals` module.
|
|
These tests pin:
|
|
|
|
* The shim re-exports the legacy frozenset and Pattern names callers
|
|
rely on (search_compressor, intelligent_context).
|
|
* Two bug fixes from the Rust port land in the Python regex too:
|
|
1. ERROR_PATTERN now matches abort/timeout/denied/rejected (was a
|
|
drift between ERROR_KEYWORDS and the compiled regex).
|
|
2. SECURITY_KEYWORDS no longer includes "token" (false-positives on
|
|
LLM-token references in our own product).
|
|
* `content_has_error_indicators` matches the Python triage semantics
|
|
(substring, no word boundary) for the canonical indicator set.
|
|
* The signals trait is reachable from Python via three thin functions
|
|
(`score_line`, `content_has_error_indicators`, `keyword_registry_snapshot`).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
|
|
def test_legacy_re_exports_present():
|
|
from headroom.transforms import error_detection as ed
|
|
|
|
# frozenset names the existing callers import directly
|
|
assert isinstance(ed.ERROR_KEYWORDS, frozenset)
|
|
assert isinstance(ed.IMPORTANCE_KEYWORDS, frozenset)
|
|
assert isinstance(ed.SECURITY_KEYWORDS, frozenset)
|
|
assert isinstance(ed.ERROR_INDICATOR_KEYWORDS, tuple)
|
|
|
|
# Pattern objects must still be re.Pattern so callers can do .search()
|
|
import re
|
|
|
|
assert isinstance(ed.ERROR_PATTERN, re.Pattern)
|
|
assert isinstance(ed.WARNING_PATTERN, re.Pattern)
|
|
assert isinstance(ed.IMPORTANCE_PATTERN, re.Pattern)
|
|
assert isinstance(ed.SECURITY_PATTERN, re.Pattern)
|
|
|
|
# Per-context priority lists used by search/diff/text compressors
|
|
assert all(isinstance(p, re.Pattern) for p in ed.PRIORITY_PATTERNS_SEARCH)
|
|
assert all(isinstance(p, re.Pattern) for p in ed.PRIORITY_PATTERNS_DIFF)
|
|
assert all(isinstance(p, re.Pattern) for p in ed.PRIORITY_PATTERNS_TEXT)
|
|
|
|
|
|
def test_bug_fix_error_regex_now_matches_canonical_keyword_set():
|
|
"""fixed_in_3e1: ERROR_PATTERN regex used to omit timeout/abort/denied/rejected
|
|
even though ERROR_KEYWORDS canonically included them."""
|
|
from headroom.transforms.error_detection import ERROR_KEYWORDS, ERROR_PATTERN
|
|
|
|
for keyword in ("timeout", "abort", "denied", "rejected"):
|
|
assert keyword in ERROR_KEYWORDS, f"{keyword} must stay in ERROR_KEYWORDS"
|
|
assert ERROR_PATTERN.search(f"FATAL: {keyword} occurred"), (
|
|
f"ERROR_PATTERN must now flag {keyword!r}"
|
|
)
|
|
|
|
|
|
def test_bug_fix_security_keywords_dropped_token():
|
|
"""fixed_in_3e1: 'token' false-positived on input_tokens/tokens_saved/etc.
|
|
in an LLM-proxy product. Dropped from the security set so the security
|
|
pattern stops misclassifying our own metric output."""
|
|
from headroom.transforms.error_detection import SECURITY_KEYWORDS, SECURITY_PATTERN
|
|
|
|
assert "token" not in SECURITY_KEYWORDS
|
|
assert "auth" in SECURITY_KEYWORDS # the real security signal
|
|
assert SECURITY_PATTERN.search("missing auth header") is not None
|
|
assert SECURITY_PATTERN.search("input_tokens=512 output_tokens=128") is None
|
|
|
|
|
|
def test_content_has_error_indicators_lax_substring_semantics():
|
|
from headroom.transforms.error_detection import content_has_error_indicators
|
|
|
|
# Python ERROR_INDICATOR_KEYWORDS includes "traceback" — must still fire
|
|
assert content_has_error_indicators("Traceback (most recent call last):")
|
|
# Substring (no word-boundary) match preserved — "errored" matches "error"
|
|
assert content_has_error_indicators("the request errored out")
|
|
# Genuine non-match
|
|
assert not content_has_error_indicators("everything is fine")
|
|
|
|
|
|
def test_rust_signals_bridge_score_line_diff_context():
|
|
"""The Phase 3g pipeline will consume the trait API directly. Today
|
|
we cover the bridge surface so a future change can't silently break
|
|
it."""
|
|
from headroom.transforms.error_detection import score_line
|
|
|
|
cat, priority, confidence = score_line("FATAL: timeout connecting", "diff")
|
|
assert cat == "error"
|
|
assert priority > 0.9
|
|
assert confidence > 0.5
|
|
|
|
cat_neutral, _, conf_neutral = score_line("the quick brown fox", "text")
|
|
assert cat_neutral is None
|
|
assert conf_neutral == 0.0
|
|
|
|
|
|
def test_rust_signals_bridge_unknown_context_raises():
|
|
from headroom.transforms.error_detection import score_line
|
|
|
|
with pytest.raises(ValueError, match="unknown importance context"):
|
|
score_line("anything", "not_a_real_context")
|
|
|
|
|
|
def test_raw_rust_score_line_returns_none_on_unknown_context():
|
|
"""The raw `headroom._core.score_line` returns `None` for unknown
|
|
contexts (the Python shim is responsible for translating to
|
|
ValueError). Pin this contract so a future change can't shift the
|
|
error-handling boundary unobserved."""
|
|
from headroom._core import score_line as _raw
|
|
|
|
assert _raw("anything", "not_a_real_context") is None
|
|
result = _raw("ERROR: test", "diff")
|
|
assert result is not None and result[0] == "error"
|
|
|
|
|
|
def test_keyword_registry_snapshot_has_dropped_token_and_added_indicators():
|
|
from headroom._core import keyword_registry_snapshot
|
|
|
|
snapshot = keyword_registry_snapshot()
|
|
assert "token" not in snapshot["security"]
|
|
assert "auth" in snapshot["security"]
|
|
assert "timeout" in snapshot["error"]
|
|
assert "traceback" in snapshot["error_indicators"]
|
|
# Markdown prefixes must include at least the canonical four
|
|
assert "# " in snapshot["markdown_prefixes"]
|
|
assert "> " in snapshot["markdown_prefixes"]
|
|
|
|
|
|
def test_python_regex_recompiled_from_rust_keyword_tables():
|
|
"""The Python shim recompiles regex from keyword data Rust hands it.
|
|
This guards against drift: if Rust and Python keyword sets ever
|
|
diverge, this fails the suite."""
|
|
from headroom._core import keyword_registry_snapshot
|
|
from headroom.transforms.error_detection import (
|
|
ERROR_KEYWORDS,
|
|
IMPORTANCE_KEYWORDS,
|
|
SECURITY_KEYWORDS,
|
|
)
|
|
|
|
rust = keyword_registry_snapshot()
|
|
assert ERROR_KEYWORDS == frozenset(rust["error"])
|
|
assert SECURITY_KEYWORDS == frozenset(rust["security"])
|
|
# IMPORTANCE_KEYWORDS is a union of error + importance + warning sets
|
|
expected_importance = (
|
|
frozenset(rust["error"]) | frozenset(rust["importance"]) | frozenset(rust["warning"])
|
|
)
|
|
assert IMPORTANCE_KEYWORDS == expected_importance
|