Files
obsidian-vault/work/projects/cpm-web-extension-public-attribution-2026-10-05.md
T

31 KiB
Executable File
Raw Blame History

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 навигации/эпизода, не причина поломки.

Окружающие события по главным цепочкам:

  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 вошёл в 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-день новой версии и знаменатель активных установок той же версии.