Skip to content

feat(opencode): dynamic quota windows — length-driven display, present-window policy, reset credits#46

Closed
iceteaSA wants to merge 2 commits into
cortexkit:mainfrom
iceteaSA:feat/dynamic-quota-windows
Closed

feat(opencode): dynamic quota windows — length-driven display, present-window policy, reset credits#46
iceteaSA wants to merge 2 commits into
cortexkit:mainfrom
iceteaSA:feat/dynamic-quota-windows

Conversation

@iceteaSA

@iceteaSA iceteaSA commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Problem

OpenAI removed the 5-hour usage window. Captured live against a team-plan account, all three quota sources (HTTP x-codex-* headers, the WS codex.rate_limits frame, and wham/usage) now report a single 7-day window in the primary slot, with secondary null/zeroed:

x-codex-primary-window-minutes: 10080   (7d)
x-codex-secondary-window-minutes: 0      (gone)

The plugin hardcodes primary ≡ 5h / secondary ≡ 7d in display, pacing, and policy, so today it:

  • mislabels the 7-day window as 5h in the sidebar (5h: 20% 7d: —),
  • paces it against a 5-hour ruler (FIVE_HOUR_MS) → wrong deficit/reserve math,
  • risks wrongly blocking failClosedOnUnknownQuota accounts, because an absent window reads as "unknown quota" rather than "not applicable".

The key realization: every source already sends the window length (x-codex-*-window-minutes / WS window_minutes / wham limit_window_seconds) — the code just discarded it.

Fix

Make the windows dynamic while keeping the slot names as stable keys.

  • Carry window length onto the quota-window type; normalizers populate it from all three sources (wham seconds → minutes).
  • Derive the label and pacing ruler from the length, never the slot name — a 10080-minute window renders 7d and paces over 7 days whether it arrives as primary or secondary. FIVE_HOUR_MS/SEVEN_DAY_MS and the literal 5h:/7d: text are gone.
  • Render only present windows — an absent/retired window shows nothing, not a mislabeled or phantom row. (The header wire encodes a retired window as an explicit zero placeholder, not by omission; that is normalized to absence.)
  • Policy iterates present windows — in both quotaSnapshotPassesPolicy and killswitchPassesPolicy, an absent window is skipped (not-applicable), while a present-but-past-reset window still counts as unknown for fail-closed. Thresholds stay keyed by slot.
  • Reset credits — surface the wham-only rate_limit_reset_credits.available_count as a top-level sidebar resets: N row, preserved across per-turn header/WS pushes (which don't carry it) and attributed to the account that actually served.

Design principle: key vs. semantics

The slot names primary/secondary stay the stable keys for storage, quota-manager rate-limit marks, killswitch thresholds, and mid-stream reset attribution — none of those change. The window length drives only the human-facing label and the pacing ruler. So if OpenAI shifts a window's length, moves it between slots, or drops/re-adds one, display and pacing follow automatically while thresholds and marks keep working.

Scope / compatibility

  • Additive and backward-compatible: every new field is optional, no schema migration, no version bump. Old persisted snapshots and old sidebar-state files still parse. An account still receiving two windows renders exactly as before.
  • resolveMidStreamRateLimitResetAt is unchanged (it was already correct and slot-keyed).
  • The killswitch threshold config parser keeps its legacy 5h/1w aliases for backward-compatible reads; only the human-facing labels became length-aware.

Testing

  • bun run build · bun run typecheck · bunx biome check src — all clean.
  • bun test604 pass / 0 fail (36 new tests: length normalization across all three sources incl. seconds→minutes and zero-placeholder-as-absence, label boundaries, one-vs-two-vs-zero window rendering, present-window policy under fail-open/fail-closed for both policy functions, reset-credit preservation + active-account attribution, and a deterministic WS ordering test for served-account attribution).
  • Reviewed by a 4-model cross-family council (2 rounds + a focused re-review). The first round caught real interaction bugs — a second policy function (killswitchPassesPolicy) that still blocked on an absent window, the header path's zero-placeholder rendering a phantom window, the mid-stream mark-clear requiring both windows, window-presence detection counting metadata as a window, and a fallback merge resurrecting a wire-absent window — all fixed and re-confirmed; a follow-up round fixed WS sidebar attribution so a fallback turn's resets count publishes against the fallback, not the previously-active account.

Operator check after merge

Restart, send one Codex request, and confirm the sidebar shows a single 7d row with the correct percent + countdown, a sane 7-day pacing projection, no phantom 5h row, and a resets: line when the plan supplies available_count.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Make quota windows dynamic and present-only across the UI and policy, and surface per-account reset credits from wham. Header/WS quota pushes are treated as complete frames so window sets replace cleanly; “all retired” clears windows, and reset credits persist across turns and follow the served account.

  • New Features

    • Derive labels and pacing from windowMinutes/limit_window_seconds; no fixed 5h/7d.
    • Show only present windows in the TUI, collapsed summaries, and command dialogs; rows use actual lengths.
    • Expose resetCreditsAvailable (rate_limit_reset_credits.available_count) as resets: N per account in the sidebar and quota command; preserved across header/WS turns and attributed to the serving account.
    • Treat quota header/WS updates as complete snapshots; only complete frames replace cached windows, and a frame reporting all windows retired clears them. Killswitch command now shows “primary/secondary thresholds”.
  • Bug Fixes

    • Stop mislabeling a 7‑day primary as 5h; pace over the reported length.
    • Policy and refresh scheduling skip absent windows; fail‑closed only blocks on present stale windows. Metadata‑only snapshots (no windows) pass under both modes.
    • Clear mid‑stream rate‑limit marks when all present windows are healthy; keep them if any present window is at 100%.
    • Prevent resurrecting/clobbering windows on incomplete frames; normalize zero placeholders/nulls as absence and convert wham seconds → minutes correctly.

Written for commit ab061e8. Summary will update on new commits.

Review in cubic

@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.

All reported issues were addressed across 18 files

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

Re-trigger cubic

Comment thread packages/opencode/src/quota-normalize.ts Outdated
Comment thread packages/opencode/src/core/accounts.ts
Comment thread packages/opencode/src/index.ts
Comment thread packages/opencode/src/tui.tsx Outdated
Comment thread packages/opencode/src/tui/command-dialogs.tsx Outdated
@iceteaSA
iceteaSA force-pushed the feat/dynamic-quota-windows branch from f0fe8dd to de571ff Compare July 16, 2026 18:56
…-window policy, per-account reset credits)

