Files
obsidian-vault/work/projects/cpm-m3-telemetry-privacy-triage.md
T

7.7 KiB

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)
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.

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.

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 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.