Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .github/pr-images/issue-1696-error-protection-fix.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 12 additions & 1 deletion headroom/transforms/error_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@ def content_has_error_indicators(text: str) -> bool:
return bool(_rust_content_has_error_indicators(text))


# Success-summary phrases from common build/test/lint tools that legitimately
# pair two indicator keywords (`error` + `fail`) while reporting a PASS, e.g.
# tsc's "Found 0 errors", jest's "0 failing" / "0 failures", eslint's
# "0 problems (0 errors, 0 warnings)". Stripped before the keyword scan below
# so a clean JS/TS toolchain run doesn't get permanently protected from
# compression for the rest of a long coding session (issue #1696).
_ZERO_RESULT_PATTERN = re.compile(
r"\b(?:0|no)\s+(?:error|errors|failing|failure|failures)\b", re.IGNORECASE
)


def content_has_strong_error_indicators(text: str) -> bool:
"""Stricter triage for compression-protection gates.

Expand All @@ -162,7 +173,7 @@ def content_has_strong_error_indicators(text: str) -> bool:
safe — downstream compressors (LogCompressor) still preserve
error lines.
"""
lowered = text.lower()
lowered = _ZERO_RESULT_PATTERN.sub(" ", text.lower())
hits = 0
for keyword in ERROR_INDICATOR_KEYWORDS:
if keyword in lowered:
Expand Down
38 changes: 38 additions & 0 deletions tests/test_error_detection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Regression tests for the error/importance detection triage helpers."""

from __future__ import annotations

from headroom.transforms.error_detection import content_has_strong_error_indicators


def test_real_error_output_is_detected() -> None:
text = "Traceback (most recent call last):\n ...\nValueError: fatal error during load"
assert content_has_strong_error_indicators(text)


def test_single_keyword_mention_is_not_flagged() -> None:
# Only one distinct indicator keyword ("error") — should not trip the
# two-keyword threshold.
text = 'Wrote error_handler.py with an "errors": [] field.'
assert not content_has_strong_error_indicators(text)


def test_tsc_passing_summary_is_not_flagged() -> None:
# Regression for issue #1696: a clean `tsc` run mentions both "error"
# and (via "0 failures" in a paired test run) "fail" while reporting
# success. Previously this tripped the two-keyword heuristic and got
# the message permanently protected from compression.
text = "Found 0 errors. Watching for file changes.\nTests: 0 failures, 42 passed"
assert not content_has_strong_error_indicators(text)


def test_eslint_passing_summary_is_not_flagged() -> None:
text = "0 problems (0 errors, 0 warnings)\nno failing tests"
assert not content_has_strong_error_indicators(text)


def test_zero_result_phrase_does_not_mask_a_real_second_error() -> None:
# "0 errors" is stripped, but a genuine second distinct indicator
# elsewhere in the same blob must still trigger protection.
text = "0 errors from linter, but the build crashed with a fatal signal"
assert content_has_strong_error_indicators(text)
Loading