Skip to content

fix(cli): follow the active claude-swap account in Claude usage - #4631

Merged
steipete merged 2 commits into
mainfrom
triage/20260921-cli-37
Oct 19, 2026
Merged

steipete merged 2 commits into
mainfrom
triage/20260921-cli-37

Conversation

@steipete

Copy link
Copy Markdown
Owner

Claude Auto usage previously followed the ordinary provider pipeline, so it could report the browser account while cards and dashboard showed the active claude-swap slot. Reuse the existing adapter and account projection to return that active slot for one-shot Auto usage, including single-slot lists.

Explicit non-auto sources, configured non-auto sources, and explicit account selection keep their existing behavior. If the adapter fails or has no usable active slot, the ordinary fetch path remains available and its source is marked, for example, web (claude-swap fallback). Identity, measurement timestamps, and last-known diagnostics belong to the reported source. No credential reads or provider registration changes were added; serve retains its existing path.

Removed redundant CLI payload/account-selection and cards forwarding wrappers to keep production code net smaller. Updated the CLI/Claude docs and the 0.77.1 changelog. Thanks @postoso for the reproduction.

Verification

All Swift checks ran through the shared host build lock with the scrubbed test environment.

  • Red on main 7f7977b9881: swift test --build-system native --jobs 2 -Xswiftc -gnone --filter CLIUsageClaudeSwapTests — 1 test failed with 5 assertions: browser identity and 0/92 usage instead of the active slot and 50/41.
  • Green: swift test --build-system native --jobs 2 -Xswiftc -gnone --filter 'CLIUsageClaudeSwapTests|CLICardsClaudeSwapTests|CLIUsageCacheTests|CLIParallelUsageTests|CLIUsageFetchSetupTests|CLIOutputTests|CLIToonSnapshotTests|CLIWebFallbackTests|TokenAccountCLISelectionTests|ProviderArchitectureGatekeeperTests|BrowserCookiePromptContractTests|ClaudeSourcePlannerTests' — 187 tests in 16 suites passed, including all 10 new cases.
  • make check — passed; SwiftLint found 0 violations in 3,052 files.
  • git diff --check and the catalog precheck — passed.
  • Independent Codex review through P2 — no actionable findings in the supplied scope.
  • Against the reviewed main baseline: production +60/−71 (net −11); tests +249/−0.

Fixtures use distinct synthetic browser/swap identities and a fake read-only adapter. No live account probes or app relaunches were used.

Fixes #4599

@clawsweeper

clawsweeper Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-19T07:28:12.382798Z 23fd5df New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: afab3b87ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +187 to +190
let active = ClaudeSwapAccountProjection.accountSnapshots(
from: list,
source: source,
previousAccounts: ClaudeSwapRetainedUsageStore.load()).first(where: \.isActive),

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 Persist the fresh adapter projection

When a previous cards/dashboard run cached an exhausted window and this path later receives a fresh non-exhausted snapshot for the same active slot, the new projection is returned but never saved. If a subsequent codexbar usage call receives an unavailable row without measurements, accountSnapshots reloads the older exhausted snapshot and can report that stale quota until its original reset time; save the projected accounts, as the cards and dashboard consumers do, before selecting the active snapshot.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-environment Preliminary submission classification; full source review pending. clawsweeper:intake:needs-repro Preliminary submission classification; full source review pending. P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-repro Preliminary submission classification; full source review pending. clawsweeper:intake:needs-environment Preliminary submission classification; full source review pending. labels Oct 19, 2026
@clawsweeper

clawsweeper Bot commented Oct 19, 2026

Copy link
Copy Markdown

Codex review: blocked before merge.

What this changes

This PR makes one-shot Claude Auto usage follow the active claude-swap account and label ordinary-source fallbacks.

Example: The browser uses slot 1 while claude-swap slot 3 is active.

  • Before: Usage reports the browser account with 0% session and 92% weekly usage.
  • After: Usage reports active slot 3 with 50% session and 41% weekly usage.

Review scores

