Skip to content

Let a monthly quota raise a pace warning - #258

Merged
tsouth89 merged 3 commits into
mainfrom
fix/monthly-pace-warnings
Aug 12, 2026
Merged

Let a monthly quota raise a pace warning#258
tsouth89 merged 3 commits into
mainfrom
fix/monthly-pace-warnings

Conversation

@tsouth89

Copy link
Copy Markdown
Owner

Summary

Follow-up to #256, which fixed the displayed pace verdict but not the toast.

  • add the tertiary slot to the windows a predictive pace warning can come from
  • extract predictive_pace_candidates so that set is testable on its own, rather than only observable by emitting a toast

Why

Predictive pace warnings looked at primary and secondary alone. A provider reports its monthly quota in the tertiary slot, so a month on course to run dry before it reset could never say so — while the weekly window beside it warned freely. That is the same blind spot #256 fixed for the on-screen verdict.

Everything else was already in place: PredictiveWarningWindow::Monthly exists, predictive_window_for already maps anything past fourteen days onto it, and the dedup key includes window_minutes (notifications.rs:52), so a tertiary window cannot collide with the secondary.

Deliberately not included

Extra windows. The displayed verdict can weigh every window because it renders one; here each candidate raises its own toast, and the extras are supplementary lanes (Codex Spark, pooled team usage) that would multiply warnings rather than add information. Easy to widen if you'd rather.

The twelve-hour floor. Display pace skips windows under twelve hours because a marker on a bursty window is meaningless. An explicit "on course to be exhausted before it resets" toast is still actionable for a five-hour session, so warnings keep their existing reach.

ceiling usage. Still weekly-only, but for a different reason than I first thought: the CLI never renders tertiary or extra windows at all (cli/usage.rs:433-434), so its pace line is consistent with what it prints. Making it monthly-aware means new output lines and belongs on its own.

Validation

  • cargo test --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml (489 passed; +3 covering the monthly case, absent slots, and cadence-over-slot naming)
  • cargo clippy --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml --all-targets -- -D warnings
  • cargo fmt --all --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 38 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 16cf6b8f-4ab8-4f13-9d45-6d3f5a831113

📥 Commits

Reviewing files that changed from the base of the PR and between 68b1a97 and b958aed.

📒 Files selected for processing (1)
  • apps/desktop-tauri/src-tauri/src/commands/providers.rs

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

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
ceiling b958aed Commit Preview URL

Branch Preview URL
Aug 12 2026, 12:23 AM

@github-actions

Copy link
Copy Markdown

Automated review

Found 5 issues:

  1. Same-cadence slots share one predictive key and clobber each other

    apps/desktop-tauri/src-tauri/src/commands/providers.rs:965 · disposition: fix-if-quick · confidence: high · severity: medium · quick win

    predictive_pace_candidates names each slot with predictive_window_for(window_minutes), so secondary and tertiary that both report e.g. 10_080 minutes both become PredictiveWarningWindow::Weekly (a shape capacity_events already tests). record_predictive_observation keys only on (provider, identity, window enum): the first slot inserts the Weekly observation baseline, the second reuses that key, and retain() drops any prior Weekly warning key before re-deciding from the later slot's pace. Result on real dual-weekly snapshots: toast on first risk without a per-window baseline, or a later will-last tertiary clears a weekly warn so the next refresh re-fires the secondary toast.

    Prompt for AI agents

    In apps/desktop-tauri/src-tauri/src/commands/providers.rs around line 965: Dedupe candidates by the named PredictiveWarningWindow before calling check_predictive_pace (keep the hotter or first core slot), or key observation/warning state by slot id while still using cadence only for the toast label. Add a test with secondary and tertiary both at 10_080 minutes that asserts only one Weekly observation/warn cycle. Verify against the current code first; if no longer valid, skip with a brief reason. Keep the change minimal.

  2. Duplicate PredictiveWarningWindow when monthly duration appears in multiple slots

    apps/desktop-tauri/src-tauri/src/commands/providers.rs:932 · disposition: fix-if-quick · confidence: medium · severity: medium · quick win

    predictive_pace_candidates names each window by its real cadence via predictive_window_for, not its slot. If secondary reports window_minutes=Some(43_200) it maps to W::Monthly, and tertiary with Some(43_200) also maps to W::Monthly. The caller then iterates candidates and calls should_notify_predictive_pace twice with the same PredictiveWarningWindow::Monthly but different RateWindowSnapshot (different used_percent/reset_at). That can produce two toasts for the same logical window or cause the NotificationManager's dedup keyed on window type to suppress the second, hiding the more critical one.

    Prompt for AI agents

    In apps/desktop-tauri/src-tauri/src/commands/providers.rs around line 932: Deduplicate candidates by named PredictiveWarningWindow after mapping, keeping the entry with highest used_percent or earliest reset_at, or make should_notify_predictive_pace key include snapshot identity. Add test with secondary=Some(rw(Some(43_200),40.0)) and tertiary=Some(rw(Some(43_200),80.0)) asserting only one Monthly candidate remains. Verify against the current code first; if no longer valid, skip with a brief reason. Keep the change minimal.

  3. Monthly predictive toast still lost when weekly already took the refresh slot

    apps/desktop-tauri/src-tauri/src/commands/providers.rs:957 · disposition: follow-up · confidence: high · severity: medium · quick win

    Candidates are ordered Session, Weekly, Monthly, and notify_predictive_pace runs after threshold check_and_notify inside a begin_refresh_cycle where Normal toasts allow only one emit per refresh. record_predictive_observation inserts predictive_warning_keys whenever pace is at risk, before emit_toast; if weekly (or a threshold) already emitted, the monthly path still inserts the warned key and emit_toast returns false, so the cycle is marked handled and later refreshes treat it as warned_this_cycle. That is exactly the PR's motivating case (weekly warning freely while the month runs dry) and leaves the user with no monthly toast for the rest of the cycle.

    Prompt for AI agents

    In apps/desktop-tauri/src-tauri/src/commands/providers.rs around line 957: Insert the predictive warning key only after emit_toast succeeds (or remove the key when emit fails) so a suppressed monthly retry can fire on a later refresh. Prove with a refresh-cycle test: weekly and monthly both at risk on the same refresh, assert monthly can still notify after the weekly toast or on the next cycle. Verify against the current code first; if no longer valid, skip with a brief reason. Keep the change minimal.

  4. Regression test only covers candidate selection, not notify path

    apps/desktop-tauri/src-tauri/src/commands/providers.rs:1161 · disposition: advisory · confidence: high · severity: low · quick win

    predictive_pace_warns_on_a_monthly_quota asserts tertiary appears in predictive_pace_candidates with Monthly and 61% used, but never builds a RateWindow with resets_at, never calls UsagePace::weekly, and never drives notify_predictive_pace/check_predictive_pace. A regression that stops passing snapshot.tertiary into the notify loop (while leaving the helper intact) would still pass these tests.

    Prompt for AI agents

    In apps/desktop-tauri/src-tauri/src/commands/providers.rs around line 1161: Keep the helper tests, and add one notify_predictive_pace or NotificationManager integration case with tertiary monthly + resets_at that expects a Monthly predictive observation/warn when only tertiary is at risk. Verify against the current code first; if no longer valid, skip with a brief reason. Keep the change minimal.

  5. Fixed 30-day default misestimates pace when monthly window_minutes is None

    apps/desktop-tauri/src-tauri/src/commands/providers.rs:945 · disposition: advisory · confidence: medium · severity: low · quick win

    Tertiary fallback is hardcoded to 43_200 minutes (30 days) and passed as default_window_minutes to RateWindow::with_details when window.window_minutes is None. Real calendar months are 28-31 days; if reset_at is 28 days away the 30-day default underestimates burn rate by ~7% and can miss a warning, or overestimates for 31 days and can false-fire. The same approximation exists for session/weekly but is now introduced for monthly.

    Prompt for AI agents

    In apps/desktop-tauri/src-tauri/src/commands/providers.rs around line 945: When window_minutes is None derive default from reset_at duration if available, falling back to 43_200 only when reset_at is also None, and document the approximation. Add test with tertiary rw(None,61.0) and reset_at 28 days out asserting pace uses reset_at-derived window. Verify against the current code first; if no longer valid, skip with a brief reason. Keep the change minimal.

