feat(dashboard): bundle install success rate and timing percentiles - #2989
Conversation
- Add POST /private/bundle_install_stats endpoint with per-bundle success rate (install / install+fail) and install time P50/P70/P90/P95 - Add BundleInstallStatsPanel on app, channel statistics, and bundle pages - Pair download start to set action for end-to-end install duration Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 33 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: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a private bundle-install statistics API with Cloudflare and Postgres aggregation, a reusable dashboard panel, page integrations, localization, generated declarations, unit tests, and a Playwright capture script. ChangesBundle install statistics
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant DashboardPage
participant BundleInstallStatsPanel
participant useBundleInstallStats
participant bundle_install_stats
participant CloudflareEvents
participant Postgres
DashboardPage->>BundleInstallStatsPanel: render panel with app and period
BundleInstallStatsPanel->>useBundleInstallStats: fetch statistics
useBundleInstallStats->>bundle_install_stats: authenticated POST request
bundle_install_stats->>CloudflareEvents: retrieve timing events
bundle_install_stats->>Postgres: query success and timing data
bundle_install_stats-->>useBundleInstallStats: return aggregated response
useBundleInstallStats-->>BundleInstallStatsPanel: update statistics state
BundleInstallStatsPanel-->>DashboardPage: render metrics and bundle table
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
Comment |
Merging this PR will not alter performance
Comparing Footnotes
|
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Visual diff passedVisual changesGenerated at 2026-08-12T08:25:21.877Z. Threshold: 0.1% pixel difference.
Commit: Open |
There was a problem hiding this comment.
All reported issues were addressed
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- Fix import sort order on channel statistics page - Correct percentile and success-rate unit expectations - Restore failed-to-fetch-statistics and sync en.context.json - Remove base-incompatible visual-diff route for new panel Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 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 `@scripts/capture-bundle-install-stats.ts`:
- Around line 8-11: Remove the duplicate declarations and stray top-level block
so the file parses: in scripts/capture-bundle-install-stats.ts lines 8-11,
retain only one declaration each for chromium, mkdirSync, and join; in lines
43-54, delete the duplicate declarations of chromium, mkdirSync, join, baseUrl,
and outDir plus the unmatched brace. Keep the single valid declarations used by
ensureLocalAuth and the rest of the script.
In `@src/components/dashboard/BundleInstallStatsPanel.vue`:
- Around line 186-195: Remove the P50 timing card and its associated rendering
from the dashboard template near the bundle-install timing section; do not use
the first sampled bundle’s timing.p50_ms as an overall metric. Only retain an
aggregate P50 display if a dedicated API-provided aggregate field is added and
consumed instead.
In `@src/composables/useBundleInstallStats.ts`:
- Around line 113-160: Rename the native-Date helper dayjsUtcEnd to a name that
reflects its implementation, updating its call in buildDemoBundleInstallStats.
Normalize the calculated start date to UTC midnight before assigning
period.start, while preserving the existing end-of-day period.end and day-count
behavior.
In `@src/pages/app/`[app].channel.[channel].statistics.vue:
- Around line 787-793: Update the BundleInstallStatsPanel usage in the channel
statistics page to pass the page’s reactive days value through :days="days" and
set hide-period-selector, ensuring install statistics follow the channel period
selector without rendering an independent period control.
In `@supabase/functions/_backend/private/bundle_install_stats.ts`:
- Around line 674-680: Update the catch block around readBundleInstallStats to
re-throw existing simpleError instances unchanged, preserving their original
code and status; only convert unknown errors into fetch_error while retaining
the current logging and message details.
- Around line 18-19: Update the SQL query construction in the bundle install
stats flow to interpolate the shared maxInstallMs and pairingLookbackMs
constants instead of hard-coding 7200000 and INTERVAL '2 hours'. Apply this
consistently to the SQL locations around the pairing lookback conditions and
install-duration bound, preserving the existing duration semantics while keeping
Cloudflare and Postgres paths synchronized.
- Around line 264-268: Replace the per-item input.successRows.find lookup in the
bundles construction with a Map<string, BundleSuccessRow> created once before
names.map; populate it by version_name and retrieve each success row from the
map while preserving the existing optional and counting behavior.
- Around line 325-338: The install timing query and its caller use inconsistent
parameter numbering: update buildInstallTimingQuery to renumber placeholders $4,
$5, and $6 as $3, $4, and $5, then update readBundleInstallStatsSB to remove
startDate from the bound parameter array so exactly five values match the query.
🪄 Autofix
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: ASSERTIVE
Plan: Pro
Run ID: 48ccf4ef-14d6-491a-ad57-052cf3aa3b3b
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (15)
cloudflare_workers/api/index.tsmessages/en.context.jsonmessages/en.jsonscripts/capture-bundle-install-stats.tssrc/auto-imports.d.tssrc/components.d.tssrc/components/dashboard/BundleInstallStatsPanel.vuesrc/composables/useBundleInstallStats.tssrc/pages/app/[app].bundle.[bundle].vuesrc/pages/app/[app].channel.[channel].statistics.vuesrc/pages/app/[app].vuesrc/route-map.d.tssupabase/functions/_backend/private/bundle_install_stats.tssupabase/functions/private/index.tstests/bundle-install-stats.unit.test.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
There was a problem hiding this comment.
All reported issues were addressed across 9 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
done |
Sanitize client errors, stop version_name cache busting, fix SQL placeholders, paginate capped AE windows, and align the panel period and summary metrics with review feedback. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@supabase/functions/_backend/private/bundle_install_stats.ts`:
- Around line 464-503: Bound readInstallTimingEventsCFWindow recursion by adding
MAX_TIMING_SPLIT_DEPTH = 4 near MIN_TIMING_WINDOW_MS, tracking split depth in
the function parameters, and returning the current chunk when that depth is
reached. Increment the depth for both recursive branches while preserving the
existing minimum-window guard and query behavior below the limit.
In `@tests/bundle-install-stats.unit.test.ts`:
- Around line 96-102: Extend the test around
bundleInstallStatsTestUtils.filterResponseByVersionName to snapshot the original
response before filtering, then assert the response remains unchanged afterward
while preserving the existing filtered assertions.
🪄 Autofix
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: ASSERTIVE
Plan: Pro
Run ID: e8dba842-37ff-4a96-bd83-3776a4ffb198
📒 Files selected for processing (8)
messages/en.context.jsonscripts/capture-bundle-install-stats.tssrc/components/dashboard/BundleInstallStatsPanel.vuesrc/composables/useBundleInstallStats.tssrc/pages/app/[app].channel.[channel].statistics.vuesupabase/functions/_backend/private/bundle_install_stats.tssupabase/functions/_backend/utils/cloudflare.tstests/bundle-install-stats.unit.test.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
💤 Files with no reviewable changes (1)
- scripts/capture-bundle-install-stats.ts
There was a problem hiding this comment.
All reported issues were addressed across 8 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Replace unbounded parallel window recursion with sequential hour/5-minute slices, fail closed when still capped, guard null bodies, and assert version filters do not mutate cached responses. Co-authored-by: Cursor <cursoragent@cursor.com>
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 `@supabase/functions/_backend/private/bundle_install_stats.ts`:
- Around line 483-529: Update readInstallTimingEventsCFWindow to carry a shared
request-wide slice/query budget through every recursive call, decrementing it
before each Cloudflare slice is queried. When the budget is exhausted, throw
fetch_error so the existing fallback path runs, while preserving sequential
slicing and normal event aggregation within the allowed budget.
🪄 Autofix
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: ASSERTIVE
Plan: Pro
Run ID: d4666dd4-091b-482d-8fc4-d758df52af31
📒 Files selected for processing (2)
supabase/functions/_backend/private/bundle_install_stats.tstests/bundle-install-stats.unit.test.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Keep one Analytics Engine query per day and error instead of deep sub-slicing when a busy day hits the 50k row cap. Co-authored-by: Cursor <cursoragent@cursor.com>
|





Summary (AI generated)
POST /private/bundle_install_statsAPI returning per-bundle install success rate and install duration percentiles (P50, P70, P90, P95)BundleInstallStatsPaneldashboard component with period selector and bundle tablefailed-to-fetch-statisticsMotivation (AI generated)
Dashboard users frequently ask for install success rate broken down by bundle, and for install timing percentiles (e.g. how long until 50% or 70% of devices finish installing). The existing update stats chart shows aggregate install/fail volumes but not per-bundle success rate or end-to-end install duration.
Business Impact (AI generated)
Teams can diagnose problematic bundles and slow installs without leaving the Capgo console. Faster release validation and fewer support back-and-forths when a rollout underperforms on a specific bundle.
Visual changes (AI generated)
New "Bundle install performance" section on app, channel statistics, and bundle pages.
App dashboard — Bundle installs panel
Test Plan (AI generated)
Generated with AI
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by CodeRabbit
New Features
Bug Fixes
Tests