[BUG] lossless_only is accepted but inert in 0.37.0 — SmartCrusher drops array items to max_items_after_crush with no CCR marker
Summary
In 0.37.0, SmartCrusherConfig.lossless_only is accepted by both the Python wrapper and the PyO3 config, but has no effect: output is byte-identical with the flag on and off. On a JSON object whose value is an array, the crusher drops items down to max_items_after_crush (default 15) and emits no CCR marker, so a consumer has no way to detect that content was removed — and no configuration produces marker-free and complete output.
This is the guarantee #1091 was closed by introducing, and it is a different failure from #1478 (there, the Rust struct rejected the kwarg with a TypeError; here it accepts it and ignores it).
Reproduce
import json
from headroom._core import SmartCrusher, SmartCrusherConfig
data = json.dumps({"slugs": [f"r{i}" for i in range(53)]})
for cfg in (dict(lossless_only=True),
dict(lossless_only=False),
dict(lossless_only=True, enable_ccr_marker=True),
dict(lossless_only=True, enable_ccr_marker=False)):
out = SmartCrusher(SmartCrusherConfig(**cfg)).crush(data, "", 1.0).compressed
print(f"{str(cfg):58} -> slugs {len(json.loads(out)['slugs']):2}/53 "
f"ccr_marker={'<<ccr:' in out}")
{'lossless_only': True} -> slugs 15/53 ccr_marker=False
{'lossless_only': False} -> slugs 15/53 ccr_marker=False
{'lossless_only': True, 'enable_ccr_marker': True} -> slugs 15/53 ccr_marker=False
{'lossless_only': True, 'enable_ccr_marker': False} -> slugs 15/53 ccr_marker=False
The package's own Python wrapper behaves identically, so this is not a matter of bypassing it:
python wrapper lossless_only=True slugs 53 -> 15 ccr_marker=False bytes 372 -> 91
python wrapper lossless_only=False slugs 53 -> 15 ccr_marker=False bytes 372 -> 91
python wrapper output identical for True/False: True
_core (PyO3) lossless_only=True slugs 53 -> 15 ccr_marker=False bytes 372 -> 91
_core (PyO3) lossless_only=False slugs 53 -> 15 ccr_marker=False bytes 372 -> 91
_core (PyO3) output identical for True/False: True
Expected
Per the crush() docstring in headroom/transforms/smart_crusher.py, with lossless_only=True "rows are never dropped and opaque cells render inline", and the output is byte-recoverable. Either that, or the row-drop path should emit the CCR marker that enable_ccr_marker=True promises — the current behaviour offers neither.
Impact (measured)
We run an LLM job scheduler that compresses large command stdout before it reaches the model, using the native primitives directly (lossless_only=True, CCR disabled — we never want a retrieval round-trip). Because we did not trust the flag, every candidate is validated by an independent JSON-equivalence check before it is allowed to replace the original, and rejected results fall back to the uncompressed output.
Over one week across ~30 agents: 260 compressions were rejected by that check. Of the 121 whose original was still recoverable, 121 were genuine data loss — dropped array elements (33 → 15, i.e. max_items_after_crush), dropped object keys (8, 15 and 35 at a time), and in some cases a list replaced by a string. None carried a marker. Zero were benign reformatting (whitespace, key order, equivalent escaping).
Without that external check, those would have been silently truncated tool results presented to a model as complete — the failure mode #1091 describes, minus the marker that at least made it visible.
For calibration on the same payloads: json.dumps(obj, separators=(",", ":")) was faithful on 335/335 and saved roughly 5x more estimated tokens than the crusher's accepted results, at ~0.5 ms per payload versus ~250 ms.
Environment
- headroom-ai 0.37.0 (wheel), Python 3.12.14, Linux x86_64 (glibc 2.36), Docker
SmartCrusherConfig.__text_signature__containslossless_only=False, so the field is accepted, not rejected
Suggested direction
Either gate the row-drop path on lossless_only in the Rust crusher (and gate the opaque-blob path as #1091 asked), or — if the guarantee cannot be honoured — reject the config at construction rather than accepting a flag that does nothing. A silently inert safety flag is worse than an absent one: it reads as a guarantee in every call site that sets it.
Source: headroomlabs-ai/headroom