[2026-09-23] eagle: work/projects/cpm-m3-telemetry-privacy-triage.md work/projects/cpm-web-extension-breakage-validation.md
This commit is contained in:
1 parent
34f4731e72
commit
b994c2479c
2 files changed
+36
-21
No files matched your search
@@ -1,10 +1,13 @@
|
||||
# TD: Pixel Definition: CPM Failure Diagnostics (macOS/iOS)
|
||||
|
||||
**Author:** Alex M
|
||||
**Reviewer:** TBD
|
||||
**Reviewer:** Michal
|
||||
**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)
|
||||
**Tech Design:** [Asana](https://app.asana.com/1/137249556945/task/1218619301158188)
|
||||
**Privacy Triage:** [Asana](https://app.asana.com/1/137249556945/task/1218627883499612)
|
||||
**Status:** [PR #6844](https://github.com/duckduckgo/apple-browsers/pull/6844) merged 2026-09-23; CI green. Merge commit `2d58ad8cf4fae728a92e2aae0d3ec6073ddf49f2`. Production rollout not yet confirmed.
|
||||
|
||||
## Background & Requirements
|
||||
|
||||
@@ -22,7 +25,9 @@ This proposal covers diagnostic collection only; it does not change recovery beh
|
||||
|
||||
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.
|
||||
`cpmDiagnosticsRecorder` controls recorder creation when the extension manager is created; changes apply to the next manager instance, normally after app restart. Disabled: no recorder or proxy, and existing failure/stuck pixels carry no recorder diagnostics.
|
||||
|
||||
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 separate `cpmBackgroundDelegateProxy` flag applies at runtime: enabling installs the proxy on the current view; disabling restores original delegates on all surviving views, including after unload. Other recorder diagnostics remain available. Both flags default to enabled and support local overrides.
|
||||
|
||||
| Pixel | Trigger | Frequency |
|
||||
|---|---|---|
|
||||
@@ -32,7 +37,9 @@ A delegate proxy records process termination and responsiveness, then forwards c
|
||||
|
||||
`<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**.
|
||||
Both existing recovery pixels (`debug_web_extension_cpm_messaging_recovered_without_extension_reload` and `debug_web_extension_cpm_messaging_recovered_after_extension_reload`) gain `recovery_from`: `initialization_failed` or `messaging_stuck`, based on the episode state before recovery. Names, triggers and daily + count frequency stay 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
|
||||
|
||||
@@ -54,10 +61,17 @@ Unavailable optional facts are omitted. The first nine parameters are booleans (
|
||||
| `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 bucketed ages relative to the snapshot. |
|
||||
| `app_version_change` | `updated` or `downgraded`; omitted if unchanged or no previous value exists. Fixed for the app session. Version/build values are stored locally, not sent in this parameter. |
|
||||
| `app_launch_age` | Time since app startup using the same age buckets as `bg_events`. Foregrounding and recorder recreation do not reset it. |
|
||||
|
||||
The recorder keeps 40 events. `bg_events` sends up to the last 12, within 255 characters, dropping older entries first. Format: `event_name@age_bucket`. Buckets: `30s` (<30s), `1m` (30–<60s), `2m` (1–<2 min), `5m` (2–<5 min), `15m` (5–<15 min), `over_15` (≥15 min). Events remain oldest first; order and repeated events within a bucket are preserved. Exact ages are not sent.
|
||||
|
||||
Events: `load`, `view`, `dealloc`, `unresponsive`, `responsive`, `proxy_on`, `proxy_off`, `died_<reason>`, `error_<descriptor>`, `context_unload_failed_<descriptor>`, `extension_files_remove_failed_<descriptor>`.
|
||||
Events: `load`, `view`, `dealloc`, `unresponsive`, `responsive`, `proxy_on`, `proxy_off`, `died_<reason>`, `error_<descriptor>`, `context_unload_failed_<descriptor>`, `extension_files_remove_failed_<descriptor>`, `extension_updated`, `base_url_changed`.
|
||||
|
||||
- `extension_updated`: successful replacement of an installed CPM extension, not first installation or ordinary reload. The latest update and its original timestamp survive context reloads.
|
||||
- `base_url_changed`: base URL differs from the previous context load with the same `uniqueIdentifier` in this recorder's lifetime. No event on first load or identifier change. Neither URL nor identifier is sent. This observes URL changes; it does not implement the stable-base-URL fix.
|
||||
|
||||
Future `hold` / `release` events belong to the graveyard mitigation and are not part of this PR.
|
||||
|
||||
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.
|
||||
|
||||
@@ -112,7 +126,16 @@ 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.
|
||||
Update the existing CPM Grafana board for the new fields and reload failures. Diagnostic removal is planned for approximately November 2026; no removal date is enforced in code. Feature flag review is due October 23, 2026. 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.
|
||||
|
||||
Feature flag registry tasks (For review, assigned to Alex M):
|
||||
|
||||
| Flag | iOS | macOS |
|
||||
|---|---|---|
|
||||
| `cpmDiagnosticsRecorder` | [Task](https://app.asana.com/1/137249556945/project/1211834678943996/task/1218785444896174) | [Task](https://app.asana.com/1/137249556945/project/1211834678943996/task/1218781680888931) |
|
||||
| `cpmBackgroundDelegateProxy` | [Task](https://app.asana.com/1/137249556945/project/1211834678943996/task/1218782530802146) | [Task](https://app.asana.com/1/137249556945/project/1211834678943996/task/1218785444683902) |
|
||||
|
||||
Task descriptions contain the template values; registry custom fields still require Platform, Is failsafe=True and Is permanent=False unless filled manually since creation.
|
||||
|
||||
**Localization / Internationalization**
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# CPM Web Extension Breakage — статус и PR-план
|
||||
|
||||
> Актуально на 2026-09-22. Полная трассировка: [[cpm-web-extension-breakage-findings]].
|
||||
> Актуально на 2026-09-23. Полная трассировка: [[cpm-web-extension-breakage-findings]].
|
||||
> Experiment Definition: [[cpm-background-graveyard-experiment-definition]].
|
||||
|
||||
## Решение
|
||||
@@ -33,7 +33,7 @@ M4 перезагружает Web Extensions при первом сигнале
|
||||
|---|---|---|
|
||||
| M1 tab lifecycle | `codex/cpm-tab-lifecycle-fixes` | **Merged:** [PR #6827](https://github.com/duckduckgo/apple-browsers/pull/6827), CI green. |
|
||||
| M2 stable base URL | `alex/cpm-stable-base-url` — `/Users/admin/DuckDuckGo/apple-browsers.git/cpm-stable-base-url` | **Production-ready:** 2 files; 11/11 targeted tests. Добавлена safe URL construction и negative validation вместо force-unwrap. |
|
||||
| M3 attribution telemetry | `alex/cpm-failure-telemetry` — `/Users/admin/DuckDuckGo/apple-browsers.git/cpm-failure-telemetry` | **Production-ready code:** passive PII-free buckets, app-update/launch attribution, stable-base-URL transition fact, iOS/macOS schema validation green. Privacy triage: [[cpm-m3-telemetry-privacy-triage]]. |
|
||||
| M3 attribution telemetry | `alex/cpm-failure-telemetry` — `/Users/admin/DuckDuckGo/apple-browsers.git/cpm-failure-telemetry` | **Merged 2026-09-23:** [PR #6844](https://github.com/duckduckgo/apple-browsers/pull/6844), CI green. Bucketed diagnostics, app launch/version attribution, `extension_updated`, `base_url_changed`, `recovery_from`, reload-error pixel; recorder и proxy имеют отдельные flags. [[cpm-m3-telemetry-privacy-triage]]. |
|
||||
| M4 hung recovery | `codex/cpm-hung-recovery` — `/Users/admin/DuckDuckGo/apple-browsers.git/cpm-hung-recovery` | **In progress:** первый `messaging init failure` открывает diagnostic episode; первый последующий `hung` перезагружает Web Extensions. |
|
||||
| M5 graveyard mitigation | `alex/cpm-graveyard-mitigation` — `/Users/admin/DuckDuckGo/apple-browsers.git/cpm-graveyard-mitigation` | **Production-ready, default off:** one retained view maximum, 3-second bounded hold, stale release cancellation, unload/reload/runtime kill-switch cleanup. 24/24 targeted tests; earlier real forced-kill iOS E2E recovered with release at ≈3.15 s. |
|
||||
| M6 graveyard A/B | `alex/cpm-graveyard-ab` — `/Users/admin/DuckDuckGo/apple-browsers.git/cpm-graveyard-ab` | **Production-ready code:** lazy exposure enrollment, stable cohorts, control/treatment isolation, bounded pending queue, operational pixels and standard `experiment_metrics` outcome. 421/421 WebExtensions tests; iOS/macOS app builds; iOS/macOS pixel validators. |
|
||||
@@ -42,11 +42,9 @@ All milestone diffs pass `git diff --check`; changed Swift lines are within 150
|
||||
|
||||
## Stack and Git state
|
||||
|
||||
Independent PRs:
|
||||
M3 merged: [PR #6844](https://github.com/duckduckgo/apple-browsers/pull/6844), merge commit `2d58ad8cf4fae728a92e2aae0d3ec6073ddf49f2`.
|
||||
|
||||
1. M2 — stable base URL.
|
||||
2. M3 — production telemetry.
|
||||
3. M4 — reload on the first `hung`, after `messaging init failure`.
|
||||
M2 — independent stable-base-URL fix. Вошедший в M3 `base_url_changed` только сообщает о смене URL между загрузками контекста с одинаковым identifier; URL и identifier не отправляются. Это не фикс M2.
|
||||
|
||||
Stacked PRs:
|
||||
|
||||
@@ -57,15 +55,9 @@ M3 telemetry
|
||||
└── M6 A/B experiment
|
||||
```
|
||||
|
||||
Current refs intentionally preserve the earlier no-commit workflow:
|
||||
Следующий Git-шаг: обновить `origin/main`, сверить diff M2/M4/M5/M6 и перенести оставшиеся изменения на merged M3 в порядке выше. Старые локальные refs не подтверждают актуальный stack; готовность M2/M5/M6 в таблице относится к предыдущей локальной валидации, не к повторной проверке после merge M3. Rebase/commit этих веток ещё не выполнялись в рамках этого обновления.
|
||||
|
||||
- M3 and M5 branch refs: `814bce5d11`; their milestone changes are unstaged.
|
||||
- M5 ghost commit used only as M6 base: `cefad244c5`.
|
||||
- M6 branch ref: `cefad244c5`; M6 changes are unstaged above it.
|
||||
- M5’s final combined pixel description has been pulled into M6.
|
||||
- Local `origin/main` advanced from the M3 merge base by one unrelated pixel-definition commit (`67a2f2b7b2`); it does not overlap CPM files.
|
||||
|
||||
Before opening PRs: commit M2 and M3, update them onto current `origin/main`, recreate/rebase the M5 commit onto M3, then rebase M6 onto that M5 commit. Do not include generated `Package.resolved` churn; Cursor currently regenerates it in the open M3 workspace.
|
||||
Не включать generated `Package.resolved` churn.
|
||||
|
||||
## Experiment contract
|
||||
|
||||
@@ -79,10 +71,10 @@ Full definition and config draft: [[cpm-background-graveyard-experiment-definiti
|
||||
|
||||
## Remaining gates
|
||||
|
||||
1. Build and validate M4, then open M2/M3/M4/M5/M6 PRs in the topology above.
|
||||
1. Обновить оставшиеся ветки поверх merged M3; build/validate M4 и повторно проверить зависимые M5/M6. Открыть M2/M4/M5/M6 PRs в topology выше.
|
||||
2. Create separate iOS and macOS experiment-log tasks.
|
||||
3. Create Privacy Configuration + privacy/schema review tasks.
|
||||
4. Create Data Science sample-size/design and Native Apps Experiment Analysis task.
|
||||
5. Ship M3 first; enable M5/M6 only if production telemetry confirms the process-death hypothesis.
|
||||
|
||||
No Asana tasks, comments, or configuration were created during this review.
|
||||
M3 merged, но ещё не подтверждён как shipped production release. Feature flag registry tasks созданы отдельно для iOS/macOS; ссылки — в [[cpm-m3-telemetry-privacy-triage]]. Это обновление затрагивает только Obsidian.
|
||||
Reference in new issue
Block a user