Files
obsidian-vault/work/projects/cpm-web-extension-code-guide-2026-10-09.md
T

104 KiB
Executable File
Raw Blame History

title, date, tags
title date tags
CPM Web Extension — карта кода по worktree и строкам 2026-10-09
work
cpm
webkit

Актуально — 19 октября 2026, uninstall fix опубликован. #7379: production e970e8c90e, 6 commits / 22 paths; отдельный review-only harness e380cf98f7, 12 paths вне main. Удаление активного CPM context отменяет pending late-document recovery; удаление старой upgrade-версии и ошибка unload сохраняют recovery. 190 unit PASS, red-before-fix 2 PASS / 1 FAIL, signed macOS и iOS Simulator builds PASS, strict lint 11 / 0. На новом app head проверено на одних подписанных бинарниках: ON 8 PASS → OFF 6 ожидаемых functional FAIL → ON 8 PASS, без skips/expected failures; все app/XCTest SHA256 совпали. CI e970e8c90e: 48 SUCCESS / 21 SKIPPED, pending/failures нет. PR description и reviewer flag steps актуализированы с сохранением ручных правок. Формы оставлены в прежнем виде; late reload flag default disabled. Предыдущие heads/results ниже — история.

Актуально — 19 октября 2026, полный повторный review #7379. Проверен локальный 5708197362 против #7376: 22 changed paths, 187 существующих тестов PASS + 1 новый probe FAIL. Новый P2: uninstall активного CPM context не отменяет pending late-document recovery. Общий launch→navigation deadline и привязка recovery pixel к точной WKNavigation исправлены локально и прошли повторные регрессии; усиление защиты форм явно отложено пользователем, исходная проверка сохранена за default-disabled флагом. В GitHub пока 08866c7eda (CI: 48 SUCCESS / 21 SKIPPED), новые production commits не опубликованы. Локальный review-only harness 4308751d59 синхронизирован; его новый ON/OFF/ON ещё не запускался. Подробности — в конце; прежние heads/results ниже относятся к истории.

Актуально — 16 октября 2026, PR review fixes. В #7379 проверены оба inline замечания: cancellation уже покрыта, повторные 5 секунд на каждую navigation исправлены общим deadline на startup. Production 08866c7eda, 3 commits / 21 paths; review-only harness 3f4d755511, 12 test-only paths, вне main. Проверки: red-before-fix 2 FAIL, после исправления 182 unit PASS, signed macOS build и iOS shared-module build PASS, strict lint 8 / 0; на одних app/XCTest binaries ON 8 PASS → OFF 6 ожидаемых functional FAIL → ON 8 PASS, без skips. Оба review threads resolved; Danger 0 failures, только PR-size advisory; flag tracking links добавлены, defaults не менялись. Пользовательские правки и reviewer steps сохранены. Подробности этого review — в конце. Более ранние heads/results ниже сохранены как история.

Актуально — 16 октября 2026, reviewer ON → OFF → ON. В #7379 восстановлена проверка выключенных production flags. Review-only branch codex/cpm-fix-init-loss-integration-tests / 543e37164b содержит два schemes: CPM Integration Tests → 8 PASS; CPM Integration Tests - Fixes Disabled → ровно 6 functional FAIL; затем normal scheme → снова 8 PASS. Проверено на одних подписанных app/XCTest binaries, без пересборки и изменения Swift code. Production PR da126120a9, 2 commits / 21 files, не менялся; harness остаётся вне main (2 test-only commits / 12 paths). Пользовательские правки PR сохранены. Подробные результаты и artifacts — в конце; прежние односхемные steps и harness head 6e4e39e67c относятся к истории.

Актуально — 16 октября 2026, harness вынесен из PR. #7379: alex/cpm-fix-init-loss / da126120a9, база #7376, 2 коммита / 21 файл, production fixes + 18 новых shared unit regressions. Все local-only app tests, Xcode entries и DEBUG app hooks — только в codex/cpm-fix-init-loss-integration-tests / 6e4e39e67c, один дочерний commit от PR head; эта ветка не идёт в main. Проверено: production app build PASS, unit 179 PASS, harness app 8/8 PASS, strict lint 19+8 / 0. Reviewer steps в PR обновлены и пользовательские правки сохранены. Ниже сохранена датированная история; прежние 3 commits / 32 files и app harness в PR больше не актуальны.

Актуальный итог — 16 октября 2026, после force push. PR #7379 теперь поверх #7376 (alex/cpm-messaging-readiness-telemetry), head aec5be9a83, ровно 3 коммита / 32 файла. Старый worktree cpm-fix-init-loss удалён; текущая директория alex/cpm-fix-p1-p2 теперь на ветке alex/cpm-fix-init-loss. Checkpoint 367759cbc1 и backup старой истории сохранены. Проверка через production feature flags без создания/переключения коммитов: signed app 8/8 PASS ON, 6/6 функциональных FAIL OFF, unit 179 PASS, strict lint 27 / 0, pixel validators обеих платформ PASS. Новый late-reload flag default disabled. Описание PR/шаги и local-only to-be-disabled before merge annotations обновлены; GitHub CI ещё не объявляется green. Подробная финальная сверка — в конце документа. Ниже сохранена датированная история: прежние «не закоммичено», старые head/base и over-budget limitation не являются текущим статусом.

App integration update — 16 октября 2026, 01:48 Бишкек. В cpm-e2e-init добавлены 20 методов настоящего app-hosted CPM suite: финальные 20/20 PASS, 0 failures/skips/expected failures, группы 18+1+1 на одной signed build. Схема CPM Integration Tests; файлы/guards/запуск/ограничения — §5 ниже, полный реестр и история — cpm-status-2026-10-15#Финальный app-hosted итог — 16 октября 2026. Без commits. Карта остальных worktree/PR ниже сохраняет свою датированную сверку 15 октября.

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 — историческая строка; worktree удалён 16 Oct alex/cpm-fix-init-loss; 7ad771e227bb PR #7379: A, первые init при install/upgrade mid-session; красное/зелёное доказательство отдельно от remaining-failures
alex/cpm-fix-p1-p2 — актуально 19 Oct alex/cpm-fix-init-loss; local/remote e970e8c90e PR #7379 / база #7376: 6 commits / 22 paths, 29 новых shared tests, 190 PASS. Launch deadline, WKNavigation attribution и uninstall/preflight race исправлены и опубликованы; формы отложены, late reload flag default disabled; builds/lint PASS
— (отдельная ветка, без своего worktree) codex/cpm-fix-init-loss-integration-tests; local/remote e380cf98f7 Синхронизирована с production e970e8c90e, README: 29 новых shared tests; 8 app methods, ON/OFF schemes, PBX + 3 DEBUG app hooks; 12 paths вне main. На одних signed binaries ON 8 PASS → OFF 6 functional FAIL → ON 8 PASS; SHA256 совпали
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 (HEAD сохранён, без новых commits) Прежний scratch native init-progress/SPM harness плюс новые 20 app-hosted XCTest methods в macOS/IntegrationTests/CPM/ и схема CPM Integration Tests; результаты и ограничения — §13 status. Наличие HEAD, совпадающего с #7385, не означает наличие untracked suites в 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 → при сбое монитор зовёт перезапуск.

  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-процесса, обновление); старая база.

5. App-hosted CPM integration tests — 16 октября 2026

