Skip to content

Port upstream 0.69.0: show Claude Web limit reset credits - #689

Draft
Finesssee wants to merge 1 commit into
port/upstream-0.69.0from
port/micro-0.69.0-claude-limit-resets-web
Draft

Finesssee wants to merge 1 commit into
port/upstream-0.69.0from
port/micro-0.69.0-claude-limit-resets-web

Conversation

@Finesssee

Copy link
Copy Markdown
Collaborator

Summary

Claude Web source now shows the user's saved usage-limit resets ("Reset for free" in Claude Settings > Usage) as a Limit Reset Credits inventory row: N available plus the soonest expiry. It appears on the tray card, the Providers detail Usage section, and in codexbar usage text/JSON, through the existing provider-neutral ProviderInventoryItem path already used by Grok. No frontend or bridge change was needed.

  • The Web usage request now asks for GET /organizations/{orgId}/usage?cedar_ember=1. If the status is not 200, 401 or 429, and it is not a Cloudflare challenge 403, the original request is retried once without the query (a surface-specific 403 may reject only the opt-in). A second failure keeps the normal error handling.
  • cedar_ember is decoded by a new provider-owned module, rust/src/providers/claude/reset_credits.rs, with #[derive(Deserialize)] structs. Only eligible: true yields an inventory. A grant counts when it is not paused, resets_left > 0, started, and not expired; usable_now is not consulted. A malformed grant (bad types, missing paused, unreadable bound, resets_left outside 0..=resets_total) is dropped without hiding the rest. More than 50 available resets or more than 200 grant records shows nothing. An empty inventory shows nothing. The usage windows are never affected.
  • Grant ids (redemption handles) are never deserialized. The inventory is transient (#[serde(skip)]), so nothing enters persisted usage JSON.
  • Web source only. OAuth, CLI and Admin sources are untouched, and Windows has no Web-extras merge into OAuth results.
  • ClaudeWebApiFetcher gains a private base_url field (default unchanged) so the wire tests can target a mock server.

Upstream reference

Ported / Deferred

Ported: opt-in query with single plain retry, cedar_ember parsing rules and caps, count and soonest-expiry display, CLI text/JSON row, Web-only scope, live-only (non-persisted) inventory.

Deferred / intentionally different:

  • Upstream renders one expiry per reset in the menu card (2d · 6d). Win-CodexBar's shared inventory row shows the count with the soonest expiry only, which is what the Grok row already does. Per-reset expiry rows would need a new shared inventory shape; not done here.
  • Upstream re-filters expired resets at render time (availableExpirations(at:)). Here the inventory is computed at fetch time; a reset that expires before the next refresh disappears on that refresh.
  • Upstream's uncached HTTP client (skips the URL cache so the raw body is not kept on disk) has no equivalent need: the reqwest client used here has no on-disk cache.
  • The .github/pr-proof log, CHANGELOG entry and Swift gatekeeper-test edits are upstream-only.
  • Bounds are parsed with RFC 3339; a zone-less timestamp is treated as unreadable (grant dropped), matching "supplied but unreadable bound is malformed".

Validation

Toolchain cargo +1.98.0, E-core pinned (wrapper recreated locally because the shared port-audit scratch directory was wiped mid-run; same CPUs 16-31 / BelowNormal via start /affinity FFFF0000 /belownormal).

  • cargo +1.98.0 fmt --all: clean
  • cargo +1.98.0 clippy --workspace --all-targets -- -D warnings: pass
  • cargo +1.98.0 test -p codexbar providers::claude:: -- --test-threads=4: 178 passed, 0 failed, 1 ignored (pre-existing; needs native Claude Code). This includes 8 new reset_credits unit tests and 6 new mockito wire tests (reset_opt_in_tests: opt-in success no retry, 400/403/404/422/500/503 retry once, retry failure keeps error handling, 401/429 not retried, Cloudflare challenge not retried, ordinary 403 retried then AuthRequired).
  • Shared code (core, settings, spend) untouched, so the full cargo test -p codexbar and the Tauri crate/frontend suites were not re-run.

File sizes: web_api.rs was already over 1000 lines (1335) and grows to 1390; all new logic lives in the new reset_credits.rs (134 lines) and sibling test files.

Affected areas

  • Claude provider (Web source)
  • Tray card / Providers detail row (existing inventory rendering, no frontend change)
  • CLI codexbar usage (existing inventory rendering)
  • Settings / float bar / installer

UI proof

Pending: coordinator will capture CUA proof on a fresh build. A live Claude Web session with saved resets is needed; otherwise seed via the unit-level fixtures.

@coderabbitai

coderabbitai Bot commented Sep 29, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

Thermo-nuclear review

Reviewed by Codex gpt-6-luna (xhigh); verified and validated by Claude

Head reviewed: 459d367

Findings:

  • P3, rust/src/providers/claude/web_api.rs:582: the plain retry goes through a pass-through helper (get_plain_usage) and repeats the same request across match arms. Style-only; no behavior defect found.

Nothing else found: provider logic stays siloed, no new dependencies, no secrets logged, no bridge or locale drift.

Follow-up (same head, no commit pushed):

  • Codex's proposed consolidation of the P3 did not compile (E0382: opted_in is moved by bytes() inside the match), so I reverted it. The existing helper is correct and behavior-neutral, so the item is left as is.
  • Validated at head: cargo +1.98.0 clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings passes. No frontend or UI changes.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

CUA proof

Build commit: 459d3677fa23297776cdd5ba93e191340011689a (PR head) plus uncommitted, reverted proof-only patches (text in proof\689\proof-only.diff):

  • Cargo.toml/Cargo.lock: [patch.crates-io] dirs shim redirecting home/config dirs under CODEXBAR_PROOF_HOME (isolated profile).
  • rust/src/providers/claude/web_api.rs: fetcher base_url read from env CODEXBAR_PROOF_CLAUDE_BASE_URL (default unchanged; no TLS/URL validation changed).

Commands: pnpm --dir apps/desktop-tauri run tauri:build:debug, then proof\689\launch.sh trayPanel (real Claude Web fetch path against a local python mock on 127.0.0.1:18689, dummy CLAUDE_AI_SESSION_KEY, settings claude_usage_source=web, theme auto) and MOCK_MODE=reject proof\689\launch.sh trayPanel. Driven and captured with cua-driver (background get_window_state only; window kept on the second monitor).

Fixture grants: 2 resets (ends +5d), 1 reset (ends +2d1h), one paused grant, one expired grant.

# Assertion Result
1 No real email/account from the user's machine visible (only dummy proof-user@example.invalid) PASS
2 Tray Claude card shows "Limit Reset Credits: 3 available" with "Next expires in 2d 0h" (paused and expired grants excluded) PASS
3 Mock log shows GET .../usage?cedar_ember=1 from the real fetch path; grant id never visible PASS
4 Session (42%) and Weekly (18%) windows still render PASS
5 Opt-in rejected with 403: log shows opt-in then a single plain GET .../usage retry; windows render, no credit row, no error PASS
6 Theme stays dark under auto PASS

Screenshots (local, not committed): C:\Users\FSOS\AppData\Local\Win-CodexBar\port-audit\proof\689\shots\tray-optin.png, ...\shots\tray-reject.png. Mock logs: proof\689\mock-optin.log, proof\689\mock-reject.log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant