Skip to content

fix(desktop-windows): wire chat quota gate into main-window send path (#10240) - #12203

Merged
kodjima33 merged 1 commit into
BasedHardware:mainfrom
formed2forge:fix/windows-chat-quota-gate
Aug 27, 2026
Merged

kodjima33 merged 1 commit into
BasedHardware:mainfrom
formed2forge:fix/windows-chat-quota-gate

Conversation

@formed2forge

@formed2forge formed2forge commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes #10240.

The main-window send path had no pre-send quota check — it fired the request, received the server's canned "You've reached your limit" reply as a chat message, and then UsageLimitTriggerHost polled the quota endpoint post-hoc to show the upgrade popup. This is now replaced with a proper pre-send gate matching Mac's AgentBridge.quotaExceeded parity and the bar's existing FloatingBarUsageLimiter parity:

  • useChat.send() calls mainChatQuotaGate.check() before the request fires. If blocked: showUsageLimit('chat') is raised immediately and the send returns — no request sent, no history entry, no canned server reply.
  • UsageLimitTriggerHost now calls chatQuotaGate.sync() on the busy→idle edge to refresh the snapshot for the next send's check, instead of polling maybeTriggerChatQuotaPopup.
  • maybeTriggerChatQuotaPopup removed from usageLimit.ts (no remaining callers).

Test plan

  • node_modules/.bin/vitest run src/renderer/src/lib/usageLimit.test.ts src/renderer/src/lib/chatQuotaGate.test.ts src/renderer/src/hooks/useChat.test.tsx — 68/68 pass
  • New describe('useChat — chat quota gate') covers: blocked send (popup shown, no fetch, no history entry) and allowed send (proceeds, recordQuery called)

Product invariants affected

  • INV-CHAT-1 (one shared transcript across surfaces): this change adds a pre-send quota gate to the main-window send path, maintaining the same chat flow invariant as Mac and the bar.

Failure-Class: none

🤖 Generated with Claude Code

Review in cubic

@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Thanks @formed2forge — this is a clean close-out of the main-window half of #10240, and it lands exactly where the tree was waiting for it: main's UsageLimitTriggerHost.tsx still carries the TODO(#10240 stream-1 ...) asking for precisely this wiring.

What I verified on the diff:

  • hooks/useChat.ts — the pre-send gate sits behind the sendingRef re-entrancy latch and ahead of setBusy(true), so a blocked send leaves no history entry and doesn't trip the busy state. Signed-out users fail open, and recordQuery() keeps the optimistic delta honest between syncs (the same contract the bar's barSend.ts already uses).
  • components/settings/billing/UsageLimitTriggerHost.tsx — the busy→idle edge now calls mainChatQuotaGate.sync() instead of the post-hoc quota probe; the 60s sync floor in chatQuotaGate.ts keeps that from becoming a per-reply network hit, and the exported singleton is the right shape for it.
  • lib/usageLimit.ts + lib/usageLimit.test.ts — maybeTriggerChatQuotaPopup is fully removed along with its tests. Two prose mentions survive elsewhere (a historical comment in chatQuotaGate.ts and docs/mac-parity-audit/track2-groundtruth/07-usage-limiter.md); a small follow-up touch-up would be nice but nothing blocks on it.
  • hooks/useChat.test.tsx — the two new cases cover the behavioral difference that matters: blocked send shows the popup with no fetch and no history entry; allowed send proceeds and records the query optimistically.
  • changelog/unreleased/2026-08-chat-quota-gate.json — accurate one-line user-facing description of the change.