Worktree /Users/admin/DuckDuckGo/apple-browsers.git/cpm-e2e-init, branch scratch/cpm-e2e-init, HEAD 46f25175c7c42766cab23ea39f447f075c7bdd24, без commits. Новая схема macOS/DuckDuckGo-macOS.xcodeproj/xcshareddata/xcschemes/CPM Integration Tests.xcscheme выбирает только две CPM classes, отключает parallel testing и включает CPM_APP_INTEGRATION=1. В ней нет Review-profile wipe/pre-action или killall tests-server.

Файл в macOS/IntegrationTests/CPM/ Роль
CPMAppIntegrationTests.swift 10 deterministic baseline/diagnostics/scope/recovery tests: slow HTTP/native, одна навигация, одна таба, несколько табов одного окна, все окна, M4, dashboard transport, proxy flag
CPMAppKnownFailureIntegrationTests.swift 10 characterization methods: actual AppDelegate flags, shared-pin window closure, Network/background crashes, first install, slow idle wake, frozen WebKit load timeout, 20k persistent-cache reload
CPMAppIntegrationHarness.swift Реальные AppDelegate/WindowsManager/MainWindowController/Tab, production navigation/monitor/recorder, JSON attachments, owned windows/data stores, bounded cleanup
CPMAppIntegrationSupport.swift Реальный macOS native handler/provider/delegate с fault boundary; recorder transport before daily dedup; extraction через production storage; in-memory installation store; test-only PID/background SPI
CPMAppIntegrationBridge.swift Instrumentation только распакованной временной extension copy: page initResp mark, реальные runtime messages и scoped drop/release controls
CPMAppFixtureServer.swift Owned HTTP loopback, eight-second resource delay, cacheable 2KiB resources with unique URLs
README.md Повторение, signing, flags, все сценарии, ограничения причинной интерпретации

Все 6 Swift files включены в Integration Tests и Integration Tests App Store. Минимальные production seams: optional manager controllerConfiguration с прежним default; DEBUG AppDelegate factory с двумя guards; отдельный ConfigurationStore directory для CPM test host; разрешён только loopback HTTP в opted-in integration Tab; macOS diagnostics flag adapter доступен через @testable без изменения поведения. SecureVault/AppMain bypass отсутствует. Существующие dirty ZIP/SPM files сохранены.

Запускать с project signing defaults, как в Xcode; unsigned override оказался ошибкой bootstrap и удалён. CLI run recipe находится в README. Для реального 30s WebKit timeout нужен test-host env CPM_APP_INTEGRATION_EXPENSIVE=1; для persistent cache — CPM_APP_INTEGRATION_CACHE=1, при необходимости CPM_APP_INTEGRATION_CACHE_ENTRIES, execution allowance 2400 s. Cache case лучше выбирать отдельно; этот opt-in включает fresh persistent UUID configuration в harness. Обычные запуски используют nonpersistent stores.

Артефакты /private/tmp/cpm-app-integration-20261015/: signed .xcresult, logs, exported JSON, app-test-results.json (история результатов и hashes исходников). Финальные результаты сверять с §13 cpm-status-2026-10-15, не считать каждый characterization test доказательством воспроизведения причины. P3 может пройти с отрицательным outcome; background crash может самоизлечиться. App P5 ограничен одной потерянной навигацией и контролями: более длинная попытка прерывалась DEBUG guard закрытого окна в XCTest. Persistent P5/stuck доказан отдельно SPM, что не превращает app attempt в green. iOS/device-only причины и естественная потеря listener metadata этим suite не доказаны.

App harness isolation follow-up: extension resources now use an owned UUID directory under unswizzled NSTemporaryDirectory(), outside com.duckduckgo.macos.tests. The latter is a shared FileManager swizzle target that TestRunHelper removes on host initialization/bundle completion. A preceding joint run passed 16/18 but lost its Network-test extension resource before reload (extensionNotFound), then the next wake test hit INT. The deleter was not identified; latest status must include that red run and the resource-isolation recheck, rather than treating prior isolated passes as a green combined suite. CPMAppExtensionStorage.resolveInstalledExtension still delegates to production and adds only missing-folder/root logging.

Финальная сверка §5: signed-isolated-regression 18/18, signed-isolated-pinned 1/1 (72.644 s), signed-isolated-cache 1/1 (43.053 s). Все summaries: 0 failures, 0 skipped, 0 expected failures. В последнем cache run 20k ресурсов за 39.113 s, post-reload probe 0.900 s, P3 не воспроизведён, UUID store удалён. Все 20 JSON exported в одноимённые *-evidence/ directories; /private/tmp/cpm-app-integration-20261015/app-test-results.json содержит текущие hashes исходников и всю per-method историю. HEAD 46f25175c7c42766cab23ea39f447f075c7bdd24 сохранён, исходный dirty ZIP не менялся. Финальный strict lint: 11 Swift files, 0 violations; PBX и scheme XML валидны. Предыдущие red attempts сохранены, не превращены в pass; единый invocation всех 20 не выполнялся.

16 Oct clarification/rerun: all 20 current app methods passed again in 18+1+1 groups, same signed build and source hashes; /private/tmp/cpm-app-integration-20261015/rerun-failed-20261016-042858/rerun-summary.json. This is an instrumented app-test environment, not an unchanged shipping binary. P1/P2 delay/SIGSTOP and message/native/dashboard loss are imposed faults; P5/P6/Network use real lifecycle paths but their production occurrence/causal attribution is a separate claim. Old long P5 is still outside the verified app scope; P3 remains unreproduced. Cache teardown has a recorded nonfatal SQLite warning. Submodules are not required by these CPM cases: privacy-reference-tests resources map to Unit Tests targets, SnapshotReferences to snapshot testing support, not XCUI accessibility snapshots. Neither submodule was initialized or modified by this rerun.

Локальный кандидат P1/P2 — 16 октября 2026 (без commits)

Worktree cpm-e2e-init, HEAD всё ещё 46f25175c7c42766cab23ea39f447f075c7bdd24. Эта секция дополняет прежнюю карту: #7379 не изменялся, новая работа пока только локальная.

  • WebExtensionLifecycleCoordinator.initialLoadWaiter: после launch gate проверяет подготовку background на каждом HTTP(S) main-frame navigation. Await ограничен прежними 5 s и отменой navigation; AsyncStream позволяет освободить navigation даже при callback WebKit, игнорирующем cancellation. Жизненный цикл load/sync этим не блокируется.
  • WebExtensionManaging.prepareEmbeddedBackgroundForNavigation: новый protocol hook с no-op default для лёгких conformers. Реализация — WebExtensionManager.swift, без нового project file.
  • WebExtensionManager.loadEmbeddedExtensionBackgroundContent: публичный callback API + одна shared startup task на текущий context. Error notification завершает/очищает старую readiness task, чтобы новая попытка не приклеилась к завершённому старому startup.
  • WebExtensionManager.recoverEmbeddedBackgroundLoadFailure: собственный текущий embedded context, настоящий domain/code 6, существующий recovery kill switch, known app_state != background, отсутствие M4 in-progress и cooldown 60 s. Повторяется только background load; context/Tab/controller не заменяются. Полный M4 reload остаётся при confirmed stuck. Старый full-context P2 prototype отброшен: он терял page initResp в existing tab при повторе.
  • CPMAppKnownFailureIntegrationTests.testSlowBackgroundWakeKeepsFirstNavigationHealthy: actual idle + 8 s worker delay, первый документ получает native+page без detector failure.
  • ...testFrozenBackgroundRecoversAutomaticallyForNextNavigation: actual one-tab idle wake, owned SIGSTOP 45 s, настоящий error 6. Требует native+page на том же failed document до новой navigation, тот же объект context и recovery_document=failed_navigation; затем healthy existing/new-window/new-tab.
  • Raw P1 и P3 characterization отключают navigation gate; P5 остаётся с gate включённым и ожидает bucket bg_view_creations=3_to_5: подготовка P1 создаёт дополнительный background перед rejected unknown-tab message. P5 tab-registration loss и healthy controls по-прежнему проверяются.

