[2026-10-16] eagle: Users/admin/obsidian/work/projects/cpm-pr0-episode-telemetry-summary-2026-10-16.md work/projects/cpm-pr0-episode-telemetry-summary-2026-10-16.md work/projects/cpm-status-2026-10-15.md

This commit is contained in:
Alexey Martemyanov committed 2026-10-16 17:54:51 +06:00
1 parent 9ffce5a191
commit d6bc977f00
3 files changed
+23 -13

No files matched your search

@@ -1,31 +1,33 @@
---
title: CPM PR0 — один итоговый отчёт о сбое
title: CPM PR0 — one terminal report per failure episode
date: '2026-10-16'
tags:
- work
- cpm
- telemetry
---
# CPM PR0: один итоговый отчёт о сбое
# CPM PR0: one terminal report per failure episode
Описание локальной правки для [PR0 #7376](https://github.com/duckduckgo/apple-browsers/pull/7376). Изменения находятся в `alex/cpm-telemetry-pr0`, без коммита.
Local changes for [PR0 #7376](https://github.com/duckduckgo/apple-browsers/pull/7376), in `alex/cpm-telemetry-pr0`, uncommitted.
**Что и зачем.** Вместо отдельных `init_failed`, `stuck`, `recovery` и CPM reload-failed отправляем один `web_extension_cpm_episode`. Причина и итог сбоя оказываются в одном отчёте: для диагностики больше не нужно соединять последовательность пикселей с повторяющимися признаками.
**What and why.** Replace separate `init_failed`, `stuck`, `recovery` and CPM reload-failed events with `web_extension_cpm_episode`. Each report contains the initial failure and its observed outcome, so diagnosis no longer requires joining a sequence of events.
**Когда отправляем.** Первый таймаут открывает эпизод и сохраняет один снимок состояния. Последующие сбои и попытки reload учитываются локально. Эпизод завершается при допустимом dashboard-ответе или через пять минут без ответа. Таймер работает и без новых навигаций. Используется существующий monitor; правила подтверждения stuck и запуска автоматического reload сохранены.
**When it fires.** The first timeout opens an episode and captures one diagnostic snapshot. Later failures and reloads update local state. A qualifying dashboard response or a five-minute deadline closes the episode and emits one logical report. The deadline works without further navigations. Existing stuck detection and automatic reload behaviour are preserved.
**Что получаем.** Отчёт содержит причину первого таймаута, был ли подтверждён stuck, последнее состояние reload и итог наблюдения. Для ответа различаем исходное измерение, последующее измерение на сбойной вкладке, другую вкладку и ответ без однозначной привязки. Время до ответа передаём тремя диапазонами: менее 30 секунд, 30–60 секунд, от минуты до конца наблюдения.
**What it contains.** Initial failure reason, stuck confirmation, latest reload state and observed outcome. Responses distinguish the original measurement, a later measurement on a failing tab, another tab and ambiguous attribution. Response delay uses three buckets: under 30 seconds, 30–under 60 seconds, and one minute to the deadline.
Снимок первого сбоя содержит только фиксированные признаки: загружен ли контекст, существует ли background view и жив ли его процесс, отвечает ли процесс, зарегистрированы ли вкладка и native-handler, совпадает ли controller, есть ли extension scripts и включён ли graveyard treatment.
The initial snapshot records fixed facts about the extension context, background view/process, tab and native-handler registration, controller match and extension scripts.
**Приватность и подсчёт.** Из отправки убраны `bg_events`, сырые ошибки, счётчики и временные характеристики приложения и memory pressure. Идентификаторы вкладок и документов не передаются. Это убирает цепочку переходов между отдельными событиями, но не гарантирует отсутствие корреляции редких сочетаний параметров.
**Privacy and counting.** Exclude `bg_events`, raw errors, identifiers, diagnostic counts and app/memory-pressure ages. Rare parameter combinations may still be correlatable.
Сохраняем `daily+count`: daily оценивает число установок с завершившимся эпизодом за день, count считает завершённые эпизоды. Первый итог за день отправляется в обеих ветках с одинаковыми данными, последующие — только в count.
Keep `daily+count`: daily estimates installations with a completed episode that day; count measures completed episodes. The first report each day sends both legs with the same payload; subsequent reports send count only.
**Границы результата.** Dashboard-ответ не доказывает доставку `initResp` конкретному документу или восстановление всех вкладок. Отсутствие ответа за пять минут означает только отсутствие наблюдаемого ответа. При завершении процесса незавершённый эпизод может потеряться.
**Fix attribution.** The agreed PR0 contract excludes graveyard attribution; removing that legacy field from the local code is still pending. Add fix-specific application/outcome metrics in the relevant fix PRs when needed. Preventive fixes must also count eligible attempts that succeed without a failure episode. Current diagnostic facts do not distinguish all five failure groups.
Удалены старые определения пикселей и их неиспользуемые параметры на iOS/macOS. Общий `debug_web_extension_reload_failed` остаётся: менеджер расширений продолжает его отправлять.
**Limits.** A dashboard response does not prove document-level `initResp` delivery or recovery of every failing tab. A deadline means no qualifying response was observed. Unfinished episodes can be lost when the process exits.
Проверено: 82 профильных теста, macOS-пиксель через PixelKitMock, определения обеих платформ и SwiftLint.
Retired pixel definitions and unused parameters are removed on both platforms. The manager still sends the separate `debug_web_extension_reload_failed` event.
Контекст: [[cpm-status-2026-10-15]], [[cpm-readiness-telemetry-tech-design-2026-10-15]].
**Validation.** 82 focused tests, macOS PixelKitMock verification, both platform definition validators and strict SwiftLint passed.
Related: [[cpm-status-2026-10-15|CPM status]], [[cpm-readiness-telemetry-tech-design-2026-10-15|Readiness telemetry design]].
+8
View File
@@ -752,3 +752,11 @@ Interpretation unchanged: this rerun demonstrates test repeatability in the inst
P2 реализация уточнена: manager наблюдает публичное `WKWebExtensionContext.errorsDidUpdateNotification`, независимо от navigation gate и пассивного recorder. В прочитанном WebKit source (`WebExtensionContextCocoa.mm:2793–2802`) service-worker failure записывает error 6 и возвращается без выполнения ожидающих `loadBackgroundContent` callbacks. Поэтому callback-ожидание дополнительно завершается по error notification и при `willReload`; recovery guard не удерживается бесконечным ожиданием нового startup. Автоматическая обработка ошибок чужого/старого/не-embedded context исключена. Восстановление пока не объявляется проверенным на app P2.
Пакет после текущих изменений: **806 XCTest, 14 skipped, 0 failures** (`unit-package-callback.log`); strict SwiftLint шести Swift-файлов — **0 violations**. Перегенерированные SPM resolver изменения версий CSS/privacy-dashboard сохраняются только в артефактах и будут исключены из итогового diff; это не часть фикса.
### P2: исходный fault воспроизведён, автоматический reload есть; page receipt ещё проверяется
`p2-original-control.xcresult`: исходный one-tab P2 **PASS 69.049 s**, реальный error 6 ровно через ~30 s после второго background view. Поэтому новый P2 regression возвращён к одному исходному tab/window; проверка нового окна/вкладки перенесена после recovery. Два baseline окна до fault не воспроизводили тот же error 6 — этот вариант остаётся отрицательным результатом.
`fixed-final.xcresult`: P1 снова **PASS 49.908 s**. P2 получил настоящий `WKWebExtensionContextErrorDomain:6` и **автоматический context reload**; но регрессия осталась **красной**: existing-tab probe имел native dashboard=true и 0 detector failures, но page initResp mark=false. Новое окно и новая вкладка получили оба подтверждения. Нельзя объявлять восстановление старого tab по одному native ack. В harness фиксированный sleep 150 ms заменён bounded polling реального page initResp (до 2 s); идёт повтор `fixed-page-ack.xcresult`. Проверка page receipt сохранена строгой, зелёный P2 пока не заявлен.
Оговорка о пользе P2: исходный standalone `testBackgroundStalledPastUnloadTimerFailsToLoad` уже проверяет, что **следующий wake может восстановиться без нового фикса**. Новый кандидат делает recovery заранее, по error notification; его проверка сама по себе не доказывает, что SIGSTOP-модель объясняет persistent iOS stuck или что без reload следующая навигация обязательно сломана.