Files
obsidian-vault/work/projects/cpm-project-summary-2026-11-03.md
T

19 KiB
Raw Blame History

tags, updated, status
tags updated status
work
cpm
summary
2026-11-03 draft

CPM stuck-messaging project: where we are, Nov/3

Internal metrics, keep out of public PRs. Task: CPM: root-cause the stuck embedded extension messaging. Details: cpm-post-release-analysis-2026-10-27, cpm-status-2026-10-15.

What the project has achieved

Goal: permanent failures below 1% of DAU (0.2-0.5% = success). Permanent = no answer for 5 minutes, repeated or needed a reload.

Now (macOS 1.214, iOS 7.244, Nov/2)

  • iOS: 0.44% of DAU (0.39% on 7.243, same day). Inside the target.
  • macOS: 1.89%. Above the target.

Fixes shipped

  • P3, OS<26.6 limit – improves extension startup after a restart from up to 32 s → 0.1 s on iOS/macOS 26.6+ (lab tests). iOS 26.6+: "background missing" failures 8.2% → 0.3% of DAU (users with any failure 14.6% → 8.3%). Effect on permanent not measurable yet (one day, 90k users).
  • macOS: pinned tab lost on window close, tab merging – real bugs fixed, UI tests added. They caused under 1% of permanent failures, about 3x fewer after the fix (macOS 1.211 → 1.213).
  • P1 – recovery after a slow wake of the extension. Triggers for 19% of iOS and 3% of macOS daily users (Nov/2).
  • P2 – retry after load error 6. Triggers for 1.7% of iOS and 0.2% of macOS daily users (Nov/2).
  • Network process crash – restart after the networking process crashes. Triggers for 6.6% of iOS and 4.2% of macOS daily users (Nov/2).
  • State restoration race – restored tabs wait up to 5 s for the extension to start. Init failures on restore: iOS ~20% → ~8.5% of DAU, macOS no clear change.

Hypotheses rejected

  • Deallocation race (A/B, flag) – fix shipped behind a flag never turned on, no relation in the data.
  • Reload on the stuck signal – 46% of macOS cases still got no answer.
  • P4 – reload the page when the extension starts late. Off by default, never triggered in production.

Fixes going public next week (Nov/9)

  • Upgrade before loading – load the new extension version first on launch. Removes part of the permanent failures right after an update (macOS 0.26% of DAU, iOS 0.05%).
  • Error 6 restart – restart the extension when a load error leaves it broken. Up to 0.08% of DAU permanent on iOS, negligible on macOS.
  • Together: macOS 1.89% → about 1.6%, iOS 0.44% → about 0.3-0.35%. Estimates, upper bounds.

Data now (% of DAU)

Permanent failures, daily trend (macOS 1.213 / iOS 7.243: Oct/26 → Nov/2; 1.214 / 7.244: Nov/2):

  • macOS: 2.07% → 3.07% (Oct/27 peak) → 1.90%; 1.214: 1.89%.
  • iOS: 0.30% → 0.42% (Oct/27 peak) → 0.39%; 7.244: 0.44%.

By group, % of DAU. Trend is failures: previous version (1.213 / 7.243) on Oct/26 → previous version on Nov/2 → new version (1.214 / 7.244) on Nov/2. Shares and permanent are for the new version.

Group Platform Trend % of all failures Permanent % of all permanent
Init on wake macOS 8.80% → 8.50% → 5.89% 39% 0.68% 36%
Init on wake iOS 1.56% → 2.34% → 1.74% 22% 0.06% 15%
Tab not connected macOS 1.18% → 0.90% → 1.26% 8% 0.42% 22%
Init after extension update macOS 5.40% → 0.92% → 2.94% 20% 0.26% 14%
Init after extension update iOS 0.37% → 0.13% → 0.34% 4% 0.05% 12%
Init after load macOS 2.73% → 3.41% → 1.73% 11% 0.19% 10%
Init after load iOS 1.86% → 2.21% → 2.54% 32% 0.18% 42%
Error 6 macOS 0.14% → 0.17% → 0.11% 1% 0.01% 1%
Error 6 iOS 0.50% → 1.32% → 0.67% 8% 0.08% 18%
Background missing macOS 1.06% → 1.13% → 0.20% 1% 0.03% 2%
Background missing iOS 0.63% → 6.90% → 0.27% 3% 0.01% 3%
Other macOS 4.75% → 4.17% → 2.92% 19% 0.30% 16%
Other iOS 1.95% → 1.10% → 2.45% 31% 0.04% 10%

1.214 / 7.244 is one day of early adopters (macOS about 9k DAU, iOS 110k), a rough picture.

Plan

