# Claude Scoped OAuth Usage Limits ## Problem Anthropic's current OAuth usage response reports Fable in `limits` as a model-scoped weekly limit instead of one of the legacy top-level Fable fields. Orca ignores `limits`, maps `fableWeekly` to `null`, and then depends on a hidden Claude `/usage` PTY read that is disabled on Windows and can fail silently elsewhere. - `src/main/rate-limits/claude-fetcher.ts:300` models only top-level OAuth windows. - `src/main/rate-limits/claude-fetcher.ts:393` maps only legacy Fable field names. - `src/main/rate-limits/service.ts:1203` disables the PTY supplement on Windows. - `src/renderer/src/components/status-bar/tooltip.tsx:172` renders Fable whenever `fableWeekly` is populated. ## Root Cause The OAuth response contract evolved from dedicated model fields to generic entries shaped like `kind: "weekly_scoped"`, `percent`, `resets_at`, and `scope.model.display_name`. Orca's response type and mapper were not updated for that shape. ## Non-goals - Do not change polling, credentials, token refresh, account switching, renderer layout, or usage percentage semantics. - Do not remove the existing PTY supplement or legacy field compatibility. - Do not generalize shared renderer state to arbitrary model windows in this targeted bug fix. ## Design 1. Extend the private OAuth response type with an optional `limits` array containing only the fields needed for safe parsing. 2. Select a Fable entry only when `kind` is `weekly_scoped`, the model display name is Fable (case-insensitive), and `percent` is finite. 3. Map the scoped entry to the existing seven-day `fableWeekly` window, including its reset timestamp. 4. Prefer the current scoped entry, then retain the three legacy top-level fields as fallbacks. 5. Keep malformed, unrelated, inactive, or absent entries non-fatal. Treat `is_active: false` as unavailable so stale promotional limits disappear; accept a missing activity flag for compatibility. ## Data Flow - OAuth response - `limits[].weekly_scoped` Fable -> `fableWeekly` - otherwise legacy explicit Fable field -> `fableWeekly` - otherwise existing optional PTY supplement - Existing provider state -> existing status-bar and details rendering ## Edge Cases - `limits` is missing, null, malformed, or contains null entries. - A scoped entry names another model. - Fable percent is missing, non-numeric, or non-finite. - Fable is inactive and should not be rendered. - `is_active` is omitted by an older server response but the remaining scoped entry is valid. - Both current and legacy fields exist; the current scoped entry wins. - Reset timestamps may be ISO strings, epoch seconds, epoch milliseconds, or absent. - Windows, WSL, SSH, and remote runtimes use the same OAuth mapper and require no platform-specific execution. ## Test Plan - Unit: reproduce a current real-response shape and assert Fable maps without a PTY attempt. - Unit: assert scoped data wins over a legacy field. - Unit: assert inactive, malformed, and unrelated scoped entries are ignored while legacy fallback remains available. - Regression: retain existing legacy-field and bare-`fable` behavior tests. - Verification: focused Claude fetcher tests, typecheck, lint, and max-lines ratchet. - Electron: refresh Claude usage and confirm Session, Weekly, and Fable remain visible in the existing status-bar details surface. ## UI Quality Bar No UI implementation changes. The existing Fable row must reappear with the same typography, spacing, progress bar, percentage semantics, and reset copy as adjacent Session and Weekly rows. ## Review Screenshots 1. Claude usage details showing Session, Weekly, and Fable from a live OAuth refresh. 2. Adjacent status-bar context showing the Claude provider remains visually unchanged outside the restored row. ## Rollout 1. Add the scoped OAuth response types and mapper. 2. Add focused current-schema and compatibility regression tests. 3. Run focused and repository checks. 4. Validate the restored row in Electron and capture review screenshots. 5. Commit, push, and open an unmerged PR. ## Lightweight Eng Review - Scope: Kept to the private OAuth mapper and tests; no shared-state or renderer generalization is required to restore Fable. - Architecture/data flow: OAuth remains authoritative, with structured scoped data preferred over legacy fields and PTY used only as the existing final supplement. - Failure modes covered: malformed optional data, unrelated models, inactive limits, missing activity flags, duplicate old/new representations, missing reset metadata, and platform-neutral execution. - Test coverage required: current-schema success without PTY, precedence, inactivity, malformed/unrelated entries, and legacy fallback. - Performance/blast radius: One bounded linear scan of the small response `limits` array per existing OAuth refresh; no new requests, polling, subprocesses, IPC, storage, or renderer work. - UI quality bar: Existing status-bar visuals must remain unchanged except for the restored Fable row. - Required review screenshots: Live Claude details with all three rows; surrounding status-bar context. - Residual risks: Anthropic may rename the scoped model display label; legacy and PTY fallbacks remain available.