7.8 KiB
TD: Pixel Definition: CPM Failure Diagnostics (macOS/iOS)
Author: Alex M
Reviewer: TBD
Stakeholders: Michal, Konrad, Russell (from the first CPM Tech Design; reviewers for this proposal to be confirmed)
Project: CPM: root-cause the stuck embedded extension messaging (macOS/iOS)
Previous Tech Design: CPM breakage pixels
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.
Terminating the extension's background process can leave CPM unable to respond, even after page reloads or opening new tabs. To investigate these failures in production, the iOS and macOS apps will attach process, extension and tab state to the existing failure pixels. This reporting does not depend on the extension responding.
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.
This proposal covers diagnostic collection only; it does not change recovery behavior or introduce an 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_<reason> |
Existing initialization failure; add diagnostic parameters. | Daily |
debug_web_extension_cpm_messaging_stuck_<reason> |
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 |
<reason>: 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_<reason>, error_<descriptor>. 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. Recovery changes and experiments are outside this proposal.
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.