Measure Result What it means
Overall readiness 🦐 gold shrimp (3/6) Useful, approved direction with focused regression coverage, but a confirmed cache-consistency defect blocks merge and existing-state upgrade coverage remains incomplete.
Proof confidence 🌊 off-meta tidepool Not applicable: This owner-authored PR is outside the ordinary contributor proof gate; supplied validation exercises the production selection function with a fake adapter and stubbed browser data.
Patch quality 🦐 gold shrimp (3/6) 1 actionable review finding remain.

Product

Kind: Bug fix · Worth it: Yes · Fix scope: Complete
User problem: Usage can show another Claude account's quota while cards identifies the active swap account.
Reason: The reporter demonstrates practical confusion, and the owner-authored PR explicitly approves changing Auto precedence while preserving explicit selections.

Merge readiness

⛔ Blocked before merge - 2 items remain

Keep open: the owner-approved account-selection change addresses a real report, but the new path can resurrect obsolete exhausted quota.

Priority: P2
Reviewed head: afab3b87ee8063cfaad56c7e10dc48d3119f5c49

Before merge

  • Persist successful projections before selecting the active account (P2) - If cards or dashboard previously cached a 100% window whose reset remains in the future, a usage call can receive fresh lower usage for that same slot and return it without updating the cache. A subsequent unavailable row with no measurements reloads the older exhausted window, so usage incorrectly returns 100% again until its old reset. Save the complete projected account array after every successful list, as cards and dashboard do, before selecting the active snapshot. Add a regression covering this sequence with isolated retained state.
  • Add data-model compatibility proof - The review found that existing stored data may not work after upgrade. Show that existing data still loads and works with this change.

Findings

  • [P2] Persist successful projections before selecting the active account — Sources/CodexBarCLI/CLIUsageCommand.swift:187-190

Tests

  • Missing end-to-end proof: The supplied validation lacks a latest-stable upgrade run preserving configured sources and retained quota, including the exhausted-to-fresh-to-unavailable sequence.
Agent review details

How this fits together

The CLI selects a Claude data source, projects adapter account measurements or fetches ordinary provider usage, and renders text, JSON, or TOON.

flowchart TD
A[Usage command] --> B[Source and account eligibility]
B --> C[Configured account adapter]
C --> D[Shared account projection]
E[Retained quota cache] --> D
D --> F[Active slot output]
B --> G[Ordinary provider fetch]
C --> G
G --> F
Loading

Technical review

Best possible solution:

Save the complete successful adapter projection through the existing retained-usage store before selecting the active slot.

Do we have a high-confidence way to reproduce the issue?

The reporter's distinct browser/active-slot measurements match current-main routing, and source inspection establishes the introduced retained-cache failure sequence; no target code was executed.

Is this the best way to solve the issue?

Reusing the existing adapter and projection is appropriate for the approved direction, but the new consumer must also honor their successful-refresh cache contract.

Full review comments:

  • [P2] Persist successful projections before selecting the active account — Sources/CodexBarCLI/CLIUsageCommand.swift:187-190
    If cards or dashboard previously cached a 100% window whose reset remains in the future, a usage call can receive fresh lower usage for that same slot and return it without updating the cache. A subsequent unavailable row with no measurements reloads the older exhausted window, so usage incorrectly returns 100% again until its old reset. Save the complete projected account array after every successful list, as cards and dashboard do, before selecting the active snapshot. Add a regression covering this sequence with isolated retained state.
    Confidence: 0.99

Overall correctness: patch is incorrect
Overall confidence: 0.97

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against 7e31e74ea662.

