v0.1.7 — fix: compress absorbs stale seq refs instead of erroring
The bug
In long sessions, compress threw seq X..Y not in the current surface when the model reused seq refs from an older nudge table or an earlier compress result — an earlier compression had already shadowed those seqs (they leave the surface, but stay in the append-only log). Prompt-only guidance ("verify with acp_status") reduced but never eliminated it, because the old tables stay in the conversation history and re-compressing an already-compressed span looks like a legitimate action.
The fix (engine-side, not prompt-only)
src/region.ts—recoverStaleRange: a requested edge that was shadowed is remapped to the still-live content of the requested span (value-ordered, checkpoint nodes excluded); a fully shadowed span throwsAlreadyCompressedRangeErrorwith the covering block ids; invented/other-session seqs (not in the log) still fail, now naming the exact edge.src/tools.ts— three outcomes instead of a hard error:- fully stale span →
Compressed 0 block(s)+seqs X..Y already compressed (block …) — decompress to recover(no phantom block, no error); - partially stale span → compresses the live remainder, e.g.
seqs 3..10 were already shadowed — compressed the live remainder 6..10; - batch with mixed entries → fresh ranges land, stale ones are skip-warned.
- Block checkpoint nodes are never folded on a stale reference — tier-2/3 distillation stays an explicit act on a LIVE checkpoint seq.
- fully stale span →
- Guidance — system prompt, nudge range-table footer, and the compress tool description now explain staleness and recovery.
- Tests — 6 new regression tests (stale remap, already-compressed no-op, multi-block coverage, checkpoint non-folding, live-middle, mixed batch): 60 total, all green; typecheck + build clean.
Live verification (repro of the reported failure)
first compress: Compressed 1 block(s), ~5162 tokens reclaimed.
second compress (same stale seqs 1..5):
Compressed 0 block(s), ~0 tokens reclaimed.
seqs 1..5 already compressed (block 10d60086) — nothing to reclaim; decompress to recover the originals
partial-stale (seqs 3..10):
Compressed 1 block(s) | block 060e5fca: seqs 6..10, 5 messages shadowed
(seqs 3..10 were already shadowed — compressed the live remainder 6..10)