headroom/tests/test_transforms
Rod Boev dbbef4bd41
fix(code-compressor): recover valid Python rewrites after local syntax rejection (#2202)
## Description

A compile-invalid Python definition rewrite currently makes
`CodeAwareCompressor` discard every otherwise valid rewrite in the file
and return the original source at 0 percent reduction. The existing
whole-file safety guard stays in place, while a Python-only recovery
replay now preserves the rejected definition and keeps independent valid
compression.

The recovery reuses the current Python validation authority in
`ast.parse()` plus `compile()`, runs only after the first assembled
module already fails `_verify_syntax()`, and stays out of non-Python
paths.

Closes #1233

## Type of Change

- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)

## Changes Made

- Added a Python-only recovery replay after the first assembled module
fails syntax validation.
- Preserved only the invalid function or class rewrite while allowing
independent valid definitions to remain compressed.
- Kept the existing whole-file syntax guard and original-source fallback
as the terminal safety check.
- Added focused invalid-node, valid-modern-syntax, and fail-safe
coverage.

## Testing

- [x] Unit tests pass (`uv run pytest
tests/test_transforms/test_code_compressor.py::TestRealASTRuns::test_python_invalid_node_falls_back_locally
tests/test_transforms/test_code_compressor.py::TestRealASTRuns::test_python_recovery_does_not_block_valid_modern_syntax
tests/test_transforms/test_code_compressor.py::TestRealASTRuns::test_python_recovery_still_returns_original_when_all_candidates_invalid
tests/test_transforms/test_code_compressor.py::TestEdgeCases::test_syntax_errors_in_input
tests/test_transforms/test_code_compressor.py::TestRealASTRuns::test_ast_preserves_structure_for_python
-v`)
- [x] Linting passes (`uv run ruff check
headroom/transforms/code_compressor.py
tests/test_transforms/test_code_compressor.py`)
- [ ] Type checking passes (`uv run mypy headroom`)
- [x] New tests added for new functionality when applicable
- [ ] Manual testing performed

### Test Output

```text
uv run pytest tests/test_transforms/test_code_compressor.py::TestRealASTRuns::test_python_invalid_node_falls_back_locally tests/test_transforms/test_code_compressor.py::TestRealASTRuns::test_python_recovery_does_not_block_valid_modern_syntax tests/test_transforms/test_code_compressor.py::TestRealASTRuns::test_python_recovery_still_returns_original_when_all_candidates_invalid tests/test_transforms/test_code_compressor.py::TestEdgeCases::test_syntax_errors_in_input tests/test_transforms/test_code_compressor.py::TestRealASTRuns::test_ast_preserves_structure_for_python -v
5 passed in 0.34s
uv run ruff check headroom/transforms/code_compressor.py tests/test_transforms/test_code_compressor.py
All checks passed!
uv run ruff format headroom/transforms/code_compressor.py tests/test_transforms/test_code_compressor.py --check
2 files already formatted
```

## Real Behavior Proof

- Environment: Windows, synced `uv` environment with `dev` and `code`
extras installed
- Exact command / steps: run the focused invalid-node regression through
public `compress(..., language="python")`
- Observed result: `1 passed in 0.19s`; the invalid candidate stays
original, the neighboring valid candidate remains compressed, and
`headroom-PR-TARGET-1233-PROOF.md` records the base `ratio=1.0`
whole-file rollback against the fixed head behavior.
- Not tested: the stale future-import mismatch discussed in the old
issue comment, already covered on current main

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review

## Checklist

- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] I have updated the CHANGELOG.md if applicable

## Additional Notes