Артефакты и snapshots: /private/tmp/cpm-p1-p2-fixes-20261016/. before-changes.tar.gz сохраняет прежние dirty changes; point-fixes.diff предназначен для delta этой работы. Начальный background-only result — 2/2 PASS, пакет 806/14 skipped/0 failures. Общий run/negative controls/P5/cache ещё выполняются; окончательный исход — в cpm-status-2026-10-15. Зелёный случай относится к macOS с imposed timing/process faults; natural iOS cause по-прежнему не доказан.

Финальная сверка P1/P2, 16 октября 12:30 UTC: работа завершена без commits. validation-summary.json: 22/22 уникальных app methods PASS, positive groups 2+19+1+1 (P2 повторён), 0 failures/skips/expected failures; оба disabled-fix controls functional FAIL. unit-package-background-retry.log: 806 / 14 skipped / 0 failures; strict lint 6 файлов — 0 violations. Source hashes после сборки не менялись, прежние dirty files/ZIP сохранены. Окончательный P2 — background-only retry и same-document native+page recovery, не context replacement. Предыдущая full-reset реализация отвергнута после повторной потери page initResp. Current patch — /private/tmp/cpm-p1-p2-fixes-20261016/point-fixes.diff; P5 ожидает дополнительный view от P1, P3 остаётся отрицательным на 20,000 resources. Cache assertions прошли, но teardown снова имеет известный SQLite vnode warning для owned UUID. Подробная проверенная матрица/ограничения и весь red-history — cpm-status-2026-10-15.

Отдельный worktree P1/P2 — 16 октября 2026

/Users/admin/DuckDuckGo/apple-browsers.git/alex/cpm-fix-p1-p2, branch alex/cpm-fix-p1-p2, от alex/cpm-messaging-readiness-telemetry (01d4a0ec22), без коммитов. Отличается от полного scratch research-набора:

  • WebExtensionLifecycleCoordinator.initialLoadWaiter: после launch открывает ограниченное 5 s ожидание background wake; cancellation-safe AsyncStream, существующий gate flag.
  • WebExtensionManager.prepareEmbeddedBackgroundForNavigation / loadEmbeddedExtensionBackgroundContent: один startup job на конкретный context object, public WK callback, release pending callers при error/reload.
  • Observer WKWebExtensionContext.errorsDidUpdateNotification / recoverEmbeddedBackgroundLoadFailure: error 6 только своего embedded context, существующий recovery flag, current background guard, throttle 60 s; повтор background load без context replacement. M4 reload остаётся fallback.
  • Recorder isApplicationInBackground: читает уже существующий appSession lifecycle provider, не добавляет telemetry dimension.
  • macOS/IntegrationTests/CPM/: пять Swift-файлов, ровно два app-теста CPMBackgroundRecoveryIntegrationTests, сокращённая инфраструктура; схема CPM Integration Tests. Реальные app windows/tabs/native handlers/WebKit, неизменный bundled ZIP, extracted startup-delay и page initResp observation, SIGSTOP только своего background PID. Scoped drop/cache/Network/P3/P5 сценарии остались в research worktree.
  • Четыре новых метода WebExtensionLifecycleCoordinatorTests: wake после launch, bounded non-cancellable callback, cancellation, disabled flag. Всего 6 новых test methods; 22 — весь прежний app-набор.

Текущая база уже перешла на episode contract. Test-only diagnostics proxy фиксирует реальный first-failure вызов, не синтезируя monitor events. P2 требует terminal failed_measurement_response / reload_state=none плюс page initResp исходного документа до другой навигации и ту же context identity. Signed app 2/2 PASS; unit 31+134=165 PASS; strict lint 14 files / 0 violations. Оба disabled-flag контроля на той же сборке функционально FAIL. Test autorelease pools исправили deallocation guard без отключения проверок. Source hashes и исходный scratch неизменны; schemas/ZIP/dependencies в diff не менялись. Артефакты и полная история: /private/tmp/cpm-p1-p2-clean-20261016/validation-summary.json, cpm-status-2026-10-15. Границы P1 cap / macOS injection / неустановленного natural iOS trigger сохраняются.

Объединение #7379 с P1/P2 и независимый lifecycle guard — 16 октября 2026

Текущий alex/cpm-fix-p1-p2 семантически заменяет #7379 в пределах прежнего navigation timeout 5 s:

  • WebExtensionManager+EmbeddedExtensions.installEmbeddedExtension вызывает trackEmbeddedBackgroundStartup(identifier:) именно для вновь установленного embedded context.
  • Manager сохраняет preferred context, а prepareEmbeddedBackgroundForNavigation захватывает конкретный context object. Fallback учитывает append-порядок installation store и не выбирает произвольный context при неизвестном порядке нескольких версий. loadEmbeddedExtensionBackgroundContent(in:) coalesces job на тот же object.
  • recoverEmbeddedBackgroundLoadFailure игнорирует superseded context. Состояние background приходит через самостоятельный isApplicationInBackground provider; iOS factory читает UIApplication.shared.applicationState независимо от diagnostics flag. Старый diagnostics getter удалён. Перед queued retry повторно проверяются flag/background.
  • Два install/upgrade-теста #7379 адаптированы в CPMBackgroundRecoveryIntegrationTests рядом с P1/P2. Реальный upgrade даёт context sets [0,1,2,1]; assertions требуют native dashboard + page initResp первого документа, а не просто загрузку context. Default delay 4500 ms.
  • Пять новых manager unit tests проверяют coexistence/newest selection, fallback после удаления replacement, diagnostics=nil + background→foreground, runtime kill switch и отказ retry старого context. Вместе с четырьмя lifecycle tests в ветке 9 новых unit methods.

Финальная валидация: общий signed app 4/4 PASS; install/upgrade 10/10 + 10/10 PASS на той же сборке; targeted unit 170 PASS, strict lint 16 files / 0 violations; WebExtensions generic iOS Simulator module BUILD SUCCEEDED. Все 4 disabled-flag controls функционально FAIL без teardown errors. Коммитов и изменений scratch/ZIP/schema/dependencies нет.

Локальные [CPM Background] logs показывают медленный WK callback (>=1 s) и release gate по deadline. Они подтвердили предел: fixture 5000 ms даёт фактическую готовность после 5 s cap и может потерять первый upgrade document (6/10 ранее). Этот over-budget режим не исправлен и сохраняется через CPM_APP_INTEGRATION_INSTALL_DELAY_MS=5000; здоровые contract regression cases проверяют 4500 ms. Это не доказательство всех natural production causes и не реальный iOS suspension/resume run. Артефакты и история: /private/tmp/cpm-p1-p2-replacement-20261016/validation-summary.json, cpm-status-2026-10-15.

Дополнение: late background recovery — 16 октября 2026, работа продолжается

По запросу сначала сохранён прежний проверенный стейт: commit dff29dfb1e (Fix CPM background wake and installation readiness) в alex/cpm-fix-p1-p2. Предыдущие утверждения «коммитов нет» относятся к проверке до этого checkpoint. Новые изменения пока не закоммичены.

