109 lines
11 KiB
Markdown
109 lines
11 KiB
Markdown
---
|
||
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)
|
||
```
|