Skip to content

Fix usage meters and iOS composer send freeze#806

Merged
arul28 merged 2 commits into
mainfrom
ade/start-skill-usage-meters-that-c892fdbb
Jul 13, 2026
Merged

Fix usage meters and iOS composer send freeze#806
arul28 merged 2 commits into
mainfrom
ade/start-skill-usage-meters-that-c892fdbb

Conversation

@arul28

@arul28 arul28 commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • Classify Codex quota windows by their declared duration so weekly and five-hour meters remain correct even when providers reorder them.
  • Extract provider quota parsing into a focused module while preserving the existing usage service contract.
  • Add renderer and service regression coverage for both pacing meters.
  • Defer and coalesce iOS composer focus transitions so a chat-specific SwiftUI update cannot deadlock the main thread during send.
  • Update usage-tracking, architecture, settings, and iOS companion documentation.

Validation

  • Desktop usage service: 132 tests passed.
  • Desktop usage renderer: 32 tests passed.
  • Desktop CI shard 1/8: 960 tests passed.
  • Desktop CI shard 2/8: affected usage tests passed; an unrelated pre-existing storage-insights timeout reproduced in isolation.
  • iOS focused suite: 19 tests passed, including repeated composer-focus regression runs.
  • ADE CLI typecheck and 51 targeted sync tests passed.
  • TUI suite: 47 files and 871 tests passed.
  • Documentation validation: 186 files and 101 internal links passed.

ADE   Open in ADE  ·  ade/start-skill-usage-meters-that-c892fdbb branch  ·  PR #806

Summary by CodeRabbit

  • New Features

    • Added support for displaying Claude usage windows, weekly and five-hour quotas, model-specific limits, and extra usage details.
    • Improved Codex quota handling across five-hour and weekly limits, including reset times and usage duration.
    • Enhanced quota pacing indicators to show progress, trends, and projected usage.
  • Bug Fixes

    • Improved composer focus transitions to prevent flicker and ensure the latest focus request is applied.

Greptile Summary

This PR updates quota parsing and iOS composer focus handling. The main changes are:

  • Extracted Claude and Codex quota parsing into providerQuotaParsers.ts.
  • Classified Codex quota windows by advertised duration instead of primary/secondary position.
  • Added usage service and renderer tests for malformed timestamps, reordered Codex windows, and pacing meters.
  • Deferred and coalesced iOS composer focus transitions to avoid synchronous UIKit responder changes during SwiftUI updates.
  • Updated usage-tracking, architecture, settings, and iOS companion documentation.

Confidence Score: 5/5

Safe to merge with low risk.

The updated code is focused, preserves the existing usage service contract, and includes tests for the quota parsing and composer focus paths changed in this PR.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • The T-Rex code-execution run was performed and a general-contract-validation-proof was produced, documenting the exact command, working directory, timestamps, and an EXIT_CODE of 0.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
apps/desktop/src/main/services/usage/providerQuotaParsers.ts Adds focused Claude/Codex quota normalization, including duration-based Codex window classification and safer malformed reset handling; no issues found.
apps/desktop/src/main/services/usage/usageTrackingService.ts Replaces inline quota parsing with imports from the new parser module while preserving poll/fallback behavior; no issues found.
apps/desktop/src/main/services/usage/usageTrackingService.test.ts Adds tests for malformed Claude timestamps and Codex duration-based/reordered window parsing; no issues found.
apps/desktop/src/renderer/components/usage/usage.test.tsx Adds renderer coverage for both Codex pacing meters when both quota windows are present; no issues found.
apps/ios/ADE/Views/Work/WorkComposerTypedTriggers.swift Introduces a shared main-actor focus scheduler that defers and coalesces UIKit responder transitions for both composer variants; no issues found.
apps/ios/ADETests/WorkComposerTriggerDetectorTests.swift Updates composer focus tests to assert deferred transitions, settled no-ops, and latest-request-wins coalescing; no issues found.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Provider as Claude/Codex quota API or CLI
participant Service as usageTrackingService
participant Parser as providerQuotaParsers
participant Snapshot as Usage snapshot/cache
participant Renderer as UsageQuotaPanel
participant SwiftUI as SwiftUI composer update
participant Scheduler as WorkComposerFocusScheduler
participant UIKit as UITextView responder

Provider->>Service: Return quota payload
Service->>Parser: parseClaudeWindows / parseCodexRateLimitWindows
Parser-->>Service: Normalized UsageWindow[] and extraUsage
Service->>Snapshot: Store provider windows and pacing inputs
Renderer->>Snapshot: getSnapshot / noteDemand
Snapshot-->>Renderer: Windows with pacing meters

SwiftUI->>Scheduler: apply latest focus binding
Scheduler->>Scheduler: Coalesce pending request
Scheduler-->>SwiftUI: Yield past updateUIView
Scheduler->>UIKit: become/resign first responder only if latest request still applies
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Provider as Claude/Codex quota API or CLI
participant Service as usageTrackingService
participant Parser as providerQuotaParsers
participant Snapshot as Usage snapshot/cache
participant Renderer as UsageQuotaPanel
participant SwiftUI as SwiftUI composer update
participant Scheduler as WorkComposerFocusScheduler
participant UIKit as UITextView responder

Provider->>Service: Return quota payload
Service->>Parser: parseClaudeWindows / parseCodexRateLimitWindows
Parser-->>Service: Normalized UsageWindow[] and extraUsage
Service->>Snapshot: Store provider windows and pacing inputs
Renderer->>Snapshot: getSnapshot / noteDemand
Snapshot-->>Renderer: Windows with pacing meters

SwiftUI->>Scheduler: apply latest focus binding
Scheduler->>Scheduler: Coalesce pending request
Scheduler-->>SwiftUI: Yield past updateUIView
Scheduler->>UIKit: become/resign first responder only if latest request still applies
Loading

Reviews (2): Last reviewed commit: "fix: address usage and focus review edge..." | Re-trigger Greptile

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Jul 13, 2026 10:38pm

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Desktop usage quotas

Layer / File(s) Summary
Provider quota normalization
apps/desktop/src/main/services/usage/providerQuotaParsers.ts
Claude and Codex responses are normalized into usage windows, reset durations, window types, and extra usage data.
Usage polling integration and parser validation
apps/desktop/src/main/services/usage/usageTrackingService.ts, apps/desktop/src/main/services/usage/usageTrackingService.test.ts
Polling imports the extracted parsers, while tests cover duration-based Codex window classification.
Codex pacing panel coverage
apps/desktop/src/renderer/components/usage/usage.test.tsx
The usage panel test covers pacing UI for concurrent five-hour and weekly Codex windows.

iOS composer focus scheduling

Layer / File(s) Summary
Coalesced composer focus transitions
apps/ios/ADE/Views/Work/WorkComposerTypedTriggers.swift
A shared scheduler asynchronously applies focus requests, cancels superseded tasks, and is used by both composer coordinators.
Asynchronous focus behavior validation
apps/ios/ADETests/WorkComposerTriggerDetectorTests.swift
Tests await focus transitions and validate request coalescing, responder state, and transition counters.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • arul28/ADE#327: Also updates the desktop usage header and UsageQuotaPanel snapshot flow.

Suggested labels: desktop, ios, docs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the two main areas changed: usage meter parsing/UI and iOS composer focus handling.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ade/start-skill-usage-meters-that-c892fdbb

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

❤️ Share

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

@arul28 arul28 changed the title codex-usage-meters-diagnosis -> Primary Fix usage meters and iOS composer send freeze Jul 13, 2026
@arul28

arul28 commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

@copilot review but do not make fixes

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/ios/ADE/Views/Work/WorkComposerTypedTriggers.swift (1)

311-355: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider skipping Task creation when nothing needs to change.