The blocker is branch state, not the change: the branch carries 43 upstream commits after its last sync, which is why GitHub shows a 208-file diff and conflicts against main. Everything outside the six files above is content that already landed through merged PRs (#11933, #12019, #12089, #12096, #12109, …), including all of the workflow/AGENTS.md/monitoring churn in the file list. Syncing your fork with upstream and rebasing fix/windows-chat-quota-gate onto current main will collapse the PR to just your six files and let Actions run the vitest suites — your reported 68/68 across usageLimit / chatQuotaGate / useChat matches the exact test count at this head, so CI should confirm quickly.

Leaving for human maintainer review before merge: routine sign-off on the rebased head once CI confirms the three suites — the Mac-parity direction itself is already settled in the issue and in chatQuotaGate.ts, so no product decision is needed.


by AI on behalf of David.

@Git-on-my-level Git-on-my-level added needs-rebase PR has merge conflicts / is behind main and needs rebasing positive-signal Automation verified a genuine fix/quality contribution windows Windows desktop work labels Aug 26, 2026
@formed2forge
formed2forge force-pushed the fix/windows-chat-quota-gate branch from 800a034 to 26bc736 Compare August 26, 2026 14:51
@formed2forge

Copy link
Copy Markdown
Contributor Author

Rebased onto current main — PR now shows 6 files (the 6 Windows files in the fix commit). Mergeable.

…BasedHardware#10240)

Replaces the post-send polling approach in UsageLimitTriggerHost with a
pre-send gate check in useChat.send(), matching Mac's AgentBridge.quotaExceeded
parity: a blocked send never fires the request, shows the upgrade popup
immediately, and leaves the chat history untouched. UsageLimitTriggerHost now
refreshes the gate snapshot (chatQuotaGate.sync) on the busy→idle edge so the
next send check reads a fresh verdict without a network round trip.

Removes maybeTriggerChatQuotaPopup (no callers remain) and its tests.

Failure-Class: none

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KADKRuaPJdho9CDE7nLXQP
@formed2forge
formed2forge force-pushed the fix/windows-chat-quota-gate branch from 26bc736 to beac65a Compare August 26, 2026 15:06
@Git-on-my-level Git-on-my-level removed the needs-rebase PR has merge conflicts / is behind main and needs rebasing label Aug 27, 2026
@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Thanks @formed2forge — the rebase did exactly what was asked: the PR now shows just the six Windows files from the fix commit, and GitHub reports it mergeable with no conflicts.

I re-verified on the rebased head (beac65a):

  • Ran the three affected suites at this commit in a clean worktree: 68/68 pass (usageLimit 8, chatQuotaGate 25, useChat 35) — matches your test plan exactly.
  • hooks/useChat.ts — gate still sits behind the re-entrancy latch and ahead of setBusy(true); blocked sends show the popup with no request and no history entry, and the signed-out fail-open guard mirrors the bar's isSignedIn() pattern in barSend.ts.
  • components/settings/billing/UsageLimitTriggerHost.tsx — busy→idle edge now refreshes the gate snapshot; the 60s sync floor in chatQuotaGate.ts keeps that off the per-reply network path.
  • lib/usageLimit.ts / usageLimit.test.ts — maybeTriggerChatQuotaPopup fully removed, no dangling importers.
  • changelog/unreleased/2026-08-chat-quota-gate.json — accurate and matches the fragment convention.

One cosmetic nit, no action needed: the new in-quota test uses void act(...) without awaiting, which trips a React act() warning on stderr.

CI has re-queued on the new head — Desktop Checks is green; Desktop Windows CI was still pending at review time. Removed the stale needs-rebase label. Leaving merge sign-off to a human maintainer.


by AI on behalf of David.

@formed2forge

Copy link
Copy Markdown
Contributor Author

Rebased and all 68/68 tests pass. Ready for maintainer merge sign-off.

@formed2forge

Copy link
Copy Markdown
Contributor Author

The Detect Changes job is failing due to runner starvation — a pure CI infrastructure issue unrelated to this PR. Could a maintainer re-run? Once green this is ready for review.

@kodjima33 kodjima33 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Clean, scoped desktop bug fix (chat quota pre-send gate, closes #10240), matches Mac/bar parity pattern, tests added, not already fixed on main. Stale Android/Dart 'Detect Changes' check re-ran clean. Owner-override (desktop fix).

@kodjima33
kodjima33 merged commit da3d62a into BasedHardware:main Aug 27, 2026
14 of 15 checks passed
@cursor
cursor Bot deleted the fix/windows-chat-quota-gate branch September 2, 2026 02:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

positive-signal Automation verified a genuine fix/quality contribution windows Windows desktop work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows port: deferred-work follow-ups from #9894 landing

3 participants