120 lines
8.3 KiB
Markdown
120 lines
8.3 KiB
Markdown
# TD: Pixel Definition: CPM Failure Diagnostics (macOS/iOS)
|
||
|
||
**Author:** Alex M
|
||
**Reviewer:** TBD
|
||
**Stakeholders:** Michal, Konrad, Russell (from the first Tech Design; confirm for this proposal)
|
||
**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 show whether the background process stopped, the extension failed to load, or the tab used the wrong extension configuration.
|
||
|
||
Terminating the extension's background process can leave CPM unable to respond, even after page reloads or opening new tabs. Add process, extension and tab state to existing iOS/macOS failure pixels, even when the extension cannot respond.
|
||
|
||
## Problem Statement
|
||
|
||
Distinguish background-process and extension-context failures from problems affecting one tab, and identify failed reloads. Collect no 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 failure/stuck detection. A shared recorder holds lifecycle and critical-memory-pressure events in memory. When a pixel fires, it captures current WebKit/tab state synchronously on the main actor. Earlier context loads cannot add events to this timeline. There are no JavaScript probes or periodic uploads.
|
||
|
||
A delegate proxy records process termination and responsiveness, then forwards callbacks to WebKit. WebKit's delegate owns the proxy; the proxy holds it weakly. The remote flag enables the proxy on the current view. Disabling restores original delegates on all surviving views, including after unload; other diagnostics remain enabled.
|
||
|
||
| 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. The first nine parameters are booleans (`true` / `false`); PIDs are never sent.
|
||
|
||
| Parameter | What is collected |
|
||
|---|---|
|
||
| `context_loaded` | Context is loaded. |
|
||
| `bg_view_alive` | Current background WKWebView exists. |
|
||
| `bg_process_alive` | Background process identifier is nonzero. |
|
||
| `bg_process_responsive` | WebKit's process-responsiveness verdict. |
|
||
| `network_restarted` | Network PID differs from the value at context load. |
|
||
| `tab_in_context` | Failing tab is in WebKit's open-tabs set. |
|
||
| `tab_controller_match` | Tab and context use the same extension controller. |
|
||
| `tab_has_ext_scripts` | Registered scripts include the expected extension world; not proof of execution. |
|
||
| `handler_registered` | Autoconsent native-message handler is registered; not proof of message delivery. |
|
||
| `critical_memory_age` | Time since critical memory pressure: `none` (not observed), `1m` (<1 min), `5m` (1–<5 min), `30m` (5–<30 min), `over_30` (≥30 min). |
|
||
| `bg_view_creations` | Creations since context load: `0`, `1`, `2`, `3_to_5`, `over_5`. |
|
||
| `bg_view_leaked_count` | Retained views beyond the expected current view; same buckets. Not proof of a leak. |
|
||
| `context_errors` | `none` or accumulated error descriptors: raw domain/code pairs, including the immediate underlying error. No localized text; no explicit payload cap. |
|
||
| `bg_events` | Recent lifecycle sequence with relative ages in whole seconds. |
|
||
|
||
The recorder keeps 40 events. `bg_events` sends up to the last 12, within 255 characters, dropping older entries first. Format: `event_name@-seconds` before the snapshot.
|
||
|
||
Events: `load`, `view`, `dealloc`, `unresponsive`, `responsive`, `proxy_on`, `proxy_off`, `died_<reason>`, `error_<descriptor>`, `context_unload_failed_<descriptor>`, `extension_files_remove_failed_<descriptor>`.
|
||
|
||
Termination reasons: `memory`, `cpu`, `client`, `crash`, `crash_limit`, `unknown`. The `error_` events record background-load failures. CPM unload failures (reload, data clearing or uninstall) and uninstall file-removal failures are also recorded. Failed unloads keep the context; file-removal errors can still be recorded after unload. These entries reach the server only with a later failure/stuck pixel; existing standalone error pixels are unchanged.
|
||
|
||
Timeline labels are lowercased, character-filtered and truncated to 64 characters, which can cut off error codes. `context_errors` and reload error fields preserve raw domain/code pairs.
|
||
|
||
Example: `view@-60,died_crash@-42` means the view was created 60 seconds before the snapshot and its process crashed 42 seconds before it.
|
||
|
||
### Reload-failure parameters
|
||
|
||
| Parameter | Values |
|
||
|---|---|
|
||
| `extension_type` | `embedded`, `darkMode`, `adBlocking`, `searchToken`, `unknown` |
|
||
| `reload_trigger` | `data_clearing`, `scriptlet_update`, `explicit` |
|
||
| `reload_phase` | `unload`, `load`, `light_load`, `full_load`, `fallback_load` |
|
||
|
||
The three fields above are allowlisted enums. The pixel also sends standard error parameters:
|
||
|
||
| Parameter | Values |
|
||
|---|---|
|
||
| `d` (`errorDomain`) | Original NSError domain. |
|
||
| `e` (`errorCode`) | Original numeric NSError code. |
|
||
| `ud` (`underlyingErrorDomain`) | Immediate underlying NSError domain, when present. |
|
||
| `ue` (`underlyingErrorCode`) | Immediate underlying numeric code, when present. |
|
||
|
||
Localized descriptions, file paths and other userInfo contents are not serialized. Only the immediate underlying error is included.
|
||
|
||
## 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. These payloads do not intentionally collect browsing URLs, search queries, page content, message payloads, tab/context IDs or PIDs. Exact-second timelines and unrestricted domain/code pairs create many distinct values; Privacy Triage must decide whether to bucket or restrict them. `data_clearing` discloses the operation preceding a failed reload.
|
||
|
||
Local context-error diagnostics log only original and immediate underlying error domains/codes, without localized descriptions or other userInfo contents.
|
||
|
||
**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. The proxy changed the bug's reproduction in an earlier test. Test the current proxy on/off to check whether it still affects the failure.
|
||
|
||
**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 cannot measure the failure rate across all process deaths or prove that all tabs failed. Older events, including the trigger, can drop out of the timeline.
|
||
|
||
**Localization / Internationalization**
|
||
|
||
None.
|