Headroom 0.34 Compression and Retrieval Contract: Fields, Modes, and Real-Endpoint Tests
ENGINEERING NOTES
Published / DavidHLPL
Treat the Headroom 0.34.0 API as a versioned contract rather than inferring fields from the dashboard, type names, or mocks. /v1/compress requires model and messages, compression metrics are top-level response fields, and /v1/retrieve returns original_content. An adapter can pass a self-consistent mock suite while getting all three wrong against the real proxy.
Contract at a glance
POST /v1/compress
{
"model": "<MODEL_NAME>",
"messages": [{ "role": "user", "content": "..." }],
"config": {}
}
A successful non-empty request on the normal compression path exposes these top-level fields:
messages
tokens_before
tokens_after
tokens_saved
compression_ratio
transforms_applied
transforms_summary
ccr_hashes
Boundaries:
- Missing
modelormessagesreturns HTTP 400. - The endpoint consumes
messages; a Codex Responsesinputarray must be converted first. tokens_savedis top-level, not nested understats.- An empty message list returns before config validation and omits
transforms_summary; the caller must still decide whether an empty list is meaningful.
POST /v1/retrieve
{ "hash": "<CCR_HASH>" }
A successful response contains:
hash
original_content
original_tokens
original_item_count
compressed_item_count
tool_name
retrieval_count
A missing hash returns HTTP 400; an absent or expired hash returns HTTP 404. Read original_content rather than probing for nonexistent content or found fields.
Compression modes are not interchangeable
config.mode |
Marker | Store write | Requirement |
|---|---|---|---|
| omitted | no | no | Default path; no CCR retrieval loop is required |
ccr |
conditional | conditional | The caller injects a retrieval tool and can reach loopback /v1/retrieve |
lossy_inline |
no | no | Lossless fold first, then Kompress on the remainder |
lossless_then_lossy |
no | no | Compatibility alias for lossy_inline |
ccr_hashes reports markers actually inserted. Even in ccr mode, ordinary text or a general function message does not guarantee a marker. SmartCrusher row-drop on structured tool output is a verified marker-producing path. Tests must not equate enabling ccr with a non-empty ccr_hashes array.
Freezing the provider-cache prefix
For a non-empty request on the normal compression path, config.frozen_message_count must be a non-negative integer. It freezes the first N messages already stored in the provider prompt cache: they remain visible to cross-message analysis but are returned byte-for-byte unchanged, avoiding cache-prefix rewrites. An empty message list returns before this validation.
It points in the opposite direction from protecting recent messages:
frozen_message_countpins the leading provider-cache prefix;protect_recentprotects recent messages near the tail.
Confusing them causes cache misses or preserves old messages that should have been compressed.
Why mocks produce false positives
Three self-consistent but incorrect mock assumptions were observed:
- reading
stats.tokens_saved; - reading
contentorfoundfrom retrieval; - allowing
modelto be omitted.
If implementation and mock share those assumptions, unit tests still pass. The minimal fix is to extract the schema from the pinned release source, then require both mocks and loopback contract tests to follow it.
Minimum contract test
Cover at least four assertions:
/v1/compresswithoutmodelreturns 400;- a valid response exposes top-level
tokens_saved; /v1/retrieveusesoriginal_content;- only a fixture that actually inserts a marker expects non-empty
ccr_hashes.
Isolate the transport environment when calling the real loopback endpoint. In some environments Bun fetch uses HTTP_PROXY without bypassing loopback as expected. Clear proxy variables in the test process or use a client that explicitly avoids proxying loopback; otherwise a connection failure can be misdiagnosed as an API-contract failure.
Scope, risk, and rollback
This page is scoped to headroom-ai==0.34.0. On upgrade, reread the pinned release source and rerun the same contract tests, especially for required fields, response nesting, mode aliases, and CCR-store behavior.
Rollback does not require deleting data: restore new requests to the default marker-free mode. Keep the retrieval tool available for any active conversation that already contains CCR markers until that conversation ends, or start a new conversation before disabling /v1/retrieve tool injection. If the CCR store already contains entries, clean it through Headroom’s lifecycle rather than modifying internal store files.
Related pages
Sources and related documents
- headroom-0-34-compress-retrieve-contract
- Headroom Single-Port Synthesis: Entry, Dynamic Upstreams, and Verification Boundaries
- Headroom Route Persistence Synthesis: Named Profiles, model_cache, and Recovery
- Headroom with cc-switch / Claude Code Coexistence: Single Synthesis and Security Boundaries
- OMP Headroom Bridge: External Routing Controller and Native Codex/OMP Proxy Boundaries
- OMP Hook Extension Concept: Decision-Point Nudges, Hard Blocks, and Status Bridges
- The LLM-Wiki Pattern: Maintaining a Compounding Personal Knowledge Base
Research notes
- Original document: src/content/note/en/headroom-compress-retrieve-contract.md
- Source revision: f49953fb0d4bd52a39bf81167b0c4b7dd7d78a64
- Evidence status: active