Summary
accounts usage only renders the top-level 5h / weekly windows and silently drops additional_rate_limits[] from the upstream payload. As a result, per-model / per-feature limits (e.g. GPT-5.3-Codex-Spark / codex_bengalfox) are never visible in the (non---json) output, even when they are the windows actually being consumed.
Split out from #23 (which is about usage not being charged at all on the responses path); this one is purely a client-side display gap and is independently fixable.
Where
src/client/usage.ts — normalizeUsage (around L98–123) only reads rate_limit.primary_window and rate_limit.secondary_window:
return {
plan_type: str(o.plan_type),
allowed: bool(rl.allowed),
limit_reached: bool(rl.limit_reached),
primary: parseWindow(rl.primary_window),
secondary: parseWindow(rl.secondary_window),
credits: ...,
raw,
};
The upstream …/wham/usage payload also contains an additional_rate_limits[] array, which is dropped here (it only survives inside raw, so --json consumers can still reach it, but accounts usage and accountsUsageCommand's human output never surface it).
Example upstream shape (observed):
"additional_rate_limits": [
{
"limit_name": "GPT-5.3-Codex-Spark",
"metered_feature": "codex_bengalfox",
"rate_limit": {
"allowed": true,
"limit_reached": false,
"primary_window": { "used_percent": 0, "limit_window_seconds": 18000, "reset_after_seconds": 18000, "reset_at": ... },
"secondary_window": { "used_percent": 0, "limit_window_seconds": 604800, "reset_after_seconds": 604800, "reset_at": ... }
}
}
]
Impact
Proposed fix
- Extend
UsageSnapshot to carry a normalized additional?: Array<{ limit_name?: string; metered_feature?: string; primary?: RateLimitWindow; secondary?: RateLimitWindow }> parsed from additional_rate_limits[].
- Render each additional bucket in
accountsUsageCommand (label by limit_name / metered_feature), and include it in usageToJson.
- Add a unit test in
src/client/usage.test.ts covering a payload with additional_rate_limits.
Notes
Strictly a display/normalization gap — does not by itself explain the missing consumption in #23 (in that investigation the additional bucket was also 0). Worth fixing so usage is fully observable once the upstream accounting question is resolved.
Summary
accounts usageonly renders the top-level 5h / weekly windows and silently dropsadditional_rate_limits[]from the upstream payload. As a result, per-model / per-feature limits (e.g.GPT-5.3-Codex-Spark/codex_bengalfox) are never visible in the (non---json) output, even when they are the windows actually being consumed.Split out from #23 (which is about usage not being charged at all on the
responsespath); this one is purely a client-side display gap and is independently fixable.Where
src/client/usage.ts—normalizeUsage(around L98–123) only readsrate_limit.primary_windowandrate_limit.secondary_window:The upstream
…/wham/usagepayload also contains anadditional_rate_limits[]array, which is dropped here (it only survives insideraw, so--jsonconsumers can still reach it, butaccounts usageandaccountsUsageCommand's human output never surface it).Example upstream shape (observed):
Impact
gpt-5.3-codex-sparkresearch-preview window),accounts usageshows0% usedon the main windows and gives no indication that a different limit is filling up — misleading for monitoring / limit checks.accounts usagewouldn't show the per-feature bucket moving.Proposed fix
UsageSnapshotto carry a normalizedadditional?: Array<{ limit_name?: string; metered_feature?: string; primary?: RateLimitWindow; secondary?: RateLimitWindow }>parsed fromadditional_rate_limits[].accountsUsageCommand(label bylimit_name/metered_feature), and include it inusageToJson.src/client/usage.test.tscovering a payload withadditional_rate_limits.Notes
Strictly a display/normalization gap — does not by itself explain the missing consumption in #23 (in that investigation the additional bucket was also
0). Worth fixing so usage is fully observable once the upstream accounting question is resolved.