OpenAI removed the 5h usage window; the live wire now sends a single 7-day
window in the primary slot with the window length on every source. Carry the
window length onto the quota window type and derive the display label and
pacing ruler from it instead of the slot name, render only the windows that
are actually present, evaluate killswitch/quota policy across present windows
only (an absent window is not-applicable, not unknown), and surface the
wham-only rate_limit_reset_credits.available_count per account in the sidebar
and the /openai-quota modal. Slot names primary/secondary remain the stable
keys for storage, marks, thresholds, and mid-stream reset attribution.
…-window policy, per-account reset credits)

OpenAI removed the 5h usage window; the live wire now sends a single 7-day
window in the primary slot with the window length on every source. Carry the
window length onto the quota window type and derive the display label and
pacing ruler from it instead of the slot name, render only the windows that
are actually present, evaluate killswitch/quota policy across present windows
only (an absent window is not-applicable, not unknown), and surface the
wham-only rate_limit_reset_credits.available_count per account in the sidebar
and the /openai-quota modal. Slot names primary/secondary remain the stable
keys for storage, marks, thresholds, and mid-stream reset attribution. A
retired window is detected by its explicit zero-length marker, not by the
absence of optional metadata.
@ualtinok

Copy link
Copy Markdown
Contributor

Superseded by the integrated implementation prepared for main. It retains length-driven quota windows and reset credits, while atomically rejecting malformed header frames, preserving legacy 5h/7d snapshots, and deriving killswitch Retry-After from policy-violating windows only. Thank you for the implementation.

@ualtinok ualtinok closed this Jul 17, 2026
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.

2 participants