Sandbox verification of the first fix exposed the remaining gap: manual
/compress runs the session.compress RPC OUTSIDE any turn, so busy never
flips and useContextBreakdown's effect deps (attempt/busy/enabled/
requestGateway/sessionId) never change — the meter kept serving the
pre-compression breakdown (441.2k/1M) after the transcript shrank 1220 →
202 messages (~5.7x), until the status-bar item was unmounted and
remounted, which reset useState and forced a fresh fetch.
Add an invalidation seam: invalidateContextBreakdown(sessionId) bumps a
per-session generation and notifies subscribers; the hook subscribes for
its own session and re-runs the fetch effect on a bump. Two call sites:
slash.ts after a successful session.compress (the no-turn path), and
lifecycle.ts on session.reclaimed (belt-and-braces with the retry ladder
— invalidation makes the refetch immediate, retries cover failures).
Also verified live: the pre-compression value was wrong by 5.7x after
compression, and unmount/remount of the footer item (the user's manual
workaround) is exactly the cache-reset the fix now does automatically.