Expand description
Generic, single-flight-guarded, proactively-scheduled credential refresh.
One RefreshScheduler instance can manage any number of independently
keyed credentials. It holds no credential state itself — callers supply
is_fresh/refresh closures that read/write through to the real backing
store (e.g. Store::muxbus_load/muxbus_save) — the scheduler only owns
refresh coordination.
This closes two related gaps:
- Concurrent-refresh races. Without a lock, two callers that both
observe a stale credential at the same time both attempt to refresh it
independently. For providers that rotate refresh tokens on use, this
can revoke the entire token family. Claude Code itself has two open
production issues from exactly this failure mode (concurrent CLI
sessions racing to refresh a shared credentials file with no lock).
ensure_freshcollapses concurrent callers for the same id onto one in-flight refresh. - Reactive-only refresh.
run_sweep_loopproactively walks every registered credential on a timer instead of only refreshing when something happens to ask for one.
Coordination state (fresh / refreshing / failed / needs-reauth) is owned
by the pure reducer in super::state — this module is a thin async
orchestrator: dispatch a command, execute whatever the returned events
say to do (call is_fresh()/refresh()), dispatch the result back in.
Same split as every other reducer in this codebase (e.g. agentmux-cef’s
host reducer emitting WindowOpacityApplied, which its IPC handler applies
after dispatch).
Preserve-on-failure (never overwrite a valid stored credential with a
failed/partial refresh result) is NOT enforced here — it’s the
responsibility of each registered refresh closure, since only the
caller knows its own store’s write semantics. See broker::mod doc.