# Release process A release is **`./scripts/release.sh`** — that one command is the executable form of this document. If this document and the script ever disagree, fix both in the same change. ## What a release does 1. **Gate 1 — static checks**: `scripts/check.sh` (go vet + staticcheck). 2. **Gate 2 — test suite**: `go test -count=1 ./...` — includes `TestNoFramesWhileIdle` (internal/test/e2e), the headless frame-regression guard. 3. **Gate 3 — frame-regression profile, EMULATOR only**: `scripts/profile_emulator.sh` (auto-selects an emulator; it never auto-selects a phone). See architecture.md §11 for what it measures and why the budgets are shaped the way they are. 4. **Build**: `scripts/build_phone.sh --no-install` (arm64+arm APK → `cmd/pad/pad-phone.apk`; static checks are skipped here, already gate 1). 5. **Install to every connected device** — emulators **and phones**. Any gate failure aborts before the install. The working tree may be dirty; the script warns, but the gates then certify the *current* (possibly uncommitted) state — commit the release work before shipping. ## Install policy - Pushing a release build to the developer's phone is the **default and expected** behavior — `release.sh` installs to all `adb devices` entries, which is what makes the phone just work without knowing its serial (the wireless-debugging `IP:port` changes on every reconnect; the install loop sidesteps that entirely). - On a phone that has never had the app, grant **"All files access"** (MANAGE_EXTERNAL_STORAGE) in system settings after the first install. ## On-device profiling/testing: NOT part of a release The release touches a phone **only to install the APK**. It never profiles, tests, force-stops, or otherwise drives a phone: - On-device runs (e.g. `scripts/profile_emulator.sh -s `) are **diagnostics**: they force-stop the app, seed and remove a file in its storage, and read its profiler output. The developer may be using the phone while a release runs. - Therefore an on-device run requires **explicit approval in the moment** (ask first, name the serial), and its results are informational, never a gate. The frame-regression *gate* is tier 2 (headless) + tier 3 (emulator) only. ## Failure handling | Gate | Fails on | First things to check | |---|---|---| | 1 static | vet/staticcheck findings | The findings; don't waive without a reason in the commit message | | 2 tests | any test | `go test -count=1 -run ./...` to isolate; e2e tests are deterministic — a flake is a bug in the test | | 3 profile | a phase over its frame budget | The printed phases + `PERF`/`PERF-PRESENT` logcat lines (a spinner is usually obvious); confirm the emulator wasn't under host load (rerun once before investigating) | | build | gogio/apktool/sign | Toolchain notes in `scripts/build_phone.sh` header | If the profile gate is in question, a diagnostic run **on the phone** (requires approval) is the escalation path — not a replacement for the gate. ## Versioning (known gap) The APK is currently built with the gogio-default version (`1.0.0.1`); releases do **not** bump a version yet. When release distribution starts mattering, add a version step here (and to `release.sh`) — until then, "which release" is identified by the git commit the APK was built from. ## Emulator requirements Gate 3 needs a running emulator (`adb devices` shows `emulator-*`). `scripts/emu.sh` manages the AVD (see its header); the AVD must have had "All files access" granted once (it has). No phone needs to be connected for a release to succeed — the install step simply reports no devices.