headroom/crates
Rod Boev 9e0778553f
feat(rust): add structured prose offload plumbing (#334) (#2378)
## Description

Structured payloads still leave long prose leaves without a dedicated
prose compressor. The Rust pipeline already handles top-level log, diff,
search, and JSON-array shapes, and the existing structured recursion
rewrites stringified JSON and opaque blobs, but a plain prose string
leaf inside structured content still falls back to generic opaque
long-string handling instead of query-aware extractive compression. That
wastes prompt budget on fields like `summary`, `description`, and
`analysis` even though `headroom-core` already ships the deterministic,
query-aware `TextCrusher`.

This PR adds a bounded prose-field path for structured leaves. It
introduces a reusable `ProseFieldOffload` backed by `TextCrusher`, then
wires that offload into `JsonOffload`'s structured recursion with
conservative byte and segment thresholds. Only detector-confirmed
`PlainText` leaves are eligible. When a leaf clears those gates and the
marker-inclusive output still saves bytes, the exact original leaf is
written to CCR and the inline output carries a prose marker keyed to
that store entry. Short prose, low-segment prose, diff-shaped strings,
stringified JSON, and opaque base64 or HTML keep their existing
behavior.

This stays inside the Rust transform stack. It does not add a PyO3 shim,
ONNX runtime, live-zone prose handling, or any new Python dependency. It
also keeps the existing wrapper-level `JsonOffload` CCR entry, so the
full structured payload remains recoverable as before.


## Type of Change

- [ ] Bug fix (non-breaking change that fixes an issue)
- [x] 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

- Add `ProseFieldOffload` as a `ContentType::PlainText` pipeline offload
backed by `TextCrusher`, with conservative byte, segment, and
target-ratio thresholds.
- Thread the prose offload into the structured `JsonOffload` recursion
so nested prose leaves can compress and recover through the orchestrator
store.
- Add a pipeline-aware `JsonOffload::from_pipeline` constructor so
`offload.prose_field` overrides actually reach the live prose hook
instead of falling back to embedded defaults.
- Preserve current behavior for short prose, low-segment prose,
diff-shaped leaves, stringified JSON containers, and opaque base64 or
HTML leaves.
- Add focused config, routing, determinism, and CCR roundtrip coverage
for the new prose path.
- Leave changelog generation to the repo's conventional-commit release
flow rather than editing `CHANGELOG.md` directly.

## Testing

- [x] Unit tests pass (`cargo test -p headroom-core --lib
transforms::pipeline::offloads::prose_field::tests`)
- [x] Linting passes (`cargo clippy -p headroom-core -- -D warnings`)
- [ ] Type checking passes (`uv run mypy headroom`)
- [x] New tests added for new functionality when applicable
- [ ] Manual testing performed

### Test Output

```text
cargo fmt --all -- --check
cargo clippy -p headroom-core -- -D warnings
cargo test -p headroom-core --lib transforms::pipeline::offloads::prose_field::tests
test result: ok. 6 passed; 0 failed
cargo test -p headroom-core --lib transforms::pipeline::offloads::json_offload::tests
test result: ok. 17 passed; 0 failed
cargo test -p headroom-core --lib transforms::smart_crusher::crusher::tests::default_crush_ignores_opt_in_prose_hook -- --exact
test result: ok. 1 passed; 0 failed
cargo test -p headroom-core --lib transforms::smart_crusher::crusher::tests::prose_hook_preserves_html_opaque_routing -- --exact
test result: ok. 1 passed; 0 failed
cargo test -p headroom-core --lib transforms::smart_crusher::crusher::tests::prose_hook_runs_for_dict_array_rows -- --exact
test result: ok. 1 passed; 0 failed
cargo test -p headroom-core --lib transforms::smart_crusher::crusher::tests::unchanged_stringified_json_container_skips_prose_hook -- --exact
test result: ok. 1 passed; 0 failed
cargo test -p headroom-core --test ccr_roundtrip nested_structured_prose_leaf_uses_ccr -- --exact
test result: ok. 1 passed; 0 failed
git diff --check
```

## Real Behavior Proof

- Environment: Windows 11, stable Rust toolchain, in-memory CCR store,
no live provider
- Exact command / steps: run the focused nested CCR roundtrip test
through `CompressionPipeline::run` on a five-row structured payload
containing a long prose leaf, then resolve the emitted prose marker key
from the same orchestrator store
- Observed result: the generic `CompressionPipeline` plus `JsonOffload`
path applies, the nested prose leaf becomes shorter on the wire, and
that prose key retrieves the byte-identical original leaf from the
orchestrator store while HTML-shaped and diff-shaped leaves stay on
their opaque marker routes
- Not tested: live provider run

## 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
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable

## Additional Notes

- The upstream issue body originally parked PR3b behind a PyO3 shim or a
later ONNX port. This PR takes the narrower Rust-native path instead by
reusing the existing `TextCrusher` already in `headroom-core`.
- This PR advances the pipeline-side PR3b slice from #334. It does not
close #334, and it does not wire live-zone or PyO3 SmartCrusher callers
to this path.
- `CHANGELOG.md` is intentionally untouched because this repo's release
pipeline generates changelog entries from conventional commits, and
`repos/headroom/config.md` marks manual changelog edits as out of
policy.
- Python lint, type checking, and pytest are not part of the focused
local proof for this slice because the change stays inside
`crates/headroom-core`.
2026-07-18 09:53:44 -07:00
..
headroom-core feat(rust): add structured prose offload plumbing (#334) (#2378) 2026-07-18 09:53:44 -07:00
headroom-parity feat: compression extraction — Rust knob exposure, CCR hardening, traffic audits (#818) 2026-06-16 20:21:13 -07:00
headroom-proxy fix(proxy): key drift detector on conversations, not credentials; canonicalize drift hashes (#2301) 2026-07-16 14:34:26 -07:00
headroom-py feat(transforms): language-aware stack-trace collapse for Go/Rust/.NET/Java/Node (#1791) 2026-07-15 19:58:30 +00:00
headroom-simulators feat(simulators): add provider simulator service (#2014) 2026-07-11 09:41:49 -07:00