Repository navigation
fix: #498 weak-overflow learning + #499 P1a affinity persistence + P1b cache-collapse warn - #504
Conversation
…on cache collapse - #498: noteWeakOverflow fires on stream truncation / upstream errors at >=90% window usage; 3 events in 15min learn a shrink-only conservative window and arm the emergency shrink (strong 4xx signals remain the primary teacher). Hooks in loop/core.ts (both adapters' truncation and UpstreamHttpError) and both plugin passthrough pipes (terminal-event detection per wire format). - #499 P1a: prefix-affinity snapshot persisted to ${XDG_STATE_HOME}/billion-context/prefix-affinity.json (atomic write, 5s debounce, flush on shutdown, hydrate on startup) so a proxy restart no longer orphans anonymous sessions. - #499 P1b: cache-warn detects prompt-cache collapse (5 consecutive large requests at ~0% hit after earlier >=50% hits) and logs a diagnostic pointer at #499 causes. Tests: 20 new (weak-overflow, plugin-truncation, cache-warn, affinity-persist). Full suite 1018/1020 (2 known env fails in plugin-agent.test.ts).
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)npm install -g billion-context@pr-504Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf billion-context-pr504.tgz
npm install -g packageThis comment is automatically updated on each push. |
…erequisite) migrateLegacyIds() re-keys sessions whose stored label differs from their id (#286 cleanup), deleting all but the newest sibling per label. Anonymous prefix-affinity sessions (#309) all carry the shared display label "prefix-affinity" != their pfa- id, so every boot re-keyed them all to the single id "prefix-affinity" and deleted every sibling but the newest — silent loss of saved compression state for anonymous clients on every restart. Exclude pfa- ids from the migration. True legacy derived-hash sessions are still re-keyed as before (regression-tested alongside the guard). Prerequisite for #504 P1a affinity-snapshot persistence: without it, routing restored across restarts lands on session files that no longer exist, so the folded view cannot be rebuilt.
[bot] 🏷 PR #504 review — pre-flight re-run on Pre-flight (verified locally)
Blocking: P1a alone does not fix #499 — needs #502's migration guardThis PR persists the routing table ( The fix already exists in open PR #502 (skip
Your call — flagging because P1a's stated goal ("restart resumes the same compressed context") is unreachable without whichever option ships. Minor (non-blocking)
Verified correct
Verdict: implementation is solid and faithful to the spec. Mergeable once (a) the #502-guard question above is resolved and (b) the e2e suite passes. I can't merge PRs (human-only) — happy to apply the |
Closes #498. Implements the bili-side half of the #499 fix family (paired with acp-kernel PR acp-kernel#196).
1. #498 — learn from weak overflow signals
Problem: non-4xx overflow evidence (stream truncation without a completion event, upstream HTTP errors on oversized requests) never taught the proxy anything, so an oversized session could fail forever without a strong 400 signal.
Fix — new
src/weak-overflow.ts(noteWeakOverflow):loop/core.tstruncation without done-event (both adapters) +UpstreamHttpErrorcatch, and both plugin passthrough pipes (chat:[DONE]/message_stop= terminal; responses: done-family events = terminal).lastInputTokens = max(...)), marks dirty, logs the decision.!upstream.okpath) remains the primary teacher; this is the fallback.2. #499 P1a — prefix-affinity persistence
Problem: prefix-affinity was pure in-memory (LRU 256, 7-day TTL) → a proxy restart re-forked every anonymous session (#351: pfa-8588 one-shot ingest of 1746 msgs / 458 662 tok, raw 458K resend, cache hit 0%).
Fix —
src/prefix-affinity.tsgainsexportSnapshot()/importSnapshot(); newsrc/affinity-persist.ts: snapshot to${XDG_STATE_HOME}/billion-context/prefix-affinity.json({version:1, entries}), atomic tmp+rename, 5 s debounced write after eachnote(), flush infinishShutdown(), hydrate on startup. Import validates entry shape, drops TTL-expired chains, re-imposes LRU/item caps.3. #499 P1b — prompt-cache collapse warn (diagnostic)
Problem: cache hit 0% on the mirror is a symptom of re-forking (or upstream KV drop); nothing surfaced it.
Fix — new
src/cache-warn.ts(warnCacheCollapse): after a session has seen ≥50% hit on a ≥8k-token request, 5 consecutive large requests at ≤10% hit log ONE warning pointing at the likely causes (restart re-fork / upstream KV drop) and what to check (upstream session id,compress.modelContextLimit). Hooks:plugin.ts applyUsageSample+loop/core.ts recordUsage. Diagnostics only — no behavior change.Tests
20 new tests across 4 files:
tests/weak-overflow.test.ts(7),tests/plugin-truncation-weak-overflow.test.ts(5),tests/cache-warn.test.ts(4),tests/affinity-persist.test.ts(4).Pre-flight:
npm run typecheck✅ ·npm test1018/1020 (2 known permanent env fails inplugin-agent.test.ts, unrelated) ✅ ·npm run build✅Out of scope (deliberate)
prompt_cache_keyforwarding unchanged.