Add the wide_return_session wide event for app returns - #9516
Conversation
f3431ce to
6d7b522
Compare
|
Privacy Review task: https://app.asana.com/0/69071770703008/1217579681353955 |
6d7b522 to
b7cb6b0
Compare
784e798 to
b707ebc
Compare
b7cb6b0 to
c1d0408
Compare
b707ebc to
b2fa6f9
Compare
b2fa6f9 to
c4fd050
Compare
0350055 to
8dd0e64
Compare
c4fd050 to
668fc71
Compare
malmstein
left a comment
There was a problem hiding this comment.
Reviewed statically, stacked PR so no CI APK. CI is green, the three red checks on the PR page are a superseded cancelled run.
Genuinely well built for its size. Session start is deferred until FirstScreenHandler has applied the opening-screen decision, so after_idle and landed_on are authoritative at flowStart rather than guessed. abortIfDisabled() on every entry point aborts rather than skips, with a comment explaining that a session started while enabled would otherwise linger and get force-completed as Unknown after a kill-switch flip. The app_terminated default in the start metadata pairs correctly with OnProcessStart cleanup. Mutations are serialised through a mutex on a single-parallelism scope, matching RealPostIdleSessionWideEvent. The -api additions on BrowserInteractionsPlugin and HatchInteractionsPlugin have default bodies so existing implementers are untouched, and the API Proposal check passes. landed_on matches ReturnSessionLanding exactly, every latency is bucketed, and nothing carries PII.
Two small non-blocking things inline, neither affecting behaviour.
668fc71 to
a770375
Compare
8dd0e64 to
7f575d2
Compare
7f575d2 to
7f795b8
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 4 total unresolved issues (including 3 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7f795b8. Configure here.
7f795b8 to
9ba46aa
Compare
9ba46aa to
1d39ae0
Compare


Task/Issue URL: https://app.asana.com/1/137249556945/project/1212810093780571/task/1217573106920334?focus=true
Tech Design URL (if applicable): https://app.asana.com/1/137249556945/project/481882893211075/task/1217382844057496?focus=true
API Proposals URL(s) (if applicable):
Description
This adds
wide_return_session.wide_return_sessionstarts after the app came to the foreground.Data
feature.data.ext.after_idle:trueonly when the inactivity treatment was applied.feature.data.ext.landed_on:ntp,ntp_user_initiated,web,serp, orduck_ai. LUT andSpecific Page returns are classified by their actual destination.
feature.data.ext.time_away_ms_bucketed: lower-bound bucket0,60000,300000,900000,1800000, or3600000.feature.data.ext.focused: one snapshot of whether the visible landing input had focus immediatelyafter the landing fragment resumed. Later focus changes do not alter it.
feature.data.ext.page_engaged,back_pressed,opening_screen_changed,close_tab_tapped, andburn_tab_tapped: sticky booleans, finalized astrueorfalse.feature.data.ext.session_duration_ms_bucketedandfeature.data.ext.time_to_first_interaction_ms_bucketed: lower-bound duration bucket0,1000,5000,10000,30000,60000,300000, or600000. Time to first interaction is omitted whenthe only terminal is app backgrounding and no interaction was recorded.
Successful terminals set
feature.status=SUCCESSandfeature.data.ext.status_reasontosearch_submitted,url_submitted,ai_prompt_submitted,return_to_page_tapped,tab_switcher_selected,favorite_selected, orchat_selected.Backgrounding sets
feature.status=CANCELLEDandfeature.data.ext.status_reason=app_backgrounded. If the process dies with an open flow, next-process cleanup emitsfeature.status=UNKNOWNandfeature.data.ext.status_reason=app_terminated.The event is gated by
returnSessionWideEventFF and the globalwideEventsframework flag.Steps to test this PR
Prerequisites
SAMPLING_PROBABILITY = 1.0finRealReturnSessionWideEvent.ktfor testing only. This will allow you to see every pixel and not a sampling of it.wideEvents,enqueueWideEventPixels,sendWideEventsViaPixels, andreturnSessionWideEvent.selfare ENABLED.How to monitor
Pixel sent: wide_return_sessionto view all the pixels sent at the end of the session (you won’t see a pixel until you finish the session)RealReturnSessionWideEventto view individual events as the session record themadb logcat | rg 'RealReturnSessionWideEvent|Pixel sent:.*wide_(return|post_idle)_session_[cd]'.Instructions
throwaway search or click on switch tab to finish that session, wait for its pixel confirming the session ended.
Pixel sent: ... wide_return_session_c; the first event of theday also sends
wide_return_session_d. Inspect the encodedfeature.data.ext.*values.landed_on, meanfeature.data.ext.landed_on.Landing, focus, submission, and coexistence
after_idle=false,landed_on=ntp_user_initiated,focused=trueafter_idle=false,landed_on=web,focused=false,page_engaged=true,status_reason=url_submittedafter_idle=false,landed_on=serp,back_pressed=trueafter_idle=false,landed_on=duck_ai,status_reason=ai_prompt_submittedfeature.status=SUCCESS,after_idle=true,landed_on=ntp,status_reason=search_submitted.https://example.comafter_idle=true,landed_on=webopening_screen_changed=trueRemaining terminals, negative case, and interaction flags
The after-idle NTP row is the primary
feature.status=SUCCESScheck. For successful rows below,inspect only the unique
status_reason. Rows ending mechanically use the baseline action withoutre-asserting
search_submitted.status_reason=favorite_selectedstatus_reason=chat_selectedstatus_reason=tab_switcher_selectedstatus_reason=return_to_page_tapped; landing treatment was already verified in the after-idle NTP rowstatus_reason=ai_prompt_submittedfeature.status=CANCELLED,status_reason=app_backgrounded,session_duration_ms_bucketedpresent,time_to_first_interaction_ms_bucketedabsentadb shell am force-stop <package>, then relaunchfeature.status=UNKNOWN,status_reason=app_terminated; landing and time-away classifications were already verified aboveclose_tab_tapped=true,burn_tab_tapped=falseburn_tab_tapped=true,close_tab_tapped=falseTiming
time_to_first_interaction_ms_bucketed,time_away_ms_bucketed, andsession_duration_ms_bucketedreflect the correct time buckets.Feature gate and reset
returnSessionWideEventoff, force-stop/relaunch,open an NTP, press Home, immediately reopen, and finish using any action. Confirm no
wide_return_session.UI changes
No UI changes
Note
Medium Risk
Touches first-screen and omnibar submission paths used on every app open. Changes are mostly additive telemetry behind a feature toggle, but misclassifying user vs internal navigation could skew session metrics.
Overview
Adds a
return_sessionwide event that runs from each foreground return until a terminal action (search, URL, AI prompt, hatch actions, background, etc.), capturing landing surface, after-idle treatment, bucketed time away, session duration, and engagement flags.RealReturnSessionWideEventstarts afterFirstScreenHandlerresolves landing (after_idle,landed_onas NTP, web, SERP, or Duck.ai). It listens viaBrowserInteractionsPlugin/HatchInteractionsPluginand is gated byReturnSessionWideEventFeature.ShowOnAppLaunchOptionHandlernow returnsShowOnAppLaunchResultso idle NTP/LUT treatments match telemetry.BrowserTabViewModelsplits user vs internal query submission so restoration and error recovery do not fire search/URL classifiers. Landing focus, back, Duck.ai prompts, hatch close/burn, and JSreportMetricsubmissions feed the same session.NtpEngagementTrackerreports NTP body engagement once per app open.Reviewed by Cursor Bugbot for commit 1d39ae0. Bugbot is set up for automated code reviews on this repo. Configure here.