feat(dashboard): update delivery latency p50/p75/p95/p99#2702
Conversation
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 26 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 (15)
Comment |
Visual diff passedVisual changesGenerated at 2026-07-16T00:53:20.084Z. Threshold: 0.1% pixel difference.
Commit: Open |
Merging this PR will not alter performance
Comparing Footnotes
|
Show p50/p75/p95/p99 time-to-deliver metrics at platform, org, and app scope using the same Observe-style cards and trend chart. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Auto-sync on main dropped the users social username columns from generated types while tests still require them. Co-authored-by: Cursor <cursoragent@cursor.com>
52839d9 to
d63ab39
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_9a23542f-352c-4592-b1cf-fd55de270170) |
There was a problem hiding this comment.
All reported issues were addressed across 11 files
Confidence score: 5/5
- Safe to merge after the addressed issues were fixed.
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
Move the app-scoped delivery latency panel to Native Observe, sync it with the page period, and replace the fake PR preview with a real Observe screenshot. Co-authored-by: Cursor <cursoragent@cursor.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_ebee0f0c-be35-4df0-93a7-6c6c7bd4f0f6) |
There was a problem hiding this comment.
All reported issues were addressed across 7 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
Harden duration parsing and query shape, clear stale panel state on scope changes, and cover null/p75 edge cases called out in review. Co-authored-by: Cursor <cursoragent@cursor.com>
Review comments addressed (AI generated)Pushed
|
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_9de8b366-988c-41ef-b76d-a4453245804d) |
There was a problem hiding this comment.
Risk: medium. Not approving: Cursor Bugbot completed with status skipping (usage limit) and did not produce a clean <!-- BUGBOT_REVIEW --> result. This dashboard/API change exceeds the low-risk approval threshold; human review is still required. Reviewers WcaleNieWolny and Dalanir are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
|
There was a problem hiding this comment.
2 issues found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/composables/useUpdateDeliveryStats.ts">
<violation number="1" location="src/composables/useUpdateDeliveryStats.ts:53">
P3: Missing app/org identifier handling now duplicates the same request invalidation and state reset block. Combining the two predicates would keep this lifecycle behavior in one place and prevent the guards from drifting.</violation>
</file>
<file name="supabase/functions/_backend/private/update_delivery_stats.ts">
<violation number="1" location="supabase/functions/_backend/private/update_delivery_stats.ts:52">
P3: Valid numeric durations longer than 15 characters are excluded, so platform latency silently loses samples such as values with leading zeros or additional fractional precision. Consider safely parsing and checking the numeric value against the 7,200,000 ms bound instead of imposing an unrelated text-length limit.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
| if (body.scope === 'app' && !body.app_id) { | ||
| latestRequest += 1 | ||
| stats.value = null | ||
| statsError.value = false | ||
| statsLoading.value = false | ||
| return | ||
| } | ||
| if (body.scope === 'org' && !body.org_id) { | ||
| latestRequest += 1 | ||
| stats.value = null | ||
| statsError.value = false | ||
| statsLoading.value = false | ||
| return | ||
| } |
There was a problem hiding this comment.
P3: Missing app/org identifier handling now duplicates the same request invalidation and state reset block. Combining the two predicates would keep this lifecycle behavior in one place and prevent the guards from drifting.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/composables/useUpdateDeliveryStats.ts, line 53:
<comment>Missing app/org identifier handling now duplicates the same request invalidation and state reset block. Combining the two predicates would keep this lifecycle behavior in one place and prevent the guards from drifting.</comment>
<file context>
@@ -45,22 +45,37 @@ export function useUpdateDeliveryStats(
async function fetchStats() {
const body = params()
- if (body.scope === 'app' && !body.app_id)
+ if (body.scope === 'app' && !body.app_id) {
+ latestRequest += 1
+ stats.value = null
</file context>
| if (body.scope === 'app' && !body.app_id) { | |
| latestRequest += 1 | |
| stats.value = null | |
| statsError.value = false | |
| statsLoading.value = false | |
| return | |
| } | |
| if (body.scope === 'org' && !body.org_id) { | |
| latestRequest += 1 | |
| stats.value = null | |
| statsError.value = false | |
| statsLoading.value = false | |
| return | |
| } | |
| if ( | |
| (body.scope === 'app' && !body.app_id) | |
| || (body.scope === 'org' && !body.org_id) | |
| ) { | |
| latestRequest += 1 | |
| stats.value = null | |
| statsError.value = false | |
| statsLoading.value = false | |
| return | |
| } |
| const durationExpression = String.raw`CASE | ||
| WHEN s.metadata ? 'duration_ms' | ||
| AND s.metadata ->> 'duration_ms' ~ '^[0-9]+(\.[0-9]+)?$' | ||
| AND char_length(s.metadata ->> 'duration_ms') <= 15 |
There was a problem hiding this comment.
P3: Valid numeric durations longer than 15 characters are excluded, so platform latency silently loses samples such as values with leading zeros or additional fractional precision. Consider safely parsing and checking the numeric value against the 7,200,000 ms bound instead of imposing an unrelated text-length limit.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At supabase/functions/_backend/private/update_delivery_stats.ts, line 52:
<comment>Valid numeric durations longer than 15 characters are excluded, so platform latency silently loses samples such as values with leading zeros or additional fractional precision. Consider safely parsing and checking the numeric value against the 7,200,000 ms bound instead of imposing an unrelated text-length limit.</comment>
<file context>
@@ -47,8 +47,14 @@ const startActions = ['download_0', 'download_zip_start', 'download_manifest_sta
- WHEN s.metadata ? 'duration' AND s.metadata ->> 'duration' ~ '^[0-9]+(\.[0-9]+)?$' THEN (s.metadata ->> 'duration')::double precision
+ WHEN s.metadata ? 'duration_ms'
+ AND s.metadata ->> 'duration_ms' ~ '^[0-9]+(\.[0-9]+)?$'
+ AND char_length(s.metadata ->> 'duration_ms') <= 15
+ THEN (s.metadata ->> 'duration_ms')::double precision
+ WHEN s.metadata ? 'duration'
</file context>





Summary (AI generated)
POST /private/update_delivery_statsthat computes delivery latency percentiles (p50, p75, p95, p99) for app, org, and platform scopesDeliveryLatencyPanel(percentile cards + daily trend chart + period selector)Motivation (AI generated)
Capgo already exposes count-based update success metrics and Native Observe launch/WebView percentiles, but operators still lack a first-class view of how long updates take to download/deliver. Platform, org, and app owners need the same latency distribution language (p50/p75/p95/p99) to spot regressions before success-rate alone moves.
Business Impact (AI generated)
Faster diagnosis of slow OTA delivery improves trust in Capgo cloud updates and helps support/admin catch CDN, bundle size, or regional latency issues earlier. This is a foundation for future alerting and SLA-style delivery reporting.
Visual changes (AI generated)
App Observe now shows update delivery latency percentiles (p50 / p75 / p95 / p99) under the overview cards, synced to the Observe period selector.
Panel detail:
Metric definition (AI generated)
download_0/download_zip_start/download_manifest_start) to download complete (download_complete/download_zip_complete)metadata.duration_mswhen present; otherwise pairs start/complete events within 2 hours (app/org scopes)Test Plan (AI generated)
bunx vitest run tests/update-delivery-stats.unit.test.ts/admin/dashboard/updates: panel renders for platform admin, empty/demo states behave correctly/dashboard: latency panel appears under usage charts for current org/app/:id: latency panel appears for the selected appGenerated with AI
Note
Medium Risk
New authenticated analytics over
statswith scope-specific SQL (including lateral pairing for app/org) can be expensive under load; platform scope is gated to admins but org/app queries still scan event data.Overview
Adds update delivery latency reporting (P50–P99) from device download stats, exposed in the dashboard at org, app, and platform levels.
A new authenticated
POST /private/update_delivery_statsendpoint aggregatespublic.statsdownload events: for app/org it usesmetadata.duration_ms/durationwhen present, otherwise pairs start/complete actions within two hours; platform scope is admin-only and metadata-only to limit query cost. Responses include overview percentiles, sample/device counts, and daily trend series for 1/3/7/30-day windows, with RBAC on app/org and platform-admin checks.The UI reuses a shared
DeliveryLatencyPanel(percentile cards, trend chart, period selector, loading/error/empty states, demo data) viauseUpdateDeliveryStats, wired into org Usage, app Observe (synced period), and admin Updates. i18n strings and unit tests cover response shaping helpers.Reviewed by Cursor Bugbot for commit 444b0b7. Bugbot is set up for automated code reviews on this repo. Configure here.