The 12 langchain integration evals generate fixture data via
`random.choice`/`random.randint` without seeding. SmartCrusher's
anchor selection consumes the same global random state, so a handful
of unseeded inputs (~1% of seed values) skip the first/last anchor
preservation and the eval flakes — surfaced on PR #319 CI even though
this PR doesn't touch SmartCrusher.
Confirmed pre-existing: identical 5/500 seed failures on `main`
@ `cf3877d`. The fix is the smallest one that doesn't paper over the
underlying selector behavior — seed `random` per-test via an autouse
fixture so dataset generation is reproducible.
The PR8 marker injection appends a sentinel object
{"_ccr_dropped": "<<ccr:HASH N_rows_offloaded>>"} to the kept-items
array on the lossy path so the LLM sees the retrieval pointer in the
prompt. Tests that iterate compressed arrays via subscript access
(e["level"], r["status"], i["labels"], m["text"]) hit KeyError on
the sentinel because it doesn't share the record schema.
Same root cause as the test_quality_retention fixes in PR8 -- these
integration tests were left out of that pass.
Ship a public helper headroom.transforms.smart_crusher.strip_ccr_sentinels
so tests can use it cleanly: `for e in strip_ccr_sentinels(entries):`
and production callers iterating compressed output get a single
canonical filter instead of inlining the _ccr_dropped check.
The 7 previously-failing tests in PR #292 CI now pass:
- langchain test_100_percent_errors_preserved_logs
- langchain test_errors_preserved_with_many_errors
- langchain test_search_results_with_query_term
- mcp test_all_log_errors_preserved
- mcp test_slack_significant_compression_with_content
- mcp test_database_error_status_preserved
- mcp test_github_bugs_partial_preservation
753 tests across the integration + transforms + retention suites pass
locally. Plugin manifests auto-bumped 0.13.3 -> 0.13.4 by the
sync-plugin-versions hook (unrelated to this fix).
PR4 flipped the OSS default to lossless-first. The MCP server and
LangChain eval tests assert wire-format and row-level retention
properties that belong to the lossy path; the lossless path
substitutes a CSV+schema STRING in place of arrays, which is great
for LLM prompts but wire-incompatible with consumers that iterate
the JSON.
Pin both call sites to the lossy + CCR-Dropped path via
`with_compaction=False`. Same retention semantics as Python's
pre-PR4 SmartCrusher behavior — full payload still cached via CCR
for tool retrieval; nothing is lost.
Modules:
- headroom/integrations/mcp/server.py — runtime MCP wrapper
- tests/test_integrations/langchain/test_evals.py — eval fixture
CI run that surfaced these: actions/runs/25025161868