For coding agents: fix BLOCK and FIX IF QUICK findings now; everything else is tracked or informational; never exceed one CodeRev fix round per PR.

Advisory. Findings generated by grok-subscription and muse-spark-1.2-contributor, each filtered through a 3-vote deepseek-v4-flash refutation panel with the changed code in evidence.

Comment thread apps/desktop-tauri/src-tauri/src/commands/providers.rs
Comment thread apps/desktop-tauri/src-tauri/src/commands/providers.rs
tsouth89 and others added 2 commits August 10, 2026 21:26
Follow-up to #256, which fixed the displayed verdict but not the toast.

Predictive pace warnings looked at the primary and secondary slots
alone. A provider reports its monthly quota in the tertiary slot, so a
month on course to run dry before it reset could never say so, while the
weekly window beside it warned freely. Everything else was already in
place: PredictiveWarningWindow::Monthly exists, predictive_window_for
already maps anything past fourteen days onto it, and the dedup key
includes window_minutes, so a tertiary window cannot collide with the
secondary.

The candidate list moved out of the loop into predictive_pace_candidates
so the set of windows a warning can come from is testable on its own,
rather than only observable by emitting a toast.

Extra windows stay excluded. The displayed verdict can weigh every
window because it shows one; here each candidate raises its own toast,
and the extras are supplementary lanes that would multiply warnings
rather than add information.

`ceiling usage` is still weekly-only, but for a different reason: the
CLI never renders tertiary or extra windows at all, so its pace line
matches what it prints. Making the CLI monthly-aware means new output
lines and belongs on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@tsouth89
tsouth89 force-pushed the fix/monthly-pace-warnings branch from b0d7ed3 to ec4282a Compare August 11, 2026 02:26
@tsouth89
tsouth89 merged commit c08bb1f into main Aug 12, 2026
11 checks passed
@tsouth89
tsouth89 deleted the fix/monthly-pace-warnings branch August 12, 2026 00:26
@tsouth89 tsouth89 mentioned this pull request Aug 12, 2026
tsouth89 added a commit that referenced this pull request Aug 12, 2026
Version bumped in all five locations from VERSIONING.md, BUILD_NUMBER=131,
Cargo.lock regenerated, and the Unreleased entries moved into a dated section.

Supersedes 1.5.28, which was tagged but whose build was cancelled before it
signed or uploaded anything, so that version produced no artifacts. The
v1.5.28 tag stays as a marker, since the repository ruleset blocks deletion
and non-fast-forward on v* tags.

Ships the on-demand spend fix (#260, reported in #191), the monthly pace
warning (#258), and reachable accessible names for settings controls
(#259, closes #215).
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