27 KiB
Executable File
title, date, tags
| title | date | tags | |||
|---|---|---|---|---|---|
| CPM Web Extension — карта кода по worktree и строкам | 2026-10-09 |
|
CPM Web Extension — карта кода по worktree и строкам
Актуальная карта — 15 октября 2026. Текущий статус PR/CI, данные и все 14 новых P5/P6 результатов: cpm-status-2026-10-15 (§2, §5, §10–12). Датированные исходные разделы 1–4 ниже сохранены; их «ничего не закоммичено», номера строк и общий worktree описывают 9 октября, а не текущее состояние.
0. Текущая карта worktree и запусков
Корень: /Users/admin/DuckDuckGo/apple-browsers.git/. Проверены git worktree list, HEAD и наличие тестовых файлов. Единого worktree со всеми suites нет. Общая база в истории не включает local dirty/untracked файлы; особенно это относится к remaining-failures и scratch init-progress E2E.
| Worktree | Ветка / текущий HEAD | Назначение и границы |
|---|---|---|
alex/cpm-web-extension-remaining-failures |
та же; a0717cf098cd |
Основное расследование без A/B watchdog: P1 (3 wake), P2 (9 load failure), P3 (2 cache/cleanup), новые P5/P6 (12 lifecycle + 2 flag). Все 28 repro opt-in; CPMRepro/ untracked. Production dirty telemetry — прежняя копия, не переносить вместе с тестами |
cpm-repro-harness |
alex/cpm-repro-harness; dfb96279196d |
PR #7378: базовый harness, быстрые CI-контроли, медленные сценарии и raw WebKit characterization; без новых P5/P6 |
cpm-fix-init-loss |
alex/cpm-fix-init-loss; 7ad771e227bb |
PR #7379: A, первые init при install/upgrade mid-session; красное/зелёное доказательство отдельно от remaining-failures |
cpm-fix-network-crash |
alex/cpm-fix-network-crash; local f1085846e7ff |
B поверх A; 5 network/termination сценариев в FullFailure + 11 watchdog unit tests. Remote PR #7381 остаётся на 39f94e12eaa4, красный Non-Sandbox; локальный fix не запушен |
cpm-fix-pixels |
alex/cpm-fix-pixels; d6d800846d1f |
A/B + PR0, измерение first_load_wait/background_restart; отдельный PR не зарегистрирован в текущем статусе |
alex/cpm-messaging-readiness-telemetry |
та же; 619869ee84c6 |
PR0 #7376: readiness/failure/recovery параметры, CI без failure/pending, review required |
cpm-readiness-baseline |
alex/cpm-readiness-baseline; 99ecf8b12787 |
#7384 поверх PR0: baseline readiness; Danger=FAILURE |
cpm-init-progress-native |
alex/cpm-init-progress-native; 46f25175c7c4 |
#7385 поверх baseline: init_stage, 11 CPMInitProgress unit tests; Danger=FAILURE. Нужен JS privacy-extension#3727 |
cpm-e2e-init |
scratch/cpm-e2e-init; 46f25175c7c4 |
Scratch harness поверх native init-progress: 3 CPMReproInitProgressE2ETests и базовые suites; наличие HEAD, совпадающего с #7385, не означает наличие scratch файлов в PR |
alex/cpm-web-extension-ready-handshake |
та же; a0717cf098cd |
Старый объединённый локальный A/B harness и slow-wake-with-fixes; архив сравнения. Текущие PR A/B нарезаны в worktree выше |
cpm-stable-base-url |
alex/cpm-stable-base-url; 570c2f8ef479 |
Старый M2 experiment: меняет baseURL всем extensions, не доведён и не прогнан через нужный integration harness. Прежнее «production-ready» в старых планах не является актуальным итогом |
CI статусы — read-only snapshot GitHub 15 октября, 17:26 UTC. Подробные head/base/checks и все оговорки — основной статус; локальные воспроизведения не дают зелёного CI незапушенному коду.
0.1. Файлы remaining-failures и полный охват
Путь тестов — SharedPackages/WebExtensions/Tests/WebExtensionsTests/CPMRepro/.
| Файл | Что искать |
|---|---|
CPMReproLifecycleHypothesisTests.swift:30 |
12 методов: nil/previous controller, startup healthy control, source-linked shared-window close + unrelated-window control, forgotten live tab, listener metadata, long documents/dashboard loss, host main-actor stall |
CPMReproProductionFlagTests.swift:30 |
2 метода: главный flag true→false→true даёт P6; true→true не меняет manager; embedded-only cycle сохраняет controller и работает после explicit ready wait |
CPMReproBackgroundLoadFailureTests.swift:31 |
9 методов P2: ≥30-секундный медленный запуск, 10-секундный контроль, file/script/bindings ошибки и четыре отрицательных process/load проверки |
CPMReproExtensionLoadCleanupTests.swift:36 |
2 метода P3: relaunch и reload при большом Network cache и смене baseURL |
CPMReproWakeExperimentTests.swift:25 |
3 метода P1: 5/12-секундный wake и сравнение readiness signals |
CPMReproTestCase.swift:37 |
Базовый opt-in CPM_REPRO=1, Options, cleanup. existingTabs (68) предоставляет сохранённые view до load нового context |
CPMReproHarness.swift:258,269,296 |
open/close additional window через production eventsListener; adopt existing view. :175 watcher без strong reference через await; :365 content marks |
CPMReproTabs.swift:29,148,165 |
Реальные WKWebView, navigation gate/monitor callbacks, window/tab delegates и multiple-window provider |
CPMReproDelayedResource.swift:26 |
Реальный 35-секундный image subresource; URL уникален на каждую навигацию |
CPMReproPrelude.swift |
DOM init/initResp marks, trace всех autoconsent payloads, startup/listener test seams |
CPMReproSupport.swift:43,92,175,213 |
Pixel recorder; optional native-method suppression; temporary instrumented extension copy; WebKit process SPI |
Результаты: все 14 новых методов P5/P6 имеют pass по нескольким запускам; последние обычные tests — 478 XCTest / 28 skipped / 0 failures (10.469 с), strict SwiftLint восьми изменённых файлов — 0. P1/P2/P3 в этом продолжении заново не запускались. Таблица всех 14, начальные красные результаты, log paths и SHA-256 — основной статус §12.
0.2. Browser → WebKit paths
P5: MainWindowController.windowWillClose (611–640) фильтрует сохраняемые tabs только для явных didCloseTab, затем unregister и didCloseWindow. MainWindowController+WKWebExtensionWindow.tabs(for:) (31) всё ещё возвращает loaded pinned + regular tabs. WindowControllersManager.unregister (178) не очищает closing-window collections. WebKit внутри WebExtensionContext::didCloseWindow сам вызывает didCloseTab для каждого delegate tab; тот попадает в forgetTab. runtimeSendMessage возвращает tab-not-found до wake. Проверены текущий browser worktree и macOS tag 1.210.0+macos; shared-window effect исполнен на системном WebKit.
P6: AppDelegate.setupWebExtensions/initializeWebExtensions (2153–2166, 2209–2221) и shared FeatureFlag/WebExtensionFeatureFlagHandler.swift: main disable → uninstall + clear references; enable при manager=nil → новый manager/controller без пересоздания старых WKWebView. WebExtensionTab::webView отвергает неправильный controller. Только test-controlled main-flag cycle доказан; исторические данные не подтверждают такой production transition. Default main flag enabled; повторный true и embedded-only toggle не заменяют controller.
WebKit source checkout: /Users/admin/Downloads/WebKit_sparse, HEAD 99051d5d08cd9f19ec76ce599f7539d070b1ae09:
Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionContextCocoa.mm:1351,1419;Source/WebKit/UIProcess/Extensions/Cocoa/API/WebExtensionContextAPIRuntimeCocoa.mm:129;Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionTabCocoa.mm:339.
Это карта source contract и system-WebKit проверки, не утверждение о полном совпадении checkout с shipped binary. В SPM исполняются production shared classes и WebKit, а app-side host callbacks/delegates реализованы harness.
0.3. Команды и предусловия
Из alex/cpm-web-extension-remaining-failures/SharedPackages/WebExtensions:
CPM_REPRO=1 CPM_REPRO_P5_P6=1 swift test --disable-automatic-resolution --filter 'CPMReproLifecycleHypothesisTests|CPMReproProductionFlagTests'
CPM_REPRO=1 CPM_REPRO_P5_P6=1 swift test --disable-automatic-resolution --filter 'CPMReproProductionFlagTests|CPMReproLifecycleHypothesisTests/testClosing'
CPM_REPRO=1 swift test --disable-automatic-resolution --filter CPMReproWakeExperimentTests
CPM_REPRO=1 swift test --disable-automatic-resolution --filter CPMReproBackgroundLoadFailureTests
swift test --disable-automatic-resolution --skip-build
Первая команда всех 14 дана для повторения: в текущей сессии 14 методов проверялись раздельными группами. --skip-build применим после актуальной сборки. Для P3 нужны CPM_REPRO_CACHE_URL (server /fill.html?n=N) и CPM_REPRO_CACHE_ENTRIES (default 20000; заполнение порядка 10 минут), затем filter CPMReproExtensionLoadCleanupTests.
Выделенный PR-harness в cpm-repro-harness имеет быстрые tests без общего opt-in и requireLocalRun для тяжёлых; raw WebKit characterization требует также CPM_REPRO_WEBKIT=1. Новые P5/P6 живут только в remaining-failures и в PR-harness ещё не переносились.
Environment P5/P6: macOS 26.7.1 (25G241), Xcode 27.1 (27A9275), embedded bundle 2026.9.29. M4 в этих 14 tests выключен, gate включён, Network PID прогрет до context-load; production bundle zip не правился, temporary copy содержит trace/DOM instrumentation. Нативные flags в production не переключались.
Архив карты на 9 октября. Все следующие разделы сохранены для старых source line references и истории экспериментов; текущие точки входа и статус — выше.
Контекст: 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-процесса, обновление); старая база.