Добавлен кандидат восстановления потерянного первого документа при startup за пределами 5 s: отдельный remote flag webExtensions.cpmLateBackgroundDocumentRecovery, default disabled. Navigation cap остаётся 5 s. Кандидат привязывает документ к конкретному unfinished startup, требует настоящий missing-dashboard timeout и успешный public WK background callback; после этого допускает одну GET-перезагрузку в пределах 30 s от старта. Смена/закрытие/ошибка документа, context replacement, background app state, выключение flag, изменённые form fields/contenteditable/loading document отменяют reload. Логика независима от diagnostics flag.

Пять новых dailyAndCount pixels различают install readiness, upgrade readiness, idle background wake, error-6 background retry и late document reload. background_ready — факт успешного WK callback после использованного navigation wait (для error-6 retry — любого успешного retry), не доказательство initResp; reload_started — принятый WK reload; response_received — однозначно атрибутированный dashboard response после reload, не ACK content script. App tests отдельно требуют настоящий page initResp. macOS names заканчиваются _macos, iOS — стандартные platform/form-factor suffixes. Только outcome, appVersion и стандартные platform parameters, без URL/tab ID/form values/raw error.

На данном этапе: targeted unit suite 178 PASS, strict lint 17 Swift / 0 violations, pixel definitions + wide-event consistency/immutability validators обеих платформ PASS. Подписанная app-сборка и реальные install/upgrade 8000 ms regression runs ещё не завершены; over-budget failure пока НЕ объявлен исправленным. Новые артефакты: /private/tmp/cpm-late-recovery-20261016/.

Итог late background recovery и fix instrumentation — 16 октября 2026

Актуальный стейт: checkpoint dff29dfb1e сохранён до новых изменений; новый код/tests/pixels в alex/cpm-fix-p1-p2 остаются незакоммиченными. Новый flag webExtensions.cpmLateBackgroundDocumentRecovery default disabled, динамически проверяется до попытки и после async safety check; remote config не менялась. Navigation cap по-прежнему 5 s.

Новый CPMBackgroundReadinessRecovery.swift в shared Autoconsent получает startup UUID manager, commit/failure/response/navigation events monitor и зарегистрированный GET WKWebView от platform tabs. Документ должен commit во время известного unfinished startup; только genuine missing-response timeout вместе с successful public background callback допускают одну GET-перезагрузку в пределах 30 s startup. Изменённый/loading/closed/failed document, main-document form edits/contenteditable, background app state, flag OFF и context replacement запрещают reload. Идентичность проверяется после async JS. Результат — replacement document на том же URL, сохранённый extension context; P2 background-only recovery исходного документа остаётся отдельным механизмом. Safety check использует настоящий async WK API label contentWorld:; ранние красные app runs поймали ошибочный callback overload с Void, и вся история сохранена.

Пять отдельных dailyAndCount pixels с prefix web_extension_cpm_: install_readiness, upgrade_readiness, background_wake, background_load_retry, late_document_reload. macOS suffix _macos, iOS standard suffixes. Первые четыре: background_ready после использованного slow navigation wait (для P2 любого successful retry), без page-ACK claim; последний: reload_started и однозначный dashboard response_received после replacement navigation. Ответ исходного документа во время safety check не получает credit. Только outcome и стандартные параметры, без URL/tab IDs/field values/raw errors. Injection + PixelKitMock adapter test, definitions/validators обеих платформ PASS. Existing episode contract сохранён; document reload даёт failed_tab_response, extension reload_state=none.

Проверено на одной финальной подписанной сборке: общий набор 8/8 PASS (7 app/WebKit scenarios + adapter test); новые 8-second install/upgrade 2/2 PASS, затем 10/10 repetitions PASS; новый flag OFF 2/2 функционально FAIL, 0 skips/expected failures/teardown errors. Во всех 14 positive over-budget executions первая загрузка 5.085–5.328 s, затем ровно один reload, настоящий page initResp + native dashboard, URL/context сохранены. Edit-veto app test PASS; прежние P1/P2/install/upgrade PASS. Targeted units 179 PASS (9 новых recovery; всего 18 новых unit methods в ветке), lint 17 files / 0 violations, новый recovery без compiler warnings. Shared iOS Simulator и FeatureFlags-iOS builds PASS; полный iOS app/runtime не запускался.

Code entry points: manager background startup callback/typed fix marker; monitor backgroundReadinessRecovery и registerReadinessRecoveryDocument; macOS PrivacyDashboardTabExtension weak view + real initiating request method; iOS TabViewController main-frame GET tracking; platform factories dedicated provider; PixelFiring adapters + platform JSON5 definitions. Все 8 app methods остаются в существующем CPM file/scheme; SharedPackages files подхватывает SwiftPM без pbxproj изменений.

Все facts/history/guards/pixel semantics: cpm-status-2026-10-15, /private/tmp/cpm-late-recovery-20261016/validation-summary.json. Source/app/test binary hashes стабильны; bundled ZIP равен checkpoint; package pin side effect убран; scratch/#7379 не менялись. Это opt-in bounded GET recovery, не универсальное исправление permanent background failures/unsafe documents. Прежние P3/P5 и natural-production/iOS suspension ограничения не сняты; 22 historical research methods отдельно.

Перенос в PR #7379 поверх #7376 — 16 октября 2026

Git и состав PR

По запросу до переноса сохранён checkpoint 367759cbc17d717b05e53ab30792c077ff103a8b в alex/cpm-fix-p1-p2 (предыдущий checkpoint dff29dfb1e также сохранён). Старый чистый worktree /Users/admin/DuckDuckGo/apple-browsers.git/cpm-fix-init-loss удалён штатно; локальные ignored settings сохранены в /private/tmp/cpm-pr7379-port-20261016/retired-worktree-local-settings.tar.gz. Research worktree cpm-e2e-init и его незакоммиченные данные не менялись.

Рабочая директория остаётся /Users/admin/DuckDuckGo/apple-browsers.git/alex/cpm-fix-p1-p2, но её текущая ветка теперь alex/cpm-fix-init-loss. Финальный HEAD aec5be9a834e97984d4cbbee01a207548222427c, ровно 3 коммита / 32 изменённых файла поверх #7376, base branch alex/cpm-messaging-readiness-telemetry, base SHA 713d67419a776b235b66210b1c594ce39da6fe03:

  1. 05b499e355 — P1/P2, ожидание нового install/upgrade context и необходимые app/unit tests.
  2. c661f805b1 — late GET document recovery, независимый flag, пять fix pixels, регрессии.
  3. aec5be9a83 — маркировка local-only fault-injection suite/scheme/README как to-be-disabled before merge.

PR #7379 обновлён разрешённым force-with-lease с точным ожидаемым старым head 7ad771e227bbd68348ed7b719684783575dd7c9f; новый head/base проверены через GitHub. Старый head и промежуточная история сохранены в backup branch alex/cpm-fix-init-loss-before-force-20261016 (70869f5c69). Зависимость от #7378/research SPM harness убрана из diff; episode contract #7376 сохранён. Промежуточный перенос на прежнюю базу с 167 unit tests — историческая попытка, окончательный результат относится к новой базе и 179 tests.

PR title/description/Testing Steps переписаны под окончательный код. Коммитить или переключать test-only/fix commits для проверки не требуется. Удалены старые инструкции и placeholder GREEN_RUN_URL; используется одна подписанная сборка с переключением production flags в test fixture.

Feature flags

Механизм Remote flag Default
Install/upgrade readiness + P1 navigation wake wait webExtensions.stateRestorationGate Enabled, существующий
P2 background-only error-6 retry webExtensions.cpmMessagingHangRecovery Enabled, существующий
Late first-document GET reload webExtensions.cpmLateBackgroundDocumentRecovery Disabled, новый независимый