This week, cleanup:

Next, metrics:

  • Permanent breakage metrics: a small fixed set, rates against DAU, added to the health indicators dashboard. Task to create.
  • Extension lifecycle metrics: find where the startup message stops, to diagnose the wake failures. Needs privacy review and releases, data in 1-2 release cycles. Task to create.
  • Data check of the Nov/9 fixes: Analyze attribution data after stage 3.

Open:

  • No fix for macOS wake failures and tab not connected. If the new metrics show nothing actionable, close the project and reset the target.

Состояние на 10 ноября: стопка PR очистки

Раскладка. PR 1 #8025, ветка alex/cpm-episode-metrics (ворктри cpm-episode-metrics), конец 6928847174 (merge origin/main ba38c366b5), запушен, метка skip pixel check, ждёт ревью. PR 2 (pixel cleanup по плану), ветка alex/cpm-pixel-cleanup (ворктри cpm-pixel-cleanup) от 6928847174, переделка в работе, сессию просили остановить, что успела изменить, неизвестно, не запушена. Старые ветки с неверно скроенным PR 2 (чистка вместе с новым пикселем, вердиктом по концу страницы и полем background) и метками диагностики init wake: alex/cpm-breakage-pixel (e6419bb910) и alex/cpm-init-diagnostics (adb28e643d), не запушены, использовать как заготовки. Расширение: правки в ~/DuckDuckGo/duckduckgo-privacy-extension, ветка alex/cpm-init-progress (PR #3727), без коммита (метка page_init_sent в shared/js/cpm.js; config_read, settings_checked, site_checked и обработка метки в cookie-prompt-management.js); тесты расширения не запускались.

PR 1 сделано. Удалены флаги и код: graveyard, hang recovery, late document recovery, P2 cpmBackgroundLoadRecovery (с веткой повтора загрузки), флаг webExtensionSharedPinnedTabWindowClose (фикс остался, безусловный). Удалены пиксели background_load_retry, late_document_reload, startup_response_missing, install_readiness, upgrade_readiness, background_wake, перечисления CPMRecoveryFix/CPMRecoveryOutcome, класс CPMBackgroundReadinessRecovery, значение cpm_messaging_hung в reload_trigger. Определения пикселей удалены сознательно. Планировщик восстановления после error 6 (cooldown, пауза в фоне, pending, возобновление) оставлен и проверяет теперь флаг cpmBackgroundLoadRestart. Остаются флаги-выключатели: cpmBackgroundLoadRestart, cpmNetworkProcessRecovery, cpmStableBaseURL, cpmUpgradeBeforeLoad, stateRestorationGate.

PR 2, целевая реализация (по плану Pixel data cleanup, без нового пикселя и без новой логики детекта). Удалить: CPMMessagingDiagnosticsRecorder, CPMMessagingDiagnostics, CPMBackgroundWebViewDelegateProxy, CPMBackgroundReadinessObserver, CPMDiagnosticsFeatureFlags и их тесты; флаги cpmDiagnosticsRecorder и cpmBackgroundDelegateProxy (PrivacyFeature, FeatureFlag обеих платформ); проводку в WebExtensionManager, +iOS, +macOS, +EmbeddedExtensions, +NativeMessaging; параметр appSession: в iOS makeManager и его вызов в MainCoordinator; cpmAppSessionDiagnostics в macOS AppDelegate; пункт «CPM Background WebContent PID» в macOS WebExtensionsDebugMenu; diagnosticsProvider в CPMMessagingHealthMonitor. Урезать пиксель web_extension_cpm_episode (имя остаётся): убрать 8 диагностических булевых, bg_events, четыре поля загрузки фона, was_stuck, interrupted, response_after; оставить reason, outcome, tabs_affected, repeat_failures, reload_state; обновить CPMMessagingEpisodeReport, определения в web_extensions.json5 и записи в params_dictionary.json5 обеих платформ (macOS сохраняет суффикс ["daily_count"] и параметры appVersion, pixelSource, channel). Таймеры, лайфсайкл эпизода, детект и restart-наблюдение не менять. Не добавлять новый пиксель, вердикт по концу страницы, поле background, метки cpmInitProgress. Изменение параметров существующего пикселя потребует метку Danger.

