[2026-10-28] eagle: work/projects/cpm-post-release-analysis-2026-10-27.md
This commit is contained in:
1 parent
5bb4d7cb7e
commit
69254dd1ef
1 file changed
+39
@@ -288,3 +288,42 @@ One CSV: `cpm-failure-groups-2026-10-26_27.csv` (iOS 7.243.0 / macOS 1.213.0, bo
|
||||
DAU proxies: macOS `m.mac.daily.active.user.d`; iOS `m.app.return.ios.{phone,tablet}.daily`. Users = `.daily` leg (install-days when combined); episodes = `.count` leg. Group priority: error 6 → no background view → tab not connected (no scripts or controller mismatch) → extension updated ≤2 min → idle wake (view <30 s after a dealloc) → recent context load ≤2 min → other. End state: recovered = any response; unconfirmed = no response, no repeat, no reload; permanent = no response with a repeat or reload.
|
||||
|
||||
Two-day headline (% of DAU-days): iOS failing 9.1%, permanent 0.43%; macOS failing 28.5%, permanent 2.87%. Largest permanent source: iOS recent context load (40% of permanent), macOS idle wake (38%), then macOS P6 (22%, 39% of P6 users permanent).
|
||||
|
||||
## Repro attempts and footprint comparison — 28 October 2026
|
||||
|
||||
Internal metrics; keep these figures out of public PRs. Data: ClickHouse via `~/Developer/grafana-data-tools` reader, iOS 7.243.0, 26–27 Oct, `web.extension.cpm.episode*.count`, episodes with `bg_load_error_after` present.
|
||||
|
||||
### What production shows
|
||||
|
||||
- 3,114 error 6 episodes, 229 permanent (`outcome=no_response_before_deadline`, 7.4%).
|
||||
- Permanent, by error timing and whether the background view is alive at report time:
|
||||
|
||||
| Group | Episodes | Share of permanent |
|
||||
|---|---|---|
|
||||
| error `under_5s`, view alive | 172 | 75% |
|
||||
| error `25s_to_35s`, view not alive (repeated `view,proxy_on,dealloc,error_6` cycles, about one per minute) | 51 | 22% |
|
||||
| error `under_5s`, view not alive | 5 | 2% |
|
||||
| error `over_35s`, view not alive | 1 | 0.4% |
|
||||
|
||||
- The 172 look like the recovered ones. Same group, permanent vs recovered (2,797): `interruption` in the footprint 98% vs 96%, `died_client` 22% vs 22%, `extension_updated` 10% vs 6%, none of the three 3 vs 92. Permanent rate inside the group about 5.8%. These tokens do not explain why they stay broken.
|
||||
- No `unresponsive` token in any permanent group.
|
||||
- `bg_view_alive` cannot tell "WebKit kept the failed view" from "WebKit created a new view after the error". No field separates the two.
|
||||
|
||||
### What I reproduced (iOS Simulator, iPhone 17, iOS 26.5, real CPM, real page)
|
||||
|
||||
1. **Suspension during a background load** (SIGSTOP of the app and WebKit helpers for 45 s, with a real HOME; also with the start slowed to 8 s): the overdue 30 s unload timer fires at resume, error 6, view released, WebKit creates a new view, the page is answered. Footprint `dealloc,view,proxy_on,interruption,error_6` matches the dominant production footprint, but it self-heals. Persistence of this family in production is NOT reproduced.
|
||||
2. **Exception thrown at service worker start** (injected, keyed on the extension origin): error 6 within 0.4 s, no underlying error, the failed view stays alive (WebKit `_loadServiceWorker` with success NO records the error and returns without unloading), the retry never completes, the page is unanswered, the second wake fails the same way, M4 heals after about 54 s. The footprint is not the dominant production one. PR #7730 (restart the context when the failed view is retained) fixes it in the simulator (restart 8 ms after the error, page answered after 0.6 s). The PR was closed before this was proven; branch `alex/cpm-error6-restart` kept. How often this state happens in production is unknown.
|
||||
3. **Hung start** (busy wait of 90 s in the worker): the 30 s timer unloads the view, error 6 about 35 s after creation, view released, the retry hangs again, M4 heals after about 54 s. Footprint matches the 25–35 s loop group. M4 healed only because it re-extracts the clean extension; real persistence across M4 is NOT reproduced. The pixel the app logged for this run does not equal production (`bg_events=load@2m`, `bg_ready_after=pending`, `bg_view_age=8s_to_30s`), because the snapshot is taken at the first failed navigation, before the first loop ends.
|
||||
4. **Extension update during a background load** (2026.10.23 over 2026.10.99): error 6 on the superseded context only, the new context answers.
|
||||
5. Separate finding: after any app relaunch the embedded worker stays silent in the simulator (stale registration: `importRegistrations failed to retrieve main script`, then `Found directly reusable registration`), no error 6. Whether a device does this is unknown.
|
||||
|
||||
### Reason for a failed start can be read
|
||||
|
||||
The background page loads with `navigator.serviceWorker.register(...)`; its rejection carries the WebKit error text (`Error: <message>`), obtainable with a `WKUserScript` and `WKScriptMessageHandler` on the background web view delivered by `didCreateBackgroundWebView` (before the page loads). Message only, no file or line. The extension's own `extensionException` messages are not handled by the app (unknown method). Verified once with an injected exception.
|
||||
|
||||
### Open
|
||||
|
||||
- Why 172 permanent episodes of the `interruption` family do not recover, when 2,797 identical-looking ones do.
|
||||
- What makes a start hang longer than 30 s (candidates from earlier notes: origin-change data migration, host main thread stall, process throttling), and why that survives M4.
|
||||
- How often the failed view is retained.
|
||||
- Pixel for the restart (none exists yet).
|
||||
Reference in new issue
Block a user