Skip to content

fix(ai): mistral quota budget window disagrees with itself — usedPercent clamped, usedAmount derived from the raw percentage #1785

Closed

Description

@dezren39

Summary

The Mistral quota budget parser (packages/ai/src/quota/providers/mistral.ts, parseBudget, mistral.ts:70-82) clamps usedPercent into [0, 100] but derives usedAmount from the unclamped percentage, so the two fields of the same window disagree whenever the console reports a percentage outside [0, 100]. The published valueLabel is built from the amount (budgetWindow, mistral.ts:96-104: $<usedAmount> / $<budgetAmount>), so the quota row can show e.g. 100% used alongside "$150.00 / $100.00", or 0% used alongside "$-10.00 / $50.00".

Evidence (verified this run, main 6c0063e)

Probe on the laptop (worktree of origin/main) importing the exported parseMistralBudget:

  • usage_percentage: 150, initial_budget: 100 → { usedPercent: 100, usedAmount: 150, budgetAmount: 100 } — percent clamped, amount not.
  • usage_percentage: -20, initial_budget: 50 → { usedPercent: 0, usedAmount: -10, budgetAmount: 50 } — a negative dollar figure reaches formatMoney and the valueLabel.
  • Control, usage_percentage: 25, initial_budget: 100 → { usedPercent: 25, usedAmount: 25 } — consistent, as expected.

Code: mistral.ts:76-77 — usedPercent: Math.min(100, Math.max(0, usedPercent)) sits directly above usedAmount: (usedPercent / 100) * budgetAmount, where usedPercent is still the raw parsed value.

Why it matters

The Mistral console read is the only quota surface for the Mistral/Vibe account (the provider's own header comment: no API-key usage endpoint exists). The dollar label is what a reader uses to judge spend against budget; a label that contradicts the window's own percentage — or shows negative dollars — erodes trust in the one number the pool-rotation decisions read. Note the deliberate contrast with Turso, where over-100% is a published real state (turso.ts, code#6227): Mistral's parser already made the opposite disposition (clamp the percent) — the amount simply doesn't follow it.

Acceptance criteria

  • usedAmount is derived consistently with the clamped usedPercent (or both fields publish the raw figure with the percent clamp removed — one disposition, applied to both, and recorded in the closing note; the current split disposition is the defect).
  • packages/ai/test/quota.test.ts mistral describe pins: an over-100 percentage case and a negative percentage case, asserting percent and amount agree under the chosen disposition.
  • Existing mistral cases (normal percentages, flat-payload fallback, empty payload) stay green.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    kind/testTest coverage, test infrastructure, or test-only fixes
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/lowNice to have; do when convenient
    queue/queuedHas a queued task in the Supabase agent queue
    app/aiPackage: ai (pkgs/ or apps/ in this repo)
    effort/xsTrivial: expected under 30 minutes of work
    on Nov 5, 2026
  2. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    🤖 Agent note · filed

  3. added
    work/assignedAn agent holds this item via the queue (claimed task)
    queue/claimedA queue worker has claimed the task for this item
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  4. 1 remaining item

  5. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    🤖 Agent note · handed off

  6. dezren39 commented on Nov 6, 2026

    @dezren39
    Author

    🤖 Agent note · adopted as phase 2 of design #1794 (one window contract for the provider quota parsers; doc: files/designs/opencode-quota-window-contract.md, keep-the-four-repos-healthy goal workspace). This issue is the contract's mistral application: rule 5 (a window's fields agree — derived fields computed from the published, post-disposition values; one disposition for the whole window). Linked as a sub-issue of #1794; its queue lifecycle is untouched and it is not re-enqueued. When it lands, design phase 1's inventory row for mistral flips from known-lossy to conforming.

  7. dezren39 commented on Nov 6, 2026

    @dezren39
    Author

    🤖 Agent note · picked up

  8. dezren39 commented on Nov 6, 2026

    @dezren39
    Author

    🤖 Agent note · PR opened

  9. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedA queue worker has claimed the task for this item
    on Nov 6, 2026
  10. dezren39 commented on Nov 6, 2026

    @dezren39
    Author

    🤖 Agent note · parked

    • Agent: repo-worker-opencode (OpenChamber scheduled lane)
    • Session / ID: task 10800; lane 3fe37e8a-c61b-419c-9e97-769ecd264d5d
    • Found via: queue claim
    • Task: Parked task 10800 for 20 minutes; PR fix(ai): keep Mistral budget fields consistent #1836 is open and GitHub currently reports no checks or workflow runs. Local targeted suite passes.
    • Expectation: effort/xs — on resume, read PR/check state fresh and merge only when checks are green and all standing criteria hold.
    • Links: fix(ai): keep Mistral budget fields consistent #1836; task 10800
  11. removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    work/assignedAn agent holds this item via the queue (claimed task)
    on Nov 6, 2026
  12. dezren39 commented on Nov 6, 2026

    @dezren39
    Author

    agent-note:v1 — state: completed via PR #1836 merged 2026-11-06; task 10800 complete. Mistral parseBudget now derives usedAmount from the clamped percent; pins for over-100 (100/$100) and negative (0/$0) added. No Codex findings on PR #1836 (reviews/comments empty); no gh CI checks reported for this repo — merge rested on diff vs acceptance + prior local quota.test.ts 79 pass record.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/aiPackage: ai (pkgs/ or apps/ in this repo)area/typescriptTypeScript code areaeffort/xsTrivial: expected under 30 minutes of workkind/bugSomething isn't working (prefixed form of the classic bug label)kind/testTest coverage, test infrastructure, or test-only fixespriority/lowNice to have; do when convenientsource/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions