Files
obsidian-vault/work/projects/cpm-telemetry-data-requirements-2026-10-15.md
T

109 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: CPM — что нужно в данных (требования к телеметрии из гипотез)
date: '2026-10-15'
tags:
- work
- cpm
- telemetry
---
# CPM: что нужно в данных
Внутренняя заметка. **Цифры из ClickHouse, в публичные PR/комментарии не переносить.** Контекст: [[cpm-readiness-telemetry-tech-design-2026-10-15]], [[cpm-web-extension-data-analysis-summary-2026-10-08]], [[cpm-web-extension-code-guide-2026-10-09]]. PR: telemetry #7376 → #7384 → #7385; harness #7378 → fix A #7379 → fix B #7381.
## Метод
- Окно: 2026-10-12…14 UTC (3 полных дня), версии с диагностикой: iOS 7.240+, macOS 1.210+. Единица: `daily`-пиксель = устройство-день на причину, не пользователь и не эпизод.
- Инструмент: `~/Developer/grafana-data-tools` (`query.py`, Grafana → ClickHouse `metrics.pixels`, read-only). Запросы ниже запускались через тот же helper (`read-dashboard.py`) отдельным раннером; SQL приведён в конце.
- Классификация когорт по приоритету: error 6 → нет background view → tab not connected → Network заменён → пробуждение (view <30 с после `dealloc`) → недавняя загрузка контекста (`load`/`base_url_changed` ≤2 мин) → other.
## Объёмы (12–14 октября)
| | iOS | macOS |
|---|---|---|
| `initialization_failed.daily` | 3 273 025 | 119 950 |
| `stuck.daily` | 511 660 | 40 842 |
| восстановились без reload (daily, `from=initialization_failed`) | 1 135 477 (34.7% от init) | 30 738 (25.6%) |
| stuck → восстановились после M4 reload (daily) | 293 557 (57.4% от stuck) | 21 865 (53.5%) |
| `reload_failed.daily` | 140 921 (27.5% от stuck) | 17 796 (43.6%) |
`initialization_failed` — только `.daily`; `stuck`, `recovered_*`, `reload_failed` — `daily`+`count`. Параметры снимка есть только на init_failed и stuck; на recovered только `recovery_from`/`recovery_document`/`recovery_after`.
## Когорты: доля init → stuck
| Когорта | iOS init → stuck | macOS init → stuck |
|---|---|---|
| error 6 | 6.1% → 21.5% | 1.0% → 1.9% |
| нет background view | 48.1% → 10.9% | 3.3% → 1.8% |
| tab not connected | 0.03% → 0.05% | 6.2% → 8.9% |
| Network заменён | 16.8% → 39.7% | 13.6% → 26.6% |
| пробуждение (view <30 с) | 7.9% → 9.5% | 32.5% → 32.2% |
| недавняя загрузка контекста | 15.7% → 6.0% | 20.0% → 6.4% |
| other | 5.3% → 12.5% | 23.4% → 22.2% |
Рост доли при переходе init → stuck значит, что когорта чаще остаётся сломанной (error 6, Network заменён, tab not connected); падение значит самоизлечение (нет view, недавняя загрузка).
## Основание для фиксов
- **B (Network-процесс)**: когорта «Network заменён» растёт в 2–2.4× при переходе в stuck; `reload_failed` высок (reload расширения не лечит мёртвый worker). Основание сильное. Ограничение: `network_restarted` это прокси «PID изменился»; причинность подтверждает только `init_stage=none` (#7385).
- **A (первая загрузка посреди сессии)**: сигнатура «загрузка ≤2 мин, не при запуске (launch age ≥15 мин), первый view»: iOS 129k init (3.9%) → 4.6k stuck (0.9%); macOS 505 → 118. Реально, но разово (0.23×) и на macOS мелко. Сигнатура неточна: захватывает и M4-reload; нужен `context_load_cause`.
## Паттерны событий без фиксов (stuck.daily, 14 октября, хвост `bg_events` без возрастов)
| Картина | Хвост | iOS / macOS (строк) | Чем различать |
|---|---|---|---|
| **P1. Цикл пробуждения**: idle-выгрузка, затем view | `view>proxy_on>dealloc>view>proxy_on` | 16.0k / 4.3k (wake) + 16.3k / 2.4k (то же, но view старше 30 с, класс other) | медленный старт или потеря: `bg_ready_after`, `bg_view_age`, `init_stage`, `recovery_after`; базлайн здоровых пробуждений (#7384) |
| **P2. Цикл «пробуждение → error 6»** | `proxy_on>dealloc>view>proxy_on>error_E:6` (23.6k), повторяется `error>dealloc>view>proxy_on>error` (5.7k), после `died_crash` (1.5k) | iOS; macOS 118 | `bg_load_error_after` (бакет 25–35 с = таймер 30 с), `bg_load_error_app_state`, `bg_view_creations` |
| **P3. Контекст загружен, view не создан** | `load` или `load>base_url_changed` | 17.1k + 0.9k / 162 + 81 | `bg_ready_after=none`, `context_load_age`, мелкие корзины `app_launch_age`, `app_state`, время загрузка→view из #7384 |
| **P4. Первая загрузка: `load>view>proxy_on`** | | 6.8k + 2.3k / 570 | `context_load_cause`, `bg_view_creations=1`; эффект A измерять `first_load_wait` |
| **P5. Фон выгружен в момент сбоя** (хвост на `dealloc`) | `proxy_on>dealloc>view>proxy_on>dealloc` | 1.9k / 494 | `bg_view_alive=false` (уже есть), `bg_ready_after`, `bg_view_age` |
| **P6. macOS: вкладка без расширения** | `load>view>proxy_on>dealloc`, часто с `extension_updated` | iOS ≈0 / 627 + 235 | есть `tab_controller_match`, `tab_has_ext_scripts`, `app_version_change`, `reason` |
В iOS-когорте «нет view» крупнейшие группы лежат в первых 30 с после запуска: восстановление сессии (около половины) и `reason=other`. Первая корзина `app_launch_age` «<30 с» слишком грубая.
## Что нужно в данных (минимум)
| Поле / пиксель | Вопрос | Где |
|---|---|---|
| `bg_ready_after` | всё ещё загружается, загрузился или упал | PR0 |
| `bg_view_age` | пробуждение или давно | PR0 |
| `bg_load_error_after`, `bg_load_error_app_state` (только при error 6) | таймер 30 с, состояние приложения | PR0 |
| `recovery_document`, `recovery_after` | опоздавший ответ или потерянный | PR0 |
| `app_state`, `open_tabs` (грубо), только на `initialization_failed` | когорта «нет view» на запуске | PR0 |
| **новое:** `context_load_cause` (запуск / установка / апгрейд / reload при восстановлении) и `context_load_age` | точная сигнатура A, замена `load@` и `extension_updated` | PR0 |
| **новое:** `bg_died_reason`, `base_url_changed` | смерть процесса, очистка при смене baseURL | PR0 |
| **новое:** мелкие корзины `app_launch_age` для первых 30 с | гонка на запуске | PR0 |
| **новое на stuck:** `stuck_after` | сколько от первого сбоя до stuck | PR0 |
| `init_stage` | дошёл ли init до background | #7385 (срочно) |
| `cpm_background_ready_{context_load,wake}` | базлайн здоровых загрузок и пробуждений | #7384 |
| `background_restart` (причина, исход), `first_load_wait` | эффект фиксов B и A | удержанная ветка |
| убрать | `loading_tabs`; в таймлайне `view`, `dealloc`, `proxy_on`, `error_*`, `hold/release/proxy_off` | |
### `bg_events`
- Сейчас единственный источник давности загрузки и причины смерти процесса. Остальные токены дублируют `bg_view_creations`, `context_errors` или нули (`hold/release/proxy_off` = 0%).
- Скаляры вместо таймлайна воспроизводят когорты загрузки и пробуждения на 100% строк (измерено 14 октября).
- Однодневная уникальность строк `stuck.daily` по всем параметрам: с `bg_events` 8.3% (iOS) и 30% (macOS); сокращённые информативные токены 2.1% / 5.2%; скаляры 0.96% / 4.4%; без событий 0.25% / 2.0%.
- Верхняя граница прироста от новых полей (синтетическое независимое равновероятное поле): с текущим `bg_events` при десяти значениях iOS 21%, macOS 65%; со скалярами 3.6% / 15.8%. Про «не станет хуже» можно говорить только со скалярами. В публичный PR цифры не писать.
## Критерии успеха и опровержения
- **B** подтверждается, если после релиза падают доля «Network заменён» среди stuck и `reload_failed`, `background_restart` показывает восстановление, а у таких stuck `init_stage=none`.
- **A** подтверждается, если сокращается когорта «мид-сессионная первая загрузка» (`context_load_cause`). Если нет, основание слабое: она около 1% stuck на iOS и почти 0 на macOS.
- Остаток P1/P3 подтверждает гипотезу «медленный старт, а не потеря», если `bg_ready_after` у упавших заметно хуже базлайна здоровых загрузок и `recovery_document=failed_navigation`.
## SQL (классификация; даты подставлять)
```sql
-- stuck.daily / init_failed.daily; приоритет когорт
multiIf(
errs LIKE '%ContextErrorDomain:6%', '1_error6',
creations = '0', '2_no_background_view',
scripts = 'false', '3_tab_not_connected',
net = 'true', '4_network_replaced',
has(ev,'view@30s') AND arrayExists(x -> startsWith(x,'dealloc@'), ev), '5_wake_view_lt30s',
arrayExists(x -> x IN ('load@30s','load@1m','load@2m','base_url_changed@30s','base_url_changed@1m','base_url_changed@2m'), ev), '6_context_load_recent',
'7_other')
-- параметры: network_restarted, context_errors, bg_view_creations, tab_has_ext_scripts, bg_events (decodeURLComponent)
```