Repository navigation
Description
Problem
The shared quota window builder toUsageWindow (packages/ai/src/quota/utils.ts:113-135) derives remainingPercent from the published usedPercent at utils.ts:125:
remainingPercent: hasFiniteUsedPercent ? Math.max(0, 100 - usedPercent) : null,The derivation guards only one side. It floors the result at 0, so an over-100 usedPercent correctly derives 0% remaining — but it never caps at 100, so a negative usedPercent derives a remainingPercent above 100%, a percent that cannot exist. That violates the window contract in packages/ai/src/quota/types.ts (rule 5: "A window's fields agree — derived fields are computed from the published (post-disposition) values"): the one shared place every parser's derived field is computed can publish a derived field outside the percent range.
Evidence (verified this run on main 2d11e0f649436d6c4d20a64ce13fd7e0501bdd96)
Probe probe-usage-window.ts, run with bun in a laptop worktree of origin/main (~/git/fleet/probe-2026-11-06-creator-1935), calling the real toUsageWindow:
usedPercent=-20 -> remainingPercent=120
usedPercent=-5 -> remainingPercent=105
usedPercent=0 -> remainingPercent=100
usedPercent=50 -> remainingPercent=50
usedPercent=100 -> remainingPercent=0
usedPercent=150 -> remainingPercent=0
Caller audit (same main): every current parser happens to clamp its own percent before calling toUsageWindow (antigravity, claude, cline-pass, codex, command-code, groq, meta, mistral, opencode-go, opendesign all clamp; openrouter caps above; turso filters negative ratios), so no live parser publishes this today. That is exactly how the sibling shared-converter defect shipped and was fixed in #1845 (toTimestamp published 1969/1970 resets until the guard moved into the shared converter): the per-parser clamping saga (#1785, #1821, #1879, #1897, #1882) shows parsers repeatedly arrive without a clamp, and a new parser that computes a raw percent from a remaining-above-limit payload — the groq/opendesign shape — would publish remainingPercent: 120 straight to consumers of the quota shape (aggregator gatherer / dashboard, code#6125) with nothing downstream re-checking the range. toUsageWindow itself has no direct pin in packages/ai/test/quota.test.ts today (grep: 0 references).
What NOT to do
Do not clamp usedPercent itself in toUsageWindow. Turso deliberately publishes over-100 usage truthfully (code#6227, turso.ts: "Over-100 is a real state, not bad data"), and its remainingPercent: 0 for those windows is correct. The defect is only in the derived field's missing upper cap.
Fix shape
Cap the derived field on both sides, e.g. Math.min(100, Math.max(0, 100 - usedPercent)). This is a no-op for every conforming input (any usedPercent >= 0 derives exactly what it derives today, including turso's over-100 → 0) and changes only the negative-input derivation (120 → 100).
Acceptance criteria
-
toUsageWindow({ usedPercent: -20 })derivesremainingPercent: 100, and-5derives100;usedPercentitself is published unchanged (provider disposition preserved, turso over-100 case included:150still derives0). - New pins in
packages/ai/test/quota.test.tsfor the out-of-range derivations (negative, zero, 100, over-100) — the shared builder's first direct pins. - Existing quota suite passes unchanged for all in-range inputs;
packages/aitypecheck clean.
Activity
dezren39 commentedon Nov 7, 2026
🤖 Agent note · filed
toUsageWindowderivesremainingPercentabove 100% for a negativeusedPercent— verified by probe on main 2d11e0f (probe-usage-window.ts, laptop worktree probe-2026-11-06-creator-1935: -20 -> 120, -5 -> 105, 150 -> 0).dezren39 commentedon Nov 7, 2026
🤖 Agent note · picked up
remainingPercentat 100 intoUsageWindow(utils.ts:125) and pin the out-of-range derivations in quota.test.ts. No queue packet (§4 self-solve path).Merge pull request #1905 from developing-today-forks/creator/1904-tou…
dezren39 commentedon Nov 7, 2026
🤖 Agent note · done
remainingPercentderivation intoUsageWindowcapped at 100 (Math.min(100, Math.max(0, …)));usedPercentpublished unchanged, so turso's publish-truthfully over-100 windows (code#6227) derive 0 exactly as before.