On-device perf testing is now proven (2026-07-06): via the #393/#395 pause-fetch hook we pre-armed the halt, detected sign-in, held prefetch/backfill so bodies stayed uncached, measured genuine cold opens (Gmail ~2.3s, connect=0ms — reuse active — vs the old 31–40s throttle), then a cold-vs-warm A/B (~190x). The device agent implemented this in a scratchpad driver (scratchpad/coldfetch-results/ — driver + analyzer scripts) that reused the repo harness (adb.py/uidump.py/breadcrumbs.py) through a shim + manual pause-hook orchestration + portability workarounds.
Goal
Refactor scripts/device-testing/ to bake that proven flow in as a first-class, reproducible scenario, so the cold-fetch reuse/throttle A/B can be re-run on demand (e.g. to catch future perf regressions). Upstream the scratchpad driver.
Fold in (the proven steps)
Pause-hook helpers — FETCH_GATE broadcast pause/resume/query (backfill,prefetch) through the guarded adb.py wrapper, with ordered-broadcast read-back parsing.
Cold-fetch A/B scenario — pre-arm halt → detect sign-in (the MailSyncer: sync all: N accounts breadcrumb) → confirm halt (prefetch skipped: fetch-gate paused) → wait for header sync (uncached bodies) → measure cold opens (ImapPerf connect/work + MailReader openMessage) → resume → measure warm (cached) opens → report cold-vs-warm delta, the connect=0ms reuse proof, and any throttle signature.
Restore semantics — always resume (clear the gate) at the end; never leave fetch paused.
Stdlib-only Python; keep the adb.py allow/deny-list safety wrapper; SPDX headers. Add unittest coverage (mock adb/breadcrumbs) for the pause-hook helpers + the A/B scenario; --dry-run must cover it. The pause hook is debug-build-only (#393/#395), so document that the scenario needs a debug build.
## Context
On-device perf testing is now **proven** (2026-07-06): via the #393/#395 pause-fetch hook we pre-armed the halt, detected sign-in, held prefetch/backfill so bodies stayed uncached, measured genuine **cold** opens (Gmail ~2.3s, `connect=0ms` — reuse active — vs the old 31–40s throttle), then a cold-vs-warm A/B (~190x). The device agent implemented this in a **scratchpad driver** (`scratchpad/coldfetch-results/` — driver + analyzer scripts) that reused the repo harness (`adb.py`/`uidump.py`/`breadcrumbs.py`) through a shim + manual pause-hook orchestration + portability workarounds.
## Goal
Refactor `scripts/device-testing/` to bake that proven flow in as a **first-class, reproducible scenario**, so the cold-fetch reuse/throttle A/B can be re-run on demand (e.g. to catch future perf regressions). Upstream the scratchpad driver.
## Fold in (the proven steps)
1. **Pause-hook helpers** — `FETCH_GATE` broadcast pause/resume/query (`backfill,prefetch`) through the guarded `adb.py` wrapper, with ordered-broadcast read-back parsing.
2. **Cold-fetch A/B scenario** — pre-arm halt → detect sign-in (the `MailSyncer: sync all: N accounts` breadcrumb) → confirm halt (`prefetch skipped: fetch-gate paused`) → wait for header sync (uncached bodies) → measure **cold** opens (`ImapPerf` connect/work + `MailReader openMessage`) → `resume` → measure **warm** (cached) opens → report cold-vs-warm delta, the `connect=0ms` reuse proof, and any throttle signature.
3. **Restore semantics** — always `resume` (clear the gate) at the end; never leave fetch paused.
4. **Portability/robustness (subsumes #392):** file-based `uiautomator dump` (not `/dev/tty`), UTF-8 I/O (`PYTHONUTF8` + adb decode), `openMessage`-breadcrumb readiness (not just UI polling), row-selection hardening (skip non-message rows).
## Constraints
Stdlib-only Python; keep the `adb.py` allow/deny-list safety wrapper; SPDX headers. Add `unittest` coverage (mock adb/breadcrumbs) for the pause-hook helpers + the A/B scenario; `--dry-run` must cover it. The pause hook is debug-build-only (#393/#395), so document that the scenario needs a debug build.
Relates: #370 (harness), #393/#395 (pause hook), #392 (subsumed), the perf drilldown.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Context
On-device perf testing is now proven (2026-07-06): via the #393/#395 pause-fetch hook we pre-armed the halt, detected sign-in, held prefetch/backfill so bodies stayed uncached, measured genuine cold opens (Gmail ~2.3s,
connect=0ms— reuse active — vs the old 31–40s throttle), then a cold-vs-warm A/B (~190x). The device agent implemented this in a scratchpad driver (scratchpad/coldfetch-results/— driver + analyzer scripts) that reused the repo harness (adb.py/uidump.py/breadcrumbs.py) through a shim + manual pause-hook orchestration + portability workarounds.Goal
Refactor
scripts/device-testing/to bake that proven flow in as a first-class, reproducible scenario, so the cold-fetch reuse/throttle A/B can be re-run on demand (e.g. to catch future perf regressions). Upstream the scratchpad driver.Fold in (the proven steps)
FETCH_GATEbroadcast pause/resume/query (backfill,prefetch) through the guardedadb.pywrapper, with ordered-broadcast read-back parsing.MailSyncer: sync all: N accountsbreadcrumb) → confirm halt (prefetch skipped: fetch-gate paused) → wait for header sync (uncached bodies) → measure cold opens (ImapPerfconnect/work +MailReader openMessage) →resume→ measure warm (cached) opens → report cold-vs-warm delta, theconnect=0msreuse proof, and any throttle signature.resume(clear the gate) at the end; never leave fetch paused.uiautomator dump(not/dev/tty), UTF-8 I/O (PYTHONUTF8+ adb decode),openMessage-breadcrumb readiness (not just UI polling), row-selection hardening (skip non-message rows).Constraints
Stdlib-only Python; keep the
adb.pyallow/deny-list safety wrapper; SPDX headers. Addunittestcoverage (mock adb/breadcrumbs) for the pause-hook helpers + the A/B scenario;--dry-runmust cover it. The pause hook is debug-build-only (#393/#395), so document that the scenario needs a debug build.Relates: #370 (harness), #393/#395 (pause hook), #392 (subsumed), the perf drilldown.