The coalescing shortcut at Line 324 only reuses pendingTask when a request with the same isFocused arrives while a task is already pending. Once that task completes (pendingTask becomes nil), any subsequent call with the same isFocused value falls through to spawn a brand-new Task + Task.yield() even though the responder already matches the desired state — this happens on every updateUIView call while the composer stays focused (i.e. on effectively every keystroke), since applyFocusRequest is called unconditionally from updateUIView (Line 416, Line 590).

This doesn't cause incorrect behavior (the task body's own guards make it a no-op), but it's avoidable churn on a hot path.

♻️ Proposed early-exit to avoid redundant Task creation
   func apply(_ isFocused: Bool, to textView: UITextView) -> Task<Void, Never>? {
     // SwiftUI may update the representable more than once for the same state.
     // Keep the queued transition instead of canceling it without a replacement.
     if lastRequest == isFocused, pendingTask != nil { return pendingTask }

     let previousRequest = lastRequest
     lastRequest = isFocused
+
+    // No transition in flight and the responder already matches the
+    // request: skip spawning a Task on every re-render (e.g. per keystroke)
+    // when nothing actually needs to change.
+    if pendingTask == nil, textView.isFirstResponder == isFocused {
+      return nil
+    }
+
     pendingTask?.cancel()
     pendingTask = nil
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ios/ADE/Views/Work/WorkComposerTypedTriggers.swift` around lines 311 -
355, Update WorkComposerFocusScheduler.apply to return early when the requested
focus state already matches the textView’s current responder state and no
transition is pending, avoiding a new Task and Task.yield on repeated
updateUIView calls. Preserve queued-task coalescing and the existing
initial-unfocused behavior, and only schedule a task when the responder state
still needs to change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/desktop/src/main/services/usage/providerQuotaParsers.ts`:
- Around line 43-46: Update computeResetsInMs to validate the parsed timestamp
with an isFinite check before subtracting Date.now(); return 0 for malformed or
otherwise non-finite dates, while preserving the existing behavior for valid
future and past dates.

---

Nitpick comments:
In `@apps/ios/ADE/Views/Work/WorkComposerTypedTriggers.swift`:
- Around line 311-355: Update WorkComposerFocusScheduler.apply to return early
when the requested focus state already matches the textView’s current responder
state and no transition is pending, avoiding a new Task and Task.yield on
repeated updateUIView calls. Preserve queued-task coalescing and the existing
initial-unfocused behavior, and only schedule a task when the responder state
still needs to change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9a4e8017-030c-4a87-a7f7-c319a25482be

📥 Commits

Reviewing files that changed from the base of the PR and between 8c4c2fb and 9b25fee.

⛔ Files ignored due to path filters (4)
  • docs/ARCHITECTURE.md is excluded by !docs/**
  • docs/features/onboarding-and-settings/README.md is excluded by !docs/**
  • docs/features/onboarding-and-settings/usage-tracking.md is excluded by !docs/**
  • docs/features/sync-and-multi-device/ios-companion.md is excluded by !docs/**
📒 Files selected for processing (6)
  • apps/desktop/src/main/services/usage/providerQuotaParsers.ts
  • apps/desktop/src/main/services/usage/usageTrackingService.test.ts
  • apps/desktop/src/main/services/usage/usageTrackingService.ts
  • apps/desktop/src/renderer/components/usage/usage.test.tsx
  • apps/ios/ADE/Views/Work/WorkComposerTypedTriggers.swift
  • apps/ios/ADETests/WorkComposerTriggerDetectorTests.swift

Comment thread apps/desktop/src/main/services/usage/providerQuotaParsers.ts
@arul28

arul28 commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

Reviewed commit: 5e5832e880

ℹ️ 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".

@arul28
arul28 merged commit 434292f into main Jul 13, 2026
33 checks passed
@arul28
arul28 deleted the ade/start-skill-usage-meters-that-c892fdbb branch July 13, 2026 23:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant