31 KiB
Executable File
CPM Web Extension: attribution и сравнение релизов — 5 октября 2026
Статус: первый завершённый 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.
Вывод: после публикации 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 и 09:46 UTC для macOS 1.210. Время после 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 навигации/эпизода, не причина поломки.
Окружающие события по главным цепочкам:
- 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 сообщения, а не ещё одного снимка состояния. - 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_*в доступном хвосте. - Повторная проверка после extension reload, iOS 670 / macOS 232. Это именно первый CPM init timeout после reload, вместе с
messaging.extension.reload.failed.daily. Типичный хвост iOSload → base_url_changed → view → proxy_on(483); macOSload → base_url_changed → view → proxy_on → dealloc → view → proxy_on(87).base_url_changedздесь совпадает с reload и сам по себе не доказывает ошибку URL. Native snapshot уже выглядит исправно у 470 iOS / 125 macOS; причина отсутствия ответа там не локализована. - 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 при живой вкладке. - 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-снимок»
- Пиксель измеряет отсутствие отдельного native-вызова. После
navigationDidFinishпри наличии context (или после lifecycleloaded) monitor ждёт до 4 секундdashboardResponse, который поступает только изAutoconsentWebExtensionMessageHandler.handleRefreshCpmDashboardStateпри вызовеrefreshCpmDashboardState. Если наnavigationDidFinishextension отсутствует, действует отдельное 30-секундное ожидание с отменой измерения. По истечении 4-секундного таймераreportFailureсобирает снимок на тот момент.isAutoconsentExtensionLoadedпроверяет наличие embedded context в controller, не готовность CPM JS. context_loaded=trueне означает завершённый startup. В просмотренномWebKit_sparseisLoaded()означает наличие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, но не факт обработки сообщения.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.- Есть конкретные места задержки и ложной атрибуции. 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 вошёл в 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 входит в 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 и двухминутная сводка).
Источники и воспроизведение сверки
Локальная выгрузка и код подсчёта: 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-день новой версии и знаменатель активных установок той же версии.