Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions devlog/_plan/260826_quota_window_and_backlog/020_phase2.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,29 +55,42 @@ showCodexSparkQuota?: boolean;
the Codex Auth page already talks to. Follow the surrounding preservation discipline: an
unrelated save must not drop it (the `oauthAccountFailover` lesson from #2568d).

### Where the row is suppressed — server, both surfaces (audit B2)
### Where the row is suppressed — server, THREE projections (implementation correction)

The Spark window is dropped from the **API projection**, not hidden with CSS: anything the
client does not render, it should not receive.

An earlier draft justified this by claiming `maxQuotaUtilisation` would reorder Codex account
An early draft justified this by claiming `maxQuotaUtilisation` would reorder Codex account
cards. That was wrong — it sorts the **Providers overview**
([ProviderOverviewDashboard.tsx:66](../../../gui/src/components/provider-workspace/ProviderOverviewDashboard.tsx)),
not the account cards. The real reason is worse for a naive fix:
not the account cards. The audit corrected it to two projections. **Implementation found a
third.**

**Spark reaches the GUI through TWO independent projections.** `/api/codex-auth/accounts`
builds its rows through `quotaForPlan` ([auth-api.ts:212](../../../src/codex/auth-api.ts)), and
`/api/provider-quotas` reaches the same data through `listCodexAuthAccountsSnapshot`
([providers/quota.ts:1129](../../../src/providers/quota.ts)). Filtering one leaves the other
still rendering the row the operator just switched off.
| Path | Reaches the data via |
|---|---|
| `/api/codex-auth/accounts` | `quotaForPlan` ([auth-api.ts:212](../../../src/codex/auth-api.ts)) |
| `/api/provider-quotas` (pooled) | `listCodexAuthAccountsSnapshot` → the same DTO |
| `/api/provider-quotas` (**direct mode**) | `fetchMainAccountInfoSnapshot` ([providers/quota.ts:1121](../../../src/providers/quota.ts)) — **never touches the Codex Auth DTO** |

The third path is how a `codexAccountMode: "direct"` install reports quota, and filtering at
`quotaForPlan` alone leaves it untouched. It surfaced because the existing
`tests/provider-quota.test.ts` Codex case **still passed** after the first attempt — a test
asserting Spark is present, passing when it was supposed to have been filtered. That is the
useful kind of test failure.

So the filter lands in a shared projection consumed by both, keyed on the exact raw label.
The filter therefore lives in `withSparkVisibility` (exported from `auth-api.ts`) and is
applied at BOTH `quotaForPlan` and `providerQuotaFromCodexQuota`, the latter being the one
point every Codex-sourced provider report funnels through.
Comment on lines +81 to +83

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Correct the stale single-filter dependency guidance

The new description correctly says direct mode bypasses quotaForPlan and requires filtering again in providerQuotaFromCodexQuota, but the unchanged Dependency section at lines 144–148 still concludes that both surfaces funnel through quotaForPlan, calls it the single filtering point, and requires only two test targets. Anyone implementing or auditing this open work unit from that summary could recreate the direct-mode leak this commit documents; update or remove that conclusion so it names both filter boundaries and the direct-mode regression case.

Useful? React with 👍 / 👎.


**Label-exact is not a nicety.** `customWindows` is the generic carrier for Cursor
(`First-party models`, `API usage`), Anthropic (`Fable`/`Opus`/`Sonnet`), Antigravity
(`Gem`/`Cla`), Kimi (`Total subscription credits`) and a dozen dynamic provider labels. A
filter written as "drop custom windows" blanks every one of them.

**Never at parse or cache time.** Custom windows participate in quota-presence checks, snapshot
reconciliation and capacity aggregation, so removing Spark upstream of the projection would
change routing state rather than display.


### Client

Expand Down
Loading