Skip to content

Copilot: surface AI credit usage for token-based-billing seats - #2647

Open
KSEGIT wants to merge 13 commits into
steipete:mainfrom
KSEGIT:copilot-ai-credits
Open

Copilot: surface AI credit usage for token-based-billing seats#2647
KSEGIT wants to merge 13 commits into
steipete:mainfrom
KSEGIT:copilot-ai-credits

Conversation

@KSEGIT

@KSEGIT KSEGIT commented Aug 4, 2026

Copy link
Copy Markdown

Closes #2593.

Rebased 2026-08-14 onto e915ca13f. Since #2613 landed stage 1 (decoding credits_used and rendering it through the shared provider-detail contract), this branch carries only the remainder: user-entered per-account credit entitlements and the progress-bar display beyond stage 1. Seat credits flow through main's shared detail rows — no parallel credit state.

The organization lane has been removed from this PR (was deferred per review). This is now seat credits only. Happy to bring the org lane back in a follow-up once an authorization model is approved.

The problem

On a Copilot Business seat with token_based_billing: true, GET /copilot_internal/user reports every quota snapshot as unlimited: true, entitlement: 0, remaining: 0, percent_remaining: 100. The #1258 guards correctly drop those so no misleading "0% used" bar appears — but the result is a Copilot card showing only the plan label and no usage at all.