Дальше по плану. Перманентный пиксель рядом со старым эпизодом на один релиз, затем старый убрать: вердикт по концу страницы, поле «пробуждение или тёплый фон» через didCreateBackgroundWebView, мгновенная поломка по cpmStage; учесть 9 находок ревью старого PR 2 (определение macOS не совпадало с отправляемым, молчащие замеры старше 5 минут отбрасывались, нет минимального времени жизни, падение процесса вкладки засчитывалось как поломка, background по загрузке дольше 1 с неверно, утечка navigationWaitContexts, нет теста на разбор cpmStage). Диагностика init wake: приём cpmInitProgress, last_stage, расширение (#3727 плюс метки). Вне PR: записи об удалённых подфичах в privacy-configuration. Не измерено: эффект P3, stateRestorationGate, pinned-tab по версиям; доля потерянных отчётов; время жизни страниц с молчащим расширением.

Решения по данным (ClickHouse, 8–9 ноября, счёт count). P2 убран: пикселя результата нет (115 тысяч повторов в день на iOS), при оставшемся view повтор не завершается (фон это service worker). Restart 9 ноября: iOS 7.245 118 перезапусков, 81% ответов страницы; macOS 1.215 54 перезапуска, 65%, выборка маленькая, контроля нет. Network recovery оставлен: iOS 388 тысяч срабатываний в день, 59% числа эпизодов, эффект не измерен (network_restarted убрали из отчёта в том же релизе), измерять выключением удалённого флага. Таймер 4 с: на iOS 7.244 6,0% эпизодов закрылись поздним ответом на ту же страницу, 42% из них позже 30 с, 19,4% без ответа за 5 минут. Доступа к статусу расширения из приложения нет (в SDK нет доступа к миру расширения, evaluateJavaScript на фоне не достаёт до воркера); порт или heartbeat как проверка здоровья не годятся (открытый порт откладывает выгрузку фона).

Данные из сессии. ~/Developer/grafana-data-tools/ и запуск SQL через Grafana с SSO через системный Chrome (grafana-auth --channel chrome). Счёт пикселей: metrics.pixels_aggregation (pixel_id = 'web'); параметры: metrics._pixels_new только с pixel_id = 'web' и одним днём.

10 ноября, вечер: разрез PR и tech design

Разрез. Ветка alex/cpm-breakage-pixel (e6419bb910) смешивала чистку с новым пикселем и удаляла эпизодный пиксель сразу, против плана. Новая раскладка: PR 1 #8025 без изменений. PR 2 alex/cpm-pixel-cleanup (ae725e6b12, поверх 6928847174) уже содержит чистую чистку по плану: удалены recorder, CPMMessagingDiagnostics, delegate proxy, readiness observer и два флага с проводкой и пунктом debug-меню macOS; эпизодный пиксель урезан до reason, outcome, tabs_affected, repeat_failures, reload_state, без нового пикселя и без изменения таймеров. Проверено: swift test пакета WebExtensions 1104 теста, 0 падений; SwiftLint strict без замечаний на CPMMessagingHealthMonitor, WebExtensionPixelFiring, WebExtensionManager. Не проверено: сборка приложений iOS и macOS, валидатор определений пикселей (CI). Не запушена, PR не создан (нужна ссылка на задачу Asana и ревьюер; метка Danger, потому что параметры существующего пикселя меняются). PR 3 (перманентный пиксель) и PR 4 (метки init и last_stage, плюс расширение) ещё не начаты, ждут ревью tech design. Старые alex/cpm-breakage-pixel и alex/cpm-init-diagnostics остаются только источником.

Что неверно в e6419bb910 (проверено по коду): тихие замеры старше 5 минут сбрасываются (discardExpiredState); нет минимального времени жизни страницы; падение процесса вкладки засчитывается поломкой; background берётся из «загрузка ≥ 1 с» и одного общего сигнала; страницы, живущие до выхода приложения, не оцениваются; определение macOS без pixelSource и channel, суффиксы от iOS; утечка navigationWaitContexts; нет теста на разбор cpmStage.

Tech design (черновики, ревьюер не назначен):

  • cpm-permanent-breakage-metric-tech-design-2026-11-10: два пикселя (web_extension_cpm_breakage с reason и background, web_extension_cpm_breakage_persistent без параметров), оценка страницы по концу документа, минимум 30 с жизни, серия из 3 подряд. Старые пиксели (эпизодный, background_load_restart, network_process_recovery_applied) удаляются в том же PR 3 вторым коммитом, без задержки на релиз; остаются только эти два.
  • cpm-wake-init-detection-tech-design-2026-11-10: метки cpmInitProgress из расширения, last_stage в пикселе, response_sent как здоровый сигнал, изменение расширения (PR #3727, ветка alex/cpm-init-progress; метки page_init_sent, config_read, settings_checked, site_checked в рабочем дереве без коммита и без запуска тестов).

Открытые вопросы для ревью: порог 30 с и серия 3; сохранять серию между запусками; считать ли response_sent здоровым до проверки без слушателя; шесть меток или меньше; нужен ли флаг для нового пикселя.