|
18 | 18 | fallback. Build it locally with `scripts/build_rust_extension.sh` |
19 | 19 | (wraps `maturin develop`) or install a prebuilt wheel. |
20 | 20 |
|
21 | | -# Functionality state (post-audit, 2026-04-28) |
| 21 | +# Functionality state (post-audit, 2026-04-29) |
22 | 22 |
|
23 | 23 | - **TOIN learning** — re-attached. `crush()` and `_smart_crush_content` |
24 | 24 | call `toin.record_compression()` after a real compression (filtered on |
25 | 25 | `strategy != "passthrough"` to ignore JSON re-canonicalization). |
26 | 26 | The retired Python class did this inline; the bridge keeps the |
27 | 27 | highest-traffic strategy fueling the learning loop. |
28 | | -- **CCR marker emission** — partial gap. The Rust port emits |
29 | | - `<<ccr:HASH N_rows_offloaded>>` markers unconditionally as part of |
30 | | - `dropped_summary`; the `ccr_config.inject_retrieval_marker=False` |
31 | | - knob is therefore not honored end-to-end. The shim now logs a |
32 | | - WARNING when callers pass `False`. Suppression needs a Rust-side |
33 | | - gate; see RUST_DEV.md. |
34 | | -- **Custom relevance scorer / scorer override** — still not wired. |
35 | | - `relevance_config` and `scorer` constructor args are accepted for |
36 | | - source compat but the Rust default `HybridScorer` is always used. |
37 | | - The shim now logs a WARNING (was: debug) when these are passed. |
| 28 | +- **CCR marker emission** — honored end-to-end. Both |
| 29 | + `ccr_config.enabled=False` and |
| 30 | + `ccr_config.inject_retrieval_marker=False` flip the Rust crusher's |
| 31 | + `enable_ccr_marker` field; the lossy row-drop path then skips both |
| 32 | + the marker text and the CCR store write. Scope: gates only the |
| 33 | + row-drop sentinel path. Stage-3c.2 opaque-string CCR substitutions |
| 34 | + still emit always — they have no Python equivalent. |
| 35 | +- **Custom relevance scorer / scorer override** — fails loud. |
| 36 | + `relevance_config` and `scorer` constructor args remain in the |
| 37 | + signature for source compat, but the shim raises |
| 38 | + `NotImplementedError` when either is non-None. Silently dropping a |
| 39 | + user-supplied scorer is a silent-fallback bug we explicitly refuse |
| 40 | + to ship; full plumbing lands with Stage-3c.2's relevance-crate |
| 41 | + Python bridge. |
38 | 42 | """ |
39 | 43 |
|
40 | 44 | from __future__ import annotations |
@@ -176,37 +180,48 @@ def __init__( |
176 | 180 | self._observer = observer |
177 | 181 |
|
178 | 182 | # CCR config is preserved on `self` for callers that read it |
179 | | - # back (`headroom.proxy.server` does). Storage-side semantics |
180 | | - # (CCR cache lookups) are honored via the Rust crusher's own |
181 | | - # CCR store. *Marker emission* is the gap: the Rust port emits |
182 | | - # `<<ccr:HASH N_rows_offloaded>>` markers unconditionally as |
183 | | - # part of `dropped_summary`, so `inject_retrieval_marker=False` |
184 | | - # has no effect on the prompt today. We log a WARNING (not |
185 | | - # debug) so it's visible. Suppression of marker emission needs |
186 | | - # a Rust-side gate; tracked in RUST_DEV.md. |
| 183 | + # back (`headroom.proxy.server` does). Both `enabled=False` and |
| 184 | + # `inject_retrieval_marker=False` collapse to the Rust crusher's |
| 185 | + # `enable_ccr_marker=False` gate — when either is off, the |
| 186 | + # lossy row-drop path skips marker emission AND the CCR store |
| 187 | + # write (no point storing a payload nothing in the prompt can |
| 188 | + # reference; storing it under `enabled=False` would also be a |
| 189 | + # surprise side effect the user explicitly disabled). |
| 190 | + # |
| 191 | + # Default falls through to `CCRConfig()` so direct callers |
| 192 | + # (the proxy and tests that don't pass an explicit config) get |
| 193 | + # the documented dataclass defaults (`enabled=True, |
| 194 | + # inject_retrieval_marker=True`). The previous override here |
| 195 | + # set `inject_retrieval_marker=False` as a no-op-intent hack |
| 196 | + # back when the Rust port silently ignored the flag; now that |
| 197 | + # the flag is honored, that override would actively suppress |
| 198 | + # markers + store writes for every caller. |
| 199 | + # |
| 200 | + # Scope: gates ONLY the row-drop sentinel path. Stage-3c.2 |
| 201 | + # opaque-string CCR substitutions still emit always — they have |
| 202 | + # no Python equivalent and no production caller has asked for |
| 203 | + # them to be suppressed. |
187 | 204 | if ccr_config is None: |
188 | | - self._ccr_config = CCRConfig(enabled=True, inject_retrieval_marker=False) |
| 205 | + self._ccr_config = CCRConfig() |
189 | 206 | else: |
190 | 207 | self._ccr_config = ccr_config |
191 | | - if not self._ccr_config.inject_retrieval_marker: |
192 | | - logger.warning( |
193 | | - "SmartCrusher: ccr_config.inject_retrieval_marker=False " |
194 | | - "is currently NOT honored by the Rust port — CCR row-drop " |
195 | | - "markers (`<<ccr:HASH N_rows_offloaded>>`) will still appear " |
196 | | - "in compressed output. Tracked as a known regression in " |
197 | | - "RUST_DEV.md until a Rust-side gate lands." |
198 | | - ) |
199 | 208 |
|
200 | | - # `relevance_config` and `scorer` are accepted for source |
201 | | - # compatibility but currently dropped — Stage 3c.1 ships with |
202 | | - # the Rust default `HybridScorer`. Custom scorers re-attach in |
203 | | - # Stage 3c.2 when the relevance crate gains a Python-bridged |
204 | | - # constructor surface. |
| 209 | + # `relevance_config` and `scorer` remain in the signature for |
| 210 | + # source compatibility, but the Rust port doesn't support |
| 211 | + # overrides yet (it always uses `HybridScorer` from the |
| 212 | + # relevance crate; the Python-bridged constructor surface |
| 213 | + # arrives in Stage 3c.2). Silently dropping a user-supplied |
| 214 | + # scorer would be a textbook silent fallback — if a caller |
| 215 | + # depends on a custom scoring function and we ignore it, the |
| 216 | + # compression they get back is wrong in a way they cannot see. |
| 217 | + # Fail loud instead. See `feedback_no_silent_fallbacks.md`. |
205 | 218 | if relevance_config is not None or scorer is not None: |
206 | | - logger.warning( |
207 | | - "SmartCrusher: custom relevance_config/scorer args are " |
208 | | - "currently ignored (Rust port uses default HybridScorer). " |
209 | | - "Tracked as a known regression in RUST_DEV.md." |
| 219 | + raise NotImplementedError( |
| 220 | + "SmartCrusher: custom `relevance_config` / `scorer` " |
| 221 | + "overrides are not yet supported by the Rust-backed " |
| 222 | + "implementation. Pass `None` to use the default " |
| 223 | + "HybridScorer. Tracked in RUST_DEV.md; full support " |
| 224 | + "lands with Stage 3c.2's relevance-crate Python bridge." |
210 | 225 | ) |
211 | 226 |
|
212 | 227 | # Lazy TOIN handle. Loaded on first compression that has items |
@@ -236,6 +251,9 @@ def __init__( |
236 | 251 | first_fraction=cfg.first_fraction, |
237 | 252 | last_fraction=cfg.last_fraction, |
238 | 253 | relevance_threshold=0.3, |
| 254 | + enable_ccr_marker=( |
| 255 | + self._ccr_config.enabled and self._ccr_config.inject_retrieval_marker |
| 256 | + ), |
239 | 257 | ) |
240 | 258 | # Default: lossless-first compaction (PR4). Lossless wins for |
241 | 259 | # cleanly tabular input where it saves ≥ 30% bytes; otherwise |
|
0 commit comments