diff --git a/work/projects/cpm-web-extension-breakage-session-summary-2026-10-07.md b/work/projects/cpm-web-extension-breakage-session-summary-2026-10-07.md index b16930e5..d2a3b351 100644 --- a/work/projects/cpm-web-extension-breakage-session-summary-2026-10-07.md +++ b/work/projects/cpm-web-extension-breakage-session-summary-2026-10-07.md @@ -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. --- diff --git a/work/projects/cpm-web-extension-code-guide-2026-10-09.md b/work/projects/cpm-web-extension-code-guide-2026-10-09.md new file mode 100644 index 00000000..84597aa9 --- /dev/null +++ b/work/projects/cpm-web-extension-code-guide-2026-10-09.md @@ -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:///`; если из идентификатора не собрать URL — ошибка `invalidIdentifier`. +- `TP/WebExtensionLoaderDelegateTests.swift:61-94` — 2 теста: URL выставлен до загрузки; неверный идентификатор → загрузка не начинается. +- Открыто: сейчас меняет URL **всем** extension (нужно — только встроенным без `web_accessible_resources`); не прогнан через harness (M4, краш Network-процесса, обновление); старая база. diff --git a/work/projects/cpm-web-extension-repro-and-fix-2026-10-08.md b/work/projects/cpm-web-extension-repro-and-fix-2026-10-08.md index 0d86e8ff..449ca22d 100644 --- a/work/projects/cpm-web-extension-repro-and-fix-2026-10-08.md +++ b/work/projects/cpm-web-extension-repro-and-fix-2026-10-08.md @@ -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.