Real consumption is available in credits_used, already present on each quota snapshot in the response CodexBar already fetches (landed in #2613).

GitHub publishes no credit entitlement anywhere

This is the finding that shaped the design. I probed all 8 documented billing endpoints plus budgets, cost-centers, included_credits, ai_credit/entitlement, copilot/metrics and usage/summary. None expose the included-credit ceiling — the "6,000" that the org billing page displays. discountQuantity reveals only what included credits absorbed, so the ceiling is observable only once exceeded.

It is derivable as seats × per-seat allowance, but the per-seat figure is currently a promotional 3,000 against a standard 1,900 — a hardcoded table would silently produce a wrong bar when the promo ends. So the denominator is user-entered and never inferred. A row with no entitlement renders as text, never a bar with a fabricated ceiling.

If you know of an endpoint I missed, that would simplify this considerably.

What this adds

Seat credit bar (builds on #2613). Extends the shared provider-detail row contract with an optional row id, progress ratio, and retained numeric usage (ProviderDetailSection.Row), so the existing "Credits used" row becomes a "31 / 3000" bar when a seat entitlement is set, and stays plain text otherwise. Created only when it carries real signal (token-billed / unlimited quota / credits > 0 / entitlement set), so metered accounts reporting credits_used: 0 don't gain a permanent empty row. No guard line in CopilotUsageFetcher.swift is modified — the #1258 guard block is byte-identical to main.

Per-account entitlements. The seat allowance is stored on the selected ProviderTokenAccount (following the z.ai per-account fields precedent), resolved in copilotSettingsSnapshot with the existing global UserDefaults value as fallback — so existing single-account setups keep working unchanged, and two Copilot accounts with different allowances each get the right denominator. The settings field writes to the selected account when one exists.

Cached rows repair immediately. Changing or clearing the entitlement rewrites the cached "Credits used" row synchronously, in both the live snapshot and the last-known-reset baseline. The numerator comes from the row's structured progress, falling back to the retained usageValue on text-only rows — never re-parsed from display text. This is what lets a cached text-only row grow a bar the moment an entitlement is entered even when the follow-up refresh never lands (offline, token lost, 401), and it is why the row carries usageValue at all.

Which surfaces this covers

Worth being explicit, since it's a menu bar app:

Surface Covered
Menu card (provider card rows) ✅ yes
Menu bar icon ❌ no
Widget ❌ no
codexbar usage CLI ❌ no

Credits are detail rows, not a RateWindow, because a row with no user-entered entitlement has no percentage to show. MenuBarLayout, IconRemainingResolver and the widget all build from primary/secondary/tertiary/extraRateWindows, so they see nothing.

The consequence: a Business token-billing user still gets an empty menu bar icon and must open the menu to see credits. I'd rather state that than have you find it.

Making the icon work needs a decision I didn't want to make unilaterally: publishing credits as a NamedRateWindow when an entitlement exists would light up the icon, widget and the existing "menu bar secondary metric" picker for free, but Copilot's extra windows are gated behind copilotBudgetExtrasEnabled in the card renderer, so it risks either double-rendering the row or coupling credits to an unrelated setting. Happy to do it in this PR if you'll say which shape you want.

Live behavior on the current head

Captured from a build of this branch against my live Copilot Business seat (token-based billing). Full sequence and caveats in this comment.

Bar renders, online — 2455 / 3000 online 3000
Cached row survives a failed refresh — offline banner, still 2455 / 3000 offline 3000
Changed entitlement re-renders the ratio — 2455 / 5000, shorter fill online 5000
And survives offline at the new entitlement offline 5000

Stated plainly: the two offline frames sit either side of a brief reconnect, so they do not form one unbroken offline stretch spanning an entitlement change. The exact text↔bar transition is covered by unit tests rather than by these captures — see UsageStoreCoverageTests.

Testing

Verified on the current head against e915ca13f:

  • 193 focused tests across the 15 touched suites green (fetcher, parser, settings, wiring, menu-card model, detail sections, cached-row repair, persistence round-trip).
  • make check — 0 violations, 0 serious across 1,878 files.
  • ProviderArchitectureGatekeeperTests — 38/38. The credit-entitlement additions shift 13 allowlisted provider constructs past the gatekeeper's two-line anchor tolerance, so this branch re-anchors those entries to their current lines; anchors, provider sets and fingerprints are unchanged.
  • Full suite, run in 4 shards: 18/18, 18/18 and 17/17 groups green, plus the 85 selections in the remaining shard re-run separately (714 tests / 59 suites green).

One pre-existing failure, unrelated to this PR: MiniMaxMenuCardBillingTests expects "1,234" but gets "1.234" (locale-dependent number grouping; this machine is en_PL). It reproduces identically on a pristine origin/main worktree with none of these changes applied. Note that a plain make test aborts on it rather than reporting and continuing — that is why the evidence above is sharded.

All new tests use ProviderHTTPTransportStub or the existing URLProtocol stub. No live network, no Keychain access, per AGENTS.md.

Regression coverage worth calling out: a test asserts the #1258 behaviour still holds — a Business token-billing payload yields credits and primary == nil, secondary == nil. Per-account tests cover: account override wins over the global fallback, fallback when the account has no value, two accounts producing different snapshot entitlements, and a Codable round-trip through the config store (including legacy JSON without the new keys). Cached-repair tests cover text→bar transition, clear-restores-text-only, no-numeric-usage no-op, and the stale-reset-baseline path.

Known limitations

  • Localization: L("AI credits") and L("credits used") have no Localizable.strings entries. Scripts/check-app-locales.mjs enforces all 23 catalogs together, so a partial addition fails make check — left out deliberately rather than done badly. Happy to add all 23 here if you'd prefer.
  • Account field semantics: an account without an override displays the global fallback value; saving the field unchanged freezes that value onto the account. Clearing the field removes the override and re-displays the fallback.
  • No pace/projection on credit rows yet, though resetsAt is available and a monthly credit budget is a good fit for it (cf. Show ahead/behind pace for all providers and in the menu bar #807, Add Projections to Copilot Tracker #2166).

Commits

12 focused commits, each with its own tests, left unsquashed so they can be reviewed in sequence. Squash on merge if you'd rather.

🤖 Generated with Claude Code

@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: aaeb632f41

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread Sources/CodexBarCore/Providers/Copilot/CopilotOrgCreditsFetcher.swift Outdated
Comment thread Sources/CodexBarCore/Providers/Copilot/CopilotOrgCreditsFetcher.swift Outdated
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. labels Aug 4, 2026
@clawsweeper

clawsweeper Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed August 16, 2026, 11:45 AM ET / 15:45 UTC.

ClawSweeper review

What this changes

Adds a per-Copilot-account AI-credit entitlement that turns token-billed seat usage into a menu-card progress row and rewrites cached rows immediately when the entitlement changes.

Merge readiness

⚠️ Ready for maintainer review - 2 items remain

Keep open for maintainer product sign-off. The implementation is coherent, has sufficient live UI proof, and no discrete correctness or security defect was found; the remaining decision is whether the menu-card-only, user-entered credit ceiling is the intended Copilot contract.

Priority: P2
Reviewed head: c39ff51594f35a86e13aba0ec7e1a62ef6d0a786
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🦞 diamond lobster (5/6) Strong live evidence and extensive focused coverage support a well-scoped implementation; only product acceptance remains.
Proof confidence 🦞 diamond lobster (5/6) ✨ media proof bonus Sufficient (screenshot): Inspected screenshots directly show the after-fix Copilot card at two entitlement values and preserve each cached ratio during an offline failure state.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (screenshot): Inspected screenshots directly show the after-fix Copilot card at two entitlement values and preserve each cached ratio during an offline failure state.
Evidence reviewed 7 items Seat-credit row implementation: The PR creates a stable Copilot credit row only when the API counter has meaningful signal, and renders a ratio only when a user-entered entitlement exists.
Per-account persistence and fallback: The selected token account overrides the legacy global fallback, preserving existing installs while allowing separate seat ceilings.
Cached-row regression coverage: Coverage exercises text-to-bar conversion, clearing back to text, missing numeric usage, and reset-baseline repair.
Findings None None.
Security None None.

How this fits together

CodexBar turns Copilot API usage snapshots into provider-detail rows shown in the macOS menu card. This change combines the existing credit counter with a user-entered per-seat ceiling to render a ratio without inventing a quota.

flowchart LR
A[Copilot usage response] --> B[Usage snapshot]
C[Selected Copilot account] --> D[Seat credit ceiling]
B --> E[Credit detail row]
D --> E
E --> F[Cached snapshot repair]
F --> G[Menu card]
Loading

Decision needed

Question Recommendation
Should CodexBar accept a menu-card-only Copilot credit ratio backed by a per-account user-entered seat allowance, while icon, widget, and CLI surfaces remain unchanged? Approve the focused seat-only scope: Land the menu-card row and per-account setting as the bounded display layer on top of the already-shipped credit decoder.

Why: The implementation avoids fabricated API data and does not change auth scope, but it adds a persisted setting and establishes a new provider-display contract that the repository vision reserves for sign-off.

Before merge

  • Resolve merge risk (P1) - Landing this creates a lasting product contract in which a manually entered allowance controls the displayed percentage while the menu-bar icon, widget, and CLI remain intentionally unchanged.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production versus test growth production/docs +400, tests +797 The shared row contract and Copilot setting are accompanied by substantially more focused regression coverage than production growth.
Review surface 28 files affected The feature spans core snapshot data, settings persistence, menu rendering, documentation, and targeted tests.

Merge-risk options

Maintainer options:

  1. Decide the mitigation before merge
    Approve the narrow menu-card contract if that is the desired product surface, keeping the ceiling explicitly user-entered and leaving broader metric publication for a separately scoped follow-up.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Technical review

Best possible solution:

Approve the narrow menu-card contract if that is the desired product surface, keeping the ceiling explicitly user-entered and leaving broader metric publication for a separately scoped follow-up.

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

Not applicable as a bug report. The changed behavior itself has a high-confidence after-fix path: four inspected live screenshots show the real Copilot menu card online and offline at two configured ceilings.

Is this the best way to solve the issue?

Unclear pending product sign-off. The implementation is a maintainable way to avoid inventing a GitHub quota, but only a maintainer can decide whether menu-card-only visibility is the intended scope.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 355f8443a55c.

Labels

Label justifications:

  • P2: This is a bounded provider-usage feature with limited blast radius and a remaining product-scope decision.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (screenshot): Inspected screenshots directly show the after-fix Copilot card at two entitlement values and preserve each cached ratio during an offline failure state.
  • proof: sufficient: Contributor real behavior proof is sufficient. Inspected screenshots directly show the after-fix Copilot card at two entitlement values and preserve each cached ratio during an offline failure state.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. Inspected screenshots directly show the after-fix Copilot card at two entitlement values and preserve each cached ratio during an offline failure state.

Evidence

What I checked:

Likely related people:

  • steipete: Authored the declarative provider-detail refactor and set the staged direction for the Copilot credit work in the PR discussion. (role: shared provider-detail architecture author and recent area contributor; confidence: high; commits: 8314a74e8613; files: Sources/CodexBarCore/ProviderDetailSection.swift, Sources/CodexBar/ProviderDetailSectionsContent.swift)
  • Yuxin-Qiao: Authored the merged implementation that retains credits_used on current main, which this UI work extends. (role: introduced the shipped credit-decoding stage; confidence: high; commits: 2d76cd9e9fca; files: Sources/CodexBarCore/Providers/Copilot/CopilotUsageFetcher.swift)
  • Zihao Qi: Authored the earlier Copilot unlimited-quota handling that this PR intentionally preserves while adding a separate credit row. (role: unlimited-quota behavior contributor; confidence: medium; commits: 6d71af30b84d; files: Sources/CodexBarCore/Providers/Copilot/CopilotUsageFetcher.swift)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (33 earlier review cycles; latest 8 shown)
  • reviewed 2026-08-10T20:46:31.316Z sha 766101c :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-12T12:09:11.863Z sha 766101c :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-14T10:54:47.693Z sha 885b10e :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-14T11:27:00.534Z sha ddd77ff :: needs real behavior proof before merge. :: [P2] Move the feature note out of released v0.49.6
  • reviewed 2026-08-14T22:17:20.929Z sha ddd77ff :: needs real behavior proof before merge. :: [P2] Remove the entry from released v0.49.6
  • reviewed 2026-08-15T00:43:51.820Z sha 2d25ce6 :: needs real behavior proof before merge. :: [P2] Keep the rebuilt row in the account cache
  • reviewed 2026-08-15T10:25:31.460Z sha 2d25ce6 :: found issues before merge. :: [P3] Remove the release-owned changelog entry
  • reviewed 2026-08-15T14:58:46.851Z sha 31281db :: needs maintainer review before merge. :: none

@steipete

steipete commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Thanks for this, and for the excellent original report in #2593 — you found both the credits_used field and the org-billing endpoint. Heads-up on sequencing: #2613 is green and staged to land stage 1 of this (decoding credits_used from the already-fetched copilot_internal/user response). Rather than closing anything, the ask is: once #2613 merges, could you rebase this PR on top so it carries just the remainder (the org billing endpoint and the UI surface beyond stage 1)? Your issue and this PR shaped the direction here, so we'd love to land the rest with your name on it.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Aug 5, 2026
@KSEGIT

KSEGIT commented Aug 7, 2026

Copy link
Copy Markdown
Author

Re status: 📣 needs proof — here's what I can evidence, and what I can't.

The upstream data is real, not inferred

Live from a Copilot Business seat (redacted), via the endpoint CodexBar already calls:

"quota_snapshots": {
  "premium_interactions": { "unlimited": true, "entitlement": 0, "remaining": 0,
                            "percent_remaining": 100.0, "credits_used": 31,
                            "token_based_billing": true, "overage_permitted": true },
  "chat":        { "unlimited": true, "entitlement": 0, "credits_used": 0 },
  "completions": { "unlimited": true, "entitlement": 0, "credits_used": 0 }
},
"organization_login_list": ["<ORG>"],
"copilot_plan": "business", "token_based_billing": true,
"quota_reset_date": "2026-09-01"

Note credits_used: 0 on chat/completions — that's why the seat lane reads only premium_interactions rather than summing, and why lane creation is gated on real signal instead of on the field merely decoding.

And the org endpoint:

{ "usageItems": [
    { "product": "Copilot", "sku": "Copilot AI Credits",  "model": "Code Review model",
      "unitType": "ai-credits", "pricePerUnit": 0.01, "grossQuantity": 31.13 },
    { "product": "Copilot", "sku": "Copilot Cloud Agent", "model": "Coding Agent model",
      "unitType": "ai-credits", "pricePerUnit": 0.01, "grossQuantity": 49.97 } ] }

31.13 + 49.97 = 81.10, which matches the "81 / 6,000 AI credits" numerator on the org billing page exactly. That agreement is the strongest evidence I have that the org lane reads the right thing.

What the card actually renders

Asserted on exact strings through the real UsageMenuCardView.Model.make(...) path, not on internals:

Case Assertion Location
Entitlement set title == "AI credits", detailLeftText == "31 / 3000", statusText == nil (bar renders) CopilotMenuCardModelTests.swift:149-151
No entitlement statusText == "31 credits used" (text row, bar suppressed) :161
Org lane row id copilot-org-credits, title carries the org login :170
Org via real fetch path org?.creditsUsed == 81.1, org?.entitlement == 6000 CopilotBudgetWebFetcherTests.swift:516-518
Org call rejected (403) copilotCredits?.org == nil, seat lane survives :582
Toggle off endpoint never contacted (Issue.record on any request) :641

The org tests drive descriptor.fetchPlan.fetchOutcome, so they exercise the production strategy rather than a shortcut.

What I can't evidence yet

No screenshot. Producing one means building this branch, packaging it, and running it against a real Copilot Business account — which per AGENTS.md is exactly the kind of validation that can raise Keychain prompts, so I didn't do it unasked. Happy to if you want it.

Two of three surfaces are untouched. I've added a table to the PR description rather than leave it implied: the menu card shows credits; the menu bar icon, the widget, and codexbar usage do not. Credits are a new UsageSnapshot field rather than a RateWindow (a lane without a user-entered entitlement has no percentage), and those three surfaces all build from primary/secondary/tertiary/extraRateWindows.

So today a Business token-billing user still gets an empty icon and has to open the menu. I can wire the icon up in this PR — publishing credits as a NamedRateWindow when an entitlement exists would cover icon, widget and the existing secondary-metric picker at once — but Copilot's extra windows are gated behind copilotBudgetExtrasEnabled in the card renderer, so it needs a call on whether to reuse that gate, add a new one, or exclude these windows from the card path to avoid double-rendering. Tell me which and I'll do it.

Since the PR was opened

  • Swapped a private number formatter for UsageFormatter.creditsNumberString (bfe422a), so Copilot and Codex credit numbers no longer disagree on grouping in the same menu.
  • Documented the global-entitlement limitation for multi-account setups, and the org-selection behaviour, in the PR description.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Aug 7, 2026
@KSEGIT
KSEGIT force-pushed the copilot-ai-credits branch from bfe422a to b7406fb Compare August 8, 2026 21:04
@KSEGIT

KSEGIT commented Aug 8, 2026

Copy link
Copy Markdown
Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 8, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot added merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. and removed merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Aug 8, 2026
@KSEGIT

KSEGIT commented Aug 15, 2026

Copy link
Copy Markdown
Author

Current-head live capture, taken from a build of this branch running against my Copilot Business seat:

Copilot credit bar at current head — Credits used 2455 / 3000

What this shows: a real token-billed Business seat rendering Credits used as a 2455 / 3000 bar in the menu card, with the reset date resolving to 1 Sep at 02:00, on a build of the current head rather than the earlier b7406fb8 one.

Being straight about its limits: this is the end state, not the transition. It does not by itself distinguish the cached text→bar repair from an ordinary successful refresh — the card reads "Updated just now", so a fetch had just landed. The offline sequence that isolates the cached rewrite (clear the entitlement with the network down, watch the row collapse to plain text and come back as a bar while the last-updated timestamp never advances) is still to come, and I'll post it as a follow-up.

Posting this now because it does close one gap the last review named: the live bar existing at the current head rather than only at b7406fb8.

KSEGIT added a commit to KSEGIT/CodexBar that referenced this pull request Aug 15, 2026
KSEGIT added a commit to KSEGIT/CodexBar that referenced this pull request Aug 15, 2026
KSEGIT added a commit to KSEGIT/CodexBar that referenced this pull request Aug 15, 2026
@KSEGIT

KSEGIT commented Aug 15, 2026

Copy link
Copy Markdown
Author

Current-head behavior evidence, all four frames captured from a build of this branch against my live Copilot Business seat (KSEGIT (Business), token-based billing).

1 — Bar renders at current head, online. Credits used as 2455 / 3000, reset date resolving.

online, 2455 / 3000

2 — The cached row survives a failed refresh. Network off; the card shows "The Internet connection appears to be offline" and the credit row is still rendered as a bar at 2455 / 3000 from cache, rather than disappearing or losing its denominator.

offline, 2455 / 3000

3 — A changed entitlement re-renders the row. Allowance changed 30005000; the row becomes 2455 / 5000 with a correspondingly shorter fill. Same numerator, new denominator, no re-fetch of usage data involved in producing the ratio.

online, 2455 / 5000

4 — And that survives offline too. Network off again; offline banner present, row still 2455 / 5000 from cache at the new entitlement.

offline, 2455 / 5000

What these do and don't establish

They establish, on the current head: the bar renders on a real token-billed Business seat; the cached row survives a failed refresh with its denominator intact at two different entitlements; and changing the entitlement re-renders the ratio.

They do not isolate the in-place cached rewrite as tightly as I'd like. Frames 2 and 4 are both offline but sit either side of a brief reconnect, so there is no single unbroken offline stretch spanning an entitlement change. I'd rather say that plainly than let the sequence imply more than it shows.

Worth noting why the literal "clear it and watch it return to text" capture is awkward on my setup specifically: the settings field resolves as account override ?? global fallback, and I have a global fallback of 3000 stored from before per-account entitlements existed. Clearing the field removes the override, the getter immediately falls back to 3000, and the box repopulates — so an empty field is unreachable without also removing the global value. That is the documented "Account field semantics" limitation, not the cached-row path, and it is the reason the evidence above changes the entitlement rather than clearing it. If that fallback-shadowing is itself worth changing, I'm happy to make clearing write an explicit empty override in a follow-up — it's a small change but it widens this diff.

Unit coverage for the exact text↔bar transition is in UsageStoreCoverageTests: text→bar on entering an entitlement, clear-restores-text-only, no-numeric-usage no-op, and the stale-reset-baseline path.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 15, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event exact_review_queue).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Aug 15, 2026
@KSEGIT
KSEGIT force-pushed the copilot-ai-credits branch from 2d25ce6 to 31281db Compare August 15, 2026 14:53
@KSEGIT

KSEGIT commented Aug 16, 2026

Copy link
Copy Markdown
Author

@steipete — short status, since my last "ready to merge" note is well out of date and the thread has grown a lot since.

The proof blocker is cleared. Review now reads ready for maintainer look with no actionable findings, real behavior verified from current-head captures on my live Business seat, and the earlier release-note issue fixed. What's left is the product question rather than anything mechanical: whether a menu-card-only, per-account user-entered credit ceiling is the contract you want, with the menu-bar icon, widget, and CLI deliberately left untouched. The recommendation on the review is to approve that seat-only scope and treat the other surfaces as follow-up, but that's your call, and I'd rather have it settled than guess.

The branch currently conflicts with main — this repo moves fast enough that it drifts within a day, and the conflicts are the mechanical kind (an allowlist line-anchor file and a changelog list that both moved on main). I've deliberately not been force-pushing rebases on a loop while it waits for a look. Say the word, or just leave a review, and I'll rebase and have it green within the hour.

No rush from my side, and no more pings from me on this — happy for it to sit until you have time.

KSEGIT and others added 13 commits August 16, 2026 17:22
Remove the opt-in organization billing lane pending an approved
authorization model for org-wide billing reads with device-flow tokens.

Rewrite the cached seat credit row immediately when the entitlement
changes so a stale denominator or bar never survives a failed refresh.
Text-only credit rows carried no structured usage, so entering an
entitlement during an offline or failed refresh left the cached row
without its bar. Stamp usageValue on the row at fetch time and use it
as the repair numerator.
Rebases landed the entry under 0.49.6, which shipped on 2026-08-14, so
merging would advertise this feature as part of that release. Move it to
0.49.7 Unreleased; 0.49.6 is now byte-identical to main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016puVootfTssyPQe2TzmK1M
The credit-entitlement additions to MenuCardView, SettingsStore, and
UsageFetcher shift 13 allowlisted provider constructs past the
gatekeeper's two-line anchor tolerance. Point each entry at its current
line; the anchors, provider sets, and fingerprints are unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016puVootfTssyPQe2TzmK1M
@KSEGIT
KSEGIT force-pushed the copilot-ai-credits branch from 31281db to c39ff51 Compare August 16, 2026 15:41
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Aug 16, 2026
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. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Copilot Business (token-based billing): surface GitHub AI credit usage — card is blank because every quota reports unlimited/zero-entitlement

2 participants