Флаги явно задаются fixture; ENV CPM_APP_INTEGRATION_DISABLE_P1_P2_FIXES=1 и CPM_APP_INTEGRATION_DISABLE_LATE_RECOVERY=1 выбирают соответствующие negative controls без изменения исходников или binary. В двух over-budget controls отключается late recovery при сохранённом 5 s navigation gate, чтобы изолировать новый механизм. Remote configuration не изменялась.

Финальная проверка запушенного head aec5be9a83

Новый прогон на базе #7376, macOS 26.7.1, Xcode 27.1, нормальная подпись Apple Development: Alexey Martemyanov (9SAT8X9S84) / team HKE973VLUW. Проверены identity подписи app и strict signatures app debug dylib / XCTest bundle; это не заявление о distribution signing/notarization или полной deep-проверке вложенных продуктов.

Проверка Результат
Все восемь методов dedicated app suite, соответствующие flags ON 8/8 PASS, 0 failures/skips/expected failures
Шесть recovery controls, соответствующие flags OFF, те же бинарники 0/6 PASS, 6 функциональных FAIL, 0 skips/expected failures, без teardown/deallocation errors
Targeted shared suites 179 PASS, 0 failures/skips (13 diagnostics + 9 recovery + 78 monitor + 31 lifecycle + 48 manager)
Strict lint относительно новой PR base 27 Swift files, 0 violations
Pixel schemas/formatting + wide-event consistency/immutability macOS и iOS PASS
Source/binary integrity Все 32 source hashes и 2 app/test binary hashes неизменны; git status чистый

Положительный набор: P1 slow idle wake, P2 реальная WK error 6 с background-only retry и ответом исходному документу без навигации, install, upgrade при coexistence contexts, late install, late upgrade, edited-document veto и PixelKitMock adapter. При 8000 ms startup в новых late install/upgrade runs первый документ завершился за 5.159 / 5.093 s, затем ровно один automatic reload (итого два finish), настоящий page initResp и native dashboard, URL/context сохранены. Navigation cap остаётся 5 s. Отдельные десять stress repetitions и более ранние iOS module/flags builds относятся к предыдущему checkpoint/проверке, не объявляются новым stress/iOS runtime run на этом head.

Красные controls на той же сборке: install/upgrade теряют первый native/page ответ; P1 получает response timeout; P2 достигает реальной error 6, но без flag не получает same-document recovery; оба over-budget случая не получают automatic document recovery. Это намеренные функциональные FAIL, не инфраструктурные crashes и не XCTExpectFailure. У controls и positive runs отдельные .xcresult / summaries / JSON attachments.

Local app suite, setup и dedicated scheme/README помечены to-be-disabled before merge. Они уже требуют CPM_APP_INTEGRATION=1 и пропускаются обычным CI без opt-in. Сценарии используют GUI-host и 45 s SIGSTOP только собственного background PID; deterministic unit regressions оставлены включёнными. General macOS UI Tests scheme локально не запускалась из-за её profile-clearing preaction.

Артефакты нового прогона: /private/tmp/cpm-pr7379-final-20261016/validation-summary.json, рядом enabled.xcresult, disabled.xcresult, JSON evidence, logs, signature/hash snapshots, pr-after.json, финальный PR body и CI snapshots. Bundled extension ZIP неизменён относительно base/checkpoint: SHA256 ff98a2b0c07819b2ee5ee6de67d6dd8d28696363c08c9fbc2c32255e9d9efa94; package pin side effect убран. Прежние red runs и расследовательские данные сохранены.

Новый remote CI после push запущен; локальный PASS не выдаётся за завершённый зелёный GitHub CI. Контракт fix pixels остаётся прежним: background_ready — callback readiness, response_received — dashboard correlation после reload; page ACK проверяет app assertion отдельно. Default-disabled late flag не включался в remote config. Natural production attribution, unreproduced P3, прежние P5 app ограничения и реальный iOS suspension/resume этой работой не закрыты.

GitHub checks после push

Финальная сверка CI для aec5be9a83: основные jobs ещё IN_PROGRESS/QUEUED; Danger — FAILURE, точная причина — новые pixels требуют label privacy review required, который создаёт privacy-review task в Asana. Label в этой работе не менялся. Дополнительно Danger предупреждает об отсутствующем Asana Feature Flags project task link для cpmLateBackgroundDocumentRecovery в macOS/iOS enum comments и размере PR; это warnings, не причина функциональных app failures. Значения flags и локальные ON/OFF результаты выше подтверждены независимо. Evidence: /private/tmp/cpm-pr7379-final-20261016/danger-comment.md, ci-final.json.

Вынос app harness из PR #7379 — 16 октября 2026

По запросу весь local-only app harness вынесен в отдельную review-only ветку codex/cpm-fix-init-loss-integration-tests, основанную непосредственно на очищенном alex/cpm-fix-init-loss. Тестовая ветка не предназначена для merge в main, отдельный PR на неё не создавался.

  • Production PR #7379: head da126120a94b625cf1d9705302c29099b4dbc62d, база #7376 / 713d67419a, 2 коммита, 21 файл. 7dbe2a25bb — P1/P2/install/upgrade; da126120a9 — late recovery + flags/pixels. Все 21 production/unit/schema файла побайтово совпадают с прежним aec5be9a83; поведение и defaults не менялись.
  • Harness branch: head 6e4e39e67c64907127bd17197a932b0117a4cb09, parent ровно production head da126120a9, один дополнительный commit, 11 test-only paths. Это пять Swift app-test files + README, CPM scheme и PBX registrations, DEBUG manager factory/config storage/loopback navigation hooks в AppDelegate, ConfigurationStore, Tab.
  • Все app hooks и Xcode project changes исключены не только из финального diff PR, но и из его двух новых коммитов. 18 новых deterministic shared unit methods остаются в production PR; восемь app methods — только в harness branch.
  • В harness комментариях прежнее to-be-disabled before merge заменено на ясное review-only назначение: эта ветка не идёт в main. Explicit scheme opt-in сохранён. Старые checkpoints и исходная история сохранены; дополнительный backup codex/cpm-fix-init-loss-before-harness-split-20261016 -> aec5be9a83.
  • Reviewer instructions в PR: unit suites на PR branch; git fetch origin, git switch --detach origin/codex/cpm-fix-init-loss-integration-tests; открыть workspace, выбрать CPM Integration Tests / My Mac, ⌘U, ожидать 8 PASS / 0 skips; затем вернуться git switch --detach origin/alex/cpm-fix-init-loss. Production description и пользовательские правки сохранены. Исторические intentional-red controls не возвращены в reviewer steps.

Артефакты разделения: /private/tmp/cpm-harness-split-20261016/: manifest с production/harness paths и исходными SHA256, раздельные patches, build/unit/lint/signing logs и snapshots PR description. Точные окончательные результаты новой проверки и remote SHA — ниже.

Проверка после разделения

  • Production da126120a9: обычная macOS Browser Debug app build PASS без harness; нормальная Apple Development подпись, team HKE973VLUW; strict app dylib verification PASS.
  • Production shared regressions: 179/179 PASS, 0 failures/skips; 18 новых unit methods сохранены в PR.
  • Review-only harness 6e4e39e67c: полный xcodebuild test (эквивалент Product → Test), 8/8 PASS, 0 failures/skips/expected failures, отдельная подписанная app/XCTest сборка. Все 32 source hashes неизменны во время run; strict dylib/XCTest signature checks PASS.
  • Strict lint: 19 production Swift files / 0 violations, 8 harness Swift files / 0 violations. PBX syntax и scheme XML валидны; каждый из пяти harness Swift files зарегистрирован ровно по одному разу в обоих native Integration Tests targets. Выполнен normal signed target, не отдельный App Store runtime run.
  • Подтверждены remote SHA обоих branches и GitHub PR diff: production da126120a94b625cf1d9705302c29099b4dbc62d, harness 6e4e39e67c64907127bd17197a932b0117a4cb09; parent harness совпадает с production head. Production PR остаётся на базе #7376. В рабочей директории снова alex/cpm-fix-init-loss, git status чистый.
  • validation-summary.json, pr-after.json, remote-heads.txt, harness-enabled.xcresult и JSON evidence находятся в /private/tmp/cpm-harness-split-20261016/. Generated Package.resolved side effect сохранён и убран из рабочей копии; production dependencies/ZIP не менялись.
  • Новые шесть disabled controls после branch-only split не повторялись: предыдущие 6/6 functional FAIL на эквивалентном production/harness code остаются историческим evidence в /private/tmp/cpm-pr7379-final-20261016/. Нового stress/iOS runtime run не заявляется. P3, прежние P5 app и natural-production/iOS ограничения сохраняются. Remote CI нового head — отдельная незавершённая проверка, snapshot ci-after-split.json.

Ранние формулировки о local-only suite внутри production PR и необходимости disable перед merge описывают прежнюю структуру. В актуальном PR этих файлов и hooks нет; review-only branch целиком остаётся вне main.

Возврат проверки production feature flags OFF → failures — 16 октября 2026

При упрощении reviewer instructions ошибочно удалён необходимый negative-control шаг. В PR #7379 восстановлен полный ON → OFF → ON workflow с конкретными Xcode schemes; остальные пользовательские правки сохранены.

В review-only branch codex/cpm-fix-init-loss-integration-tests добавлен commit 543e37164b369c8da8b6734e500af4a203944943, только два файла: новый shared scheme CPM Integration Tests - Fixes Disabled и README с точными cases/flags/ожидаемыми failures. Эта ветка теперь содержит 2 test-only commits / 12 paths сверх production da126120a9; в main она не идёт. Production PR остаётся 2 commits / 21 files, его head/code/unit regressions не менялись.

  • CPM Integration Tests → 8 tests должны PASS.
  • CPM Integration Tests - Fixes Disabled → автоматически выбирает ровно 6 recovery methods и задаёт обе fixture ENV variables CPM_APP_INTEGRATION_DISABLE_P1_P2_FIXES=1 / CPM_APP_INTEGRATION_DISABLE_LATE_RECOVERY=1. Ожидаются 6 functional FAIL / 0 PASS / 0 skips.
  • Снова CPM Integration Tests → все 8 должны PASS.

Ручное редактирование ENV или выбор отдельных tests reviewer больше не нужны. OFF scheme через fixture отключает реальные production flags: webExtensions.stateRestorationGate для install/upgrade/slow wake, webExtensions.cpmMessagingHangRecovery для error-6 retry, webExtensions.cpmLateBackgroundDocumentRecovery для late GET recovery. Late recovery выключен и в ранних controls, чтобы не маскировать их; в двух over-budget controls navigation gate сохраняется ON.

Ожидаемые причины FAIL: потерянный native/page first response после install/upgrade; CPM timeout после slow wake; timeout same-document recovery после реальной WK error 6; timeout automatic first-document recovery в late install/upgrade. Setup failures, host crashes или skips не подтверждают работу флага. Полные test names и mapping находятся в README тестовой ветки. В PR сохранены checkout/test/return commands и добавлен возврат к ON scheme.

Артефакты этой проверки: /private/tmp/cpm-flag-controls-20261016/; compiler/test Swift sources и production ref не менялись. Предыдущие 179 unit PASS / production build PASS остаются предыдущей проверкой, не объявляются новым unit/build run.

Финальная проверка ON → OFF → ON

Baseline normal scheme на 6e4e39e67c ранее дал 8/8 PASS. После добавления только OFF scheme/README на 543e37164b выполнены оба shared schemes через xcodebuild test-without-building -workspace DuckDuckGo.xcworkspace -scheme … на тех же подписанных app/XCTest binaries:

Run Результат
CPM Integration Tests - Fixes Disabled 6 failed / 0 passed / 0 skipped / 0 expected failures, exit 65
CPM Integration Tests после OFF 8 passed / 0 failed / 0 skipped / 0 expected failures, exit 0

У OFF все шесть failure records сопоставлены точным test names и ожидаемым функциональным причинам; никаких deallocation/setup failures или подмены через XCTExpectFailure. Возврат ON восстанавливает PASS для прежних P1/P2/install/upgrade, обоих late cases, edit veto и pixel adapter. SHA256 app debug dylib и XCTest binary неизменны до/после обоих runs, Swift sources не менялись относительно baseline harness. Remote config и production defaults не редактировались.

Artifacts: /private/tmp/cpm-flag-controls-20261016/validation-summary.json, off.xcresult, on.xcresult, summaries, exported JSON evidence, binary-hashes-before.json, pr-after.json, source/branch verification. Это новая runtime-проверка переключения flags, без нового production build/unit run. Reviewer теперь выбирает два готовых schemes: не редактирует ENV вручную, не выбирает шесть methods и не переключает commits. Production PR и прежние P3/P5/natural-production/iOS ограничения сохраняются.

16 октября 2026 — исправления замечаний review #7379

Production head: 08866c7eda9b1395f7c0baf9887c827bd3f59ec5, branch alex/cpm-fix-init-loss, PR #7379, база #7376 / alex/cpm-messaging-readiness-telemetry / 713d67419a. Три commits / 21 changed paths. Новый commit Share CPM startup deadline across navigations изменяет 8 существующих Swift files; app fixture/hooks в production diff не возвращены. Production и review-only branch обновлены обычным push без переписывания истории.

Что проверено и исправлено

  • Замечание о неотменяемом Task.value: исходное замечание уже было закрыто реализацией cancellable AsyncStream bridge и regression testBackgroundWakeWaitIsBoundedWhenWebKitIgnoresCancellation. Проверено повторно на текущем коде: timeout освобождает navigation, даже когда реальный startup task не реагирует на cancellation; физический WebKit startup не отменяется.
  • Повторные пять секунд на каждом navigation: замечание оказалось актуальным по поведению, несмотря на устаревшее имя файла в тексте. Раньше каждый waiter имел отдельный deadline. Теперь manager возвращает стабильный Task текущего startup, а coordinator хранит один bounded wait для его identity. Оба уже подготовленных waiter и последующие navigation после timeout используют завершившийся wait и не платят ещё по 5 секунд.
  • Новый startup/replacement получает собственный deadline. cancelAll() отменяет только navigation wait и очищает его cache. Startup completion очищается при matching uninstall/unload/reload/error-6 retry или замене context; поздний callback старого task не может очистить текущий startup. Timeout сам по себе не отменяет background: поздний успешный callback по-прежнему может запустить отдельный late-document recovery.
  • В Mac PrivacyDashboardTabExtension и iOS TabViewController вызов provider ограничен main-frame HTTP(S), поскольку получение task теперь сразу запускает подготовку background. Iframes и другие URL schemes не начинают этот startup через navigation gate.
  • Добавлены три CI unit regressions: testTimedOutBackgroundStartupDoesNotDelayLaterNavigations (включая waiter, подготовленный до истечения deadline), testNewBackgroundStartupCanWaitAfterEarlierStartupTimesOut, testCancelAllReleasesPendingBackgroundNavigation. Test double сохраняет identity pending startup; зависший callback моделируется неотменяемым task, затем continuation явно освобождается при cleanup.

