16 KiB
title, date, tags
| title | date | tags | |||
|---|---|---|---|---|---|
| CPM Web Extension — карта кода по worktree и строкам | 2026-10-09 |
|
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 → при сбое монитор зовёт перезапуск.
SP/Lifecycle/WebExtensionLifecycleCoordinator.swift:79-93—initialLoadWaiter, его вызывают обе платформы на каждой main-frame навигации. Было: после открытия стартового gate →nil. Стало::89зовётmanager.prepareEmbeddedBackgroundForNavigation()и ждёт его не дольшеinitialLoadTimeout(5 с,:91-92).SP/Manager/WebExtensionManager+EmbeddedBackground.swift(новый)::35prepareEmbeddedBackgroundForNavigation()— сначалаwatchdog.restartBackgroundIfStale()(:36), потом возвращает waiter, если идёт первый старт background только что установленного extension.:45trackEmbeddedBackgroundStartup(identifier:)— запускаетcontext.loadBackgroundContent()(:49) какTaskи держит его вembeddedBackgroundStartup, пока не завершится. Зачем: WebKit при первой загрузке нового идентификатора грузит background сразу и теряетinit, пришедший до выполнения скрипта (317981).
SP/Manager/WebExtensionManager+EmbeddedExtensions.swift:178-180— послеinstallationStore.addдля.embeddedвызываетсяtrackEmbeddedBackgroundStartup. Покрывает установку и обновление посреди сессии (на запуске это уже делал стартовый gate).SP/Manager/WebExtensionManager.swift::134-139— свойстваembeddedBackgroundWatchdogиembeddedBackgroundStartup.:167— параметр initisEmbeddedBackgroundRecoveryEnabled(по умолчанию{ true }, к удалённому флагу не подключён).:186— создание watchdog.:217-221—healthMonitor.onEpisodeStarted→restartBackgroundIfResponsive(reason:): перезапуск по первому сбою.:757— в делегатеdidCreateBackgroundWebViewwatchdog получает новую background view.
SP/Lifecycle/EmbeddedBackgroundLivenessWatchdog.swift(новый)::63init — все зависимости подменяемые (PID, перезапуск, проба отзывчивости).:76backgroundWebViewDidChange— запоминает view и PID Network-процесса, запускает периодическую проверку.:85restartBackgroundIfStale— PID Network-процесса сменился (или исчез) → перезапуск. Это и есть детектор «Network-процесс упал, worker мёртв».:107restartBackgroundIfResponsive— перезапуск по сбою, только если процесс ответил наreturn 1за 1 с (:166-170). Замороженный не трогаем: убийство остановленного процесса давало глухой новый worker.:137периодическая проверка раз в 1 с;:156_networkProcessIdentifier(SPI через KVC);:173-180перезапуск через_killWebContentProcessAndResetState— WebKit поднимает новый worker, и чинятся даже уже открытые документы.
SP/Autoconsent/CPMMessagingHealthMonitor.swift:96-100— колбэкonEpisodeStarted;:656-658— вызывается на первом сбое нового эпизода, только дляfailureReason == .other(не session restoration).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::51recorder диагностики;:191contextErrorCodes;:196папка установленного extension;:203prependToBackgroundScript— дописывает код в начало background-скрипта на диске (WebKit читает его заново на каждом пробуждении);:212PID Network-процесса;:262loadRealPage(для наполнения кэша).TP/CPMRepro/CPMReproBackgroundLoadFailureTests.swift— error 6, 9 тестов, все с проверками::59новый процесс background заморожен на 45 с при пробуждении → только:6,bg_load_error_after=25s_to_35s. Это таймер выгрузки WebKit.:7010 с → 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, затем поздний ответ.:2812 с + навигация →stuck→ M4.:31сигналы готовности:isLoading=falseчерез 0,1 с (бесполезен), completionloadBackgroundContentи первое нативное сообщение — ровно на старте worker'а.
- Продовые изменения здесь (
CPMMessagingDiagnostics*, JSON5,WebExtensionManager+iOS.swift,AppDelegate.swift) — старая копия телеметрии error 6, она целиком перенесена в worktree телеметрии. Отсюда не коммитить.
3. Телеметрия фазы 1 — alex/cpm-messaging-readiness-telemetry
Только параметры пикселей, поведение детектора не меняется.
SP/Autoconsent/CPMMessagingDiagnostics.swift::29ApplicationState,:38провайдер состояния приложения вCPMAppSessionDiagnostics.:50CPMBackgroundReadiness: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.- Бакеты:
:248error 6 (вокруг таймера 30 с),:258возраст view,:269готовность (вокруг 4 с монитора и 30 с WebKit),:285число вкладок.
SP/Autoconsent/CPMBackgroundReadinessObserver.swift(новый) — откуда берётсяbg_ready_after::52observeна создании view: ставитpendingи на следующем шаге run loop (:56) зовётloadBackgroundContent. View уже есть, поэтому вызов лишь присоединяется к идущей загрузке и ничего не будит.- completion →
loaded(секунды от создания view)илиfailed; ответ для заменённой view игнорируется. :34загрузчик подменяется в тестах;:72readiness(of:)— только для текущей view.
SP/Autoconsent/CPMMessagingDiagnosticsRecorder.swift::125,:141наблюдатель;:223сброс при новом контексте.:311-316наблюдение включается тем же флагом, что и delegate proxy (cpmBackgroundDelegateProxy).:413-415поля error 6;:426состояние приложения;:430-431возраст view и готовность;:435-438open_tabs/loading_tabsизcontext.openTabsиwebView(for:).isLoading.:503-517recordContextErrors— при error 6 фиксирует состояние приложения и секунды от создания view.
SP/Pixels/WebExtensionPixelFiring.swift::71,:73— у recovery-событий появилсяdetails(по умолчаниюnil, старые вызовы не ломаются).:85CPMMessagingRecoveryDetails:failed_navigation(опоздавший ответ) /later_navigation/unattributed+:108бакетыrecovery_after.:181-188параметры пикселя.
SP/Autoconsent/CPMMessagingHealthMonitor.swift::451-452неатрибутированный ответ закрывает stuck →unattributed.:712-716обычное восстановление: тот же упавший замер →failed_navigation, иначеlater_navigation.:722recoveryDetails— секунды от первого сбоя эпизода.
- Приложения:
iOS/DuckDuckGo/WebExtensions/WebExtensionManager+iOS.swift:107-114(UIApplication.applicationState),macOS/DuckDuckGo/Application/AppDelegate.swift:122-123(NSApp.isActive). - JSON5:
- словари
iOS/PixelDefinitions/pixels/params_dictionary.json5(:602recovery,:619error 6,:643готовность и вкладки) иmacOS/.../params_dictionary.json5(:677,:694,:718); - определения — iOS
debug_pixels.json5, macOSweb_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-процесса, обновление); старая база.