- The stale future-import comment on #1233 is not the live slice here;
current main already validates Python with `compile()` and already
covers that ordering case.
- This fix keeps the existing whole-file fail-safe and does not broaden
into cross-language recovery or new syntax models.
- `CHANGELOG.md` remains unchanged because Headroom generates release
notes from conventional commits.

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-14 20:19:46 -07:00
..
__init__.py Initial commit: Headroom SDK - LLM context optimization toolkit 2026-01-06 23:16:58 -08:00
test_code_compressor.py fix(code-compressor): recover valid Python rewrites after local syntax rejection (#2202) 2026-07-14 20:19:46 -07:00
test_code_compressor_cjk.py fix(code-compressor): CJK-aware relevance-query symbol matching (#1747) 2026-07-07 12:49:26 -05:00
test_content_router.py fix(proxy): cold-start fast pass — defer only Kompress, not the whole pipeline (#2073) 2026-07-14 06:34:41 -04:00
test_detect_fallback_1123.py fix(deps): remediate dependency CVEs and publish SBOM (#1509) 2026-06-27 15:28:12 -07:00
test_diff_compressor.py fix(transforms): normalize diff compressor context (#1801) 2026-07-05 14:03:33 -07:00
test_diff_compressor_rust_parity.py feat(rust): retire python diff_compressor, ship rust-only via pyo3 2026-04-26 09:15:37 -07:00
test_html_extractor.py fix(tests): skip HTML extractor tests when trafilatura not installed 2026-01-31 15:39:55 -08:00
test_kompress_compressor.py fix(proxy): make Kompress eager preload cache-only so a cold cache can't block startup (#783) 2026-06-11 12:53:03 -05:00
test_kompress_deadline.py perf(compression): take large cold-start contexts off the synchronous kompress path (#1171) (#1298) 2026-06-23 10:48:06 -05:00
test_kompress_remote.py feat(kompress): optional remote compression endpoint (HEADROOM_KOMPRESS_ENDPOINT) (#2171) 2026-07-13 22:01:11 -07:00
test_kompress_size_gate.py perf(compression): take large cold-start contexts off the synchronous kompress path (#1171) (#1298) 2026-06-23 10:48:06 -05:00
test_ort_dylib.py fix(core): load ONNX Runtime dynamically so headroom._core imports on non-AVX2 x86-64 (#1715) 2026-07-14 13:25:41 -04:00
test_pipeline_waste_signal_limit.py fix(proxy): keep large compression results on the critical path (#296) (#1352) 2026-06-24 10:15:59 -05:00
test_read_lifecycle.py fix(read-lifecycle): persist STALE Read originals in the CCR store (#1488) 2026-06-28 14:50:45 -07:00
test_smart_crusher_attribution.py feat(transforms): attribute read_lifecycle + smart_crush tags (#249) 2026-06-11 11:51:26 -05:00
test_smart_crusher_audit_safe.py feat(compression): add audit-safe mode with protected pattern matching (#1899) 2026-07-09 09:39:35 -04:00
test_smart_crusher_bugs.py Marker-free lossless_only mode + gate opaque-blob CCR markers behind enable_ccr_marker (#1129) 2026-06-23 12:52:15 -05:00
test_smart_crusher_ccr_retrieve_exemption.py fix(proxy): stop re-compressing headroom_retrieve output and emitting unredeemable markers (#1323) 2026-06-25 10:11:42 -05:00
test_smart_crusher_ccr_roundtrip.py chore(rust): SmartCrusher CCR marker injection + walker unification 2026-04-27 20:25:22 -07:00
test_smart_crusher_lossless_default.py feat(rust): SmartCrusher PR4 — lossless-first default + CCR-Dropped restoration 2026-04-27 16:30:22 -07:00
test_smart_crusher_rust_parity.py feat(rust): SmartCrusher PR4 — lossless-first default + CCR-Dropped restoration 2026-04-27 16:30:22 -07:00
test_tag_protector.py fix: A9 — tag protector discards wrap on placeholder loss 2026-05-02 18:01:24 -07:00
test_text_crusher.py perf(compression): take large cold-start contexts off the synchronous kompress path (#1171) (#1298) 2026-06-23 10:48:06 -05:00
test_text_crusher_parity.py perf(compression): take large cold-start contexts off the synchronous kompress path (#1171) (#1298) 2026-06-23 10:48:06 -05:00
test_text_crusher_routing.py fix(router): compact JSON evades compression via whitespace token counting (#1857) 2026-07-14 06:54:01 -04:00
test_tree_sitter_thread_safety.py fix(transforms): use thread-local tree-sitter parsers to prevent pyo3 Unsendable panic (#604) 2026-06-10 18:30:00 -05:00