Skip to content

refresh usage after turn

Kazushi Kamegawa edited this page Aug 12, 2026 · 1 revision

Refresh Codex Usage After Conversation Turns

日本語

Date: 2026-08-12
Tracking: Issue #143; sub-issues #144, #145, #146, #147
Implementation: codex/feature-refresh-usage-after-turn, PR #142

Background

Remaining Usage Flyout (ADR-005) scoped usage freshness to a connection generation and a 60-second TTL: the first signed-in Ready state fetches once, opening the popup refreshes only after the TTL, and a Busy-to-Ready turn transition by itself does not refetch. That kept the display stable across ordinary turns, but it also meant a completed turn — which has just consumed model calls — could show a stale remaining-usage percentage for up to a minute. This plan adds an explicit usage-consumption boundary on top of the existing model, without touching any of its guarantees.

Design

  • Treat a completed conversation turn, and a completed context compaction, as explicit usage-consumption boundaries, independent of the Busy-to-Ready state transition ADR-005 already excludes.
  • After the existing UI transcript/status projection for the event finishes, force one worker/account/rateLimits read. "Force" means the read bypasses the 60-second TTL check but still goes through the existing connection-generation and push-version guards, so a concurrent push or a lifecycle invalidation still wins over a stale in-flight read.
  • TurnCompleted also covers turns the app-server reports as interrupted — it still arrives as turn/completed. A transport-level failure (network loss, app-server exit) is different: it surfaces as a Degraded connection state instead, under which usage is already considered unavailable, so it is explicitly not a forced-refresh trigger. The last successful snapshot simply remains visible until reconnection restores availability.
  • Context compaction needed its own trigger because /compact consumes model calls but the app-server does not always follow completion with turn/completed — the Worker already special- cases this same gap to restore the Ready connection state after compaction.
  • If the forced read itself fails, the last successful snapshot and its timestamp stay visible, and the next turn/compaction boundary (or the existing TTL//status paths) retries it.

Implementation phases

  1. Design and ADR (#144) — amend ADR-005 and the usage-freshness sections of the design/implementation docs with the new trigger and the explicit turn-failure exclusion.
  2. Implementation and tests (#145) — force the refresh from both ChatViewModel.OnConversationEventAsync (on TurnCompleted) and ChatViewModel.OnContextCompactedAsync (on completed compaction), reusing the existing refresh gate, connection generation, push version, and lifetime cancellation. No Worker/RPC contract, XAML, or package change.
  3. Manual verification (#146) — confirm in a Visual Studio Experimental Instance that the header, Usage popup, and updated timestamp stay in sync after a normal turn, after /compact, and after an interrupted turn.
  4. Terminal-failure follow-up (#147) — confirm whether the app-server protocol has a distinct terminal-turn-failure notification separate from turn/completed, and extend the forced-refresh trigger to it if one exists.

Acceptance and verification

  • A TurnCompleted event forces exactly one additional rate-limit read within the TTL window, and the header/popup reflect the new percentage and updated time.
  • The same holds for a completed context/compacted event; an in-progress compaction event is a no-op.
  • No forced read occurs when usage is unavailable (signed out, disconnected, or Degraded).
  • A failed forced read preserves the last successful snapshot and is retried on the next boundary.
  • Existing regression coverage remains green: Busy-to-Ready alone does not refetch, a push always wins over a stale in-flight read, and a disposed view model discards late responses.
  • dotnet build CodexForVisualStudio.slnx -c Release is warning-free; full Codex.VisualStudio.Core.Tests and Codex.VisualStudio.Ui.Tests pass.

Non-goals

No Worker/RPC contract version bump, no new NuGet package, no XAML change, and no forced-refresh trigger for a turn that ends via Degraded (tracked separately in #147 as an open question, not assumed here).

Clone this wiki locally