# TD: Pixel Definition: CPM M3 Telemetry (macOS/iOS) **Author:** Alex M **Reviewer:** TBD **Stakeholders:** Michal, Konrad, Russell (from the first CPM Tech Design; confirm for M3) **Project:** [CPM: root-cause the stuck embedded extension messaging (macOS/iOS)](https://app.asana.com/1/137249556945/task/1216761517055116) **Previous Tech Design:** [CPM breakage pixels](https://app.asana.com/1/137249556945/task/1218005985662983) ## Background & Requirements The first CPM pixels detect initialization failure, a stuck messaging episode and recovery. They do not explain whether a failure coincides with background-process termination, a context-load error or incorrect tab wiring. Forced background-process termination can reproduce a persistent CPM outage. M3 adds native-side diagnostics to investigate whether the same failure occurs in production on iOS and macOS, without relying on the extension's messaging channel. ## Problem Statement Distinguish background-process/context failures from tab-local problems and identify failed extension reload operations. Collect the diagnostic state alongside existing failures, without page content, URLs or persistent identifiers. M3 provides evidence for the production-validation milestone; it does not implement graveyard mitigation or an A/B experiment. ## Recommended Approach Keep the existing CPM failure/stuck detection. A shared in-memory recorder collects lifecycle events, critical-memory-pressure notifications and current WebKit/tab state. When a failure or stuck pixel fires, attach a best-effort snapshot. No additional JavaScript probes or periodic telemetry uploads are introduced. A forwarding delegate proxy observes background-process termination and responsiveness callbacks. The original delegate owns the proxy; the proxy references it weakly. A remote flag enables/disables proxy installation, not the entire diagnostics recorder. | Pixel | Trigger | Frequency | |---|---|---| | `debug_web_extension_cpm_initialization_failed_after_` | Existing initialization failure; add diagnostic parameters. | Daily | | `debug_web_extension_cpm_messaging_stuck_` | Existing failure confirmed by a later eligible navigation; add diagnostic parameters. | Daily + count, once per episode | | `debug_web_extension_reload_failed` | **New:** extension unload/load fails during a reload operation. Applies to all supported extension types. | Daily + count | ``: `session_restoration`, `tab_crash`, `extension_reload`, `other`. PixelKit applies standard frequency/platform suffixes. Standard metadata includes `appVersion`; macOS also declares `pixelSource` and `channel`. Recovery pixels remain unchanged. The new reload-failure pixel reports a failed reload operation, unlike the existing `cpm_messaging_extension_reload_failed`, which reports CPM failure **after a successful reload**. ### Failure / stuck parameters Unavailable optional facts are omitted. Boolean values are `true` / `false`. | Parameter | What is collected | |---|---| | `extension_context_loaded` | Context is loaded — boolean. | | `background_view_alive` | Current background WKWebView exists — boolean. | | `background_web_process_alive` | Background process identifier is nonzero — boolean; PID is not sent. | | `background_web_process_responsive` | WebKit's process-responsiveness verdict — boolean. | | `network_process_restarted` | Network PID differs from the value at context load — boolean; PIDs are not sent. | | `tab_known_to_webkit` | Failing tab is in WebKit's open-tabs set — boolean. | | `tab_controller_matches_context` | Tab and context use the same extension controller — boolean. | | `tab_has_extension_user_scripts` | Registered scripts include the expected extension world — boolean, not proof of execution. | | `native_handler_registered` | Autoconsent native-message handler is registered — boolean, not proof of message delivery. | | `memory_pressure_critical` | Age of last observed critical pressure: `none`, `under_1_min`, `under_5_min`, `under_30_min`, `over_30_min`. | | `background_view_create_count` | Creations since context load: `0`, `1`, `2`, `3_to_5`, `over_5`. | | `background_view_leaked_count` | Retained views beyond the expected current view; same buckets. Not proof of a leak. | | `extension_context_errors` | `none` or accumulated error descriptors: mapped context-error names, with raw domain/code for other or underlying errors. No localized text; no explicit payload cap. | | `background_events` | Recent lifecycle sequence with relative ages in whole seconds. | The recorder keeps 40 events in memory; the pixel includes at most the last 12 and 255 characters, dropping oldest entries first. Format: `event_name@-seconds`, relative to snapshot time. Events: `load`, `view`, `dealloc`, `unresponsive`, `responsive`, `proxy_on`, `proxy_off`, `died_`, `error_`. Termination reasons: `memory_limit`, `cpu_limit`, `requested_by_client`, `crash`, `shared_crash_limit`, `unknown`. Error events represent background-load failures. Event labels are lowercased, character-filtered and capped at 64 characters. Example: `view@-60,died_crash@-42,error_background_failed_to_load@-41`. ### Reload-failure parameters | Parameter | Values | |---|---| | `extension_type` | `embedded`, `darkMode`, `adBlocking`, `searchToken`, `unknown` | | `reload_trigger` | `data_clearing`, `scriptlet_update`, `explicit` | | `reload_phase` | `unload`, `load`, `lightweight_load`, `full_load`, `fallback_load` | | `reload_error` | `already_loaded`, `not_loaded`, `base_url_in_use`, `no_background_content`, `background_failed_to_load`, `unknown`, `other` | These are allowlisted enums; this pixel does not send raw error domains, codes or messages. ## Testing - Unit tests: parameter serialization, buckets, timeline limits, attachment to failure/stuck pixels, reload-error mapping, delegate forwarding, ownership and runtime flag changes. - Integration validation on iOS/macOS: force background-process termination, check the emitted diagnostics, test proxy on/off and extension reload failures. Confirm unknown SPI values are omitted. - Privacy validation: inspect actual payloads and run both platform schema validators. Confirm URLs, identifiers and error messages are absent. Review exact-second timelines and error-domain/code values before release. ## Additional Considerations (if applicable) **Privacy** New pixel and additional parameters require Privacy Triage. No intentional collection of browsing URLs, search queries, page content, message payloads, tab/context IDs or PIDs in these payloads. Exact-second timelines and unrestricted error-domain/code combinations can be high-cardinality; bucketing/allowlisting needs a decision. `data_clearing` discloses the operation preceding a failed reload. Current local diagnostics logs separately include raw errors with `privacy: .public`; remove/redact these before production. Pixel approval does not approve those logs. **Security** Uses guarded private WebKit selectors for process/script facts. Validate supported OS versions; missing facts must not block pixel delivery. **Site Breakage** No intended page-behavior changes. However, the investigation recorded a changed reproduction with the delegate proxy installed; validate the current proxy on/off before treating observations as an unaffected baseline. **Experimentation** None in M3. Graveyard mitigation and A/B testing remain separate milestones. **Operational** Update the existing CPM Grafana board for the new fields and reload failures. Agree a diagnostic removal/review date; none is enforced currently. Failure-only snapshots do not provide a denominator of all process deaths or prove an all-tabs outage. Rolling timelines can lose the trigger; deferred snapshots can observe newer state. **Localization / Internationalization** None.