headroom/crates
Focused Instability 0632eba6c3
fix(policy): correct warm-cache penalty in net_mutation_gain to (S + dT) (#903)
Fixes #906.

## What

Part of #904 (net-cost policy completion tracking). Follows up #856 /
#857 with the corrected gain term raised in [this #856
comment](https://github.com/chopratejas/headroom/issues/856#issuecomment-4679706939)
— prerequisite for P2 (pipeline consumption), which would otherwise wire
in a formula that is always-pro-mutation by exactly `P_alive·(w−r)·ΔT`.

## Why the corrected form is right

With a live cache, the ΔT tokens a mutation removes are **already
cache-written** — keeping them costs only reads (`ΔT·r·R`), so a
mutation cannot avoid a fresh write of them. Blending alive (`ΔT·r·R −
(w−r)·S`) and dead (`ΔT·(w + r·(R−1))`, no suffix penalty) cases over
`P_alive`:

```
gain = ΔT·(w + r·(R−1)) − P_alive·(w−r)·(S + ΔT)
```

Three independent confirmations:

1. **Direct cost check** (w=1.25, r=0.1, warm, ΔT=50K, S=10K, R=2):
keeping costs 60K·0.1·2 = 12,000 in reads; mutating costs 10K·1.25
(suffix rewrite, the first of the R touches) + 10K·0.1 (remaining read)
= 13,500 — mutation loses 1,500, matching the corrected gain of −1,500.
The old form said +56,000.
2. **The issue's own anchors**: corrected break-even is exactly `R =
11.5·S/ΔT` → 2K/50K = 287.5 (~290, as the issue says) and 50K/10K = 2.3
— the spec text's anchor numbers can only be derived from the corrected
penalty. The implemented form gave 276 and *negative*.
3. **Internal consistency**: `break_even_reads` already shipped with the
~11.5·S/ΔT shape; this PR reconciles `net_mutation_gain` with it (and
drops break_even's stray −1 term).

## Behavior changes (formula is still dead code — nothing consumes it
yet)

- 50K-shave/10K-suffix/R=3 golden: +61,000 → **+3,500** (tight win,
consistent with 2.3-read break-even).
- 2K-shave/50K-suffix/R=10 golden: −53,200 → **−55,500**.
- S=0 boundary: an edit of already-cached content with no suffix is
profitable whenever ≥1 read remains (`gain = ΔT·r·R`), and exactly 0 at
R=0 warm. Not-yet-cached (live-zone) content should bypass the formula —
now documented on both implementations.

Rust + Python goldens updated in lockstep: 13 Rust + 19 Python tests
green.

## Next (separate PRs)

- **P2**: flag-gated consumption (`HEADROOM_NET_COST_POLICY=1`) with
decision telemetry.
- **P3**: batch deep edits (reclaim threshold), idle-timer compaction
near TTL lapse.

Co-authored-by: integration-check <integration@local>
2026-06-12 17:14:30 -05:00
..
headroom-core fix(policy): correct warm-cache penalty in net_mutation_gain to (S + dT) (#903) 2026-06-12 17:14:30 -05:00
headroom-parity fix: B1 — retire ICM, RollingWindow, scoring, relevance + dependents 2026-05-02 12:23:17 -07:00
headroom-proxy fix(observability): G3 remediation — bound cardinality + wire dead metrics 2026-05-24 10:41:56 -07:00
headroom-py feat: gated Markdown-KV compaction formatter (serialization-aware output) (#859) 2026-06-11 13:03:50 -05:00