Provenance checked

  • CLI adapter precedence changes intended behavior with a stated reason (fa2e211: Show claude-swap accounts in CLI cards #2188 limited adapter precedence to cards and preserved explicit account/source intent.)
  • Single-account precedence changes intended behavior with a stated reason (16805eb: Allow single-account claude-swap cards #2280 retained the cards threshold by default; this PR explicitly chooses active-slot usage even for single-slot lists.)
  • Payload and account-selection forwarding helpers keeps the original intent (5bfd1d1: Payload construction supported pace output, while account selection dates to 37dd301; inlining preserves both behaviors.)

Testing

Proof path: in-process harness.

Security

None.

Evidence

Acceptance criteria:

  • swift test --filter 'CLIUsageClaudeSwapTests|CLICardsClaudeSwapTests|ClaudeSwapAccountProjectionTests|ClaudeSwapRetainedCacheCompatibilityTests'
  • make check
  • git diff --check
  • Verify an upgrade from v0.77.0 with source preferences and retained quota intact, using synthetic accounts and no live provider or Keychain access.

What I checked:

Likely related people:

  • Peter Steinberger: Raw commit 61fbe9f adds Sources/CodexBarCLI/CLIClaudeSwapCards.swift:97 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: 61fbe9fac507; files: Sources/CodexBarCLI/CLIClaudeSwapCards.swift)
  • Mike Bannister: Raw commit fa2e211 adds Sources/CodexBarCLI/CLIClaudeSwapCards.swift:97 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: fa2e211001c0; files: Sources/CodexBarCLI/CLIClaudeSwapCards.swift)
  • sf-jin-ku: Raw commit 6ed9d98 adds Sources/CodexBarCLI/CLIClaudeSwapCards.swift:140 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: 6ed9d98e3550; files: Sources/CodexBarCLI/CLIClaudeSwapCards.swift)

Review metrics

Metric Value Why it matters
Introduced code size Production +60/-71; tests +249 The implementation reuses existing projection and rendering owners while reducing production code; the tests cover distinct account-selection and fallback scenarios.

Root-cause cluster

Relationship: fixed_by_candidate
Canonical: #4599
Summary: This PR implements the active-slot direction requested as one resolution of the linked account-selection report.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Labels

Label changes:

  • add P2: Incorrect quota can mislead multi-account CLI users, with explicit-source and dashboard alternatives available.
  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🌊 off-meta tidepool and patch quality is 🦐 gold shrimp.
  • add status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action.

Label justifications:

  • P2: Incorrect quota can mislead multi-account CLI users, with explicit-source and dashboard alternatives available.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🌊 off-meta tidepool and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action.

Rating scale

6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

Reviewed October 19, 2026, 12:26 AM ET / 04:26 UTC.

@steipete
steipete merged commit 59a7d46 into main Oct 19, 2026
9 checks passed
j3r0lin added a commit to j3r0lin/CodexBar that referenced this pull request Oct 19, 2026
Merge fork/main (265d2af) into upstream main (59a7d46).

Conflict handling:
- Overview/menu: the fork's Overview row model and removal of the provider
  switcher win (StatusItemController+Menu/MenuPresentation/OverviewSubmenus/
  SwitcherViews, switcher tests). Upstream steipete#4549's plugin gauge helper moves
  to StatusItemController+SwitcherMetrics.swift for the icon code that still
  uses it. Upstream steipete#4626 "Show all accounts in Overview" keeps its setting
  and mergedOverviewRows, but the fork Overview does not read them yet.
- Claude: upstream steipete#4517 tcr source merged alongside magpie ownership:
  claude-swap runs only while magpie does not own Claude
  (claudeSwapEffectivelyEnabled, native-route gate in the runtime), the
  account heading/ordinal/source label handle tcr and magpie, and widget
  owner keys keep claude/swap, claude/tcr and claude/magpie namespaces.
- CLI: upstream steipete#4631 claude-swap follow is skipped while the magpie switch
  owns Claude.
- Config: upstream shareUsageWithCLI and the fork's top-level magpie config
  are both encoded; the legacy Claude cookie migration keeps the fork's
  magpie gate on top of upstream's table-driven migrator.
- Settings: upstream mergedOverviewAllAccounts kept next to the fork's
  overview window filter and collapsed groups; switcherShowsIcons and
  switcher shortcuts stay removed but still import from older exports.
- UsageStore: postQuotaWarning/postPredictivePaceWarning move to an
  extension to keep the class body under the SwiftLint limit after both
  sides added stored properties.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLI: usage --provider claude reports the browser's account while cards shows the active claude-swap account

1 participant