Skip to content

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

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

Copilot: surface AI credit usage for token-based-billing seats#2647
KSEGIT wants to merge 10 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-08. Since #2613 landed stage 1 (decoding credits_used and rendering it through the shared provider-detail contract), this branch was rebuilt on current main and now carries only the remainder: the opt-in organization lane, user-entered credit entitlements (now per GitHub account), and the progress-bar display beyond stage 1. Seat credits flow through main's shared detail rows — no parallel credit state.

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 two places CodexBar didn't read:

  1. credits_used, already present on each quota snapshot in the response CodexBar already fetches (landed in Decode Copilot credits_used for token-billed seats (#2593) #2613).
  2. GET /organizations/{org}/settings/billing/ai_credit/usage — org-wide, per-model (this PR).

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 lane with no entitlement renders a text row, 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 and progress ratio (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.

Org lane (opt-in, off by default). GET /organizations/{org}/settings/billing/ai_credit/usage (the documented path), org read from organization_login_list.first, summing usageItems[].grossQuantity filtered to credit unit types — "credits" per the organization-report docs, "ai-credits" per the user-level docs and live org responses; both are accepted, unrelated unit types are rejected (a response with no credit items returns nil, never a fabricated 0). Strictly best-effort, shaped like the existing addBudgetWindowsIfNeeded: any failure returns the snapshot untouched. The device flow still requests only read:user, so rejection is the expected common case, not an error — it logs a warning rather than failing silently.

On my account the org endpoint returns 31.13 + 49.97 = 81.10, matching the billing page's numerator exactly.

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

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 lane 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.

Testing

  • 191 focused tests across the 10 touched suites green (fetcher, parser, settings, wiring, menu-card model, detail sections, persistence round-trip).
  • make check — 0 violations across 1,811 files.
  • make test — full suite green except MiniMaxMenuCardBillingTests, which fails identically on a clean origin/main checkout on this machine (locale-dependent number grouping, "1.234" vs "1,234"); unrelated to this PR.
  • 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. New 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).

Known limitations

  • Localization: L("AI credits"), L("Org credits"), 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.
  • Org selection: organization_login_list.first wins when a user belongs to several orgs. The row title names the org so it isn't ambiguous, but there's no picker.
  • 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.
  • Entitlement lives on the fetch path rather than being applied at render time. Consequence: the bar appears only after a successful refresh, and clearing the field leaves the cached denominator until one succeeds.
  • 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

9 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".

else { return nil }
return CopilotDeviceFlow.makeRequestURL(
host: CopilotUsageFetcher.apiHost(enterpriseHost: enterpriseHost),
path: "/orgs/\(encoded)/settings/billing/ai_credit/usage")

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 Use the documented organizations billing path

For the organization AI-credit flow, GitHub's REST docs list this endpoint as GET /organizations/{org}/settings/billing/ai_credit/usage, not /orgs/{org}/... (checked https://docs.github.com/en/rest/billing/usage#get-billing-ai-credit-usage-report-for-an-organization). With the current path, authorized org admins receive a 404 and fetchCreditsUsed returns nil, so the new organization credits row never appears.

Useful? React with 👍 / 👎.

return 0
}

let creditItems = report.usageItems.filter { $0.unitType == "ai-credits" }

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 Accept the org AI-credit unit type

For organization AI-credit reports, GitHub's example response uses unitType: "credits", while "ai-credits" is shown for user-level reports (checked https://docs.github.com/en/rest/billing/usage#get-billing-ai-credit-usage-report-for-an-organization). After the path is corrected, real org responses will fall into the “none matched” branch here and return nil, so organization usage still will not render unless this accepts the org unit type.

Useful? React with 👍 / 👎.

@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 real behavior proof before merge. Reviewed August 9, 2026, 6:02 PM ET / 22:02 UTC.

ClawSweeper review

What this changes

The PR adds per-Copilot-account AI-credit entitlements and renders token-billed seat consumption as a menu-card text row or progress bar.

Merge readiness

Blocked until stronger real behavior proof is added - 4 items remain

Keep this PR open: it adds the remaining menu-card presentation beyond current main’s raw Copilot credit row, but its claimed offline cached-row repair still cannot turn a text-only row into a bar after an entitlement is entered.

Priority: P2
Reviewed head: 14599df8eb86225f1ae8f1189183cf6597189a1a

Review scores

Measure Result What it means
Overall readiness 🦐 gold shrimp (3/6) Useful live UI evidence and broad tests exist, but a P2 cached-state defect and proof predating the current repair keep the PR below merge-ready.
Proof confidence 🦐 gold shrimp (3/6) Needs stronger real behavior proof before merge: The supplied live screenshot convincingly shows the original menu-card bar, but it predates the current head’s cached-row repair and does not demonstrate the text-row-to-bar transition; post redacted after-fix evidence from the current head. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Patch quality 🦐 gold shrimp (3/6) 1 actionable review finding remain.

Verification

Check Result Evidence
Real behavior Needs proof Needs stronger real behavior proof before merge: The supplied live screenshot convincingly shows the original menu-card bar, but it predates the current head’s cached-row repair and does not demonstrate the text-row-to-bar transition; post redacted after-fix evidence from the current head. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed 6 items Current main baseline: Current main already decodes Copilot credits and renders a plain detail row, but has no entitlement-aware progress data; this PR still has a distinct UI feature to contribute.
Cached text row cannot be rebuilt: The current PR head only updates rows that already have progress. A normal no-entitlement credit row has no progress, so entering an entitlement returns without changing the cached snapshot.
Fetcher confirms the failing state: The PR deliberately creates a text-only row without progress when no entitlement is configured, which is the common initial state the cached update must handle.
Findings 1 actionable finding [P2] Preserve numeric usage for text-only credit rows
Security None None.

How this fits together

CodexBar fetches Copilot usage into a provider snapshot and renders its detail rows in the macOS menu card. A saved seat-credit entitlement is combined with observed credit usage to display an accurate ratio without inventing a quota.

flowchart LR
A[Copilot usage response] --> B[Usage snapshot]
C[Saved seat entitlement] --> D[Credit row builder]
B --> D
D --> E[Cached provider snapshot]
E --> F[Menu-card credit row]
Loading

Before merge

  • Add real behavior proof - Needs stronger real behavior proof before merge: The supplied live screenshot convincingly shows the original menu-card bar, but it predates the current head’s cached-row repair and does not demonstrate the text-row-to-bar transition; post redacted after-fix evidence from the current head. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • Preserve numeric usage for text-only credit rows (P2) - An initial no-entitlement snapshot has progress == nil, so this guard returns before the setter can rebuild it after the user enters an entitlement. The added text-only-row test currently asserts that no-op, leaving offline or failed-refresh users without the promised immediate bar; retain structured usage for that row and cover the text-to-bar transition.
  • Resolve merge risk (P1) - An existing cached text-only credit row remains unchanged when a user enters an entitlement during an offline or failed refresh, so the promised local bar update is not delivered.
  • Complete next step (P2) - The repair is source-clear, but current-head real behavior proof must come from the contributor’s Copilot setup before merge.

Findings

  • [P2] Preserve numeric usage for text-only credit rows — Sources/CodexBar/Providers/Copilot/UsageStore+CopilotCredits.swift:30-35
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Patch size 27 files, +1,104/-39 lines The change spans shared detail-row, persistence, Copilot, and menu-card layers.
Production versus tests app/core +357, tests +728, docs/release +19 The substantial regression coverage is useful, but the affected text-row transition remains asserted as a no-op.

Merge-risk options

Maintainer options:

  1. Repair the text-row transition (recommended)
    Preserve structured usage for no-entitlement rows and add coverage that entering an entitlement changes a cached text row into a bar without a refresh.

Technical review

Best possible solution:

Retain structured raw credit usage for every seat-credit row, then rebuild text-only and progress rows immediately when the entitlement changes; attach redacted current-head proof of that offline transition.

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

Yes, from source: fetch and cache a token-billed credit row without an entitlement, enter one while refresh fails, and the current guard leaves the text-only row unchanged.

Is this the best way to solve the issue?

No. The proposed immediate-update path lacks a structured numerator for text-only rows, so it cannot create the promised cached bar without a successful refresh.

Full review comments:

  • [P2] Preserve numeric usage for text-only credit rows — Sources/CodexBar/Providers/Copilot/UsageStore+CopilotCredits.swift:30-35
    An initial no-entitlement snapshot has progress == nil, so this guard returns before the setter can rebuild it after the user enters an entitlement. The added text-only-row test currently asserts that no-op, leaving offline or failed-refresh users without the promised immediate bar; retain structured usage for that row and cover the text-to-bar transition.
    Confidence: 0.99

Overall correctness: patch is incorrect
Overall confidence: 0.99

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 6f27b777afba.

Labels

Label justifications:

  • P2: The PR has a bounded but user-visible Copilot settings and menu-card correctness defect.
  • merge-risk: 🚨 compatibility: Existing cached Copilot rows can fail to reflect a newly saved entitlement until a successful refresh.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The supplied live screenshot convincingly shows the original menu-card bar, but it predates the current head’s cached-row repair and does not demonstrate the text-row-to-bar transition; post redacted after-fix evidence from the current head. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The supplied live screenshot convincingly shows the original menu-card bar, but it predates the current head’s cached-row repair and does not demonstrate the text-row-to-bar transition; post redacted after-fix evidence from the current head.

Evidence

What I checked:

Likely related people:

  • steipete: Recent declarative-detail and Copilot refactors, plus the public sequencing direction for this work, connect this person to the affected UI and provider boundary. (role: recent area contributor; confidence: high; commits: 8314a74e8613, 61fbe9fac507; files: Sources/CodexBar/ProviderDetailSectionsContent.swift, Sources/CodexBarCore/ProviderDetailSection.swift, Sources/CodexBar/Providers/Copilot/CopilotProviderImplementation.swift)
  • Yuxin-Qiao: The merged stage-one Copilot credits change established the raw credit detail row that this PR extends. (role: introduced current credit-decoding behavior; confidence: high; commits: 2d76cd9e9fca; files: Sources/CodexBarCore/Providers/Copilot/CopilotUsageFetcher.swift)
  • Zihao Qi: The unlimited-quota guard remains the compatibility boundary this feature must preserve. (role: adjacent behavior contributor; confidence: medium; commits: 6d71af30b84d; files: Sources/CodexBarCore/Providers/Copilot/CopilotUsageFetcher.swift)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Retain structured usage for text-only rows and add a regression test for entering an entitlement without a successful refresh.
  • Post redacted current-head runtime proof showing a text-only credit row changing to a bar after editing the entitlement while refresh is unavailable.

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 (24 earlier review cycles; latest 8 shown)
  • reviewed 2026-08-08T22:58:20.379Z sha b7406fb :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-09T05:44:03.657Z sha b7406fb :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-09T07:16:30.325Z sha b7406fb :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-09T08:32:39.020Z sha b7406fb :: needs maintainer review before merge. :: none
  • reviewed 2026-08-09T11:00:08.310Z sha b7406fb :: needs maintainer review before merge. :: none
  • reviewed 2026-08-09T14:17:20.254Z sha b7406fb :: found issues before merge. :: [P2] Update cached credit rows when entitlements change
  • reviewed 2026-08-09T19:21:46.140Z sha 14599df :: needs changes before merge. :: [P2] Preserve a numerator for text-only credit rows
  • reviewed 2026-08-09T19:49:53.189Z sha 14599df :: needs changes before merge. :: [P2] Rebuild text-only rows when an entitlement is entered

@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. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. labels Aug 8, 2026
@KSEGIT

KSEGIT commented Aug 9, 2026

Copy link
Copy Markdown
Author

After-fix runtime proof — head b7406fb8, built from the branch, packaged and run locally 2026-08-09 against my live Copilot Business seat.

Menu card (live)

Copilot menu card: Credits used 1188 / 3000 with progress bar

  • CREDITS"Credits used — 1188 / 3000", reset 1 Sep at 01:00, progress bar at ~40% (1188/3000 = 39.6%). Numerator comes from the already-fetched copilot_internal/user response; the 3000 denominator is the per-account seat entitlement.
  • The bar only renders because an entitlement is set — without one this is a text row, per the no-fabricated-ceiling design.

Org lane trace (live)

log show on com.steipete.codexbar:providers during a refresh:

09:23:06 Error CodexBar: [providers] Copilot org credits unavailable (statusCode=404)

The best-effort degradation works exactly as designed: warning logged, card unaffected, no fabricated org row, seat lane intact.

A finding from the live run: the 404 is a scope issue, not a path issue

With a read:org token I get 200 from both /orgs/{org}/settings/billing/ai_credit/usage and /organizations/{org}/settings/billing/ai_credit/usage, for every org I belong to (verified via gh api). So both spellings route — and this PR uses the documented /organizations/ one.

The Copilot device flow requests only read:user, and GitHub hides org billing endpoints from such tokens behind 404 (the docs require org "Administration" read for fine-grained tokens; classic tokens need read:org plus admin membership). So as shipped, the org lane can only succeed for users whose token already carries org billing visibility — the device-flow token never will. Options: (a) ship as-is — opt-in lane, documented best-effort; (b) add read:org to the device-flow scope so the lane can actually light up for org admins, at the cost of a bigger scope ask on every Copilot sign-in. I stayed with (a) since (b) is a product call, but flagging it explicitly now that it's proven live rather than assumed.

@KSEGIT

KSEGIT commented Aug 9, 2026

Copy link
Copy Markdown
Author

@clawsweeper re-review

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. 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 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. labels Aug 9, 2026
@KSEGIT

KSEGIT commented Aug 9, 2026

Copy link
Copy Markdown
Author

@steipete Hi there, I think it is ready to merge :) Let me know if you want me to do anything more :)

