[2026-10-08] eagle: work/projects/cpm-web-extension-breakage-session-summary-2026-10-07.md work/projects/cpm-web-extension-repro-and-fix-2026-10-08.md

This commit is contained in:
Alexey Martemyanov committed 2026-10-08 16:54:27 +06:00
1 parent 242931e503
commit ef1b44e2e0
2 files changed
+50 -1

No files matched your search

@@ -258,6 +258,8 @@ Error 6 частично ложится на путь `refreshCpmDashboardState`
- **Полный отказ:** падение Network-процесса оставляет background живым, а worker мёртвым; ломаются все вкладки и уже открытые документы; M4 чинит только новые навигации. Закрыто watchdog'ом, который перезапускает только background-процесс.
- **Смерть worker'а при живом Network-процессе** (SPI или удаление SW-регистраций) из приложения не обнаружить; закрыто перезапуском background по первому сбою (стоит одну навигацию).
- Сверка с данными 5 октября: смена Network-процесса заметно чаще в группе «без видимой ошибки» (iOS 17–21%, macOS 30–45% против ~10% и 1–3% в остальных группах), но это не доказательство — нужен параметр `network_replaced_since_view`. Error 6 на iOS (~1/3 строк), привязка вкладок и большая часть «здоровых» сбоев фиксами не покрыты.
- **Error 6 (iOS):** механизм воспроизведён на macOS — процесс нового background'а не выполняется ≥30 с во время загрузки → таймаут SW → error 6 с продовой сигнатурой. Вероятный iOS-путь: будильник CPM `cpm-summary` будит background, пока приложение в фоне и процессы приостановлены. Ждёт подтверждения на устройстве с iOS 26 (подключённый iPhone на 18.1).
- **Привязка вкладок (macOS):** гипотеза «флаг мигает → новый менеджер» отброшена — флаг всегда `enabled`; проверяются popup-вкладки и пересборка user scripts.
- Фикс не закоммичен; открытые вопросы (feature flag, телеметрия, SPI, сборка приложений, ping в extension) — в заметке по ссылке.
---
@@ -20,6 +20,7 @@ tags:
- Оба класса отказа воспроизведены, причины найдены, фикс на стороне app написан, тесты зелёные.
- Сверка с данными 5 октября: механизм краша Network-процесса подкреплён лишь частично (20–45% «здоровых» `stuck`); error 6 на iOS (~1/3 строк), привязка вкладок и большая часть «здоровых» сбоев фиксами не покрыты. Нужна телеметрия до или вместе с фиксами (раздел «Телеметрия для валидации»).
- Весь пакет: 490 тестов, 0 падений (repro-тесты без env пропускаются). SwiftLint `--strict` чистый.
- **8 октября:** разбор непокрытых групп ведётся в отдельном worktree `alex/cpm-web-extension-remaining-failures` (без фиксов, как в проде) — см. раздел «Непокрытые группы: расследование». Error 6 воспроизведён на macOS, найден естественный iOS-путь (будильник CPM будит background, пока приложение в фоне); ждёт подтверждения на устройстве с iOS 26.
## Что нашли
@@ -96,6 +97,50 @@ tags:
- **Нет background view** — WebKit не пересоздал background; обоим механизмам нужен живой view.
- **«Здоровые» без смены Network-процесса — крупнейший необъяснённый остаток** (1 170 iOS / 497 macOS). Кандидаты: другая смерть worker'а (поймает перезапуск по сбою), поздний или несопоставленный `refreshCpmDashboardState` при живом worker'е (перезапуск — ложное срабатывание), первая загрузка вне gate. Без `native_seen` не разделить.
## Непокрытые группы: расследование (8 октября)
Worktree `alex/cpm-web-extension-remaining-failures`, ветка от того же коммита `a0717cf098`, **без фиксов** — чтобы воспроизводить на коде как в проде. Фиксы остаются незакоммиченными в `alex/cpm-web-extension-ready-handshake`.
- В harness перенесена инфраструктура (без watchdog/recovery) и подключён production `CPMMessagingDiagnosticsRecorder`: воспроизведённые сбои дают те же параметры пикселей, что и прод (`bg_events`, `context_errors`, `network_restarted`, …). Watcher логирует `context.errors`.
- Новый набор `CPMReproBackgroundLoadFailureTests`: idle-выгрузка (~32 с), затем пробуждение навигацией при заданном условии.
### Error 6 (`BackgroundContentFailedToLoad`, ~1/3 строк `stuck` на iOS)
WebKit (`WebExtensionContextCocoa.mm`): error 6 ставится, когда `_loadServiceWorker` вернул `success=false` (`:2796`) или упала навигация background-страницы (`:3052`). **Код 7 — внутренний `ScriptExecutionError`** (`didEncounterScriptError`, `:284`): JS-ошибка в скрипте extension во время работы. В проде: `7,6` — 283, только `6` — 259, `6,7` — 103 из 645 строк iOS с error 6.
| Условие при пробуждении (macOS) | Результат |
|---|---|
| Без помех | доставлено |
| Network-процесс заморожен 5/10/60 с | пробуждение потеряно, error 6 нет, потом всё работает |
| Network-процесс убит перед пробуждением | доставлено |
| Background убит во время загрузки | пробуждение потеряно (`died_client`), error 6 нет |
| Файлы extension отсутствуют | error 6 + `WKWebExtensionErrorDomain:2` — **в проде кода 2 нет, не причина** |
| Background-скрипт бросает на верхнем уровне / нет `browser`/`chrome` | error 6 **без** кода 7 — точная продовая сигнатура «только 6», но продовой причины падения скрипта не нашлось |
| **Новый процесс background заморожен ≥30 с во время загрузки** | **таймаут загрузки SW → `background none` + error 6**, цепочка `view, proxy_on, unresponsive, error:6, dealloc`; 10 с — error 6 нет; после разморозки работает |
**Естественный путь на iOS (гипотеза):** в настоящем приложении в iOS Simulator видно, что CPM сам будит background будильником `cpm-summary` (через 2 мин после активности, шлёт `autoconsent_summary`) — **в том числе когда приложение в фоне**. На устройстве RunningBoard не даёт фоновому приложению держать новый WebContent-процесс активным → процесс приостанавливается посреди загрузки SW → таймаут ~30 с → error 6. Объясняет, почему error 6 почти только на iOS (579 против 3).
Ограничения проверки:
- Тесты пакета в iOS Simulator непоказательны: процесс `xctest` не получает RunningBoard assertions (`Failed to acquire RBS assertion`), background не работает с самого начала.
- В приложении в симуляторе фоновое приложение не приостанавливается (background живёт 40–50 с и грузится), поэтому сам error 6 там не появляется.
- **Нужно устройство с iOS 18.4+ (лучше 26.x).** Подключённый iPhone 12 mini — на iOS 18.1: CPM-extension там не включается (`@available(iOS 18.4)`). Сборка DDG iOS (Debug), локальный HTTP-сервер со страницами и сценарии через `simctl`/`devicectl` готовы.
Сценарий для устройства: открыть страницу → свернуть приложение → ждать 2–3 мин (будильник `cpm-summary`) → вернуться → навигация; снимать логи `WebExtensions` (`[CPM Diagnostics]`, `Context error`).
Возможный фикс, если подтвердится: при возврате приложения на передний план, если `context.errors` содержит error 6 или background мёртв, — перезапустить background; либо не давать будильнику будить background, пока приложение в фоне (изменение extension или WebKit).
### Привязка вкладок на macOS (`tab_controller_match=false` + нет scripts, ~100 строк)
- **Гипотеза атрибуции не подтвердилась.** Путь в коде есть: выключение флага `webExtensions` вызывает `uninstallAllExtensions()` и обнуляет менеджер, включение создаёт новый с новым controller, а `WKWebViewConfiguration` старых вкладок не меняется. Но флаг `.webExtensions` = `remoteReleasable(WebExtensionsSubfeature.featureEnabled)` с `defaultValue: .enabled`, а подфичи `featureEnabled` нет ни во встроенном, ни в текущем удалённом `macos-config.json` → флаг всегда `enabled` (отсутствующая подфича возвращает `defaultValue`). Мигать нечему.
- **Порядок запуска не объясняет:** `setupWebExtensions()` (`AppDelegate.swift:1509`) вызывается до восстановления сессии (`:1526`), раньше вкладки не создаются.
- `tab_controller_match` считается как `tabController != nil && tabController === context.webExtensionController` (`CPMMessagingDiagnosticsRecorder.swift:378`) — `false` и при **отсутствующем** controller у вкладки, и при устаревшей ссылке на контекст.
- Следующие кандидаты: вкладки из `createWebViewWith` (popup / `target=_blank`) и кэш закреплённых вкладок; пересборка user scripts в `UserContentController` приложения при обновлении правил content blocking — может стирать скрипты extension из вкладки (на iOS есть группа «скриптов нет при верном controller»).
### Ещё не начато
- **Нет background view** (158 iOS / 35 macOS).
- **«Здоровые» сбои без смены Network-процесса** (1 170 iOS / 497 macOS) — разделять после `native_seen`.
## Телеметрия для валидации
Выпустить раньше фиксов или вместе с ними в A/B — иначе эффект фиксов не отделить. Все значения — bool/enum/bucket, без URL и идентификаторов; оформить через `ddg-add-pixel`, privacy triage (прецедент — [[cpm-m3-telemetry-privacy-triage]]).
@@ -131,7 +176,9 @@ tags:
- [ ] **Риск перезапуска по первому сбою.** Первых сбоев много (~6.6k установок/день на iOS); часть — не мёртвый worker (нет инъекции, медленный native). Перезапуск дешевле M4, но рвёт незавершённую работу background для других вкладок. Решить: включать сразу или через эксперимент.
- [ ] **Телеметрия.** Восстановление после перезапуска сейчас попадает в `recovered_without_extension_reload` и неотличимо. Реализовать план из раздела «Телеметрия для валидации»; минимум — `network_replaced_since_view`, `native_seen` и пиксель `background_restarted`.
- [ ] **Порядок выкатки.** Телеметрия раньше фиксов или вместе с ними в A/B-эксперименте с когортой в CPM-пикселях.
- [ ] **Error 6 на iOS** (~1/3 строк `stuck`) не покрыт фиксами. Следующий шаг — воспроизвести в harness (цепочка `dealloc → error:6 → view`).
- [ ] **Error 6 на iOS** (~1/3 строк `stuck`) не покрыт фиксами. Механизм воспроизведён на macOS (заморозка нового background ≥30 с во время загрузки). **Обновить iPhone до iOS 26.x** и подтвердить сценарий с будильником `cpm-summary` в фоне; затем решить про фикс.
- [ ] **Привязка вкладок на macOS:** гипотеза мигания флага отброшена; проверить popup-вкладки, кэш закреплённых вкладок и пересборку user scripts.
- [ ] Телеметрия для error 6: причина в `context_errors` (описание ошибки, хотя бы категория) и состояние приложения в момент ошибки (foreground/background).
- [ ] **Остаток «здоровых» сбоев без смены Network-процесса** (1 170 iOS / 497 macOS) не объяснён; разделить после `native_seen`.
- [ ] **SPI.** Перезапуск через `_killWebContentProcessAndResetState`, детекция через `_networkProcessIdentifier`; есть `responds(to:)`. Согласовать с командой (приложение уже использует SPI WebKit в этом месте).
- [ ] **Сборка приложений.** iOS и macOS не собирал; изменения обратно совместимы (дефолтная реализация нового метода протокола, дефолтный параметр init). Проверить сборку и прогнать на iOS Simulator.