Repository navigation
Description
fix(ai): groq quota accepts remaining above the limit — "150 / 100 requests remaining" publishes beside 0% used / 100% remaining
Verified 2026-11-06 on origin/main 2d11e0f649 (merge of PR #1896), in a laptop worktree (~/git/fleet/probe-2026-11-06-creator-1635, kept). Gates this run: check:workflows and check:doc-env-vars GREEN; check:bounded-http 7 / check:numeric-boundaries 3 / check:proto-reads 4 RED = exactly #1724's set — no new drift.
The defect
packages/ai/src/quota/providers/groq.ts builds both rate-limit windows from the x-ratelimit-* headers with a strict plain-count parser (#1793: non-negative decimals only — negatives, hex, and exponents read as absent), but neither window ever checks the pair against each other:
- :124-131 (requests): any
remainingRequestsis accepted whenlimitRequests > 0; :128 clamps the derived percent into [0, 100], and :131 publishes the raw remaining in the label:`${remainingRequests} / ${limitRequests} requests remaining`. - :136-143 (tokens): the identical shape for
remainingTokens/limitTokens.
A remaining count above its limit is an impossible pair — the same class of bad data #1793 made the parser reject in its other spellings ("bad data reads as absent"). Here it is instead published, and the window's fields contradict each other: the percent follows the clamp while the label follows the raw wire, and toUsageWindow derives remainingPercent from the clamped percent — the failure window-contract rule 5 in packages/ai/src/quota/types.ts ("derived fields are computed from the published (post-disposition) values; the out-of-range disposition … is applied to the whole window, never split") exists to prevent.
Runtime probe (laptop worktree, probe-groq.ts, kept in the worktree)
Against the real provider.fetchQuota with a stubbed fetch (the test-suite's own harness shape):
- Headers
x-ratelimit-limit-requests: 100,x-ratelimit-remaining-requests: 150→ window published:usedPercent: 0,remainingPercent: 100,valueLabel: "150 / 100 requests remaining"— the label claims 150% of the limit remains beside fields saying 100%. - Headers
x-ratelimit-limit-tokens: 10000,x-ratelimit-remaining-tokens: 12000→ window published:usedPercent: 0,remainingPercent: 100,valueLabel: "12000 / 10000 tokens remaining". - Control
limit-requests: 100,remaining-requests: 40→usedPercent: 60,remainingPercent: 40,valueLabel: "40 / 100 requests remaining"(correct).
Why it matters
These windows are the only quota surface Groq offers (no first-party usage endpoint exists — the module's own header comment), so a contradictory window is the whole signal for this provider in the opencode quota output and for quota-aware consumers. #1793 already established this parser's disposition for impossible values — reject them so bad data reads as absent — but only enumerated the negative/hex/exponent/reset-duration spellings; the remaining-above-limit pair slipped through because each value is individually a well-formed plain count.
Acceptance criteria
- A remaining count above its limit gets one explicit, whole-window disposition in both the requests and tokens windows — either the pair reads as absent (no window, per fix(ai): groq quota header parsing accepts values it should reject — negative remaining publishes a spent window, partial reset durations publish a wrong resetAt #1793's bad-data-reads-as-absent philosophy) or the remaining is clamped to the limit so percent, remainingPercent, and label all derive from the same published figure (the fix(ai): command-code quota windows split their out-of-range disposition — percent clamped, label raw; non-positive resetAt published as a 1969/1970 date #1821 rule-5 shape). The choice is recorded in the fix and pinned by tests.
- No published groq window can carry a
valueLabelclaiming more remaining than the limit while its percent fields say otherwise. - Tests pin both over-limit cases (requests and tokens) plus the in-range control in
packages/ai/test/quota.test.ts; the existing groq tests (fix(ai): groq quota header parsing accepts values it should reject — negative remaining publishes a spent window, partial reset durations publish a wrong resetAt #1793 cases included) still pass. - The types.ts parser inventory row for groq is updated if the fix changes its disposition description.
Related: #1793 (this parser's strictness fix), #1794 / rule 5 of the window contract in packages/ai/src/quota/types.ts, #1821 (whole-window clamp precedent).
Activity
dezren39 commentedon Nov 6, 2026
🤖 Agent note · state: filed
developing-today commentedon Nov 7, 2026
Picked up by
repo-worker-opencode-a— working this now. (Fleet queue fallback mode: the queue backend is down, so this issue's comments carry the claim. The claim stays live whilerepo-worker-opencode-aposts progress markers; after 30 minutes of silence any other worker may pick this up.)developing-today commentedon Nov 7, 2026
Progress from
repo-worker-opencode-a: triaged-confirmed at main 10f3058: groq.ts both windows accept remaining>limit, percent clamped inline while label publishes raw remaining; routing task/small-fix7 remaining items
dezren39 commentedon Nov 7, 2026
Progress from
repo-worker-opencode: fix: verified groq.ts windows, disposition = whole-window clamp per #1821, creating worktreedezren39 commentedon Nov 7, 2026
Parked — PR opened, awaiting Codex/CI (lane opencode-a, fallback mode)
PR #1921 OPEN, MERGEABLE, head
ae6169ba5fon branchqueue/fallback-1897-groq-remaining-clamp: whole-window clamp of groq remaining to its limit in both windows, new quota test pinning both over-limit cases. Laptop targeted tests:bun test test/quota.test.ts -t groq— 9 pass / 0 fail.Resume condition: read PR #1921's Codex findings and disposition each (fix or reply), check CI state, merge under the standing criteria, verify #1897 closed, then release/complete. No Codex review or checks had reported at park time, so this was parked rather than merged past an unseen review.
agent-note:v1 · agent: repo-worker-opencode · lane: opencode-a · mode: fallback (queue backend down, code#6619) · state: parked
dezren39 commentedon Nov 7, 2026
Progress from
repo-worker-opencode: parked: PR 1921 open ae6169b, resume on Codex findings + CI, then merge and verify #1897 closeddezren39 commentedon Nov 7, 2026
🤖 Agent note · adopted as design phase 3 by repo design architect (opencode pass 2026-11-07)