@clawsweeper clawsweeper Bot added 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. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. and removed 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. labels Aug 9, 2026
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.
@KSEGIT

KSEGIT commented Aug 9, 2026

Copy link
Copy Markdown
Author

@clawsweeper re-review

Addressed the 2026-08-09 14:17 UTC review on head 14599df:

  • Org lane deferred (owner-decision item): removed the opt-in organization billing request, org entitlements, toggle, fetcher, and docs — this PR is now seat credits only, per the recommended option. Happy to bring the org lane back in a follow-up once an authorization model is approved.
  • Stale cached rows fixed (P2): changing or clearing the seat entitlement now rewrites the cached Credits used row synchronously in both the live snapshot and the last-known-reset baseline (numerator taken from the row's structured progress, never parsed from display text), so an offline/failed refresh can no longer leave a stale denominator or bar. Covered by 5 new UsageStoreCoverageTests cases including the stale-reset-baseline path.

make check clean (SwiftFormat + SwiftLint, 0 violations); focused Copilot/UsageStore suites green. Full make test: 68/69 groups pass — the one failure is a pre-existing locale-sensitive MiniMax billing assertion on main (unrelated files, untouched by this PR).

@clawsweeper

clawsweeper Bot commented Aug 9, 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: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. proof: sufficient Contributor real behavior proof is sufficient. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

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