Skip to content

measure: sweep the compaction headroom policy (#150) - #158

Merged
yuanhao merged 1 commit into
mainfrom
measure/150-headroom-sweep
Aug 23, 2026
Merged

measure: sweep the compaction headroom policy (#150)#158
yuanhao merged 1 commit into
mainfrom
measure/150-headroom-sweep

Conversation

@yuanhao

@yuanhao yuanhao commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

The measurement #150 asks for. It contradicts what I wrote on that issue.

Why offline

Two of the four things that matter — how often a session compacts, and how much history survives each time — are pure functions of the compaction code. So they sweep densely for free and deterministically, with no provider in the loop and no nondeterministic model. examples/headroom_sweep.rs drives the real effective_target_ratio and compact_messages, not a reimplementation.

Only prefix-cache hit rate and splice rate need live runs, and those are worth spending on a shortlist rather than a grid.

Result

At the crate-default 96K budget over 120 turns:

growth policy compactions mean held min after
tool-heavy (~3K/turn) Some(30) 4 50,132 12,074
Some(5) 9 71,575 66,308
very heavy (~8K/turn) Some(30) 10 47,764 8,035
Some(5) 19 66,127 48,100

Some(30) takes half to a third as many compactions — prefix-cache invalidations — for about 30% less mean retention. That is the aggressive-but-rare trade working, not a bug.

I had called it "the aggression that makes compaction destructive." The data does not support that framing, and I have corrected it on the issue.

Below ~740 tok/turn at a 26K budget (~2.7K at 96K) every policy resolves identically, so none of this touches light or moderate sessions.

What the data does flag

The post-compaction cliff — context drops to 8–12K of a 96K budget immediately after a compaction, against 48–66K under Some(5). Mean retention recovers, so it is transient, but it is the mechanism behind the LOST answer in the earlier live run. MIN_HEADROOM_RATIO = 0.15 is the one number the data actually questions.

What is not here

The cache half. long_horizon now takes YO_HEADROOM so it can be run per policy, but that run hung twice at compaction #2 and I stopped it rather than keep paying for a flaky measurement. The offline half stands on its own; the cache half does not exist yet, and I would not change the default without it.

No library change — an example plus one env knob on an existing example.

🤖 Generated with Claude Code

The measurement #150 asks for, and it contradicts what I wrote there.

Two of the four things that matter are pure functions of the compaction
code — how often a session compacts, and how much survives each time — so
they sweep densely for free and deterministically, no provider in the
loop. This drives the real effective_target_ratio and compact_messages
rather than reimplementing them.

Result at the crate-default 96K budget over 120 turns:

  tool-heavy (~3K/turn)   Some(30): 4 compactions, 50132 mean held
                          Some(5):  9 compactions, 71575 mean held
  very heavy (~8K/turn)   Some(30): 10 compactions, 47764 mean held
                          Some(5):  19 compactions, 66127 mean held

Some(30) takes half to a third as many compactions — i.e. prefix-cache
invalidations — for about 30% less mean retention. That is the
aggressive-but-rare trade working, not a bug. I had called it "the
aggression that makes compaction destructive"; the data does not support
that framing.

What the data does flag is the post-compaction cliff: immediately after a
compaction the context drops to 8-12K of a 96K budget, against 48-66K
under Some(5). Mean retention recovers, so the cliff is transient, but an
agent asked something right after a compaction has very little to work
with.

Below ~740 tok/turn at a 26K budget (~2.7K at 96K) every policy behaves
identically, so this only affects tool-heavy sessions.

long_horizon takes YO_HEADROOM so the live half — does the lower
compaction count actually buy cache hits — can be run per policy. That
run hung twice and is not included; the offline half stands on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@yuanhao
yuanhao merged commit f9b4634 into main Aug 23, 2026
8 checks passed
@yuanhao
yuanhao deleted the measure/150-headroom-sweep branch August 23, 2026 22:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant