Adds .claude/skills/preflight/local_instrumented.sh (+ a short sibling README): a helper for running LibreMail's instrumented / E2E tests locally without Gradle Managed Devices.
On this machine (Windows + AEHD 2.2), local GMD tasks (apiXXDebugAndroidTest) fail in GMD's AVD snapshot step (AvdSnapshotHandler$EmulatorSnapshotCannotCreatedException: Snapshot creation timed out) — the emulator itself boots fine; only GMD's snapshot machinery is broken. CI is unaffected (it uses connectedDebugAndroidTest, not GMD).
The helper cold-boots one emulator by hand (-no-snapshot, no GMD), waits for sys.boot_completed, then runs :app:connectedDebugAndroidTest filtered to the class(es) you pass — the same technique CI and api37_e2e.py already use:
Key properties (all documented in the script header + README):
Targeted by design — takes an explicit <fully.qualified.TestClass>[,...] list. The full ~114-test suite tends to wedge mid-run on this box; small sets don't.
Emulator hygiene is mandatory — force-kills stray qemu/emulator processes before booting, tears the emulator down afterward (via an EXIT/INT/TERM trap so it runs on Ctrl-C/error too), and exits non-zero (code 3) if an orphaned qemu-system-x86_64-headless.exe survives. Accumulated orphans have frozen this machine, so this is not optional.
Pins JAVA_HOME to a JDK 17–21 (AGP 9.2 fails on 25+); everything is env-overridable (LOCAL_INSTRUMENTED_*).
Scope note
This PR delivers the reusable helper that encodes the known-reliable local recipe. It does not by itself rewire preflight's api35/api36 steps off GMD (part of #269's broader DoD) — that follow-up can build on this helper.
Validation
Script/doc change — validated by careful review + bash -n (clean) + an arg-guard smoke test (exits 2 with usage). No live emulator run was performed: although adb devices was empty (a run was permitted), the box showed fresh signs of wedged GMD state (active_gradle_devices: MDLockCount 2, stale .lock files) on a shared, freeze-prone machine, so I took the review-only path. The emulator/gradle commands are a faithful composition of the battle-tested manual recipe and the already-proven api37_e2e.py pattern.
## What
Adds `.claude/skills/preflight/local_instrumented.sh` (+ a short sibling README): a helper for running LibreMail's instrumented / E2E tests **locally without Gradle Managed Devices**.
On this machine (Windows + AEHD 2.2), local GMD tasks (`apiXXDebugAndroidTest`) fail in GMD's AVD **snapshot** step (`AvdSnapshotHandler$EmulatorSnapshotCannotCreatedException: Snapshot creation timed out`) — the emulator itself boots fine; only GMD's snapshot machinery is broken. CI is unaffected (it uses `connectedDebugAndroidTest`, not GMD).
The helper cold-boots **one** emulator by hand (`-no-snapshot`, no GMD), waits for `sys.boot_completed`, then runs `:app:connectedDebugAndroidTest` filtered to the class(es) you pass — the same technique CI and `api37_e2e.py` already use:
```bash
.claude/skills/preflight/local_instrumented.sh org.libremail.ui.compose.ComposeScreenE2ETest
```
Key properties (all documented in the script header + README):
- **Targeted by design** — takes an explicit `<fully.qualified.TestClass>[,...]` list. The full ~114-test suite tends to wedge mid-run on this box; small sets don't.
- **Emulator hygiene is mandatory** — force-kills stray `qemu`/`emulator` processes *before* booting, tears the emulator down afterward (via an `EXIT`/`INT`/`TERM` trap so it runs on Ctrl-C/error too), and **exits non-zero (code 3) if an orphaned `qemu-system-x86_64-headless.exe` survives**. Accumulated orphans have frozen this machine, so this is not optional.
- Pins `JAVA_HOME` to a JDK 17–21 (AGP 9.2 fails on 25+); everything is env-overridable (`LOCAL_INSTRUMENTED_*`).
## Scope note
This PR delivers the reusable **helper** that encodes the known-reliable local recipe. It does not by itself rewire preflight's `api35`/`api36` steps off GMD (part of #269's broader DoD) — that follow-up can build on this helper.
## Validation
Script/doc change — validated by careful review + `bash -n` (clean) + an arg-guard smoke test (exits 2 with usage). No live emulator run was performed: although `adb devices` was empty (a run was permitted), the box showed fresh signs of wedged GMD state (`active_gradle_devices: MDLockCount 2`, stale `.lock` files) on a shared, freeze-prone machine, so I took the review-only path. The emulator/gradle commands are a faithful composition of the battle-tested manual recipe and the already-proven `api37_e2e.py` pattern.
Closes #269
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.
What
Adds
.claude/skills/preflight/local_instrumented.sh(+ a short sibling README): a helper for running LibreMail's instrumented / E2E tests locally without Gradle Managed Devices.On this machine (Windows + AEHD 2.2), local GMD tasks (
apiXXDebugAndroidTest) fail in GMD's AVD snapshot step (AvdSnapshotHandler$EmulatorSnapshotCannotCreatedException: Snapshot creation timed out) — the emulator itself boots fine; only GMD's snapshot machinery is broken. CI is unaffected (it usesconnectedDebugAndroidTest, not GMD).The helper cold-boots one emulator by hand (
-no-snapshot, no GMD), waits forsys.boot_completed, then runs:app:connectedDebugAndroidTestfiltered to the class(es) you pass — the same technique CI andapi37_e2e.pyalready use:Key properties (all documented in the script header + README):
<fully.qualified.TestClass>[,...]list. The full ~114-test suite tends to wedge mid-run on this box; small sets don't.qemu/emulatorprocesses before booting, tears the emulator down afterward (via anEXIT/INT/TERMtrap so it runs on Ctrl-C/error too), and exits non-zero (code 3) if an orphanedqemu-system-x86_64-headless.exesurvives. Accumulated orphans have frozen this machine, so this is not optional.JAVA_HOMEto a JDK 17–21 (AGP 9.2 fails on 25+); everything is env-overridable (LOCAL_INSTRUMENTED_*).Scope note
This PR delivers the reusable helper that encodes the known-reliable local recipe. It does not by itself rewire preflight's
api35/api36steps off GMD (part of #269's broader DoD) — that follow-up can build on this helper.Validation
Script/doc change — validated by careful review +
bash -n(clean) + an arg-guard smoke test (exits 2 with usage). No live emulator run was performed: althoughadb deviceswas empty (a run was permitted), the box showed fresh signs of wedged GMD state (active_gradle_devices: MDLockCount 2, stale.lockfiles) on a shared, freeze-prone machine, so I took the review-only path. The emulator/gradle commands are a faithful composition of the battle-tested manual recipe and the already-provenapi37_e2e.pypattern.Closes #269
🤖 Generated with Claude Code