9.2 KiB
CPM Web Extension Breakage — статус и PR-план
Актуально на 2026-09-23. Полная трассировка: cpm-web-extension-breakage-findings.
Experiment Definition: cpm-background-graveyard-experiment-definition. 2026-09-25 source audit: cpm-service-worker-architecture-and-diagnostics. Earlier readiness/test results below are historical, not validation of the newly identified gaps. Additional gates: M2 stable-origin + M5/M6 reload/Fire interaction; worker exception contract; distinguish dashboard response from actual page initialization. No new device tests were run for this audit.
Решение
Есть два независимых класса проблем:
- Per-tab lifecycle исправлен в M1 и уже merged.
- All-tabs CPM outage: M3 telemetry merged; M4 hung recovery и объединённый M5+M6 graveyard A/B — независимые follow-up PRs.
M4 перезагружает Web Extensions при первом сигнале hung, который подтверждает global CPM outage после предшествующего messaging init failure. Сам messaging init failure остаётся диагностическим: он не меняет состояние расширений.
Статус проблем
| Проблема | Статус | Что делаем |
|---|---|---|
| Forced background-process death → persistent all-tabs CPM outage | Подтверждено | M3 измеряет production incidence; объединённый M5+M6 PR лечит и сравнивает control/treatment. |
| Natural crash/memory/CPU termination → production outage | Не проверено в production | Один production release M3 до включения M5/M6. |
| Close Other Tabs, popup duplicate, pin/unpin/reorder/move/merge/window close | Исправлено, merged | M1 PR #6827. |
| Нестабильный Web Extension base URL | Исправлено локально | M2 задаёт deterministic base URL до load/reload и отвергает malformed identifier без crash. |
| Startup/session-restore content-script miss | Подтверждено как transient | Не объясняет persistent all-tabs outage. |
| Failed background load навсегда блокирует WebKit | Отвергнуто | WebKit повторяет load; нужна повторяемая причина/traffic. |
| Critical memory pressure как root cause | Не воспроизведено | Остаётся diagnostic correlation M3. |
| Event starvation / JSC hang / native messaging stall | Не проверено | Остаётся в M3 diagnostic buckets. |
| Network process restart | Отвергнуто | На проверенной сборке CPM восстановился. |
| removeAllUserScripts / flag transition / scriptlet reload / page JS как all-tabs cause | Отвергнуто | Это не persistent global failure mode. |
Milestones
| Milestone | Branch / worktree | Готовность |
|---|---|---|
| M1 tab lifecycle | codex/cpm-tab-lifecycle-fixes |
Merged: PR #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 |
Merged 2026-09-23: PR #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+M6 graveyard mitigation + A/B | alex/cpm-graveyard-mitigation — /Users/admin/DuckDuckGo/apple-browsers.git/cpm-graveyard-mitigation |
Production-ready, default off; one PR over merged M3: one retained view maximum, 3-second bounded hold, weak scheduled release, runtime cleanup, lazy stable cohort enrollment, control/treatment isolation, bounded pending outcomes, operational and experiment pixels. 431/431 WebExtensions tests; iOS/macOS builds and pixel validators pass; earlier real forced-kill iOS E2E recovered with release at ≈3.15 s. |
| M7 state-restoration readiness gate | alex/cpm-state-restoration-race — /Users/admin/DuckDuckGo/apple-browsers.git/cpm-state-restoration-race |
Production-ready locally from origin/main (a18fca47c3): restored main-frame HTTP(S) navigation now waits for initial Web Extension loadAndSync; Swift package and full macOS Browser builds pass. Targeted tests pass: 19/19 coordinator suite (including 3 new M7 cases) and 3/3 navigation-gate tests. |
All milestone diffs pass git diff --check; changed Swift lines are within 150 columns.
M7 plan — state restoration / Web Extension load race
Confirmed race: setupWebExtensions() creates the manager/controller before state restoration, but starts WebExtensionLifecycleCoordinator.loadAndSync() without awaiting it. stateRestorationManager.applicationDidFinishLaunching() runs immediately afterward. A restored tab can therefore begin its main-frame navigation while the CPM WKWebExtensionContext is not loaded, so WebKit cannot inject the CPM content script at document start. The existing Content Blocking navigation responder already waits for internal user scripts and rule lists; M7 adds the equivalent readiness boundary for Web Extensions.
- Add an awaitable initial-load readiness API to
WebExtensionLifecycleCoordinator; it must reuse the existing coalescedloadAndSynctask and complete on success, empty/disabled embedded set, or cancellation. - Inject a narrow readiness waiter into tab extensions and await it from the navigation policy path before main-frame HTTP(S) navigation proceeds. Do not poll
isAutoconsentExtensionLoaded, because a disabled/failed CPM extension must not deadlock navigation. - Keep the wait startup-only: once initial
loadAndSyncfinishes, later navigations pass immediately. Non-web and subframe navigations do not wait. - Cover coordinator blocking/release/cancellation and navigation-gate scope with unit tests; run targeted WebExtensions/macOS tests after explicit approval.
- Acceptance: a restored page cannot start before the initial extension load/sync settles; disabled Web Extensions and cancelled startup work never hold a tab; normal post-launch navigation has no added asynchronous work.
Stack and Git state
M3 merged: PR #6844, merge commit 2d58ad8cf4fae728a92e2aae0d3ec6073ddf49f2.
M2 — independent stable-base-URL fix. Вошедший в M3 base_url_changed только сообщает о смене URL между загрузками контекста с одинаковым identifier; URL и identifier не отправляются. Это не фикс M2.
Stacked PRs:
M3 telemetry — merged into origin/main
├── M4 hung recovery
└── M5+M6 graveyard mitigation + A/B — one PR
M5+M6 объединены на origin/main (2d58ad8cf4fae728a92e2aae0d3ec6073ddf49f2) без commit: в worktree лежат 19 unstaged файлов mitigation и A/B. Старый M6 worktree сохранён только как источник/backup и не является отдельным PR. M4 не изменён.
Не включать generated Package.resolved churn.
Experiment contract
- Experiment:
cpmBackgroundGraveyardExperiment. - Cohorts:
control,treatment. - Enrollment: only on an actual eligible CPM background-process termination.
- Primary framework metric:
cpmBackgroundGraveyardOutcome, window0...1, valueshealthy,initialization_failed,not_measured. - Rollback: disable both
cpmBackgroundGraveyardExperimentandcpmBackgroundGraveyard.
Full definition and config draft: cpm-background-graveyard-experiment-definition.
Remaining gates
- Обновить и проверить M4 поверх merged M3. Открыть M2, M4 и объединённый M5+M6 PRs в topology выше.
- Create separate iOS and macOS experiment-log tasks.
- Create Privacy Configuration + privacy/schema review tasks.
- Create Data Science sample-size/design and Native Apps Experiment Analysis task.
- Ship M3 first; enable M5/M6 only if production telemetry confirms the process-death hypothesis.
M3 merged, но ещё не подтверждён как shipped production release. Feature flag registry tasks созданы отдельно для iOS/macOS; ссылки — в cpm-m3-telemetry-privacy-triage. Это обновление затрагивает только Obsidian.