Skip to content

fix(ai): cline-pass quota silently overwrites duplicate limit entries (last wins) — diverges from the #1750 keep-first convention, and the mapping is unpinned #1769

Closed

Description

@dezren39

Summary

The ClinePass quota provider (packages/ai/src/quota/providers/cline-pass.ts) builds its windows record by unconditional assignment — windows[kind.key] = ... (cline-pass.ts:86) — so when the usage-limits response carries two entries of the same type, the later entry silently overwrites the earlier one. That is the opposite of the convention the suite adopted in #1750 for opendesign coding-plan windows ("duplicate durations keep the first entry instead of silently overwriting"). The mapping is also entirely unpinned: packages/ai/test/quota.test.ts never imports cline-pass, and the parse logic is embedded in fetchForKey rather than an exported pure function (it is still testable end-to-end via the injectable fetchImpl, as the probe below shows).

Evidence (verified this run, main 4b9febf)

Probe on the laptop (~/git/fleet/probe-2026-11-05-cline-pass/probe.ts) calling provider.fetchQuotaForCredential with a stubbed fetchImpl returning:

{ "data": { "limits": [
  { "type": "five_hour", "percentUsed": 10, "resetsAt": "2026-11-06T00:00:00Z" },
  { "type": "five_hour", "percentUsed": 90, "resetsAt": "2026-11-06T01:00:00Z" },
  { "type": "weekly",    "percentUsed": "42", "resetsAt": "2026-11-12T00:00:00Z" },
  { "type": "weekly",    "percentUsed": 7,  "resetsAt": "2026-11-13T00:00:00Z" },
  { "type": "monthly",   "percentUsed": 55, "resetsAt": "2026-12-01T00:00:00Z" }
] } }

Published windows: 5h → 90% used (the 10% entry silently dropped), weekly → 7% used (the "42" entry silently dropped), monthly → 55%. No error, no log, no indication a duplicate ever existed. Whether first-wins or last-wins is correct for Cline's wire is currently an undocumented accident of loop order; #1750 already settled the house convention as keep-first for the identical shape in opendesign.

Why it matters

ClinePass is one of the plan pools the fork rotates across. If Cline ever returns split or repeated limit entries (per-model splits, plan migrations), the published usage flips to whichever entry happens to sort last, with nothing recording that a choice was made. The parser also has no test pinning its string/number percentUsed handling, unknown-type skipping, or the empty-windows "No quota data in response" path — the same unpinned-parser gap #1725 / #1750 closed for the other providers.

Acceptance criteria

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/sSmall: expected under 2 hours of work
    on Nov 5, 2026
  2. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    🤖 Agent note · filed

  3. 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
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  4. developing-today commented on Nov 5, 2026

    @developing-today

    Triage (task 10761, lane opencode-a): CONFIRMED LIVE on current main; disposition DECIDED — keep-first, matching the #1750 convention.

    Re-verified this shift against a fresh raw read of packages/ai/src/quota/providers/cline-pass.ts on main: the limits loop assigns windows[kind.key] = toUsageWindow({...}) unconditionally, so a duplicate limit entry of the same type silently overwrites the earlier one (last wins, no trace). The mapping is unpinned: packages/ai/test/quota.test.ts does not import cline-pass (the parse logic is embedded in the fetch path and is testable via the injectable fetchImpl / fetchQuotaForCredential, as the filing probe showed).

    Decision — the fix (enqueued separately, dedupe key repo-health:v1:fix:developing-today/opencode:issue:1769): on a duplicate window kind, keep the FIRST entry and skip later duplicates, with a code comment naming the convention. This is the same disposition adopted for the identical shape in #1750 (OpenDesign coding-plan duplicate durations, merged today in PR #1766): duplicate entries for the same window are a payload anomaly, not an update, and the first entry is the API's primary report. No alternative disposition was recorded because consistency across the quota module's parsers is itself the fix for this class — a per-provider exception would recreate the divergence this issue files.

    Pinning tests required in the fix (packages/ai/test/quota.test.ts, driving the provider with a stubbed fetch, mirroring the filing probe): duplicate five_hour entries publish the first percent; duplicate weekly entries publish the first; distinct types publish both; a payload with no usable limits returns the existing "No quota data in response" contract; existing quota tests keep passing.

    Triaged by: lane opencode-a, task 10761 — keep-first disposition recorded; fix enqueued separately

  5. added
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    queue/claimedA queue worker has claimed the task for this item
    on Nov 5, 2026
  6. added a commit that references this issue on Nov 5, 2026
  7. developing-today commented on Nov 5, 2026

    @developing-today

    Merged — PR #1773 landed as 9eea0a5 and this issue auto-closed. Verification on the PR branch (laptop): bun test test/quota.test.ts 35/35 pass; both ai tsgo configs exit 0; PR mergeable, no Codex reviews posted.

    Completed by: lane opencode-a, task 10762

  8. removed
    queue/queuedHas a queued task in the Supabase agent queue
    work/assignedAn agent holds this item via the queue (claimed task)
    on Nov 5, 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)area/typescriptTypeScript code areaeffort/sSmall: expected under 2 hours 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