Brings the #334 API-37 boot/E2E diagnostics to the e2e matrix (API 29-36) so any flake or failure in an emulator E2E leg is diagnosable. The trigger: E2E (31) recently died on a bare sdkmanager exit 1 with zero diagnostic trail, and emulator flakes across the matrix left nothing behind (the matrix uploaded only its test report).
Scoped to the e2e matrix job only — e2e-preview is deliberately untouched (PR #372 is restructuring/sharding it and it already has these diagnostics). reactivecircus/android-emulator-runner and the existing boot-race retry are kept; diagnostics are added around/inside them (no conversion to manual boot).
Changes (all in the e2e job)
Stream logcat per API level — adb logcat -v time > "$RUNNER_TEMP/logcat-api<level>.txt" 2>&1 & at the top of the script: in both the "Run E2E tests" and "Run E2E tests (retry…)" reactivecircus steps (the emulator is booted there). Backgrounded; ./gradlew connectedDebugAndroidTest stays the last foreground command so the step's exit status is still the test result.
Failure-time state dump — new if: failure() step prints (each guarded || true) adb devices, adb logcat -d tail, emulator -accel-check, ls -l /dev/kvm, free -h, df -h to the step log andtees them to a diagnostics-api<level>.txt file.
Always-upload artifact — new if: always()actions/upload-artifact (same pinned v7 SHA as the rest of the file) named e2e-diagnostics-api<level>, carrying the logcat + diagnostics files, if-no-files-found: warn.
SDK-install diagnosability — the E2E (31) failure was sdkmanager exit 1 with no trail. The step now retries up to 3× with backoff (self-heals a transient package-mirror/network hiccup) and prints sdkmanager --list_installed on a hard failure instead of a bare exit 1.
Validation
python -m yaml safe-load parses the whole workflow; all e2e steps present and ordered.
git diff --check clean (no whitespace/EOL issues); 5 hunks, all within the e2e job; e2e-preview unchanged.
Additive/diagnostic only — no boot-affecting emulator flags changed. The real validation is this PR's own CI run: the matrix must stay green and produce the e2e-diagnostics-api<level> artifacts.
## What
Brings the #334 API-37 boot/E2E diagnostics to the **`e2e` matrix (API 29-36)** so any flake or failure in an emulator E2E leg is diagnosable. The trigger: `E2E (31)` recently died on a bare `sdkmanager` exit 1 with **zero** diagnostic trail, and emulator flakes across the matrix left nothing behind (the matrix uploaded only its test report).
Scoped to the `e2e` matrix job **only** — `e2e-preview` is deliberately untouched (PR #372 is restructuring/sharding it and it already has these diagnostics). `reactivecircus/android-emulator-runner` and the existing boot-race retry are kept; diagnostics are added around/inside them (no conversion to manual boot).
## Changes (all in the `e2e` job)
- **Stream logcat per API level** — `adb logcat -v time > "$RUNNER_TEMP/logcat-api<level>.txt" 2>&1 &` at the top of the `script:` in **both** the "Run E2E tests" and "Run E2E tests (retry…)" reactivecircus steps (the emulator is booted there). Backgrounded; `./gradlew connectedDebugAndroidTest` stays the last foreground command so the step's exit status is still the test result.
- **Failure-time state dump** — new `if: failure()` step prints (each guarded `|| true`) `adb devices`, `adb logcat -d` tail, `emulator -accel-check`, `ls -l /dev/kvm`, `free -h`, `df -h` to the step log **and** `tee`s them to a `diagnostics-api<level>.txt` file.
- **Always-upload artifact** — new `if: always()` `actions/upload-artifact` (same pinned v7 SHA as the rest of the file) named `e2e-diagnostics-api<level>`, carrying the logcat + diagnostics files, `if-no-files-found: warn`.
- **SDK-install diagnosability** — the `E2E (31)` failure was `sdkmanager` exit 1 with no trail. The step now retries up to 3× with backoff (self-heals a transient package-mirror/network hiccup) and prints `sdkmanager --list_installed` on a hard failure instead of a bare exit 1.
## Validation
- `python -m yaml` safe-load parses the whole workflow; all `e2e` steps present and ordered.
- `actionlint` passes (exit 0) — expressions, `${{ matrix.api-level }}` interpolation, block scalars, `if:` conditions all valid.
- `git diff --check` clean (no whitespace/EOL issues); 5 hunks, all within the `e2e` job; `e2e-preview` unchanged.
- Additive/diagnostic only — no boot-affecting emulator flags changed. The real validation is this PR's own CI run: the matrix must stay green **and** produce the `e2e-diagnostics-api<level>` artifacts.
Closes #387.
🤖 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
Brings the #334 API-37 boot/E2E diagnostics to the
e2ematrix (API 29-36) so any flake or failure in an emulator E2E leg is diagnosable. The trigger:E2E (31)recently died on a baresdkmanagerexit 1 with zero diagnostic trail, and emulator flakes across the matrix left nothing behind (the matrix uploaded only its test report).Scoped to the
e2ematrix job only —e2e-previewis deliberately untouched (PR #372 is restructuring/sharding it and it already has these diagnostics).reactivecircus/android-emulator-runnerand the existing boot-race retry are kept; diagnostics are added around/inside them (no conversion to manual boot).Changes (all in the
e2ejob)adb logcat -v time > "$RUNNER_TEMP/logcat-api<level>.txt" 2>&1 &at the top of thescript:in both the "Run E2E tests" and "Run E2E tests (retry…)" reactivecircus steps (the emulator is booted there). Backgrounded;./gradlew connectedDebugAndroidTeststays the last foreground command so the step's exit status is still the test result.if: failure()step prints (each guarded|| true)adb devices,adb logcat -dtail,emulator -accel-check,ls -l /dev/kvm,free -h,df -hto the step log andtees them to adiagnostics-api<level>.txtfile.if: always()actions/upload-artifact(same pinned v7 SHA as the rest of the file) namede2e-diagnostics-api<level>, carrying the logcat + diagnostics files,if-no-files-found: warn.E2E (31)failure wassdkmanagerexit 1 with no trail. The step now retries up to 3× with backoff (self-heals a transient package-mirror/network hiccup) and printssdkmanager --list_installedon a hard failure instead of a bare exit 1.Validation
python -m yamlsafe-load parses the whole workflow; alle2esteps present and ordered.actionlintpasses (exit 0) — expressions,${{ matrix.api-level }}interpolation, block scalars,if:conditions all valid.git diff --checkclean (no whitespace/EOL issues); 5 hunks, all within thee2ejob;e2e-previewunchanged.e2e-diagnostics-api<level>artifacts.Closes #387.
🤖 Generated with Claude Code