Files
obsidian-vault/work/projects/cpm-ios-uncovered-groups-2026-10-30.md
T

138 lines
20 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.
---
tags:
- cpm
- ios
- telemetry
updated: '2026-10-30'
status: analysis
---
# CPM iOS: оставшиеся группы и следующий фокус — 30 октября 2026
Продолжение: [[cpm-ios-idle-wake-investigation-2026-10-30]] — browser actions, shipped app/extension/WebKit paths, проверка storage/state queue, публичные аналоги и конкретный telemetry proposal. Уточнение интерпретации M4: `reload_state=loaded` без квалифицирующего нового замера не доказывает провал messaging recovery; отдельно выделены `response_timed_out` и предложен post-recovery opportunity counter.
Обновлён ClickHouse-срез и проверены актуальные PR. **Следующий основной фокус — потеря ответа после idle wake при уже готовом фоне; второй — старт с `pending` без текущей error 6. Отдельно остаётся непроверенный хвост error-6 history → replacement view → pending: его нельзя объявлять закрытым #7730.** Это выбор следующего расследования и исправления по наблюдаемым симптомам, а не доказанная причинная классификация.
macOS в этом пересчёте не анализировалась.
## Данные и проверка
Источник: Grafana ClickHouse datasource `dekdbd6bqq1hcd`, `metrics.pixels`, agent `ddg_ios`, pixel_id `web`, `web.extension.cpm.episode.{count,daily}.ios.{phone,tablet}`.
Запрос episodes выполнен **30 октября 11:01:52 UTC / 17:01:52 Бишкек**. Проверка свежести: последние события — **10:50:01 UTC / 16:50:01 Бишкек**. Серверная timezone независимо проверена: `America/New_York`. Все даты ниже — `metrics.date`, то есть Eastern; 30 октября — незавершённый день, а не полный UTC-день.
Выгружена последняя неделя, 23–30 октября. Основной анализ — **7.243.0, 26–29 октября**, отдельно последний завершённый день 29 октября и частичный 30 октября. 23–25 октября содержат только семь count-событий до публичного релиза и исключены из production-приоритетов. У 7.244.0 найдены лишь два count-события 29 октября; это не выборка эффекта сегодняшних фиксов. Различить public/internal traffic внутри версии по этим полям нельзя.
Обработаны **404 222 агрегированные строки**. За 26–29 октября: **477 214 count-эпизодов**, **305 853 первых дневных отчёта**, **15 576 подтверждённых cross-tab no-response эпизодов**, **5 902 таких первых дневных отчёта**.
Независимый SQL повторяет классификацию на сервере; второй контроль проверяет исходы без неё. Завершённые дни сошлись точно, проверены 336 значений групп по окнам и метрикам. На 30 октября последовательные запросы расходятся из-за продолжающейся загрузки событий, даже при ограничении event timestamp. Числа частичного дня привязаны к сохранённому export, а не представлены как неизменяемый snapshot базы.
Определения:
- `no_response`: `outcome=no_response_before_deadline`, окно около пяти активных минут. Это не доказательство вечной поломки.
- Подтверждение: `repeat_failures=1/2+` или `reload_state≠none`.
- Cross-tab: `tabs_affected=2/3+`, плюс no-response и подтверждение выше.
- `count` — эпизоды. `daily` — первый завершившийся эпизод установки за день; это нижняя оценка тяжёлых случаев, а не «хотя бы один тяжёлый сбой за день». Сумма по дням — install-days, не уникальные пользователи недели.
- Ответ закрывает эпизод, но не доказывает доставку initResp каждой ранее падавшей вкладке.
Приоритет непересекающихся групп сохранён из предыдущего разбора: error 6 в текущем поле или истории → no view → нет scripts/controller mismatch → update <2 мин → idle wake → context load/baseURL change <2 мин → other. `@30s` означает возраст **меньше 30 секунд**, `@2m` — меньше двух минут. Возраст view дополнительно проверяется по `bg_view_age`.
## Последний полный день: 29 октября
Всего **364 695 эпизодов**, из них **9 849 подтверждённых cross-tab no-response**; на daily-leg — **4 090** соответствующих первых дневных отчётов.
Доли ниже — от этих 4 090 daily-отчётов; число эпизодов указано отдельно:
- **Idle wake: 1 331 / 32,5%; 2 920 эпизодов.**
- **Recent context load: 841 / 20,6%; 1 710 эпизодов.**
- **Error 6, включая историю: 712 / 17,4%; 2 818 эпизодов.**
- Extension updated: 559 / 13,7%; 571 эпизод.
- No background view: 342 / 8,4%; 760 эпизодов.
- Other: 305 / 7,5%; 1 070 эпизодов.
- Tab disconnected/P6: 0 daily, 0 cross-tab эпизодов; 15 подтверждённых no-response эпизодов без cross-tab условия.
Первые две группы дают **53,1%** таких daily-отчётов. Wake + other — **40,0%**, но это не доказанный объём одного механизма.
На частичном 30 октября в сохранённом export: 106 436 эпизодов, 3 317 подтверждённых cross-tab no-response; 1 322 соответствующих daily-отчёта. Wake — 372 / 28,1%, recent load — 306 / 23,1%, error 6 — 224 / 16,9%. Это поддерживает порядок приоритетов, но внутридневные частоты с полным днём не сравниваются.
## 1. Idle wake: крупнейшая группа без отдельного целевого исправления
Все следующие footprints относятся к **2 920 cross-tab подтверждённым no-response count-эпизодам 29 октября**.
Форма: `dealloc → view → proxy_on`, часто несколько циклов. У **2 688 / 92,1%** `bg_ready_after=under_1s`; у **2 774 / 95,0%** все восемь native-флагов true. Это делает «просто долго грузился background» слабым объяснением основной части этой группы. Native readiness не проверяет listener и доставку конкретного init/ответа.
**660 / 22,6%** имеют только повторяющиеся `dealloc>view>proxy_on` в доступной истории, без load, origin change, update, interruption, died или error. Это видимый минимум немаркированного ядра; в **2 038 / 69,8%** всей wake-группы история достигает 12 токенов, поэтому отсутствие старого события ничего не доказывает.
В истории `died_client` есть у 420 / 14,4%, `died_crash` — у 72 / 2,5%; ни один из них не объясняет большинство. `interruption` в истории встречается у 1 660, но `interrupted=true` самого первого замера — лишь у 50: это разные признаки. У 776 после M4 зафиксирован `reload_state=response_timed_out`; смена контекста сама по себе не гарантировала ответ.
**Что исследовать для следующего фикса:** путь первого init после idle/resume при background-ready <1 s: дошёл ли init в worker, завершились ли native вызовы, был ли dashboard response и почему он не атрибутировался. Затем — bounded retry/re-init или другая recovery только для воспроизведённого разрыва. Простые длинные idle-тесты ранее были чистыми; повторять только их недостаточно. Нужен сценарий iOS resume/navigation и совпадение footprint.
1 275 из этих эпизодов на OS <26.6; stable-origin policy там не применяется. Но и на 26.6+ wake не становится автоматически покрытым P3.
## 2. Старт остаётся отдельным крупным кандидатом; recent load нельзя целиком вычесть как P3
Из 1 710 cross-tab эпизодов recent load **1 241 без `base_url_changed` в истории**, и **1 065 из них с текущим background `pending`**. На daily-leg соответствующий pending-поднабор — **585** первых дневных тяжёлых отчётов. Типичная короткая история: `load@30s,view@30s,proxy_on@30s`. У всей recent-load группы только 463 эпизода уже имели readiness <1 s.
P3 устраняет подтверждённые задержки очистки данных при смене origin; эти симптомы могут частично улучшиться. Однако **recent load не является причинной меткой P3**, а отсутствие `base_url_changed` не исключает origin cleanup при первом контексте процесса: token сравнивает контексты только внутри текущего процесса.
Следующая проверка после rollout P3 — pending startup отдельно от ready/no-response, с OS <26.6 / 26.6+ и фактическим состоянием флага. P4 late-document recovery в известной конфигурации default OFF; `startup_response_missing` — detection, не применённое лечение. На 26–29 октября найдено 226 933 count detection-события, но без ключа связи с эпизодом это не размер исправляемой тяжёлой группы.
## 3. Весь error-6 cohort не закрывается PR #7730
29 октября из 2 818 cross-tab эпизодов этой группы:
- **508** имеют текущую атрибутированную error 6 в `bg_load_error_after`.
- **2 310** имеют error 6 только в истории.
- **2 276 из этих 2 310** уже относятся к новому текущему view с readiness `pending`; daily-leg этого поднабора — **311**.
- **1 929** имеют не меньше двух error-токенов в хвосте истории.
Частый pattern: `dealloc → error_6 → view → proxy_on`, повторённый несколько раз. В коде создание нового view очищает текущую атрибуцию load error, но сохраняет lifecycle history. Поэтому broad error-6 group существенно шире «нынешний view упал с error 6».
[#7730](https://github.com/duckduckgo/apple-browsers/pull/7730), OPEN, head `cf668e2938`: restart того же failed view, если он ещё удерживается; released view сохраняет P2 retry, replacement view намеренно не трогается. PR также исправляет deferred/cooldown scheduling и дедупликацию старых ошибок.
**Остаток не доказанно закрыт, но и точный uncovered share из этих чисел не выводится:** нет identity failed/replacement view на момент принятия recovery-решения, событий после первого snapshot и связанного outcome treatment. Повторный error token в старом recorder не обязательно означает новую независимую ошибку.
Нужен отдельный OFF/ON сценарий с released failed view → новый view → pending на точном #7730. Если он остаётся красным, следующий фикс относится к stalled replacement load, а не к ещё одному restart уже покрытого retained view.
## 4. Other и no-view
Other: 1 070 cross-tab эпизодов; у 863 readiness <1 s. Часто это те же idle-циклы, но текущему view уже 30 s–2 min, поэтому жёсткая граница wake классификатора переносит их в other. Это возможное продолжение того же пути потери init; считать одинаковую причину установленной нельзя.
No-view — **158 115 / 43,4% всех эпизодов 29 октября**, но **только 760 / 7,7%** тяжёлых cross-tab эпизодов. Для 151 232 / 95,6% no-view эпизодов зарегистрирован какой-либо последующий ответ. Группа смешивает свежий `load` без view и уже работавший фон после dealloc. Большой объём transient failures не делает её первой целью исправлений browser-wide no-response.
## Что уже учтено как покрытие
- [#7753](https://github.com/duckduckgo/apple-browsers/pull/7753) MERGED в `release/ios/7.244.0`; фильтр error documents и итоговые OS/flag ограничения stable origin. Это merge в будущий релиз, не измеренное исправление текущего 7.243.0. P3 [#7493](https://github.com/duckduckgo/apple-browsers/pull/7493) уже merged; runtime effect зависит от версии, OS и включения stable-origin флага.
- [#7767](https://github.com/duckduckgo/apple-browsers/pull/7767) OPEN, head `45593bbb4e`: CPM upgrade-before-load на запуске; private origin переносится только при допустимой policy и отсутствии живого старого контекста. Хорошее целевое покрытие launch-upgrade пути, но не всех событий `extension_updated`, всех runtime upgrades или всех startup hangs.
- #7730 — retained failed view и scheduling, с ограничениями выше.
- [#7784](https://github.com/duckduckgo/apple-browsers/pull/7784) — instrumentation времени navigation readiness; поведение CPM recovery не исправляет.
- [#7385](https://github.com/duckduckgo/apple-browsers/pull/7385) — полезная идея init progress, но PR всё ещё stacked на закрытом #7384 и описывает прежний контракт. Это не готовое покрытие текущих episodes; перенос требует адаптации к действующей схеме и extension bundle.
- P6 на iOS сейчас практически не влияет на cross-tab результат. Graveyard не обоснован этим wake-срезом.
Production effect ни одного нового PR этим анализом не измерен. Широкие symptom cohorts нельзя вычесть из знаменателя как будто все входящие эпизоды уже исправлены.
## iOS error pages: уточнение к прежним заметкам
В [[cpm-post-release-analysis-2026-10-27]] осталось утверждение, что iOS runtime не проверялся. Есть более свежая отдельная проверка 29 октября: реальный diagnostic app на iOS 26.5/27.0, DNS и connection-refused отменяли замер; SSL и phishing предупреждения получали CPM dashboard response; после idle также не было episodes/M4. Подробности: [iOS runtime report](/Users/admin/DuckDuckGo/apple-browsers.git/cpm-ios-error-page-verification-2026-10-29/REPORT.md).
Это поддерживает отдельный iOS-анализ. Проверка была simulator/dev-build, не полный набор физических устройств и не доказательство отсутствия любых false positives.
## Рабочая последовательность
1. Завершить уже подготовленные #7730 и #7767 по их существующему scope.
2. **Новая основная ветка исправлений: iOS idle/resume → init delivery/response attribution при уже ready фоне.** Одновременно отделять совпадающий other.
3. **Второй трек: pending startup без текущей error 6**; измерить остаток после включённого P3 и воспроизвести потерянный первый документ, прежде чем менять late recovery.
4. **Параллельная проверка границы #7730:** historical error 6 → replacement pending. Расширять recovery только после совпадающего воспроизведения.
5. Для разграничения причин нужны init-stage evidence и события после первого failure. Нынешний `bg_events` — только snapshot начала эпизода, один phase, максимум 12 событий / 255 символов; он не показывает развитие сбоя и результат конкретного retry.
## Воспроизводимость
Локальный каталог: `/Users/admin/DuckDuckGo/apple-browsers.git/cpm-ios-groups-2026-10-30/`.
- `episodes.sql/.tsv/.json` — агрегированная выгрузка, без install/session IDs и URL страниц.
- `inventory`, `freshness`, `controls`, `group_verification` — SQL, raw responses и TSV контрольных запросов.
- `denominators_26…30` — запросы отдельно по дням; единый пятидневный запрос превысил лимит 7B rows, после чего разбит на дни.
- `treatments` — события readiness/recovery/detection; связанного episode outcome в них нет.
- `summary.json`, `groups.csv` — разбивки по count/daily, окнам, состоянию, OS и footprints.
- `analyze.py`, `verify.py`, `query.py` — разбор, независимая сверка и read-only runner.
- `pr-*.json` — проверенный GitHub snapshot состава и scope PR.
- `verification-result.json` — точное совпадение завершённых дней и отдельно drift текущего дня.
Код приложения, remote config и PR не менялись; внешним участникам данные не отправлялись.