#3625·headroom

[BUG] lossless_only is accepted but inert in 0.37.0 — SmartCrusher drops array items to max_items_after_crush with no CCR marker

Author: wehnsdaefflaeCreated Sep 17, 2026Updated Sep 17, 2026

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__ contains lossless_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