Skip to content

feat(quota): background poll keeps idle account quota fresh#56

Open
iceteaSA wants to merge 1 commit into
cortexkit:mainfrom
iceteaSA:feat/quota-background-poll
Open

feat(quota): background poll keeps idle account quota fresh#56
iceteaSA wants to merge 1 commit into
cortexkit:mainfrom
iceteaSA:feat/quota-background-poll

Conversation

@iceteaSA

@iceteaSA iceteaSA commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Why

Quota is push-primary (x-codex-* headers / WS codex.rate_limits frames), so a fallback account that is not currently being routed to shows stale or missing quota until the operator manually runs /openai-quota. The sibling anthropic-auth plugin keeps idle accounts fresh with a background poll; this brings the same behavior here — without request spam from multiple concurrent opencode processes, and without letting any process publish stale data over fresh.

What

Background poll

  • core/background-quota-refresh.ts — singleton 5-minute timer (±30 s jitter per process), unref'd so it never keeps the process alive, idempotent start, stopped from both the plugin-level and auth-loader dispose paths.
  • Overlap-safe: the timer holds the in-flight run's promise and drops a tick that fires while the previous run is still executing (skip, not queue) — no concurrent token refreshes or duplicate wham calls from a slow tick.
  • Each tick calls the existing refreshAllQuota with respectBackoff: true plus a 4-minute freshness gate (skipFresherThanMs). Rides the 15 s abort timeout + quota-channel logging from fix(quota): bound and log the active quota fetch path #52. Deliberate deviation from the sibling: no immediate first run — the boot seed covers startup; first poll fires at the jittered 5-minute mark.

Cross-process dedup (no locks)

  • The freshness gate consults BOTH the in-memory QuotaManager snapshot AND the machine-global sidebar state file (written on every quota push by any process, read once per tick, tolerant reader, fail-open on missing/corrupt/malformed checkedAt). Whichever process polls first refreshes the file; every other process's tick inside the window sees the fresh checkedAt and skips. Worst case under jitter collision is 2 concurrent fetches, never N.
  • An all-skipped background tick performs no sidebar write (nothing new to publish).

Stale-write clobber fix (machine-state sidebar writes)

  • Previously any process's sidebar write replaced the machine-global quota rows wholesale from its own memory — an idle process with a stale cache could overwrite fresher rows another process just wrote (and thereby corrupt the dedup gate reading those rows). setSidebarMachineState now freshness-merges per-account inside the existing compare-retry callback: for main and each fallback (matched by id), the side with the fresher finite checkedAt wins; invalid/missing loses to valid; both missing → incoming wins. activeId/route keep last-writer semantics; activeRouting merge unchanged.
  • Snapshot-level quota.checkedAt added: a complete authoritative frame may retire every window (no primary.checkedAt left), and without a timestamp on the snapshot itself the freshness merge would resurrect the retired window from disk.

Unchanged: the manual /openai-quota command path (no gate, always writes) and the boot seed. No new config keys, commands, or TUI changes.

Verification

  • RED-first throughout: freshness gate (expected 1 wham call, got 3), cross-process skip (empty memory + fresh file: expected 0 calls, got 3), stale-write clobber (fresh disk rows expected retained, got stale 90/40), all-skipped no-write (expected 0 writes, got 1), tick overlap (expected 1 run, got 2), window-retirement tombstone.
  • Review (gemini-3.1-pro): APPROVE 0 must / 1 should — lifecycle, gate ordering (skip before token refresh), backoff interaction, restart-with-empty-cache behavior, command/boot-seed invariance verified; the should (jitter bounds untested) folded as a test pinning random()=0/1 → ∓30 s.
  • cubic P2 (tick overlap) fixed in the same commit; thread resolved.
  • Gates: build ✓ · tsc ✓ · full suite 692/0 ✓ · biome clean.

@iceteaSA
iceteaSA force-pushed the feat/quota-background-poll branch from 1399ceb to e67f58c Compare July 21, 2026 20:31

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed against the latest diff

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/opencode/src/index.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant