What happened
The TUI context gauge can briefly show a much larger, stale value while sending a message to a stopped or newly selected session, then return to the correct value when the first settled usage arrives. For example:
before send: ctx 131k/1.0M 12%
during send: ctx 831k/1.0M 83% (the exact value varies)
after usage: ctx 131k/1.0M 12%
The observed transition does not require /compact, and the transient value does not represent confirmed context growth.
Reproduction
- Open a session whose last known context is around
131k/1.0M.
- Stop the session or switch to a session that is not currently running.
- Send a normal text message.
- Observe the ctx gauge while the turn is starting / before the first settled usage is shown.
- The gauge can temporarily jump to an arbitrary larger value, then return to the correct value when the next usage refresh completes.
The component-level race is deterministic on the current head: start a diagnostics refresh, deliver a newer token_usage value, then resolve the older in-flight diagnostics read. The older result is still applied, producing 131k -> 831k -> 131k.
Expected behavior
A context gauge must never apply a diagnostics result that is older than the latest usage/event state already shown. Until a newer settled request is authoritative, it should retain the last valid value; it should not briefly display a stale snapshot.
Technical cause
The TUI refresh path in packages/cli/src/tui-context-refresh.ts drops a result only when a newer diagnostics query has already been issued. A newer token_usage event schedules another query but does not invalidate an in-flight query. Therefore an older read can resolve in the debounce window and overwrite the newer displayed value.
Desktop's createLiveContextUsageTracker has the same event-to-query freshness shape, so the composer gauge may have the same transient race. Existing tests cover query-versus-query ordering, but not an in-flight query resolving after a newer token_usage / event update.
The Runtime tests and current settled-snapshot rules still correctly reject failed/aborted/compaction attempts as the latest context. This issue is about presentation freshness, not changing context accounting or compaction semantics.
Proposed fix
- Invalidate an in-flight diagnostics read as soon as a newer authoritative usage/event state is received, or carry an explicit event/snapshot sequence and apply only results newer than the displayed state.
- Share the freshness rule between TUI and Desktop.
- Add regression tests for
in-flight diagnostics -> token_usage -> old diagnostics resolution, plus the normal query-versus-query and session-switch cases.
Environment
What happened
The TUI context gauge can briefly show a much larger, stale value while sending a message to a stopped or newly selected session, then return to the correct value when the first settled usage arrives. For example:
The observed transition does not require
/compact, and the transient value does not represent confirmed context growth.Reproduction
131k/1.0M.The component-level race is deterministic on the current head: start a diagnostics refresh, deliver a newer
token_usagevalue, then resolve the older in-flight diagnostics read. The older result is still applied, producing131k -> 831k -> 131k.Expected behavior
A context gauge must never apply a diagnostics result that is older than the latest usage/event state already shown. Until a newer settled request is authoritative, it should retain the last valid value; it should not briefly display a stale snapshot.
Technical cause
The TUI refresh path in
packages/cli/src/tui-context-refresh.tsdrops a result only when a newer diagnostics query has already been issued. A newertoken_usageevent schedules another query but does not invalidate an in-flight query. Therefore an older read can resolve in the debounce window and overwrite the newer displayed value.Desktop's
createLiveContextUsageTrackerhas the same event-to-query freshness shape, so the composer gauge may have the same transient race. Existing tests cover query-versus-query ordering, but not an in-flight query resolving after a newertoken_usage/ event update.The Runtime tests and current settled-snapshot rules still correctly reject failed/aborted/compaction attempts as the latest context. This issue is about presentation freshness, not changing context accounting or compaction semantics.
Proposed fix
in-flight diagnostics -> token_usage -> old diagnostics resolution, plus the normal query-versus-query and session-switch cases.Environment
29f13bdb3a