docs/refresh-loop.md
RefreshFrequency: Manual, 1m, 2m, 5m (default), 15m, 30m, Adaptive.UserDefaults via SettingsStore. The default stays 5m for new and existing users; nothing
auto-migrates an existing fixed selection to Adaptive.UsageStore (usage + credits + optional web scrape).AdaptiveRefreshPolicy (Sources/CodexBar/AdaptiveRefreshPolicy.swift) is a pure function of an Input
(current time, last menu-open time, Low Power Mode, thermal state) that returns the next delay and a
stable Reason. It reads no clock and no ProcessInfo state itself — UsageStore.startTimer() gathers
those impure signals immediately before each tick.
Policy table, first match wins:
| Condition | Delay | Reason |
|---|---|---|
Low Power Mode enabled, or thermal state .serious/.critical | 30 min | constrained |
| Menu opened within the last 5 min (including future/clock-adjusted timestamps) | 2 min | recentInteraction |
| Menu opened 5 min–1 h ago | 5 min | warm |
| Menu opened 1–4 h ago | 15 min | idle |
| No recorded menu open, or opened 4+ h ago | 30 min | longIdle |
Every decision falls in the 2–30 min range by construction. Deliberately excludes quota, latency, error, account, and time-of-day signals.
UsageStore tracks lastMenuOpenAt in memory only (never persisted; resets on launch). noteMenuOpened(at:)
is called from StatusItemController.menuWillOpen(_:). A menu open can bring a pending adaptive tick
forward to the recent-interaction cadence, but never postpones an earlier tick or refreshes synchronously.
Each adaptive tick recomputes the delay after the previous refresh completes, sleeps, then calls the same
UsageStore.refresh() used by fixed-interval mode, so the existing isRefreshing coalescing guard still
applies — only one provider-batch refresh runs at a time regardless of cadence mode.
Selected delay and reason are logged (e.g. reason=warm delay=300s in the adaptive-refresh category) through
the existing local logger; never provider identity, account, email, workspace, path, credentials, or response data.
Interval-derived heuristics (reset-boundary refresh, OpenAI web staleness, persistent-CLI-session idle windows)
read UsageStore.normalRefreshIntervalForHeuristics(), which resolves adaptive mode to the current decision's
delay — they stay active in adaptive mode rather than degrading to manual, whose interval is nil.
codex exec --skip-git-repo-check --json "ping" (currently not executed).See also: docs/status.md, docs/ui.md.