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

This commit is contained in:
Alexey Martemyanov committed 2026-10-09 15:19:50 +06:00
1 parent 40a4a4a713
commit 7f45813b83
3 files changed
+164 -19

No files matched your search

@@ -5,6 +5,8 @@
## Короткий вывод
> Разделы 1–9 — состояние на 7 октября. Актуальный статус и находки после воспроизведения — **раздел 10**.
Главный production-сигнал — не доказанная потеря `initResp`, а отсутствие в течение 4 секунд native-вызова `refreshCpmDashboardState` после завершения навигации. Поэтому большая группа, где native-снимок выглядит здоровым, означает: WebKit controller/context/scripts могли существовать, но CPM не прислал или native не сопоставил ожидаемый dashboard refresh. Она не доказывает, что extension вообще не загрузился.
Наиболее близкие к этому симптому WebKit-кандидаты — гонки при cold start service worker:
@@ -249,18 +251,35 @@ Error 6 частично ложится на путь `refreshCpmDashboardState`
---
## 10. Статус на 8 октября
## 10. Статус на 9 октября
Подробно: [[cpm-web-extension-repro-and-fix-2026-10-08]].
Подробно: [[cpm-web-extension-repro-and-fix-2026-10-08]]. Сводки на английском для Asana: [[cpm-web-extension-data-analysis-summary-2026-10-08]] и [[cpm-web-extension-repro-and-fixes-summary-2026-10-08]]. Карта кода по строкам: [[cpm-web-extension-code-guide-2026-10-09]]. **Ничего не закоммичено.**
- Сделан harness на реальном WebKit (раздел 8): production extension, `WebExtensionManager`, coordinator + navigation gate, монитор и M4 в настоящих `WKWebView`.
- **Одна вкладка:** потеря `init` при первой загрузке background нового идентификатора (установка или обновление) воспроизведена, это 317981. При запуске её уже закрывает gate coordinator'а; открытыми оставались установка или обновление посреди сессии — закрыто.
- **Полный отказ:** падение 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):** причина найдена в коде WebKit — при пробуждении 30-секундный idle-таймер выгрузки взводится до окончания загрузки service worker'а; загрузка дольше 30 с закрывается → error 6 (продовый порядок `dealloc → error:6 → view`). Тест-репро на macOS есть. На iPhone с iOS 26.7.1 в четырёх сценариях (фон, будильник CPM, звук в фоне) не воспроизвёлся; добавлена телеметрия `bg_load_error_app_state` / `bg_load_error_after`, чтобы прод показал условия.
- **Привязка вкладок (macOS):** гипотеза «флаг мигает → новый менеджер» отброшена — флаг всегда `enabled`; проверяются popup-вкладки и пересборка user scripts.
- Фикс не закоммичен; открытые вопросы (feature flag, телеметрия, SPI, сборка приложений, ping в extension) — в заметке по ссылке.
**Воспроизведено и закрыто фиксами (worktree `alex/cpm-web-extension-ready-handshake`):**
- Harness на реальном WebKit (раздел 8): production extension, `WebExtensionManager`, coordinator + navigation gate, монитор, M4, production-recorder диагностики.
- **Одна вкладка:** потеря `init` при первой загрузке background нового идентификатора (установка или обновление), 317981. При запуске её закрывает gate coordinator'а; установку и обновление посреди сессии закрыл новый gate.
- **Полный отказ:** падение Network-процесса оставляет background живым, а worker мёртвым; ломаются все вкладки и открытые документы; M4 чинит только новые навигации. Закрыто watchdog'ом, перезапускающим только background-процесс.
- **Смерть worker'а при живом Network-процессе** из приложения не обнаружить; закрыто перезапуском background по первому сбою (стоит одну навигацию). **Риск:** при медленном пробуждении, когда процесс отвечает, перезапуск убьёт грузящийся worker.
**Сверка с данными 5 октября:**
- Network-процесс объясняет не больше 20–45% «здоровых» `stuck`.
- **Группа 1** («здоровые» без смены Network-процесса, iOS 748 / macOS 228 daily): около половины — сразу после пробуждения background после idle-выгрузки; около четверти iOS и 15% macOS — после загрузки или reload контекста.
- **Поправка:** `recovered_without_extension_reload(initialization_failed)` к stuck не относится — он закрывает только init-эпизоды. Init → recovery без reload: 23% iOS / 25% macOS устройство-дней; stuck → recovery после M4: 64% / 74%. Сбои после загрузки контекста чаще проходят сами; на пробуждении чаще доходят до stuck.
**Новые находки 8–9 октября (worktree `alex/cpm-web-extension-remaining-failures`, без фиксов):**
- **Медленный старт worker'а на пробуждении** (> 4 с) воспроизводит сигнатуру группы 1 полностью: `bg_process_responsive=true`, `context_errors=none`, хвост `dealloc → view → proxy_on@30s`. 5 с → `initialization_failed`, затем поздний ответ; 12 с + следующая навигация → `stuck` → M4, который убивает живой медленный worker. Старт до 2,5 с — потерь нет. Почему на устройствах старт бывает долгим — неизвестно.
- **Error 6 (iOS, ~1/3 строк):** причина в WebKit — 30-секундный таймер выгрузки взводится до окончания загрузки. Репро на macOS есть, на iPhone (iOS 26.7.1) не воспроизвёлся.
- **WebKit 320812 / 312231@main (26.6+):** при смене `baseURL` загрузка контекста удаляет website data старого origin, включая весь дисковый кэш, и только потом инъецирует content scripts и грузит background. У DDG `baseURL` новый на каждом запуске и reload. На Mac с ~20–24 тыс. записей кэша задержка 0,75–1,35 с. Кандидат-митигация — стабильный `baseURL` (ветка `alex/cpm-stable-base-url`).
- **Другие баги WebKit:** 324743 (worker «загружен» до завершения регистрации; исправлен 22 сен, нет в 26.7/27.0) и 314194 (Lockdown Mode блокирует все service worker'ы; открыт).
- **Сигналы готовности background:** окончание загрузки страницы background view бесполезно (0,1 с); completion `loadBackgroundContent` и первое нативное сообщение worker'а точно отмечают его старт.
- **Отброшено:** блокировка устройства / data protection, устаревший URL вкладки на iOS, мигание флага для привязки вкладок на macOS.
**Телеметрия фазы 1 (worktree `alex/cpm-messaging-readiness-telemetry`, от свежего `main`):**
- На сбоях: `bg_ready_after`, `bg_view_age`, `app_state`, `open_tabs`, `loading_tabs`, `bg_load_error_app_state`, `bg_load_error_after`.
- На восстановлениях: `recovery_document`, `recovery_after`.
- Проверено на реальном WebKit; 677 тестов пакета, SwiftLint, `validate-pixel-defs`, сборка iOS и macOS — зелёные.
**Дальше:** фаза 2 детектора (отсчёт 4 с с момента готовности background, без эскалации до неё), раннее пробуждение background, стабильный `baseURL`, флаги и A/B для фиксов, репорты в WebKit. Не воспроизведены: привязка вкладок на macOS, «нет background view», код 7, первый сбой после M4.
---
@@ -0,0 +1,118 @@
---
title: CPM Web Extension — карта кода по worktree и строкам
date: '2026-10-09'
tags:
- work
- cpm
- webkit
---
# CPM Web Extension — карта кода по worktree и строкам
Контекст: [[cpm-web-extension-breakage-session-summary-2026-10-07]] (раздел 10), [[cpm-web-extension-repro-and-fix-2026-10-08]]. Номера строк — на 9 октября. **Ничего не закоммичено.** Корень всех worktree — `/Users/admin/DuckDuckGo/apple-browsers.git/`; пути ниже даны от корня worktree. `SP` = `SharedPackages/WebExtensions/Sources/WebExtensions`, `TP` = `SharedPackages/WebExtensions/Tests/WebExtensionsTests`.
| Worktree | Ветка, база | Что внутри |
|---|---|---|
| `alex/cpm-web-extension-ready-handshake` | та же, `a0717cf098` | Фиксы + основной harness |
| `alex/cpm-web-extension-remaining-failures` | та же, `a0717cf098` | Прод-код без фиксов, error 6 телеметрия (старая копия), репро error 6, очистки, медленного пробуждения |
| `alex/cpm-messaging-readiness-telemetry` | та же, `main` `92e09cdbbc` | Телеметрия фазы 1 (включает error 6) — кандидат на первый PR |
| `cpm-stable-base-url` | `alex/cpm-stable-base-url`, старая база `570c2f8ef4` | Эксперимент со стабильным `baseURL` |
## 1. Фиксы — `alex/cpm-web-extension-ready-handshake`
Цепочка: навигация → coordinator спрашивает менеджер → менеджер проверяет watchdog и незавершённый первый старт background → при сбое монитор зовёт перезапуск.
1. `SP/Lifecycle/WebExtensionLifecycleCoordinator.swift:79-93` — `initialLoadWaiter`, его вызывают обе платформы на каждой main-frame навигации. Было: после открытия стартового gate → `nil`. Стало: `:89` зовёт `manager.prepareEmbeddedBackgroundForNavigation()` и ждёт его не дольше `initialLoadTimeout` (5 с, `:91-92`).
2. `SP/Manager/WebExtensionManager+EmbeddedBackground.swift` (новый):
- `:35` `prepareEmbeddedBackgroundForNavigation()` — сначала `watchdog.restartBackgroundIfStale()` (`:36`), потом возвращает waiter, если идёт первый старт background только что установленного extension.
- `:45` `trackEmbeddedBackgroundStartup(identifier:)` — запускает `context.loadBackgroundContent()` (`:49`) как `Task` и держит его в `embeddedBackgroundStartup`, пока не завершится. Зачем: WebKit при первой загрузке нового идентификатора грузит background сразу и теряет `init`, пришедший до выполнения скрипта (317981).
3. `SP/Manager/WebExtensionManager+EmbeddedExtensions.swift:178-180` — после `installationStore.add` для `.embedded` вызывается `trackEmbeddedBackgroundStartup`. Покрывает установку и обновление посреди сессии (на запуске это уже делал стартовый gate).
4. `SP/Manager/WebExtensionManager.swift`:
- `:134-139` — свойства `embeddedBackgroundWatchdog` и `embeddedBackgroundStartup`.
- `:167` — параметр init `isEmbeddedBackgroundRecoveryEnabled` (по умолчанию `{ true }`, к удалённому флагу не подключён).
- `:186` — создание watchdog.
- `:217-221` — `healthMonitor.onEpisodeStarted` → `restartBackgroundIfResponsive(reason:)`: перезапуск по первому сбою.
- `:757` — в делегате `didCreateBackgroundWebView` watchdog получает новую background view.
5. `SP/Lifecycle/EmbeddedBackgroundLivenessWatchdog.swift` (новый):
- `:63` init — все зависимости подменяемые (PID, перезапуск, проба отзывчивости).
- `:76` `backgroundWebViewDidChange` — запоминает view и PID Network-процесса, запускает периодическую проверку.
- `:85` `restartBackgroundIfStale` — PID Network-процесса сменился (или исчез) → перезапуск. Это и есть детектор «Network-процесс упал, worker мёртв».
- `:107` `restartBackgroundIfResponsive` — перезапуск по сбою, только если процесс ответил на `return 1` за 1 с (`:166-170`). Замороженный не трогаем: убийство остановленного процесса давало глухой новый worker.
- `:137` периодическая проверка раз в 1 с; `:156` `_networkProcessIdentifier` (SPI через KVC); `:173-180` перезапуск через `_killWebContentProcessAndResetState` — WebKit поднимает новый worker, и чинятся даже уже открытые документы.
6. `SP/Autoconsent/CPMMessagingHealthMonitor.swift:96-100` — колбэк `onEpisodeStarted`; `:656-658` — вызывается на первом сбое нового эпизода, только для `failureReason == .other` (не session restoration).
7. `SP/Manager/WebExtensionManaging.swift:164-168` — требование протокола; `:176-178` — реализация по умолчанию `{ nil }`, чтобы моки и платформы не ломались.
**Тесты:**
- `TP/EmbeddedBackgroundLivenessWatchdogTests.swift` — 11 unit-тестов (`:48`–`:150`): смена PID, исчезновение Network-процесса, отзывчивый и неотзывчивый процесс, выключатель, `stop()`, периодическая проверка.
- `TP/WebExtensionLifecycleCoordinatorTests.swift:193, :217, :227, :243` — навигация ждёт первый старт; не ждёт, если готов; ожидание ограничено 5 с; при выключенном gate ничего не готовится. Мок — `:667`.
- `TP/CPMMessagingHealthMonitorTests.swift:50, :61, :71` — `onEpisodeStarted` на первом сбое; не на session restoration; снова для нового эпизода.
- **Harness** `TP/CPMRepro/` (запуск: `CPM_REPRO=1 swift test --filter CPMRepro` из `SharedPackages/WebExtensions`):
- `CPMReproSingleTabTests.swift` — 10 тестов одной вкладки: холодный старт `:32`, обновление на запуске `:46`, **установка/обновление посреди сессии `:64`, `:87`** (до фикса терялись), перезапуск `:111`, `:128`, после reload `:146`, `:165`, пробуждение `:187`, падение background `:206`.
- `CPMReproFullFailureTests.swift` — краш Network-процесса `:33`, `:38`, `:55` (без M4); смерть worker'а через SPI `:76` и удаление регистраций `:85` (стоит одну навигацию); не-триггеры `:124`, `:129`, `:136`.
- `CPMReproWebKitTests.swift` — 7 тестов, нужен `CPM_REPRO_WEBKIT=1`: защиты выключены, утверждают, что баги WebKit ещё есть (`:45` потеря `init` при первой загрузке, `:80`/`:87`/`:151` мёртвый worker, `:97` только перезапуск background чинит открытые документы, `:133` сообщение из страницы background не доходит до worker'а).
- `CPMReproWakeExperimentTests.swift:27-28` — **эксперимент, не для коммита**: медленное пробуждение 5 и 12 с с фиксами. Для него в `CPMReproHarness.swift` свойство `storage` сделано не `private`.
## 2. Расследование без фиксов — `alex/cpm-web-extension-remaining-failures`
Прод-код как в релизе; harness перенесён без watchdog, с production-recorder'ом, поэтому сбои дают те же параметры пикселей, что в проде.
- `TP/CPMRepro/CPMReproHarness.swift`: `:51` recorder диагностики; `:191` `contextErrorCodes`; `:196` папка установленного extension; `:203` `prependToBackgroundScript` — дописывает код в начало background-скрипта на диске (WebKit читает его заново на каждом пробуждении); `:212` PID Network-процесса; `:262` `loadRealPage` (для наполнения кэша).
- `TP/CPMRepro/CPMReproBackgroundLoadFailureTests.swift` — **error 6**, 9 тестов, все с проверками:
- `:59` новый процесс background заморожен на 45 с при пробуждении → только `:6`, `bg_load_error_after=25s_to_35s`. Это таймер выгрузки WebKit.
- `:70` 10 с → error 6 нет.
- `:79`, `:89`, `:96` — другие пути к error 6 (нет файлов, скрипт бросает, нет `browser`) — быстрые, `under_5s`; в проде их сигнатур нет.
- `:104`, `:111`, `:118`, `:125` — условия, которые error 6 не дают.
- `TP/CPMRepro/CPMReproExtensionLoadCleanupTests.swift:49, :69` — задержка очистки при смене `baseURL` на перезапуске и reload. Нужен локальный сервер: `CPM_REPRO_CACHE_URL`, `CPM_REPRO_CACHE_ENTRIES` (наполнение ~10 мин).
- `TP/CPMRepro/CPMReproWakeExperimentTests.swift` — **эксперимент, не для коммита**:
- `:27` старт worker'а 5 с на пробуждении → `initialization_failed` с сигнатурой группы 1, затем поздний ответ.
- `:28` 12 с + навигация → `stuck` → M4.
- `:31` сигналы готовности: `isLoading=false` через 0,1 с (бесполезен), completion `loadBackgroundContent` и первое нативное сообщение — ровно на старте worker'а.
- Продовые изменения здесь (`CPMMessagingDiagnostics*`, JSON5, `WebExtensionManager+iOS.swift`, `AppDelegate.swift`) — **старая копия телеметрии error 6**, она целиком перенесена в worktree телеметрии. Отсюда не коммитить.
## 3. Телеметрия фазы 1 — `alex/cpm-messaging-readiness-telemetry`
Только параметры пикселей, поведение детектора не меняется.
1. `SP/Autoconsent/CPMMessagingDiagnostics.swift`:
- `:29` `ApplicationState`, `:38` провайдер состояния приложения в `CPMAppSessionDiagnostics`.
- `:50` `CPMBackgroundReadiness`: `noBackground` / `pending` / `loaded(seconds)` / `failed`.
- `:109-123` новые поля снимка (error 6, `applicationState`, возраст view, готовность, вкладки).
- `:182-188` имена параметров (`bg_load_error_*`, `app_state`, `bg_view_age`, `bg_ready_after`, `open_tabs`, `loading_tabs`).
- `:217-231` сериализация: error 6 — `none`, если ошибки не было, и опускается, если неизвестно; остальные опускаются при `nil`.
- Бакеты: `:248` error 6 (вокруг таймера 30 с), `:258` возраст view, `:269` готовность (вокруг 4 с монитора и 30 с WebKit), `:285` число вкладок.
2. `SP/Autoconsent/CPMBackgroundReadinessObserver.swift` (новый) — откуда берётся `bg_ready_after`:
- `:52` `observe` на создании view: ставит `pending` и на **следующем шаге run loop** (`:56`) зовёт `loadBackgroundContent`. View уже есть, поэтому вызов лишь присоединяется к идущей загрузке и ничего не будит.
- completion → `loaded(секунды от создания view)` или `failed`; ответ для заменённой view игнорируется.
- `:34` загрузчик подменяется в тестах; `:72` `readiness(of:)` — только для текущей view.
3. `SP/Autoconsent/CPMMessagingDiagnosticsRecorder.swift`:
- `:125`, `:141` наблюдатель; `:223` сброс при новом контексте.
- `:311-316` наблюдение включается тем же флагом, что и delegate proxy (`cpmBackgroundDelegateProxy`).
- `:413-415` поля error 6; `:426` состояние приложения; `:430-431` возраст view и готовность; `:435-438` `open_tabs` / `loading_tabs` из `context.openTabs` и `webView(for:).isLoading`.
- `:503-517` `recordContextErrors` — при error 6 фиксирует состояние приложения и секунды от создания view.
4. `SP/Pixels/WebExtensionPixelFiring.swift`:
- `:71`, `:73` — у recovery-событий появился `details` (по умолчанию `nil`, старые вызовы не ломаются).
- `:85` `CPMMessagingRecoveryDetails`: `failed_navigation` (опоздавший ответ) / `later_navigation` / `unattributed` + `:108` бакеты `recovery_after`.
- `:181-188` параметры пикселя.
5. `SP/Autoconsent/CPMMessagingHealthMonitor.swift`:
- `:451-452` неатрибутированный ответ закрывает stuck → `unattributed`.
- `:712-716` обычное восстановление: тот же упавший замер → `failed_navigation`, иначе `later_navigation`.
- `:722` `recoveryDetails` — секунды от первого сбоя эпизода.
6. Приложения: `iOS/DuckDuckGo/WebExtensions/WebExtensionManager+iOS.swift:107-114` (`UIApplication.applicationState`), `macOS/DuckDuckGo/Application/AppDelegate.swift:122-123` (`NSApp.isActive`).
7. JSON5:
- словари `iOS/PixelDefinitions/pixels/params_dictionary.json5` (`:602` recovery, `:619` error 6, `:643` готовность и вкладки) и `macOS/.../params_dictionary.json5` (`:677`, `:694`, `:718`);
- определения — iOS `debug_pixels.json5`, macOS `web_extensions.json5`: по 8 пикселям сбоя и 2 пикселям восстановления.
**Тесты:**
- `TP/CPMMessagingDiagnosticsTests.swift`:
- бакеты `:135`, `:144`, `:149`; полный набор параметров `:154`;
- error 6 `:279`, `:417`;
- готовность: загрузилась `:304`, упала `:327`, заменённая view `:343`, наблюдение выключено `:360`;
- состояние приложения `:377`; вкладки на реальном контроллере с незавершающейся загрузкой `:384`.
- `TP/CPMMessagingHealthMonitorTests.swift`: опоздавший ответ `:1061`, следующая навигация `:1081`, `unattributed` `:1095`, бакеты `:1112`, обновлённый тест параметров `:1119`.
- Проверка на реальном WebKit (harness временно копировался): медленное пробуждение 5 с → `bg_ready_after=pending`, `bg_view_age=4s_to_8s`, затем `recovery_document=failed_navigation`, `recovery_after=under_4s`.
## 4. Стабильный `baseURL` — `cpm-stable-base-url`
- `SP/Loading/WebExtensionLoader.swift:56`, `:93`, `:134`, `:154`, `:158-165` — в `makeContext` выставляется `context.baseURL = webkit-extension://<uniqueIdentifier>/`; если из идентификатора не собрать URL — ошибка `invalidIdentifier`.
- `TP/WebExtensionLoaderDelegateTests.swift:61-94` — 2 теста: URL выставлен до загрузки; неверный идентификатор → загрузка не начинается.
- Открыто: сейчас меняет URL **всем** extension (нужно — только встроенным без `web_accessible_resources`); не прогнан через harness (M4, краш Network-процесса, обновление); старая база.
@@ -14,13 +14,15 @@ tags:
Среда: macOS 26.7.1 (25G241), system WebKit, production embedded extension 2026.9.29.
Код: worktree `alex/cpm-web-extension-ready-handshake`, пакет `SharedPackages/WebExtensions`. **Ничего не закоммичено.**
## Статус
## Статус (9 октября)
- Harness на реальном WebKit готов: реальные `WebExtensionManager`, `WebExtensionLifecycleCoordinator` + navigation gate, `CPMMessagingHealthMonitor` (4 с), M4, production extension без изменений логики.
- Оба класса отказа воспроизведены, причины найдены, фикс на стороне 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: причина найдена в коде WebKit (30-секундный idle-таймер взводится до окончания загрузки), есть тест-репро на macOS; на iPhone с iOS 26.7.1 не воспроизвёлся; добавлена телеметрия `bg_load_error_app_state` / `bg_load_error_after` (не закоммичено).
Карта кода по строкам: [[cpm-web-extension-code-guide-2026-10-09]]. Сводки на английском: [[cpm-web-extension-data-analysis-summary-2026-10-08]], [[cpm-web-extension-repro-and-fixes-summary-2026-10-08]]. **Ничего не закоммичено.**
- **Фиксы** — worktree `alex/cpm-web-extension-ready-handshake`: gate первой загрузки посреди сессии, watchdog Network-процесса, перезапуск по первому сбою. Тесты зелёные (490 в пакете на момент фикса).
- **Расследование без фиксов** — worktree `alex/cpm-web-extension-remaining-failures`: error 6 (причина в WebKit, репро на macOS), задержка очистки при смене `baseURL` (репро на macOS), медленный старт worker'а на пробуждении — сигнатура группы 1 воспроизведена.
- **Телеметрия фазы 1** — worktree `alex/cpm-messaging-readiness-telemetry` от свежего `main`: готовность background, возраст view, состояние приложения, вкладки, error 6, детали восстановления. 677 тестов, SwiftLint, валидатор пикселей, сборка iOS и macOS — зелёные.
- **Эксперимент** — ветка `alex/cpm-stable-base-url`: стабильный `baseURL` (на старой базе, не прогнан через harness).
- Не воспроизведены: привязка вкладок на macOS, «нет background view», код 7, первый сбой после M4; error 6 на iPhone.
## Что нашли
@@ -224,7 +226,7 @@ cd SharedPackages/WebExtensions && CPM_REPRO=1 swift test --filter CPMReproBackg
### Ещё не начато
- **Нет background view** (158 iOS / 35 macOS).
- **«Здоровые» сбои без смены Network-процесса** (1 170 iOS / 497 macOS) — разделять после `native_seen`.
- Причина долгого старта worker'а на реальных устройствах (группа 1): мерить на iPhone от пробуждения до первого `recv init` при загружающейся вкладке; дождаться `bg_ready_after` / `bg_view_age` / `open_tabs` из прода.
## Телеметрия для валидации
@@ -281,9 +283,15 @@ cd SharedPackages/WebExtensions && CPM_REPRO=1 swift test --filter CPMReproBackg
- [ ] На тестовом iPhone стоит debug-сборка DDG вместо 7.221.0 — вернуть из App Store, когда тесты закончатся.
- [ ] **Привязка вкладок на macOS:** гипотеза мигания флага отброшена; проверить popup-вкладки, кэш закреплённых вкладок и пересборку user scripts.
- [x] Телеметрия для error 6: состояние приложения и задержка до ошибки — реализовано в `alex/cpm-web-extension-remaining-failures` (не закоммичено). Нужны privacy triage и решение, в каком PR выпускать.
- [ ] **Остаток «здоровых» сбоев без смены Network-процесса** (1 170 iOS / 497 macOS) не объяснён; разделить после `native_seen`.
- [ ] **Остаток «здоровых» сбоев без смены Network-процесса** (группа 1): около половины — пробуждение, сигнатура воспроизведена медленным стартом worker'а; около четверти iOS — после загрузки контекста (задержка очистки при смене `baseURL`). Подтвердить телеметрией фазы 1.
- [ ] **SPI.** Перезапуск через `_killWebContentProcessAndResetState`, детекция через `_networkProcessIdentifier`; есть `responds(to:)`. Согласовать с командой (приложение уже использует SPI WebKit в этом месте).
- [ ] **Сборка приложений.** iOS и macOS не собирал; изменения обратно совместимы (дефолтная реализация нового метода протокола, дефолтный параметр init). Проверить сборку и прогнать на iOS Simulator.
- [ ] **Сборка приложений с фиксами.** Worktree с фиксами (`alex/cpm-web-extension-ready-handshake`) iOS и macOS не собирал; изменения обратно совместимы. Worktree телеметрии собран на обеих платформах.
- [ ] **Перезапуск по первому сбою vs медленное пробуждение.** Если медленный старт не занимает CPU, проба ответит и перезапуск убьёт грузящийся worker. Не перезапускать и не эскалировать в M4, пока background не готов (`bg_ready_after=pending`) или view моложе ~15 с — это фаза 2 детектора.
- [ ] **Фаза 2 детектора:** отсчёт 4 с от готовности background; отдельный пиксель «background не стартовал за 30 с»; stuck / M4 / перезапуск только при готовом background.
- [ ] **Раннее пробуждение background** при начале навигации и выходе приложения на передний план (`loadBackgroundContent`, без блокировки).
- [ ] **Стабильный `baseURL`:** ограничить встроенными расширениями без `web_accessible_resources` (сейчас диф меняет URL для всех в `makeContext`), прогнать harness (M4, краш Network-процесса, обновление), перенести на свежий `main`.
- [ ] **Выпуск телеметрии фазы 1:** privacy triage, решить, отдельным PR или вместе с фиксами в A/B.
- [ ] **Номер сборки ОС с фиксом 318756@main** (очистка при смене `baseURL`) — не проверен.
- [ ] **Zero-loss для смерти worker'а.** Нужен ping-канал в extension (native port с heartbeat или обработчик ping) — задача в репозитории extension.
- [ ] **Не воспроизведено:** продовое «первый probe после M4 падает» (670 iOS / 232 macOS). В тестах после M4 навигации проходят.
- [ ] **WebKit-баги для репорта:** (1) потеря сообщения при eager-загрузке background первой загрузки; (2) после краша Network-процесса или удаления регистраций `WebExtensionContext` не замечает мёртвый worker.