Concrete depletion ETA in Calm pace + dashboard (SOU-274) - #64
Conversation
Ceiling already computes PaceSnapshot.etaSeconds but only showed a vague
"Running low". Surface the actual time left, since the number is already there.
- capacityPresentation: new formatShortDuration ("42m", "1h 30m", "2d 3h").
calmPaceState now returns "~42m left" (tone watch) instead of "Running low"
when the pace won't last to reset; "On pace" still carries the reset-aware
meaning (lasts to the window reset). FloatBar renders the label unchanged.
- ProviderDetailView pace section adds "At this pace, about ~42m left before
this window runs out." when running low, tone-colored on risk.
Tests: formatShortDuration across ranges + negative guard; calmPresentation
asserts the concrete label; dashboard render asserts the ETA line. Frontend
262 green, tsc clean.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ceiling | f612eb8 | Commit Preview URL Branch Preview URL |
Jul 19 2026, 03:31 AM |
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 3 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughChangesThe capacity presentation layer now formats finite depletion ETAs into compact duration labels. Provider detail views conditionally display the ETA when usage will not last to reset, with dedicated default and risk-tone styling and updated unit/UI tests. Provider Pace ETA
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant ProviderDetailView
participant PaceSection
participant capacityPresentation
participant styles_css
ProviderDetailView->>PaceSection: pass pace state and etaSeconds
PaceSection->>capacityPresentation: formatShortDuration(etaSeconds)
capacityPresentation-->>PaceSection: compact duration
PaceSection->>styles_css: render pace ETA element
styles_css-->>ProviderDetailView: apply default or risk styling
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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-tauri/src/lib/capacityPresentation.ts`:
- Around line 248-268: Update calmPaceState so the ETA label does not prepend
"~" when formatShortDuration returns the "under 1m" sentinel; retain the
approximation prefix for other durations. Apply the same conditional formatting
in ProviderDetailView’s ETA label so it renders “under 1m left” rather than
“about under 1m left”.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 81fe39c5-dd0a-4744-a01d-412eee20c3ab
⛔ Files ignored due to path filters (3)
design/x-header.pngis excluded by!**/*.pngdesign/x-profile.pngis excluded by!**/*.pngdocs/images/ceiling-cahrts.pngis excluded by!**/*.png
📒 Files selected for processing (5)
apps/desktop-tauri/src/lib/capacityPresentation.test.tsapps/desktop-tauri/src/lib/capacityPresentation.tsapps/desktop-tauri/src/styles.cssapps/desktop-tauri/src/surfaces/ProviderDetailView.test.tsxapps/desktop-tauri/src/surfaces/ProviderDetailView.tsx
| /** | ||
| * Trustworthy pace state for Calm mode, or null when there isn't enough signal. | ||
| * Never invents an "on pace" state (SOU-178): it only speaks when the provider | ||
| * actually reports usable pace data. | ||
| * actually reports usable pace data. When the current pace will NOT last to the | ||
| * reset, surface the concrete time left ("~42m left") instead of a vague | ||
| * "Running low", since the number is already computed (SOU-274). "On pace" | ||
| * already carries the reset-aware meaning: the pace lasts until the window | ||
| * resets. | ||
| */ | ||
| function calmPaceState(pace: PaceSnapshot | null): CalmPaceState | null { | ||
| if (!pace) return null; | ||
| // Data-backed and reassuring: the current pace lasts to the reset. | ||
| if (pace.willLastToReset) return { label: "On pace", tone: "steady" }; | ||
| // Only warn when there is a real, finite estimate of running out; otherwise | ||
| // stay silent rather than fabricate a state. | ||
| // stay silent rather than fabricate a state. Show the concrete ETA. | ||
| if ( | ||
| typeof pace.etaSeconds === "number" && | ||
| Number.isFinite(pace.etaSeconds) && | ||
| pace.etaSeconds > 0 | ||
| ) { | ||
| return { label: "Running low", tone: "watch" }; | ||
| return { label: `~${formatShortDuration(pace.etaSeconds)} left`, tone: "watch" }; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Avoid malformed sub-minute ETA labels.
When formatShortDuration returns "under 1m", this branch renders ~under 1m left; ProviderDetailView.tsx Lines [194]-[195] similarly renders about under 1m left. Make the approximation prefix conditional for this sentinel.
🤖 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/desktop-tauri/src/lib/capacityPresentation.ts` around lines 248 - 268,
Update calmPaceState so the ETA label does not prepend "~" when
formatShortDuration returns the "under 1m" sentinel; retain the approximation
prefix for other durations. Apply the same conditional formatting in
ProviderDetailView’s ETA label so it renders “under 1m left” rather than “about
under 1m left”.
formatShortDuration returns "under 1m" for <60s, so "~${d} left" and
"about ${d}" read "~under 1m left" / "about under 1m left". Drop the
approximation prefix for the sub-minute case: "under 1m left" in the Calm
pill and "under a minute" in the dashboard sentence. Adds a sub-minute test.
Version bump to **1.2.0** across manifests + `version.env`, with the 1.2.0 changelog entry. No code changes beyond version strings; all feature work already merged and green on main. ### Since 1.1.0 - **Depletion ETA** — Calm mode and the dashboard show "about ~42m left" instead of just flagging a running-low window (SOU-274, #64) - **`statusline` command** — cache-only, prints remaining capacity for editor status bars without waking the app or hitting the network (SOU-271, #65) - **Per-project cost** — 30-day spend split by project alongside model/effort (SOU-272, #66) - **CSV export** — export a provider's 30-day spend to Downloads from the charts view (SOU-273, #67) - **Cursor activity card** — activity-by-model share from local request logs (#61) Release doctor passes. Tag `v1.2.0` will be pushed after merge to trigger the signed Windows build. Co-authored-by: tsouth89 <tsouth89@users.noreply.github.com>
Closes SOU-274.
Ceiling already computes
PaceSnapshot.etaSecondsbut only showed a qualitative "Running low." This surfaces the concrete time left, since the value is already there.Changes
formatShortDuration(compact: "42m", "1h 30m", "2d 3h").calmPaceStatenow returns~42m left(tonewatch) instead of "Running low" when the pace won't last to reset. "On pace" is unchanged and already carries the reset-aware meaning (the pace lasts to the window reset). FloatBar renderspace.label/toneunchanged, so no float-bar UI change.Tests
formatShortDurationacross ranges + negative guard.calmPresentationasserts the concrete~1h left/~42m leftlabels.Frontend 262 green,
tscclean. Frontend-only. First of the round-2 gap items (the cheapest / highest-signal: pure surfacing of a value already computed).Summary by CodeRabbit
New Features
Bug Fixes