fix(dashboard): read Native Observe stats from Analytics Engine - #2772
Conversation
Mirror the update-delivery dual path so prod Observe charts use APP_LOG/DEVICE_INFO instead of empty Postgres stats. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 43 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 (2)
📝 WalkthroughWalkthroughThe PR adds Cloudflare-based native observe aggregation with duration parsing, percentile metrics, UTC-day chunking, release markers, and CF/SB path selection. It also adds Analytics Engine plugin-version reads, SQL fixtures, and unit tests. ChangesNative observe statistics
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant NativeObserveStats
participant CloudflareTimingEvents
participant ReleaseMarkers
participant NativeObserveAggregation
NativeObserveStats->>CloudflareTimingEvents: fetch timing events by UTC day
NativeObserveStats->>ReleaseMarkers: fetch release markers
CloudflareTimingEvents->>NativeObserveAggregation: normalize and fold samples
ReleaseMarkers->>NativeObserveStats: provide release metadata
NativeObserveAggregation-->>NativeObserveStats: return metric rows and percentiles
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
Merging this PR will not alter performance
Comparing Footnotes
|
Sum DEVICE_INFO plugin-version device counts before slicing the top 12 so share denominators match Postgres. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Stale comment
Risk: medium. Left a non-blocking comment — Cursor Bugbot is clean on the latest commit, but this Analytics Engine dual-path stats change exceeds the low-risk approval threshold, so it is not approved. A human reviewer is already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
Aggregate each day chunk as it arrives so high-volume apps cannot pin large event arrays in the worker. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Risk: medium. Left a non-blocking comment — Cursor Bugbot is clean on the latest commit with prior findings resolved, but this Analytics Engine dual-path stats change exceeds the low-risk approval threshold, so it is not approved. A human reviewer is already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
Use a separate DEVICE_INFO total-devices query with a limited top-12 list, and cap folded events plus duration samples to keep worker memory/CPU bounded. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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/native_observe_stats.ts`:
- Around line 347-365: Replace the unbounded duration arrays and device-id Sets
in NativeObserveAggregateState, including dailyMap, actionMap, versionMap,
allDevices, and issueDevices, with bounded percentile summaries and approximate
distinct counters. Update the aggregation and percentile/reporting logic to use
these representations while preserving existing metrics and keeping memory usage
independent of event volume.
- Around line 652-675: The foldNativeObserveTimingEventsCFChunked loop currently
performs every daily Analytics Engine request serially without timeout or
partial-failure handling. Update this function to process chunks with bounded
concurrency, such as 4–6 requests in flight, fold each result as it resolves,
and apply an abort/timeout to each readUpdateDeliveryTimingEventsCF request
while preserving bounded memory usage.
- Around line 468-498: Update the stats aggregation around versionRows and
overviewRow to copy and sort each launchDurations and webviewDurations
collection once, then reuse the sorted arrays for both percentileCont calls.
Apply the same reuse within each version mapping callback and for the overview
state arrays, preserving all existing percentile values and row behavior.
In `@supabase/functions/_backend/utils/cloudflare.ts`:
- Around line 1343-1347: Update the device-state SELECT to retrieve
plugin_version, is_prod, and is_emulator from one deterministic latest event
rather than independent argMax aggregates; use a supported row-valued aggregate
or timestamp plus a unique secondary ordering key, and add a fixture covering
duplicate timestamps to verify the fields remain coherent.
In `@tests/native-observe-stats.unit.test.ts`:
- Line 94: Update the pure-helper test cases at the tests beginning “aggregates
CF observe samples…” and the additionally referenced test to use it.concurrent()
instead of it().
🪄 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: ASSERTIVE
Plan: Pro
Run ID: 6b0433f3-527e-4a62-a7fb-ab75c72f4646
📒 Files selected for processing (4)
supabase/functions/_backend/private/native_observe_stats.tssupabase/functions/_backend/utils/cloudflare.tstests/helpers/collectAnalyticsEngineSqlFixtures.tstests/native-observe-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.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f42df9d. Configure here.
Sort duration samples once, fetch day chunks with bounded concurrency, and run pure Observe helper tests concurrently. 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_d735a8c6-42a9-4071-a713-1095ffea7e86) |
Drop Math.random reservoir replacement and fold day chunks from newest to oldest so caps truncate older days instead of recent ones. 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_fc6eb9ff-21a9-4aac-9f41-9fc58cfd003e) |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
supabase/functions/_backend/private/native_observe_stats.ts (1)
666-689: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy liftDo not silently return only the oldest 100,000 events.
The cursor advances from
start, and Lines 679 and 687 stop folding once the cap is reached. High-volume apps will therefore receive incomplete totals and omit later days—often the most recent ones—without any truncation signal. Preserve complete range-level counters via Analytics Engine aggregation, or explicitly surface/handle truncation instead of reporting partial statistics as complete.🤖 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 `@supabase/functions/_backend/private/native_observe_stats.ts` around lines 666 - 689, The chunked aggregation in foldNativeObserveTimingEventsCFChunked must not silently report partial results when MAX_NATIVE_OBSERVE_EVENTS is reached. Replace the event-cap truncation with Analytics Engine aggregation that preserves complete range-level counters, or propagate an explicit truncation state through the caller and response so consumers cannot treat incomplete totals as complete; retain day-by-day folding for ranges that remain within the limit.
🤖 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/native_observe_stats.ts`:
- Around line 324-332: Update pushDurationSample to track a per-target count of
all observed durations, including samples retained before MAX_DURATION_SAMPLES.
Increment the count for every value, then after the cap draw the replacement
index from [0, seen) rather than target.length + 1, replacing only when the
index is within the reservoir; preserve the existing cap and target-specific
sampling behavior.
---
Outside diff comments:
In `@supabase/functions/_backend/private/native_observe_stats.ts`:
- Around line 666-689: The chunked aggregation in
foldNativeObserveTimingEventsCFChunked must not silently report partial results
when MAX_NATIVE_OBSERVE_EVENTS is reached. Replace the event-cap truncation with
Analytics Engine aggregation that preserves complete range-level counters, or
propagate an explicit truncation state through the caller and response so
consumers cannot treat incomplete totals as complete; retain day-by-day folding
for ranges that remain within the limit.
🪄 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: ASSERTIVE
Plan: Pro
Run ID: 82acacd8-d859-4bf4-a097-f1616978d6cc
📒 Files selected for processing (3)
supabase/functions/_backend/private/native_observe_stats.tssupabase/functions/_backend/utils/cloudflare.tstests/helpers/collectAnalyticsEngineSqlFixtures.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
Extract bucket/counter helpers so Sonar cognitive complexity and duplicated aggregation paths stay under the quality gate. 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_17c8b91c-4b55-4f80-8836-96dde517e03a) |
|





Summary (AI generated)
POST /private/native_observe_statsto the same dual path as other private stats:APP_LOGfor global Observe metrics,DEVICE_INFOfor plugin versions, Postgres only when those bindings are absent.readUpdateDeliveryTimingEventsCFfor Observe actions, aggregate durations/issues in JS, and keep release markers on Postgresdeploy_history.Motivation (AI generated)
Production plugin stats land in Cloudflare Analytics Engine when
APP_LOG/DEVICE_INFOare set. Observe still queried Postgrespublic.stats/public.devices, so the console chart stayed empty after the delivery-latency fix (#2770).Business Impact (AI generated)
Native Observe becomes usable in production again, so customers can see launch/webview latency and crash signals without waiting on Postgres-backed stats that no longer receive this traffic.
Test Plan (AI generated)
bunx vitest run tests/native-observe-stats.unit.test.ts tests/analytics-engine-sql.unit.test.tsAPP_LOG: Observe still returns Postgres-backed dataAPP_LOG: global Observe charts populate from AEDEVICE_INFO: plugins tab shows plugin_version breakdowndeploy_historyGenerated with AI
Made with Cursor
Summary by CodeRabbit