301 lines
32 KiB
Markdown
Executable File
301 lines
32 KiB
Markdown
Executable File
# CPM Web Extension breakage — полное summary сессии
|
||
|
||
> **Текущее продолжение — 15 октября 2026:** [[cpm-status-2026-10-15]]; актуальная карта worktree — [[cpm-web-extension-code-guide-2026-10-09]] (§0). Разделы 1–9 ниже относятся к 7 октября, §10 — к 9 октября; они не являются последним статусом.
|
||
>
|
||
> Добавлены 14 P5/P6 tests, все текущие методы имеют green в раздельных запусках. Найдены и проверены пути browser window-close → WebKit forgetTab → P5/tab=false и условный main-feature-flag handler cycle → replacement controller → P6. Для P5/tab=true, естественной потери metadata, actual iOS suspend/resume и production main-flag transitions доказательств нет. Полный AppKit flow не запускался; browser source contract прочитан, production shared classes и system WebKit исполнены.
|
||
>
|
||
> Пакет: 478 XCTest / 28 opt-in skipped / 0 failures; strict SwiftLint — 0. Ранние красные ожидания, проблемы постановки и отрицательные результаты не удалены: см. основной статус §10–12. Состояния PR/CI и нарезка worktree теперь проверены отдельно; прежнее «всё локально» относится к датированной части.
|
||
|
||
|
||
|
||
**Дата:** 7 октября 2026
|
||
**Охват:** public-attribution после релиза iOS 7.240 / macOS 1.210, исходный код Browser и WebKit, release bundle CPM, WebKit tracker и upstream regression tests.
|
||
|
||
## Короткий вывод
|
||
|
||
> Разделы 1–9 — состояние на 7 октября; раздел 10 — продолжение на 9 октября. Текущий статус — [[cpm-status-2026-10-15]].
|
||
|
||
Главный production-сигнал — не доказанная потеря `initResp`, а отсутствие в течение 4 секунд native-вызова `refreshCpmDashboardState` после завершения навигации. Поэтому большая группа, где native-снимок выглядит здоровым, означает: WebKit controller/context/scripts могли существовать, но CPM не прислал или native не сопоставил ожидаемый dashboard refresh. Она не доказывает, что extension вообще не загрузился.
|
||
|
||
Наиболее близкие к этому симптому WebKit-кандидаты — гонки при cold start service worker:
|
||
|
||
1. **317981:** content script отправляет `runtime.sendMessage`, пока background ещё загружается; WebKit не должен терять сообщение.
|
||
2. **324743:** worker считается загруженным и получает сообщение до завершения activation/восстановления clients.
|
||
|
||
Два других WebKit-багa могут объяснять ухудшение после перезагрузки/recovery, но пока не доказано, что они происходят в CPM:
|
||
|
||
3. **322881:** после reload worker теряет существующие extension clients.
|
||
4. **324754:** при site isolation перезагруженный worker может оказаться в новом процессе без Web Extension bindings.
|
||
|
||
M4 recovery даёт сильный сигнал восстановления измеряемого background → native пути, но не подтверждает восстановление `initResp` или всей CPM-функции. Следующая работа: воспроизвести upstream-сценарии на system WebKit и одновременно добавить event-level instrumentation, которая разделит content `init`, worker receive, `initResp` и dashboard refresh.
|
||
|
||
---
|
||
|
||
## 1. Что измеряет current telemetry
|
||
|
||
### Основной сигнал
|
||
|
||
После `navigationDidFinish` `CPMMessagingHealthMonitor` ждёт до 4 секунд native `dashboardResponse`. Он приходит только когда background вызывает `refreshCpmDashboardState`, а native handler принимает и сопоставляет его с текущим документом.
|
||
|
||
```text
|
||
navigationDidFinish
|
||
→ ожидание dashboardResponse (4 s)
|
||
→ нет ответа
|
||
→ initialization.failed.after.*.daily
|
||
→ при следующем qualifying timeout в пределах episode
|
||
→ messaging.stuck.*.daily
|
||
→ M4 reload embedded extension
|
||
```
|
||
|
||
Следствия:
|
||
|
||
- `initialization.failed` не равно «content script не отправил init».
|
||
- `initialization.failed` не равно «background не получил init».
|
||
- `initialization.failed` не равно «initResp не дошёл до content script».
|
||
- `context_loaded`, живой background view, зарегистрированные scripts и native handler не подтверждают, что service worker уже активирован или обработал именно этот message.
|
||
|
||
`context_loaded` в WebKit означает, что controller уже назначен. Это происходит раньше асинхронной подготовки storage, создания background view, регистрации scripts и injected content. `tab_has_ext_scripts` отражает зарегистрированные `WKUserScript`, а не факт их исполнения в этом документе.
|
||
|
||
### Почему `initResp` и dashboard refresh не одно и то же
|
||
|
||
В release bundle content script отправляет `init` в background. Успешная ветка background запускает `updateCpmDashboardState(...).then(refreshDashboardState(...))` без `await`, а затем отдельно отправляет `initResp` во вкладку. В части веток (`config_unavailable`, `settings_missing`, `setting_disabled`, `site_disabled`) отправляется dashboard refresh, но `initResp` не отправляется.
|
||
|
||
Значит возможны оба расхождения:
|
||
|
||
- `initResp` был, но refresh задержался, не пришёл или не сопоставился — monitor сообщает failure.
|
||
- refresh пришёл, но `initResp` не было — monitor считает путь здоровым.
|
||
|
||
Дополнительные реальные задержки до refresh: remote config, native settings/site checks, последовательная async queue, session storage. JS native-request timeout в bundle — 20 секунд, тогда как monitor ждёт 4 секунды. URL сопоставляется по scheme, host, port, path и query; поздний refresh или другой query также дают failure при работающем JS.
|
||
|
||
---
|
||
|
||
## 2. Public attribution: охват и контрольные суммы
|
||
|
||
Окно: полный UTC-день 5 октября 2026, только события после release tag каждой платформы. `.daily` — максимум одно событие каждого имени в сутки на установку. Это не пользователи, не эпизоды и не transition rate.
|
||
|
||
| После release tag | iOS 7.240 | macOS 1.210 |
|
||
|---|---:|---:|
|
||
| Первое `initialization.failed.after.*.daily` | 6 624 | 1 377 |
|
||
| Последующее `messaging.stuck.*.daily` | 1 440 | 487 |
|
||
| Первый неудачный CPM probe после reload | 670 | 232 |
|
||
| `recovered.after.extension.reload.daily` | 963 = 916 stuck + 47 init | 362 = 354 stuck + 8 init |
|
||
| Все CPM daily по именам | 11 252 | 2 804 |
|
||
|
||
Контроль: 8 001 init + 1 927 stuck = основные первичные/вторичные строки после tag. До macOS tag в выгрузку попали 28 init, 2 stuck и 39 CPM daily; они вынесены из public-среза. До iOS tag строк этой версии нет.
|
||
|
||
### Группы снимков на первом failure
|
||
|
||
Каждая строка относится к одной группе по приоритету. Это описание состояния в момент timeout, не первопричина.
|
||
|
||
| Группа | iOS init | macOS init | iOS stuck | macOS stuck |
|
||
|---|---:|---:|---:|---:|
|
||
| Native snapshot без видимой ошибки | 3 717 | 911 | 789 | 335 |
|
||
| Tab attachment / injection | 931 | 116 | 53 | 38 |
|
||
| Background state | 768 | 158 | 457 | 35 |
|
||
| Только история context errors | 343 | 158 | 87 | 79 |
|
||
| Недостаточно tab facts | 865 | 34 | 54 | 0 |
|
||
|
||
Крупнейшая группа — **3 717 iOS / 911 macOS** — не является подтверждением «нормальной загрузки». Она только не содержит видимого native-признака поломки на момент снимка.
|
||
|
||
### Главные окружающие цепочки
|
||
|
||
- **Session restoration:** 952 iOS / 68 macOS init failures. На iOS у 604 controller совпадает, scripts отсутствуют, background view не создавался; 754 лежат в первых 30 секундах запуска. Это согласуется с временным startup miss, но 260 снимков выглядят здоровыми и требуют timings сообщений.
|
||
- **Обычные навигации iOS:** часты `load → view → proxy_on` и `load → view → proxy_on → dealloc → view → proxy_on`. `dealloc` означает освобождение background view, не process crash. Явный `died_*` есть лишь в 85 первичных iOS строках.
|
||
- **После extension reload:** 670 iOS / 232 macOS первых timeout. Типичный хвост содержит `load → base_url_changed → view → proxy_on`; `base_url_changed` сопутствует reload и не доказывает URL defect.
|
||
- **macOS controller/scripts mismatch:** после tag 77/1 377 init и 35/487 stuck имеют неверный controller и отсутствующие scripts; до tag таких строк нет. 45 из 77 совпали с `app_version_change=updated`, но update сам по себе не доказывает, что живая вкладка осталась на старом controller. Нужен отдельный event смены manager/controller при живой вкладке.
|
||
- **WebKit error 6:** в 364 iOS stuck снимках есть `WKWebExtensionContextErrorDomain:6`; в 363 перед ним есть `dealloc`. Это `BackgroundContentFailedToLoad`: service worker/background не удалось загрузить. Пиксель не содержит первичную причину registration/load failure.
|
||
|
||
---
|
||
|
||
## 3. Связь init failure и stuck
|
||
|
||
В коде связь прямая: первый timeout создаёт `Episode`; stuck появляется только после следующего qualifying timeout, обычно в пределах пяти минут. Причина stuck наследуется от первого failure, а stuck snapshot снимается со второй вкладки. Recorder хранит общую history background context, поэтому `stuck.bg_events` может содержать события до первого init failure.
|
||
|
||
В public-срезе сравнивались длинные цепочки (`>=6` событий) в окне пяти минут: порядок токенов и возраста событий должны были совпадать. Контроль — те же правила, но stuck timestamps сдвинуты на ±10 минут.
|
||
|
||
| Platform | Stuck | Длинная цепочка | Совпала с более ранним init | Контроль +10 / −10 min | Один кандидат |
|
||
|---|---:|---:|---:|---:|---:|
|
||
| iOS | 1 440 | 1 025 | 693 | 255 / 270 | 467 |
|
||
| macOS | 487 | 368 | 168 | 29 / 19 | 148 |
|
||
|
||
Это подтверждает, что stuck чаще продолжает предшествующий timeout-эпизод, чем случайную соседнюю цепочку. Это не соединение одного пользователя: нет reporter ID, `.daily` дедуплицирует события, короткие хвосты недостаточно уникальны.
|
||
|
||
**Важно:** один потерянный `init` сам по себе не доказывает global stuck. Для production stuck нужны два qualifying timeout в одном episode. Поэтому тест «один tab потерял init, второй сам сломался» не был честным доказательством и не получен. Проверять нужно: два timeout в одном стартовом окне → настоящий M4 recovery → третья вкладка без injection.
|
||
|
||
---
|
||
|
||
## 4. Проверка релизов и mitigation
|
||
|
||
### Session-restoration gate
|
||
|
||
M7 gate уже ждёт initial `loadAndSync` перед первой main-frame HTTP(S) navigation restored tab с bounded timeout. По public data временные session-restoration failures **не исчезли**: 952 iOS / 68 macOS. Без связки событий нельзя посчитать, какая часть затем восстановилась.
|
||
|
||
### Tab lifecycle fixes
|
||
|
||
Новые controller/scripts поля появились только в новом атрибуционном релизе, поэтому старые версии нельзя сравнивать по tab bugs напрямую. Доступен только proxy `stuck.other / init.other` на macOS:
|
||
|
||
| Версия | Proxy |
|
||
|---|---:|
|
||
| 1.208 | 39.52% |
|
||
| 1.209, содержит M1 tab identity fix | 38.81% |
|
||
| 1.210 public day | 39.81% |
|
||
|
||
Разница 1.208 → 1.209 составляет 0.71 п.п. и не доказывает эффект или его отсутствие: различаются cohort и нагрузка.
|
||
|
||
### M4 after-stuck recovery
|
||
|
||
M4 делает reload embedded extension после подтверждённого hang. После tag `recovered.after.extension.reload.daily` с `recovery_from=messaging_stuck` есть у 916 iOS и 354 macOS. Отношение всех `recovered.after` к stuck daily: 66.9% iOS и 74.3% macOS; на предыдущих версиях proxy был 3.23% / 2.70%.
|
||
|
||
Это сильный признак, что reload часто возвращает измеряемый background → native refresh. Это **не success rate** и не доказательство восстановленного CPM/initResp. После reload первый probe всё ещё timeout-ится 670 раз на iOS и 232 на macOS.
|
||
|
||
---
|
||
|
||
## 5. Другие CPM/Web Extension сигналы
|
||
|
||
После tag Web Extension продолжает работать на значимой части навигаций:
|
||
|
||
| Signal | iOS | macOS | Что доказывает |
|
||
|---|---:|---:|---|
|
||
| `autoconsent_init.daily`, `fromExtension=1` | 56 906 | 2 825 | Background получил какой-то init и отправил native pixel; не delivery `initResp` |
|
||
| `web_extension_loaded.daily` | 61 902 | 2 870 | Manager загрузил хотя бы одно extension |
|
||
| `web_extension_state_checked.daily` | 62 004 | 2 805 | Lifecycle проверил loaded contexts |
|
||
| `web_extension_embedded_not_loaded.daily` | 3 389 | 1 | Embedded extension отсутствовал в manager во время проверки |
|
||
| `web_extension_load_error.daily` | 4 | 4 | Ошибка общей загрузки extension |
|
||
|
||
Также есть extension-sourced `popup-found` и `done`, значит CPM functional path работает у части навигаций. Общие имена пикселей разделены с legacy user script: выводы допустимы только с `fromExtension=1`.
|
||
|
||
На macOS лишь один `embedded_not_loaded.daily` при 77 init failures с controller mismatch/no scripts. Это согласуется с локальной проблемой вкладки при исправном глобальном manager.
|
||
|
||
---
|
||
|
||
## 6. WebKit hypotheses
|
||
|
||
### 317981 — сообщение в cold start worker
|
||
|
||
Upstream regression test `SendMessageFromContentScriptWhileBackgroundIsLoading`:
|
||
|
||
1. Загружает MV3 extension с non-persistent background.
|
||
2. Background синхронно регистрирует `runtime.onMessage`.
|
||
3. Сразу открывает web tab без ожидания background readiness.
|
||
4. Content script сразу вызывает `runtime.sendMessage`.
|
||
5. Ожидает ответ background.
|
||
|
||
Правильное поведение — очередь до registration listener. Без фикса сообщение может быть потеряно. Это ближе всего к цепочке `scripts/context есть → init отправлен → нет response/refresh` и не требует искусственного JS timeout.
|
||
|
||
Статус: fix 317981 присутствует в public Safari/WebKit ветке `safari-7625.1.29.*`. macOS 27 VM из проверки имела WebKit bundle `22625.1.29.11.27`; точное соответствие Apple OS build и WebKit commit нельзя доказать лишь CFBundleVersion. Нужен system-framework regression run на конкретной VM, а не предположение по номеру.
|
||
|
||
### 324743 — worker получает event до activation
|
||
|
||
Upstream test выгружает worker, будит его `runtime.sendMessage` из extension tab и прямо в message listener проверяет `clients.matchAll()` без polling. Offscreen document обязан быть уже controlled client. Без фикса worker обрабатывает message, пока activation/reconnect ещё не завершились.
|
||
|
||
Это также похоже на primary telemetry: controller/view выглядят живыми, но реальная обработка message идёт в неправильный момент.
|
||
|
||
### 322881 — reload потерял extension clients
|
||
|
||
Upstream test создаёт offscreen document, проверяет его presence в `clients.matchAll()`, reload-ит background и проверяет, что новый worker вновь видит тот же client. В production relevance пока не установлена: CPM обычно работает с web tab/content script, а не обязательно с extension-owned offscreen page.
|
||
|
||
### 324754 — worker в новом process без bindings
|
||
|
||
Upstream test включает site isolation, создаёт offscreen document, reload-ит worker, проверяет смену PID и затем наличие `browser.runtime.getURL`. Без фикса JavaScript worker стартует в процессе без Web Extension API bindings.
|
||
|
||
Это хороший кандидат для проблемы после reload/recovery, но не доказанный источник current CPM data. Сначала нужен upstream-shaped reproduction с offscreen/extension page, затем full CPM scenario.
|
||
|
||
### Связь с error 6
|
||
|
||
Error 6 частично ложится на путь `refreshCpmDashboardState`: если background не загрузился, он не вызовет refresh. Но error 6 не говорит, где именно сломалось: service-worker registration, process, storage, bindings или другая внутренняя WebKit ошибка. Он не доказывает 317981, 324743, 322881 или 324754.
|
||
|
||
---
|
||
|
||
## 7. Fix в browser code
|
||
|
||
В рабочем дереве `alex/cpm-web-extension-ready-handshake` подготовлен некоммитнутый JS fix, ориентированный на потерянное/слишком раннее `init` сообщение: content side ждёт explicit readiness/ответ и повторяет handshake вместо того, чтобы считать один message окончательным. ZIP с extension — release artifact; в нормальной жизни он собирается из исходников расширения и попадает в bundle приложения на build/release pipeline, а не загружается пользователем.
|
||
|
||
Смысл фикса: не менять WebKit и не «лечить» искусственной задержкой, а сделать CPM handshake идемпотентным. Если первый init попал в cold-start race, content script повторно инициирует состояние и получает актуальный dashboard path. Это покрывает потерю первого сообщения/ранний readiness contract, но не восстановит worker без `browser.runtime` и не исправит WebKit process/client bug сам по себе.
|
||
|
||
Существующий fixture с `setTimeout` полезен как test retry protocol, но не доказывает настоящую WebKit race. Он показал важное ограничение: единичная потеря init не делает все tabs stuck автоматически.
|
||
|
||
---
|
||
|
||
## 8. План точного воспроизведения без изменения WebKit logic
|
||
|
||
### Почему не C++ `DYLD_INTERPOSE`
|
||
|
||
Нужные C++ пути выполняются внутри отдельных WebContent/Network processes и используют internal hidden symbols. Вызовы внутри WebKit dylib обычно не проходят через interposable imported symbol stubs. Инъекция dylib в Apple WebContent subprocesses ненадёжна из-за hardened runtime, SIP и XPC environment. Это не практичный первый метод.
|
||
|
||
### Рабочий harness
|
||
|
||
1. Создать Swift integration harness с Objective-C runtime swizzle и `RaceGate`; тесты запускать serially, потому что swizzle process-global.
|
||
2. Для 317981 не ставить gate: портировать exact upstream cold-start race и многократно запускать на system WebKit.
|
||
3. Для 324743 swizzle `-[WKWebExtensionContext loadBackgroundContentWithCompletionHandler:]`: сообщить completion test coordinator раньше, а оригинальный вызов удержать до explicit release. Это контролирует scheduling на публичной ObjC boundary, не меняя extension logic или C++ WebKit code.
|
||
4. Для real lifecycle использовать доступные private test SPI динамически: `_terminateServiceWorkers`, `_backgroundWebView`, `_killWebContentProcessAndResetState`, `_webProcessIdentifier`, `_setSiteIsolationEnabled:`.
|
||
5. Логировать OS build, WebKit CFBundleVersion, timestamps init/response, background PID до/после, outcome каждой итерации.
|
||
|
||
### Матрица
|
||
|
||
| Сценарий | Реальный триггер | Успех/отказ |
|
||
|---|---|---|
|
||
| 317981 | Сразу открыть tab после extension load | Каждый init получает ответ/refresh |
|
||
| 324743 | Gate вокруг background load completion, tab уже навигировался | Message не должен исполняться до activation |
|
||
| 322881 | Создать extension client, `_terminateServiceWorkers`, разбудить message | Client есть в `clients.matchAll()` |
|
||
| 324754 | Site isolation, убить/restart background, дождаться нового PID | В новом worker есть `browser.runtime.*` |
|
||
| CPM amplification | Два timeout в одном shared start window, настоящий M4 reload, затем third tab без injection | Third tab работает; иначе доказан cascade/recovery defect |
|
||
|
||
Нельзя подтверждать global stuck одним искусственно потерянным init на одной вкладке. Для честного test нужны два timeout, которые переводят health monitor в stuck, после чего injection выключается перед третьей вкладкой.
|
||
|
||
---
|
||
|
||
## 9. Какие данные нужны дальше
|
||
|
||
Приоритетная telemetry с общим, privacy-safe navigation/episode correlation ID:
|
||
|
||
1. `content_init_sent`.
|
||
2. `background_init_received` и окончание async prerequisites.
|
||
3. `initResp_sent` / `initResp_received`.
|
||
4. `refreshCpmDashboardState_sent` / `received` / URL match result.
|
||
5. worker lifecycle: start, activation, PID/process generation, background load error code, recovery generation.
|
||
|
||
Эти точки разделят пять разных случаев, которые сегодня попадают в один `init failure`: content injection miss, runtime message miss, worker activation race, delayed/mismatched dashboard refresh и native routing failure.
|
||
|
||
|
||
---
|
||
|
||
## 10. Статус на 9 октября
|
||
|
||
Подробно: [[cpm-web-extension-repro-and-fix-2026-10-08]]. Сводки на английском для Asana: [[cpm-web-extension-data-analysis-summary-2026-10-08]] и [[cpm-web-extension-repro-and-fixes-summary-2026-10-08]]. Карта кода по строкам: [[cpm-web-extension-code-guide-2026-10-09]]. **Ничего не закоммичено.**
|
||
|
||
**Воспроизведено и закрыто фиксами (worktree `alex/cpm-web-extension-ready-handshake`):**
|
||
- Harness на реальном WebKit (раздел 8): production extension, `WebExtensionManager`, coordinator + navigation gate, монитор, M4, production-recorder диагностики.
|
||
- **Одна вкладка:** потеря `init` при первой загрузке background нового идентификатора (установка или обновление), 317981. При запуске её закрывает gate coordinator'а; установку и обновление посреди сессии закрыл новый gate.
|
||
- **Полный отказ:** падение Network-процесса оставляет background живым, а worker мёртвым; ломаются все вкладки и открытые документы; M4 чинит только новые навигации. Закрыто watchdog'ом, перезапускающим только background-процесс.
|
||
- **Смерть worker'а при живом Network-процессе** из приложения не обнаружить; закрыто перезапуском background по первому сбою (стоит одну навигацию). **Риск:** при медленном пробуждении, когда процесс отвечает, перезапуск убьёт грузящийся worker.
|
||
|
||
**Сверка с данными 5 октября:**
|
||
- Network-процесс объясняет не больше 20–45% «здоровых» `stuck`.
|
||
- **Группа 1** («здоровые» без смены Network-процесса, iOS 748 / macOS 228 daily): около половины — сразу после пробуждения background после idle-выгрузки; около четверти iOS и 15% macOS — после загрузки или reload контекста.
|
||
- **Поправка:** `recovered_without_extension_reload(initialization_failed)` к stuck не относится — он закрывает только init-эпизоды. Init → recovery без reload: 23% iOS / 25% macOS устройство-дней; stuck → recovery после M4: 64% / 74%. Сбои после загрузки контекста чаще проходят сами; на пробуждении чаще доходят до stuck.
|
||
|
||
**Новые находки 8–9 октября (worktree `alex/cpm-web-extension-remaining-failures`, без фиксов):**
|
||
- **Медленный старт worker'а на пробуждении** (> 4 с) воспроизводит сигнатуру группы 1 полностью: `bg_process_responsive=true`, `context_errors=none`, хвост `dealloc → view → proxy_on@30s`. 5 с → `initialization_failed`, затем поздний ответ; 12 с + следующая навигация → `stuck` → M4, который убивает живой медленный worker. Старт до 2,5 с — потерь нет. Почему на устройствах старт бывает долгим — неизвестно.
|
||
- **Error 6 (iOS, ~1/3 строк):** причина в WebKit — 30-секундный таймер выгрузки взводится до окончания загрузки. Репро на macOS есть, на iPhone (iOS 26.7.1) не воспроизвёлся.
|
||
- **WebKit 320812 / 312231@main (26.6+):** при смене `baseURL` загрузка контекста удаляет website data старого origin, включая весь дисковый кэш, и только потом инъецирует content scripts и грузит background. У DDG `baseURL` новый на каждом запуске и reload. На Mac с ~20–24 тыс. записей кэша задержка 0,75–1,35 с. Кандидат-митигация — стабильный `baseURL` (ветка `alex/cpm-stable-base-url`).
|
||
- **Другие баги WebKit:** 324743 (worker «загружен» до завершения регистрации; исправлен 22 сен, нет в 26.7/27.0) и 314194 (Lockdown Mode блокирует все service worker'ы; открыт).
|
||
- **Сигналы готовности background:** окончание загрузки страницы background view бесполезно (0,1 с); completion `loadBackgroundContent` и первое нативное сообщение worker'а точно отмечают его старт.
|
||
- **Отброшено:** блокировка устройства / data protection, устаревший URL вкладки на iOS, мигание флага для привязки вкладок на macOS.
|
||
|
||
**Телеметрия фазы 1 (worktree `alex/cpm-messaging-readiness-telemetry`, от свежего `main`):**
|
||
- На сбоях: `bg_ready_after`, `bg_view_age`, `app_state`, `open_tabs`, `loading_tabs`, `bg_load_error_app_state`, `bg_load_error_after`.
|
||
- На восстановлениях: `recovery_document`, `recovery_after`.
|
||
- Проверено на реальном WebKit; 677 тестов пакета, SwiftLint, `validate-pixel-defs`, сборка iOS и macOS — зелёные.
|
||
|
||
**Дальше:** фаза 2 детектора (отсчёт 4 с с момента готовности background, без эскалации до неё), раннее пробуждение background, стабильный `baseURL`, флаги и A/B для фиксов, репорты в WebKit. Не воспроизведены: привязка вкладок на macOS, «нет background view», код 7, первый сбой после M4.
|
||
|
||
---
|
||
|
||
## Источники
|
||
|
||
- Public attribution: `cpm-web-extension-public-attribution-2026-10-05.md` и папка `cpm-public-attribution-2026-10-06/` в `apple-browsers.git`.
|
||
- Historical validation/methodology: `cpm-web-extension-breakage-validation.md`.
|
||
- WebKit 317981 regression: `Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKWebExtensionAPIRuntime.mm`, `SendMessageFromContentScriptWhileBackgroundIsLoading`.
|
||
- WebKit 322881/324743/324754 regressions: `Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKWebExtensionAPIOffscreen.mm`.
|
||
- Browser implementation: `CPMMessagingHealthMonitor.swift`, `CPMMessagingDiagnosticsRecorder.swift`, `WebExtensionManager.swift`, `AutoconsentWebExtensionMessageHandler.swift`.
|