Repository navigation
Description
fix(ai): openrouter quota unlimited path publishes a negative spend — "$-5.00 spent" for usage_monthly below zero
Verified 2026-11-06 on origin/main 529cf7fa05 (merge of PR #1908), in a laptop worktree (~/git/fleet/probe-2026-11-06-creator-2135, kept).
The defect
packages/ai/src/quota/providers/openrouter.ts, the unlimited path (limit === null, ~:126-132): the monthly window's only figure is usage_monthly, read via the shared toNumber — which accepts any finite number, including negatives — and formatted straight into the label:
usedPercent = null
valueLabel = `$${formatMoney(usageMonthly)} spent`Nothing checks the sign. A negative usage_monthly — a spend figure that cannot exist — publishes as a successful quota read whose window claims the account has spent a negative amount of money. The provider's own neighbouring code already treats impossible figures as no data: a zero/negative limit returns the no-data contract (#1799, window-contract rule 4). The spend figure on the unlimited path is the one figure in this provider with no sign check at all.
Sibling parsers guard the same shape: turso's numNonNegative, opencode-go's toMicroCents (rejects < 0), and command-code's monthlyRemaining >= 0 gate (#1744) all read a negative amount as absent. OpenRouter's limited path is also safe by construction — its label derives from used = max(0, limit − limit_remaining) and its over-limit shape is pinned publish-truthfully by the quota suite ($120.00 / $100.00 at a clamped 100%). Only the unlimited path's raw spend escapes.
Runtime probe (laptop worktree, probe-antigravity.ts, kept in the worktree)
Driving the real provider.fetchQuota with a stubbed fetch (the test suite's own harness shape):
{ data: { limit: null, limit_remaining: null, usage_monthly: -5 } }→ok: true, windowmonthlypublished withusedPercent: nullandvalueLabel: "$-5.00 spent".- Control
{ data: { limit: null, limit_remaining: null, usage_monthly: 12.5 } }→ok: true,valueLabel: "$12.50 spent"(correct, unchanged). - Control (existing test, fix(ai): openrouter quota publishes a zero-limit window — $0.00 / $0.00 with null percent reads as headroom where there is no limit #1799 describe):
{ limit: 0, limit_remaining: -5, usage_monthly: 5 }→ no-data error — the negative remaining on a zero limit is already dispositioned; only a negative spend on the unlimited path slips through.
Why it matters
On the unlimited path this label is the provider's entire quota signal — there is no percent and no limit to cross-check it against. A negative spend is impossible wire data (a billing reset glitch, a credits/refund adjustment spelled as spend, a gateway mimicking the /key shape with a signed balance); publishing it as ok: true quota data teaches downstream consumers a figure that cannot be true, in the one shape (credits/spend balance) where this fleet has repeatedly chosen "bad data reads as absent" over fabrication.
Acceptance criteria
- A negative
usage_monthlyon the unlimited path gets one explicit disposition — read as absent (so a payload with no other figure returns the existing "No quota data in response" contract) is the sibling-consistent choice; any other disposition is chosen and recorded in the closing note. - Positive and zero
usage_monthlyon the unlimited path are unchanged ($12.50 spent,$0.00 spentcontrols). - The limited path is unchanged, including its pinned publish-truthfully over-limit shape.
-
packages/ai/test/quota.test.tspins the negative-spend case beside the existing fix(ai): openrouter quota publishes a zero-limit window — $0.00 / $0.00 with null percent reads as headroom where there is no limit #1799 openrouter describe. - Existing quota suite stays green.
Dedup
Searched open + closed issues for openrouter negative spend / usage_monthly this run: no covering issue. #1799 (closed) covered the zero/negative-limit no-data contract; #1725 (open) covers test pinning for opencode-go's parsers and resolveResetAt plus opencode-go's reset-null window drop — not this spend figure. The over-limit limited-path label is deliberately pinned publish-truthfully by the suite and is explicitly out of scope.
Activity
dezren39 commentedon Nov 7, 2026
🤖 Agent note · filed
probe-antigravity.tsin laptop worktree ~/git/fleet/probe-2026-11-06-creator-2135 (origin/main 529cf7f); body file bodies/opencode-openrouter-negative-monthly-spend.md in the goal hidden_files.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: openrouter.ts unlimited path formats usageMonthly into the label with no sign check (only a null check); routing task/small-fixdeveloping-today commentedon Nov 7, 2026
Triage — CONFIRMED (lane opencode-a, fallback mode)
Verified fresh against
origin/main@10f305865fe8(laptop primary~/git/opencode, clean, on main):packages/ai/src/quota/providers/openrouter.ts: the unlimited branch (limit === null, ~lines 126–132) setsvalueLabel =$${formatMoney(usageMonthly)} spent`` directly fromtoNumber(data.usage_monthly). The only guard on that figure is the null check just above it (`limit === null && usageMonthly === null` → no-data contract) — there is no sign check, and `toNumber` accepts any finite number, negatives included. A negative `usage_monthly` therefore publishes `$-5.00 spent` with `ok: true`, exactly as the filed probe shows.Math.max(0, limit − limit_remaining)— the unlimited path's raw spend is the one unchecked figure, as filed.Routing:
task/triage→task/small-fix, back toqueue/queuedwithstatus/needs-triage. Sibling-consistent disposition (negative reads as absent → existing no-data contract) is named in the criteria as the expected choice; positive/zero controls and the limited path's pinned over-limit shape stay untouched. Tests pin the negative case beside the existing #1799 openrouter describe. No Drew decision needed.agent-note:v1 · agent: repo-queue-opencode-worker-a · lane: opencode-a · mode: fallback (queue backend down, code#6619)
5 remaining items
dezren39 commentedon Nov 7, 2026
Picked up by
repo-worker-opencode— 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-opencodeposts progress markers; after 30 minutes of silence any other worker may pick this up.)dezren39 commentedon Nov 7, 2026
Progress from
repo-worker-opencode: verified: inspecting openrouter unlimited path + 1799 describe; next: worktree + sign guarddezren39 commentedon Nov 7, 2026
Progress from
repo-worker-opencode: implementation_complete: negative spend read as absent, quota suite 133 pass, neg control fails stashed; next: PR + mergeMerge pull request #1938 from developing-today-forks/queue/1913-1913-…
dezren39 commentedon Nov 7, 2026
Released by
repo-worker-opencode(outcome: done). fixed_merged: PR #1938 MERGED 59834b0 (branch queue/1913-1913-openrouter-negative-spend); negative usage_monthly read as absent -> no-data contract on unlimited path; quota.test.ts 133 pass, neg control fails stashed; issue CLOSED; backlog + sweep.log updated