Skip to content

fix(ai): opendesign quota parseCodingPlanWindows publishes out-of-range remaining raw — "-50 / 100 credits" at 100% used, "150 / 100 credits" at 0% used #1879

Closed

Description

@dezren39

fix(ai): opendesign quota parseCodingPlanWindows publishes out-of-range remaining raw — "-50 / 100 credits" at 100% used, "150 / 100 credits" at 0% used

Verified 2026-11-06 on origin/main 90453b467f (merge of PR #1874), in a laptop worktree (~/git/probe-2026-11-06-creator-1235, kept). Gates this run: check:workflows, check:gates, 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/opendesign.ts:78-107 (parseCodingPlanWindows) guards the limit (limit <= 0 entries are dropped, :94 — the #1750 disposition) but never range-checks remainingCredits:

  • :99 clamps the derived percent into [0, 100]: Math.min(100, Math.max(0, (1 - remaining / limit) * 100))
  • :104 publishes the raw remaining in the label: `${remaining} / ${limit} credits`

Percent and label therefore derive from different figures and can contradict each other — the exact failure the window contract's rule 5 (whole-window clamp, #1821, implemented for command-code) exists to prevent: "percent and label derive from one clamped used figure, so they can never contradict each other."

Runtime probe (laptop worktree, probe-quota-caps.ts, kept in the worktree)

Against the real parseCodingPlanWindows imported from main, one 5h window (durationSeconds: 18000, limitCredits: 100, resetsAt: 1893456000):

  • remainingCredits: -50 → window published: usedPercent: 100, valueLabel: "-50 / 100 credits" — a negative remaining balance rendered to the user.
  • remainingCredits: 150 → window published: usedPercent: 0, valueLabel: "150 / 100 credits" — 0% used alongside a label claiming 150 of 100 credits remain.
  • Control remainingCredits: 25 → usedPercent: 75, valueLabel: "25 / 100 credits" (correct).

Why it matters

The label is the user-facing figure in the opencode quota output. A negative-remaining label is nonsense on its face, and the over-limit case silently hides a real state: command-code's monthly window hit the same over-included-remaining shape and dispositions it explicitly (#1744: publish at 0% used with the real remaining figure annotated, ${used} / ${included} (${remaining} remaining)), because rollover/promo/higher-tier remaining above the nominal limit is information, not noise. OpenDesign currently gets the worst of both: the percent follows the clamp while the label follows the raw wire, with no annotation explaining the discrepancy.

Acceptance criteria

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/aiPackage: ai (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Nov 6, 2026
  2. dezren39 commented on Nov 6, 2026

    @dezren39
    Author

    🤖 Agent note · filed

    • Agent: new-issue-creator job (new-issue-creator-opencode)
    • Session / ID: cron new-issue-creator-opencode run 2026-11-06T18:35Z
    • Found via: filed this run
    • Task: Filed the opendesign parseCodingPlanWindows out-of-range-remaining defect: percent is clamped but the valueLabel publishes remainingCredits raw, so a negative remaining renders "-50 / 100 credits" at 100% used and an over-limit remaining renders "150 / 100 credits" at 0% used. Verified with a laptop probe against the real parser on main 90453b4. Enqueued as a triage packet — the over-limit disposition (fix(ai): Command Code quota monthly window vanishes when remaining credits exceed the hard-coded 10 included — an over-limit payload reads as 'could not be parsed' #1744 annotation vs plain clamp) is the worker's call.
    • Expectation: effort/s — one consistent disposition for out-of-range remaining, pinned by tests for the negative, over-limit, and in-range cases.
    • Links: probe probe-quota-caps.ts in laptop worktree ~/git/probe-2026-11-06-creator-1235 (kept)
  3. dezren39 commented on Nov 7, 2026

    @dezren39
    Author

    🤖 Agent note · adopted as design phase 3 by repo design architect (opencode pass 2026-11-07)

  4. added
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    and removed on Nov 8, 2026
  5. 9 remaining items

  6. added
    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 8, 2026
  7. developing-today commented on Nov 8, 2026

    @developing-today

    🤖 Agent note · picked up

  8. developing-today commented on Nov 8, 2026

    @developing-today

    🤖 Agent note · triaged

  9. added
    task/fixQueued scoped fix task
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    on Nov 8, 2026
  10. added a commit that references this issue on Nov 8, 2026
  11. removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 8, 2026
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)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/fixQueued scoped fix task

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions