--- updated: '2026-10-20' --- # CPM Web Extension: attribution и сравнение релизов — 5 октября 2026 > **Исторический отчёт за 5 октября; контекст сверён 20 октября 2026.** Таблицы, release-tag cutoffs и контрольные суммы сохранены без пересчёта. Актуальные PR/CI, отдельные когорты 12–14 октября и проверка обрезания history за 14 октября — [[cpm-status-2026-10-15]]. Новые числа нельзя переносить в прежние знаменатели. > > #7376 заменяет раздельные события terminal episode report (daily+count), four-state `stuck` и `initial;pre-stuck` timeline с `...`; PR закрыт без merge. Старый parser и параметры этой заметки не являются текущим wire contract. См. [[cpm-pr0-episode-telemetry-summary-2026-10-16]]. Совпадающие `bg_events` и ratios независимо deduplicated daily events не доказывают пару одного пользователя или recovery success. > > Shared-pinned window-close fix #7473 **merged 20 октября в `release/macos/1.213.0` (`9bcce0264e`)**, default ON + remote failsafe; rollout/effect ещё не подтверждены (подробности — [[cpm-status-2026-10-15#P5 — merged 20 октября 2026]]); per-view Network recovery — #7459 с applied pixel, stable-origin P3 — #7493. Их наличие не превращает прежние snapshot cohorts в доказанные causal shares. ## Историческое дополнение — 15 октября 2026 > **Исторический отчёт за 5 октября; контекст обновлён 15 октября.** Таблицы, release-tag cutoffs и контрольные суммы этого дня сохранены без пересчёта. Текущие когорты 12–14 октября, PR/CI и P5/P6 tests — [[cpm-status-2026-10-15]]; переносить новые числа в прежние знаменатели нельзя. > > Дополнительная проверка показала: фильтр сохранённых tabs перед явным didCloseTab уже присутствует в release 1.210, однако последующий didCloseWindow заставляет WebKit снова закрыть shared pinned tabs, которые возвращает delegate. Этот путь воспроизвёл P5/tab=false; наличие исходного M1 fix не доказывает устранение всего window-close контракта. Условный main-flag cycle воспроизводит P6, но его occurrence в этом или более позднем production-срезе не доказан. Полная область объяснения и контроли — основной статус §11–12. **Статус:** первый завершённый UTC-день с данными версий iOS 7.240.0 и macOS 1.210.0. Главный сигнал — `initialization.failed.after.*.daily`; `messaging.stuck.*.daily` проверен отдельно как более поздний, менее точный сигнал. Выгрузка сделана 6 октября из Grafana ClickHouse `metrics.pixels`, интервал `[2026-10-05 00:00, 2026-10-06 00:00) UTC`, `agent` и `appVersion` зафиксированы. **Основные таблицы ниже включают только события после публикации release tag каждой платформы**; отдельный раздел сохраняет всё попавшее в выгрузку до публикации. [Dashboard](https://grafana.duckduckgo.com/d/dfon7whlilnggb/cpm-weird-error-investigation?orgId=1). **Вывод:** после публикации macOS tag есть **77** первых init failures и **35** stuck с несовпадающим controller вкладки и отсутствующими extension scripts; **до публикации таких строк нет**. iOS session restoration по-прежнему даёт 952 первых сбоя, из них 604 со совпадающим controller, но без scripts и background view; у macOS после публикации таких session-restoration сбоев 68, из них 12 с той же сигнатурой. **Крупнейшая группа с «исправным native-снимком» не доказывает нормальную загрузку или потерю `initResp`: health monitor измеряет отдельный вызов background → native `refreshCpmDashboardState`.** После reload этот вызов вновь наблюдается гораздо чаще, но восстановление фактического `initResp` из пикселей не следует. Эффект исправлений tab lifecycle в совокупном тренде не выделяется. ## 1. Охват и контрольные суммы | После release tag: независимые имена `.daily` пикселей | iOS 7.240 | macOS 1.210 | |---|---:|---:| | Первое `initialization.failed.after.*` | **6 624** | **1 377** | | Позднее `messaging.stuck.*` | 1 440 | 487 | | Первый неудачный post-reload CPM probe | 670 | 232 | | CPM ответ после reload, оба `recovery_from` | 963 = 916 stuck + 47 init | 362 = 354 stuck + 8 init | | CPM ответ без reload, `initialization_failed` | 1 555 | 346 | | **Сумма записей CPM daily по именам пикселей** | **11 252** | **2 804** | Контроль после release tag: `6 624 + 1 377 = 8 001` первичных строк; `1 440 + 487 = 1 927` вторичных строк; `11 252 + 2 804 = 14 056` CPM daily записей по именам пикселей. До tag есть ещё 28 init, 2 stuck и 39 CPM daily записей, все на macOS; полные файлы поэтому содержат `8 029` init, `1 929` stuck и `14 095` CPM daily. Разделение по времени и pixel name воспроизводит `release_cutover_daily.tsv`, полный день сходится с `inventory.tsv` и `release_cpm_daily_trends.tsv`. Включать `debug.web.extension.reload.failed.daily` в сумму CPM нельзя: это отдельное семейство операций Web Extensions. Внутри CPM `initialization.failed.after.extension.reload.daily` и `messaging.extension.reload.failed.daily` обычно посылаются вместе на одной неудачной post-reload проверке: их суммы не обозначают разные эпизоды. `.daily` ограничен одним событием **на имя пикселя** за UTC-день на установку; разные имена могут относиться к одному пользователю и эпизоду. Переход версии внутри дня тоже меняет наблюдаемые суммы. Здесь нет числа уникальных пользователей, DAU той же версии и идентификатора для связывания событий. Публикация release tag состоялась 5 октября в 15:18 UTC для [iOS 7.240](https://github.com/duckduckgo/apple-browsers/releases/tag/7.240.0%2Bios) и 09:46 UTC для [macOS 1.210](https://github.com/duckduckgo/apple-browsers/releases/tag/1.210.0%2Bmacos). Время после tag — доступная граница, **не доказательство public-канала у каждого отправителя**: пиксель не содержит channel/rollout cohort, и internal testing могло продолжаться после публикации. ### До публикации release tag: отдельный срез В пределах выгрузки за 5 октября до публикации iOS tag нет CPM daily событий версии 7.240. До публикации macOS tag у версии 1.210 есть **28 init failure.daily, 2 stuck.daily, 2 post-reload failed.daily, 7 recovered.without.reload.daily, 0 recovered.after.reload.daily** — всего **39 CPM daily**. В этих 28 init: 12 native snapshot без видимой ошибки, 7 background state, 5 только context error history, 3 tab attachment/injection (2 без scripts/zero views и 1 tab-not-in-context), 1 с неполными tab facts. В двух stuck нет отсутствующих scripts или controller mismatch. `debug.web.extension.reload.failed.daily` до tag нет. Более ранние internal-testing данные 28 сентября – 4 октября сохранены в [[cpm-web-extension-breakage-validation]] как архив и **не смешиваются** с таблицами после публикации. ## 2. Первичный сигнал: группы и события рядом с `init failure.daily` Каждая строка попадает ровно в одну диагностическую группу по приоритету: tab scripts/controller → явные признаки background → история ошибок → неполные поля → видимо исправный native snapshot. Это **классификация снимка**, а не доказательство первопричины. Полные пересекающиеся признаки сохранены отдельно. | После release tag: диагностическая группа | iOS init, из 6 624 | macOS init, из 1 377 | iOS stuck, из 1 440 | macOS stuck, из 487 | |---|---:|---:|---:|---:| | Native snapshot без видимой ошибки | 3 717 (56,1%) | 911 (66,2%) | 789 (54,8%) | 335 (68,8%) | | Tab attachment / injection | 931 (14,1%) | 116 (8,4%) | 53 (3,7%) | 38 (7,8%) | | Background state | 768 (11,6%) | 158 (11,5%) | 457 (31,7%) | 35 (7,2%) | | Только история ошибок context | 343 (5,2%) | 158 (11,5%) | 87 (6,0%) | 79 (16,2%) | | Недостаточно tab facts | 865 (13,1%) | 34 (2,5%) | 54 (3,8%) | 0 | Контроль групп после tag: iOS init `3717+931+768+343+865=6624`; macOS init `911+116+158+158+34=1377`; iOS stuck `789+53+457+87+54=1440`; macOS stuck `335+38+35+79=487`. Контроль причин первого сбоя: iOS `other 4803 + session.restoration 952 + extension.reload 670 + tab.crash 199 = 6624`; macOS `1050+68+232+27=1377`. Это `reason` навигации/эпизода, **не причина поломки**. **Окружающие события по главным цепочкам:** 1. **iOS session restoration, 952.** У 604 (63,4%) `tab_controller_match=true`, scripts отсутствуют, `bg_view_creations=0`; у 607 хвост `bg_events` содержит только `load`, ещё у 283 — `load → view → proxy_on`. 754 первых сбоя попали в bucket первых 30 секунд запуска. Код ожидает начальный `loadAndSync` и загрузку background content перед первой HTTP(S)-навигацией restored tab, но общий дедлайн ожидания — 5 секунд; неоконченная загрузка и более позднее внедрение script всё ещё способны дать временный timeout. 260 снимков уже выглядят исправно и требуют timings сообщения, а не ещё одного снимка состояния. 2. **iOS `other`, 4 803.** 2 921 выглядят исправно; 831 имеют неполные tab facts; 334 содержат background load error code 6; 239 — scripts отсутствуют при нулевом числе background views. Частые хвосты `load → view → proxy_on` (1 450) и `load → view → proxy_on → dealloc → view → proxy_on` (934). `dealloc` фиксирует освобождение background view, не падение процесса; только 85 первичных iOS строк имеют явный `died_*` в доступном хвосте. 3. **Повторная проверка после extension reload, iOS 670 / macOS 232.** Это именно первый CPM init timeout после reload, вместе с `messaging.extension.reload.failed.daily`. Типичный хвост iOS `load → base_url_changed → view → proxy_on` (483); macOS `load → base_url_changed → view → proxy_on → dealloc → view → proxy_on` (87). `base_url_changed` здесь совпадает с reload и сам по себе не доказывает ошибку URL. Native snapshot уже выглядит исправно у 470 iOS / 125 macOS; причина отсутствия ответа там не локализована. 4. **macOS `other`, 1 050.** 713 выглядят исправно, 132 не имеют живого background view, 110 имеют только историческую context error, 47 — неверный controller без scripts. За все причины init неверный controller без scripts есть у **77/1 377 после tag и 0/28 до tag**; в stuck — **35/487 после tag и 0/2 до tag**. Init-сигнатура встречается с 10:34 до 23:21 UTC, а не только сразу после публикации в 09:46. Из 77 после tag 45 имеют `app_version_change=updated`. App update сам по себе не сохраняет старый `WKWebView`; эти строки не доказывают сценарий «вкладка осталась у старого контроллера после обновления». Требуется событие смены manager/controller при живой вкладке. 5. **iOS `tab.crash`, 199.** 47 имеют code 6, 37 — явную смерть background процесса, 35 — scripts отсутствуют и background view не создан. Название reason означает навигацию после crash вкладки, а не установленную смерть CPM worker. Вторичный stuck сдвигает iOS-картину: background state 768/6 624 (11,6%) на первом сбое против 457/1 440 (31,7%) на stuck; no-scripts/zero-view 917/6 624 против 52/1 440. Это согласуется с временными startup misses и более устойчивой background-проблемой, **но это не переходная вероятность**: имена `.daily` считаются независимо. У iOS code 6 находится в 364 stuck снимках (в 363 `dealloc` раньше первой ошибки); WebKit регистрирует code 6 как `BackgroundContentFailedToLoad` после неудачной загрузки service worker. Причина отказа регистрации из пикселя неизвестна. Хвост `bg_events` ограничен 12 событиями и может обрезать старые события. ### Проверка по коду: что означает «исправный native-снимок» 1. **Пиксель измеряет отсутствие отдельного native-вызова.** После `navigationDidFinish` при наличии context (или после lifecycle `loaded`) monitor ждёт до 4 секунд `dashboardResponse`, который поступает только из `AutoconsentWebExtensionMessageHandler.handleRefreshCpmDashboardState` при вызове `refreshCpmDashboardState`. Если на `navigationDidFinish` extension отсутствует, действует отдельное 30-секундное ожидание с отменой измерения. По истечении 4-секундного таймера `reportFailure` собирает снимок **на тот момент**. `isAutoconsentExtensionLoaded` проверяет наличие embedded context в controller, не готовность CPM JS. 2. **`context_loaded=true` не означает завершённый startup.** В просмотренном `WebKit_sparse` `isLoaded()` означает наличие `m_extensionController`; он назначается до асинхронного `moveLocalStorageIfNeeded`, создания background view, регистрации scripts и `addInjectedContent()`. `bg_view_alive=true` означает живой `WKWebView`, а `bg_process_responsive=true` — что WebKit не признал его зависшим; это не проверка выполненного service worker listener. `tab_has_ext_scripts=true` проверяет список зарегистрированных `WKUserScript`, но не их выполнение в текущем документе. `handler_registered=true` проверяет запись в native router, но не факт обработки сообщения. 3. **`initResp` и наблюдаемый monitor сигнал расходятся в release bundle.** Content script отправляет `init` в background. В успешной ветке background делает `updateCpmDashboardState(...).then(refreshDashboardState(...))` **без await**, затем отдельно вызывает `chrome.tabs.sendMessage(..., {type: "initResp"})`. В ветках `config_unavailable`, `settings_missing`, `setting_disabled`, `site_disabled` он отправляет dashboard refresh и возвращается **без `initResp`**. Значит, `init failure.daily` возможен даже после отправки `initResp`, если dashboard refresh задержался или не сопоставился с документом; обратное тоже возможно: успешный health-сигнал без `initResp`. 4. **Есть конкретные места задержки и ложной атрибуции.** Background перед успешной веткой ждёт remote config и native setting/site checks; native request timeout в bundled JS — 20 секунд против 4-секундного окна monitor. Обновление dashboard state проходит через последовательную async-очередь и session storage. Monitor сопоставляет URL refresh с текущим документом по scheme/host/port/path/**query**; несоответствие или опоздание оставит timeout даже при работающем JS. Сколько случаев пришло из каждого участка, текущие пиксели не показывают. Эта проверка проведена именно на bundle из release tags `1.210.0+macos` и `7.240.0+ios` (zip-файлы совпадают); текущий `main` уже содержит другой bundle. Приоритет следующей telemetry — отдельные времена `content init sent`, `background init received`, `initResp sent/received`, `dashboard refresh sent/received` и результат сопоставления URL. ## 3. Session restoration: ушли ли временные сбои? **Нет.** После release tag есть 952 iOS и 68 macOS первых `session.restoration` failures. Соответствующий поздний `stuck.session.restoration.daily` встречается 118 / 8 раз, но без связи событий нельзя сказать, какие именно первые сбои восстановились. `recovered.without.extension.reload.daily` (1 555 iOS / 346 macOS) не содержит `reason`, поэтому доля временных session-restoration эпизодов также неизвестна. Сравнение по имени пикселя на одинаковых пятидневных окнах после предыдущих release tags: iOS 7.238 (23–27 сентября) — 3 372 386 session restoration из 5 821 858 init daily (57,9%); iOS 7.239 (30 сентября – 4 октября) — 3 014 131 из 5 390 550 (55,9%). У iOS 7.240 за **первый неполный день** — 952 из 6 624 (14,4%). Это сильное изменение состава сигналов, совместимое с readiness gate, вошедшим в 7.240, но не оценка снижения риска на пользователя: новая версия имеет иной ранний cohort и нет DAU. macOS 1.208 (23–27 сентября) — 4 531/76 336 (5,94%); 1.209 (30 сентября – 4 октября) — 7 425/114 075 (6,51%); 1.210 после публикации — 68/1 377 (4,94%). На macOS явного снижения по этому proxy пока нет. Gate входит в macOS 1.210 / iOS 7.240 и по умолчанию включён, но фактическое состояние remote flag у отправителей не передано. ## 4. Исправления tab lifecycle: виден ли эффект? [M1 tab identity fix](https://github.com/duckduckgo/apple-browsers/pull/6827) вошёл в macOS 1.209, а в 1.208 его нет; PR менял только macOS. Старые версии не посылали новые поля controller/scripts, поэтому сравним лишь общий proxy `stuck.other.daily / initialization.failed.after.other.daily`, **не частоту tab bugs**. В сопоставимых пятидневных окнах он равен 27 493/69 565 = **39,52%** на macOS 1.208 и 40 030/103 135 = **38,81%** на 1.209. Изменение на 0,71 процентного пункта мало и может отражать состав cohort/нагрузки; это не измеренный эффект фикса. Новый 1.210 после публикации даёт 418/1 050 = **39,81%**. Следовательно, по агрегатному тренду исчезновение tab breakage не подтверждено и не опровергнуто; именно относящиеся к нему события старых версий нельзя выделить без attribution. ## 5. After-stuck recovery mitigation: работает ли? **Узкий функциональный сигнал есть.** [M4](https://github.com/duckduckgo/apple-browsers/commit/41656f8d17) входит в macOS 1.210 / iOS 7.240 и при подтверждённом hang пытается reload embedded extension (remote flag по умолчанию enabled). `recovered.after.extension.reload.daily` означает, что после reload текущего поколения снова поступил и был сопоставлен **native dashboard refresh**; получение `initResp` content script этот пиксель не проверяет. После публикации таких событий от `messaging_stuck` — **916 iOS / 354 macOS**. Все `recovered.after` вместе дают 963/1 440 = **66,9%** от числа stuck daily на iOS и 362/487 = **74,3%** на macOS, тогда как в предшествующих пятидневных окнах число пикселей этого имени относительно stuck daily составляло **3,23%** (iOS 7.239) и **2,70%** (macOS 1.209). Это большой скачок, согласующийся с автоматическим reload. Эти отношения **не success rate**: имена пикселей независимо throttled, эпизоды не соединены, одни установки могли дать несколько разных сигналов. **Ограничение эффекта:** после публикации первый post-reload CPM probe всё ещё завершился timeout 670 раз на iOS и 232 на macOS, поэтому reload не гарантирует немедленного восстановления даже измеряемого native-вызова. Это не сбой самого API reload. Отдельный `debug.web.extension.reload.failed.daily` после публикации содержит один macOS error для `embedded / cpm_messaging_hung / load` и 223 iOS errors для **другого** `adBlocking / scriptlet_update / unload` extension; до публикации этих operation errors нет. На текущих данных M4 восстанавливает измеряемый background → native путь у части установок; нельзя вычислить долю stuck-эпизодов с полноценным `initResp` и CPM-функцией, которые остались невосстановленными, или изменение общей частоты init failures. ## 6. Другие CPM / Web Extension пиксели: что реально видно в системе Сверка сделана по тем же версиям, полному UTC-дню 5 октября и с разделением по времени release tag. Полный наблюдаемый перечень `autoconsent` и `web.extension` с `pixel_id`, именем, platform suffix, частотой и числом записей — `related_pixels.tsv` (329 сгруппированных строк, включая отдельный pre-tag срез). `autoconsent_sources.tsv` делит каждый daily-пиксель по `fromExtension=1`, `0` и отсутствующему параметру; `autoconsent_summary.tsv` делает то же для standard summary и раскрывает счётчики событий внутри него. В таблице ниже только **после release tag**; записи до tag остаются в TSV отдельно. | Сигнал после tag | iOS 7.240 | macOS 1.210 | Что он проверяет | |---|---:|---:|---| | `autoconsent_init.daily`, только `fromExtension=1` | **56 906** | **2 825** | Background Web Extension получил `init`, дошёл до разрешённой ветки CPM и отправил native pixel. Это происходит до отдельной попытки `chrome.tabs.sendMessage(initResp)` и не подтверждает доставку ответа. | | `autoconsent_summary`, только `fromExtension=1` | **324 549** standard-отчётов; **1 760 177** накопленных `init` | **54 421** отчёт; **213 878** `init` | Фоновый скрипт накопил события и позже отправил сводку через native. Это наблюдение многих успешных background→native проходов, но не denominator для `init failure.daily`: другое окно, другой тип частоты, эпизоды не соединены. | | `web_extension_loaded.daily` | 61 902 | 2 870 | Manager загрузил хотя бы одно extension; имя не указывает, что это CPM, и ничего не говорит о конкретной вкладке. | | `web_extension_state_checked.daily` | 62 004 | 2 805 | Lifecycle coordinator проверил набор ожидаемых/загруженных extension в manager. | | `web_extension_embedded_not_loaded.daily` | **3 389** | **1** | Во время хотя бы одной проверки embedded extension ожидался, но отсутствовал в manager. Не проверяет controller/scripts конкретной вкладки. | | `web_extension_load_error.daily` | 4 | 4 | Ошибка общей загрузки extension. Это отдельный сигнал от CPM timeout; по одному имени тип extension не известен. | **Почему `autoconsent_init` нужно делить по источнику.** Одинаковое имя пикселя используют Web Extension и старый Autoconsent user script. Всего `init.daily` после tag пришло 60 720 на iOS и 3 351 на macOS; из них `fromExtension=1` — 56 906/2 825, `fromExtension=0` — 1 100/1, без параметра — 2 714/525. В release-коде user script ставит `0` только при доступном Web Extensions API, но недоступном autoconsent extension; отсутствие параметра также не доказывает работу extension. `.daily` ограничен по общему имени, поэтому нельзя считать этот split долей всех init-вызовов. Standard summary не имеет такого daily throttle: extension-источник дал 324 549/54 421 сводок с `init` счётчиками, но сводка запускается двухминутным alarm и может прийти существенно позже навигации. **Функциональные CPM-события тоже есть:** с `fromExtension=1` после tag получены `autoconsent_popup-found.daily` 31 363 iOS / 1 918 macOS и `autoconsent_done.daily` 23 050 / 1 578; `disabled-for-site.daily` 4 763 / 694. Они показывают, что Web Extension действительно обнаруживает и обрабатывает popup на части навигаций. Ошибки `error_optout.daily` 513/107 и `error_reload-loop.daily` 280/49 относятся к обработке popup, а не к доставке `initResp`. `self-test-fail.daily` 153/97 **не имеет `fromExtension=1`** в этих данных и потому не служит сигналом ошибки extension. Все эти имена общие с legacy user script, поэтому исходный `fromExtension` обязателен. **Lifecycle и соседние семейства:** `web_extension_embedded_installed.daily` 51 958/1 756 и `embedded_upgraded.daily` 804/741 отражают операции установки, а не исполнение content script. Есть отдельные пиксели install/uninstall, ad-blocking, dark-reader, scriptlet fetch/validation/install и `web_extension_ad_blocking_not_loaded`; полный набор реально поступивших имён и чисел в `related_pixels.tsv`. Они полезны для общей работоспособности Web Extensions, но не локализуют CPM `init`-timeout. Все debug CPM health-пиксели и actual `web_extension_reload_failed` разобраны выше в разделах 1–5. **Вывод для крупнейшей группы init failure:** в совокупности данные подтверждают, что Web Extension широко запускается и обрабатывает CPM на этих билдах. Они **не подтверждают**, что в 3 717 iOS / 911 macOS строках с исправным native-снимком background получил именно тот `init`, отправил `initResp` и content script его принял. Нет event/pixel для `content init sent`, `background init received` с общим navigation ID, `initResp sent/received`, начала/результата `refreshCpmDashboardState` или исхода сопоставления URL. Сопоставить `autoconsent_init`/`summary` с конкретным `initialization.failed` по текущей анонимной телеметрии нельзя. На macOS лишь 1 общий `embedded_not_loaded.daily` при 77 init failures с controller mismatch без scripts: это согласуется с тем, что глобальный manager может быть исправен, пока отдельная вкладка прикреплена неверно. Код release tags: `WebExtensionPixelFiring.swift` (семейства и частоты CPM); `WebExtensionManager.swift` (`.loaded` после общего load); `WebExtensionLifecycleCoordinator.swift` (`stateChecked`/`embeddedNotLoaded`); платформенные `AutoconsentMessageHandlerDelegate` (пересылка Web Extension пикселей); `AutoconsentUserScript.swift` (то же имя с `fromExtension=0` или без параметра); release bundle background `handleAutoConsentMessage`, `firePixel`, `sendSummaryPixel` (`init`, `initResp` и двухминутная сводка). ## 7. Общие `bg_events` у init failure и последующего stuck **Кодовая связь сильнее совпадения строк.** Внутри `CPMMessagingHealthMonitor.reportFailure` первый timeout создаёт `Episode`, а `messaging.stuck` отправляется только после ещё одного timeout проверки, начатой позже первого failure (для confirmation — не session-restoration). Episode живёт не более пяти минут. Имя stuck наследует `failureReason` **первого** timeout; диагностика `stuck` снимается с вкладки **второго** timeout. `CPMMessagingDiagnosticsRecorder` сохраняет общую историю background context между этими снимками и при каждом берёт последние 12 событий; первый failure не очищает её. Поэтому `stuck.bg_events` действительно может содержать события, случившиеся до первого init failure. Новый context или вытеснение старых событий обрывает это наблюдение. **Проверка на выгрузке после release tag.** Для каждого stuck искался более ранний init failure той же платформы и с тем же `reason` в окне пяти минут. Требовалось точное совпадение порядка токенов `bg_events` без возрастных суффиксов и совместимость всех возрастных buckets после прибавления разницы timestamps (допуск ±30 с). Для сильного сигнала оставлены цепочки длиной **не менее шести** событий. Контроль: timestamps stuck сдвинуты на +10 и −10 минут внутри post-tag интервала; все прочие правила те же. Это тест **обогащения совпадениями**, не восстановление анонимного reporter ID. Время пикселя может отличаться от времени снимка из-за доставки. | После tag | Stuck daily | С цепочкой ≥6 | Совпало с более ранним init | Контроль +10 / −10 мин | Ровно один кандидат в выгрузке | |---|---:|---:|---:|---:|---:| | iOS 7.240 | 1 440 | 1 025 | **693** | 255 / 270 | 467 | | macOS 1.210 | 487 | 368 | **168** | 29 / 19 | 148 | Иными словами, длинные цепочки у последующих stuck совпадают с цепочками более ранних init failures значительно чаще, чем при соседнем сдвинутом времени. Но «ровно один кандидат» означает один подходящий **анонимный пиксель** в этой выгрузке, а не доказанный один пользователь. `.daily` мог подавить настоящий первый пиксель, а часто встречающиеся цепочки способны совпасть у разных пользователей. **Какие группы дают эту связь:** | Группа stuck после tag | Stuck всего | Длинная цепочка совпала | Контроль +10 мин | Уникальный кандидат с той же группой init | |---|---:|---:|---:|---:| | iOS, исправный native-снимок | 789 | **437** | 199 | 249 | | iOS, background load error 6 | 338 | **152** | 20 | 142 | | macOS, исправный native-снимок | 335 | **138** | 21 | 120 | | macOS, только история context error | 79 | **20** | 6 | 14 | Пример совместимой пары iOS с одним кандидатом: в init-хвосте после повторных `dealloc→view→proxy_on` стоит `error_wkwebextensioncontexterrordomain:6@30s`; 41 секунду спустя stuck содержит **тот же порядок 12 токенов**, а последний error уже помечен `@2m`. Это согласуется с одним сохраняющимся background-сбоем через два timeout, но без reporter/episode ID остаётся вероятностным сопоставлением. В группе с исправным native-снимком найдены аналогичные пары с тем же длинным `load→view→proxy_on→dealloc→view→proxy_on...` и более старшими age buckets на stuck: два timeout могут происходить без нового видимого WebKit lifecycle-события. Метод намеренно слаб для коротких хвостов `load` и `load→view→proxy_on`, в том числе startup `no scripts/no view` и macOS controller mismatch: у 35 macOS stuck с неверным controller только 3 хвоста длиной ≥6, поэтому отсутствие длинного match здесь ничего не опровергает. Из этих таблиц **нельзя вычислять вероятность перехода отдельного init failure в stuck**: нет идентификатора установки или episode, а `.daily` дедуплицирует имена. Тем не менее сочетание state machine в коде и превышения над контролем подтверждает, что stuck-пиксели отражают повторные timeout-эпизоды, а не просто новое имя для одиночного init failure. Воспроизведение: `match_event_chains.py` → `chain_match_summary.tsv`, `chain_match_transitions.tsv` в каталоге выгрузки. Исходные строки: `initialization_daily.tsv` и `events_daily.tsv`. Числа выше используют только after-tag строки; до публикации остаются отдельно. ## Источники и воспроизведение сверки Локальная выгрузка и код подсчёта: `cpm-public-attribution-2026-10-06/` в `/Users/admin/DuckDuckGo/apple-browsers.git`. `inventory.tsv` — полный CPM daily/count перечень и actual reload errors; `release_cutover_daily.tsv` — все CPM daily и actual reload daily по обе стороны release-tag timestamp; `initialization_daily.tsv` и `events_daily.tsv` — PII-free строки attribution с точным timestamp; `release_cutover_groups.tsv` и `release_cutover_reasons.tsv` — группы и причины по обе стороны tag, воспроизводятся `analyze_cutover.py`; `daily_groups_exclusive.tsv`, `daily_families.tsv`, `daily_reasons.tsv`, `daily_signatures.tsv` — сводки **полного дня, включая pre-tag**; `release_cpm_daily_trends.tsv` — 982 строки дневных трендов шести версий. Код поведения: `CPMMessagingHealthMonitor.swift` (`reportFailure`, `reportSuccess`), `WebExtensionManager.swift` (`onConfirmedHang`, `reloadEmbeddedExtensionAfterCPMMessagingHang`), `WebExtensionLifecycleCoordinator.swift` (navigation gate), `PixelKit.swift` (лимит `.daily` по имени и UTC). Снимок законченного дня; для вывода о динамике incidence нужен следующий полный UTC-день новой версии и знаменатель активных установок той же версии.