Feature flag tracking и review status

Default/config flags не менялись: stateRestorationGate и cpmMessagingHangRecovery сохраняют прежние default; отдельный cpmLateBackgroundDocumentRecovery остаётся false. Remote configuration не редактировалась. Для нового flag добавлены реальные per-platform задачи в Apple Feature Flags Registry и ссылки непосредственно над enum case:

Оба review threads проверены и resolved; открытых inline threads после readback — 0. Danger на 08866c7eda: 0 failures / 1 warning, только advisory о размере PR (1090 added lines); предупреждение об отсутствующих flag tracking links исчезло. Отдельная Privacy Review task уже существовала, дубликат не создавался.

Проверки и отдельная test branch

  • До исправления две новые проверки дали 2/2 functional FAIL, после успешной компиляции: повторный navigation wait и освобождение через cancelAll.
  • После исправления пять выбранных shared suites: 182 PASS / 0 failures (13 diagnostics + 9 readiness recovery + 78 monitor + 34 lifecycle + 48 manager). Относительно базы PR теперь 21 новый shared unit method.
  • Strict SwiftLint: 8 changed Swift files / 0 violations.
  • Production macOS Browser Debug, обычная Apple Development signing, build PASS. Подпись app debug dylib проверена. Shared WebExtensions module для iOS Simulator build PASS; это не full iOS app build и не runtime validation iOS suspension/resume.
  • Review-only codex/cpm-fix-init-loss-integration-tests / 3f4d7555113d547797b45ff6b2c7b883efedd520 синхронизирована merge нового production head; отдельный doc-only commit актуализировал README (7 новых coordinator regressions, 21 shared regression суммарно). Над production — два прежних harness commits + sync merge + README correction; diff всё ещё ровно 12 test-only paths, 8 app methods и два shared schemes. Эта ветка не идёт в main.
  • Description #7379 изменена только в двух местах для shared deadline и риска зависшего callback. Пользовательские правки и понятные Xcode steps ON → OFF → ON, названия schemes и ожидаемые 8 PASS / 6 FAIL / 8 PASS сохранены. Коммитить или редактировать Swift для reviewer run не нужно.

Финальный runtime cycle на одном наборе подписанных app/XCTest binaries:

Scheme / запуск Passed Failed Skipped Результат
CPM Integration Tests — ON 8 0 0 PASS
CPM Integration Tests - Fixes Disabled — OFF 0 6 0 Все шесть functional failures совпали с ожидаемыми симптомами
CPM Integration Tests — ON повторно, без сборки 8 0 0 PASS

OFF действительно отключает production flag для соответствующего сценария: install/upgrade/slow-wake потеряли первый ответ, P2 не дождался same-document recovery после фактического error 6, late install/upgrade не дождались automatic first-document recovery. expectedFailures в XCTest — 0: OFF остаётся явным красным контрольным запуском, а не ignored CI failure. Fixture setup/host crash/skips не засчитаны как воспроизведение. SHA256 app dylib и XCTest executable совпали до OFF, после OFF и после повторного ON. Бинарники собраны на sync head d0922bb277; финальный test-branch commit 3f4d755511 меняет только README.

CI snapshot 08866c7eda на 16:19 UTC: 31 SUCCESS, 12 SKIPPED, 3 QUEUED, 5 IN_PROGRESS; failures отсутствуют. SwiftLint, macOS/iOS pixel validation и Danger — SUCCESS. Полный CI ещё не объявлен зелёным: оставшиеся unit/UI/release jobs были pending/running.

Артефакты этого прогона: /private/tmp/cpm-pr7379-review-fixes-20261016/. red-tests.log — red-before-fix; unit-final.log, lint-final.log, production-build-final.log, ios-module.log — final validation. Отдельные app-on*, app-off*, app-on-restored* содержат xcresult summaries и exported evidence. SHA256 app/XCTest сохранены до OFF и после каждого последующего run; review/PR/Danger/CI snapshots и validation-summary.json находятся там же.

Это не новая декларация воспроизведения всех production причин. Ограничения прежнего исследования P3/P5 и iOS runtime сохраняются. Точные два новых navigation/cancellation failures сначала воспроизведены deterministic shared tests; восемь app methods проверяют реальные WebKit/app пути существующих install/upgrade, P1/P2 и late recovery сценариев. В ON evidence P2 снова записан фактический WKWebExtensionContextErrorDomain:6; late install/upgrade завершили первый navigation примерно за 5.18 / 5.10 секунды, затем получили отдельный recovery reload, без увеличения navigation timeout.

19 октября 2026 — полный повторный review после точечных правок

Объём. Повторно прочитан весь production diff: локальный alex/cpm-fix-init-loss / 57081973629e1ad43b9312fee479d27e34232abf против alex/cpm-messaging-readiness-telemetry / 713d67419a (#7376), 5 commits / 22 changed paths; manager/lifecycle, native callers обеих платформ, recovery/health monitor, flags, pixel adapters/definitions и shared tests. Опубликованный #7379 пока остаётся на 08866c7eda: 3 commits / 21 files; его CI snapshot — 48 SUCCESS, 21 SKIPPED, без failures. Это не CI непушенных исправлений.

Сохранённые исправления предыдущего review. Launch gate переносит уже израсходованный deadline на тот же pending startup; следующий navigation не платит ещё пять секунд. Safety preflight отделён от синхронного reload; attribution вооружается после проверок и сопоставляется с конкретной WKNavigation из принятого automatic reload, включая синхронный didStart. После await повторно проверяются flag, app state, document identity и 30-секундный срок. Пять новых regression methods увеличили выбранные suites со 182 до 187 PASS (13 diagnostics + 13 readiness recovery + 78 monitor + 35 lifecycle + 48 manager). Оба production builds macOS/iOS Simulator и strict lint десяти изменённых Swift files прошли на этом коде; logs сохранены в /private/tmp/cpm-pr7379-review-selected-fixes-20261016/.

Формы — явно отложено пользователем. После сообщения «пока не парься на счёт форм, оставить как есть оно за фича флагом» document-start tracker, новые conservative veto и четыре form-safety tests убраны отдельным коммитом 5708197362. Исходный JavaScript predicate побайтно совпадает с 08866c7eda; новая instrumentation не установлена ни на macOS, ни на iOS. Известное ограничение для controlled inputs с изменяемым defaultValue и Shadow DOM остаётся нерешённым; результаты предыдущего реального WKWebView воспроизведения не отменены. Независимый webExtensions.cpmLateBackgroundDocumentRecovery по-прежнему default disabled на обеих платформах. Форма не заявляется исправленной.

Новый P2 — удаление extension не инвалидирует поздний reload. WebExtensionManager.uninstallExtension после реальной выгрузки вызывает clearEmbeddedBackgroundStartup(identifier:), но не инвалидирует document recovery. Если успешный startup уже запустил async safety preflight и в это время отключить/удалить активный embedded context, late-recovery flag может остаться включённым. Document identity сохранена; после завершения preflight вызывается reload closure для уже отключённого CPM. Изолированный testFreshReviewUninstallInvalidatesPendingLateRecovery использовал production manager и default loader: context действительно исчез из controller, installation record удалён, затем reload callback вызван 1 раз вместо 0. Следует инвалидировать recovery удаляемого активного context; удаление старой версии при upgrade не должно отменять recovery её замены. Production-код в ходе повторного review не исправлялся.

Проверка finding. Production sources скопированы побайтно (96 файлов) в изолированный package; добавлен только временный probe. Финальный запуск: 188 методов выполнены, 187 PASS / 1 assertion FAIL, без падения host. Первый запуск временного probe упал в WebKit dealloc искусственно созданной WKNavigation (CFRetain NULL); этот тестовый setup исправлен, и затем получен именно функциональный failure callback count. Артефакты: /private/tmp/cpm-pr7379-full-review-20261019/selected-tests-final.log, review-results.json, source-copy.json. В production tests этот probe не добавлен.

Harness и публикация. Локальный codex/cpm-fix-init-loss-integration-tests / 4308751d593bcc63abfb4baaced83e35bd19255f обычным merge синхронизирован с 5708197362; README исправлен на 26 новых shared regressions и прежнюю защиту форм. Над production по-прежнему ровно 12 harness-only paths, 8 app methods и два ON/OFF schemes; они не идут в main. Удалён только собственный generated Package.resolved diff от предыдущего test run. Рабочая production branch чистая. Production и harness commits пока не push; PR body не перезаписан. Старый ON 8 PASS → OFF 6 functional FAIL → ON 8 PASS относится к опубликованному 08866c7eda / test branch 3f4d755511; на новом локальном head этот app cycle ещё не повторён.

Замечание о стиле URL check. Для HTTP(S) подходит URL.NavigationalScheme.hypertextSchemes из Common; initializer сохраняет регистр, поэтому lowercased необходимо сохранить. Это ответ на вопрос, source replacement не выполнялся.

19 октября 2026 — исправление uninstall/preflight race и push

Production e970e8c90eca76e55217f75c13122735a72664c5, branch alex/cpm-fix-init-loss, #7379, база #7376 / 713d67419a. Опубликованы все три локальных commits после 08866c7eda; итоговый diff — 6 commits / 22 paths. Push обычный fast-forward, без переписывания истории. Review-only codex/cpm-fix-init-loss-integration-tests / e380cf98f7e9709085ce76289211f3e1e43c8395 синхронизирована обычным merge, над production по-прежнему ровно 12 harness-only paths; они не идут в main.

Исправление. До unload запоминается, удаляется ли текущий выбранный embedded context. После успешного unload его background document recovery инвалидируется, включая уже ожидающую async safety preflight. Неудачный unload выходит до invalidation; удаление старого context при upgrade не отменяет recovery replacement. Добавлены постоянные shared regressions testUninstallingActiveEmbeddedContextCancelsPendingDocumentRecovery, testUninstallingOldEmbeddedContextPreservesReplacementDocumentRecovery и testFailedUninstallPreservesActiveDocumentRecovery. Первые два используют production loader с настоящими WKWebExtensionContext; третий моделирует ошибку unload и проверяет сохранение live context. HTTP(S)-checks в native navigation callers macOS/iOS переведены на URL.NavigationalScheme.hypertextSchemes с сохранением lowercased.

Проверки. До fix новые три tests: 2 PASS / 1 functional FAIL — активное удаление оставляло выполняющийся reload callback. После fix пять выбранных shared suites: 190 PASS / 0 failures (13 background diagnostics + 13 readiness recovery + 78 monitor + 35 lifecycle + 51 manager), всего 29 новых shared regression methods относительно базы PR. Unit run выполнен в изолированной копии 96 побайтно совпадающих production source files. Полные macOS и iOS Simulator builds — PASS; macOS app подписан Apple Development, team HKE973VLUW, strict verification всего app bundle PASS. Strict lint всех 11 непушенных Swift files — 0 violations. Схемы/имена/параметры/frequency pixels не менялись.

Формы и flags. По явному указанию пользователя новая защита форм не возвращена. Original JavaScript predicate побайтно совпадает с 08866c7eda; known limitation controlled/defaultValue и Shadow DOM остаётся. Независимый webExtensions.cpmLateBackgroundDocumentRecovery всё ещё default disabled на обеих платформах. Deadline launch→navigation и attribution по конкретной WKNavigation сохранены из предыдущих локальных исправлений и теперь опубликованы.

Документация и app validation. PR body точечно уточняет общий launch/navigation deadline, invalidation при удалении активного context и точную WKNavigation attribution. Пользовательские правки, testing branch link и ON 8 PASS → OFF 6 functional FAIL → ON 8 PASS instructions сохранены. README harness обновлён: 8 новых manager regressions / 29 новых shared methods. На новом head первый ON: 8 PASS; OFF: ровно 6 functional FAIL, 0 PASS/skips/expected failures. Проверены реальные причины отказа: install/upgrade/slow-wake first response, P2 same-document recovery timeout и late install/upgrade automatic-reload timeout. App/XCTest SHA256 до и после OFF совпали. Повторный ON завершился 8 PASS; SHA256 до OFF, после OFF и после повторного ON совпали. CI опубликованного e970e8c90e: 48 SUCCESS / 21 SKIPPED, failures/pending нет. Старые app результаты не перенесены на новый head.

Артефакты: /private/tmp/cpm-pr7379-uninstall-fix-20261019/ (unit-green.log, unit-evidence.json, lint.log, mac-build.log, ios-build.log, signature logs, heads.json, PR snapshots); red control — /private/tmp/cpm-pr7379-full-review-20261019/uninstall-red.log.

Итог app validation и CI на опубликованном head

Production e970e8c90e, review-only harness e380cf98f7. Все три запуска выполнены на одних Apple Development-signed app/XCTest binaries; OFF и повторный ON — test-without-building.

Запуск Passed Failed Skipped Expected failures
CPM Integration Tests — первый ON 8 0 0 0
CPM Integration Tests - Fixes Disabled 0 6 0 0
CPM Integration Tests — повторный ON 8 0 0 0

OFF failure reasons проверены по xcresult: install/upgrade/slow-wake потеряли первый ответ; P2 дождался реального WebKit error 6, но не получил same-document recovery; late install/upgrade не дождались automatic first-document reload. Это шесть намеренно красных функциональных контролей, без host crashes/setup failures/skips. Все 8 ON assertions восстановились после включения flags. SHA256 app debug dylib и XCTest executable совпали до OFF, после OFF и после повторного ON.

Из exported ON evidence: P2 записал actualBackgroundLoadError=[6] и затем прошёл проверки ответа оригинальному document без context replacement или ручной навигации; последующие existing-tab/new-tab/new-window assertions также PASS. При 8-секундном startup первая navigation завершилась за 5.167 s (install) / 5.089 s (upgrade), затем был ровно один automatic GET reload (finishCount=2), реальный page initResp и оба этапа pixel reload_started / response_received. Эти измерения включают локальную загрузку документа после прежнего 5-секундного gate; его лимит не увеличен.

CI опубликованного e970e8c90e завершён: 48 SUCCESS / 21 SKIPPED, failures/pending нет. GitHub readback подтвердил оба remote heads, прежнюю базу #7376 / 713d67419a и точное сохранённое PR body. Production worktree возвращён на alex/cpm-fix-init-loss, tracked/untracked diff пуст; обе ветки up to date. Новых production изменений после validation нет. Формы оставлены как согласовано; independent late-recovery flag default disabled.

Артефакты /private/tmp/cpm-pr7379-uninstall-fix-20261019/: validation-summary.json, три app-*-summary.json и .xcresult, exported attachment folders, app-on-evidence-summary.json, три hashes-*.json, pr-final.json, remote-heads.txt. Прежние промежуточные snapshots выше сохранены как история.