Pad/doc/README.md
Greg Pomerantz b1a1719f17 scripts: emu.sh — reliable emulator lifecycle + on-device debug helpers
Replaces the ad-hoc adb/nohup sequences used throughout verification with
one self-contained script: up/down/status, app start|stop|restart, shot,
log, tap, type, cmd (one-shot editor debug command), perf on|off|pull,
push/pull of Notes test files. Encodes the machine-local paths
(Notes/, PadPerf/ profiler + cmd file) in one auditable place.

Reliability findings baked in (each hit during testing):
- The AVD auto-saves a 'default_boot' instant-boot snapshot on clean
  shutdown; a corrupted one makes the emulator segfault during restore
  (device never comes online). up() detects it (process death / no adb
  device within PAD_ONLINE_TIMEOUT) and falls back to a cold boot with
  -no-snapshot-load; the next clean down() re-saves a good snapshot, so
  this self-heals. down() is the only sanctioned stop (clean kill saves
  the snapshot; SIGKILL corrupts it).
- The emulator process identity is ambiguous (launcher vs
  qemu-system-*-headless), and crashpad/netsimd children carry the AVD
  name in their command lines. Liveness and kill therefore use a tight
  signature: comm matches qemu-system-* AND cmdline contains ' -avd
  <AVD>' (never a broad pkill -f pattern — one matched and killed the
  calling shell during testing).
- Before any launch, orphaned qemu instances are cleared (they hold the
  AVD lock and make new launches fail silently); before starting a
  replacement, the old one must be fully gone (lingering device/lock
  causes false success).
- Timeouts: short online window for the snapshot attempt, full
  BOOT_TIMEOUT for the fallback cold boot (~20 s).

Tested: idempotent up, 10 s snapshot-restore boot, forced fallback
(30 s end-to-end, verified correct instance), orphan cleanup, perf/cmd/
push/pull/shot/log on-device. doc/README.md now documents it.
2026-08-16 22:00:56 -04:00

94 lines
4.8 KiB
Markdown

# Pad documentation
Three documents, kept at the level of *what, why, and invariants* — not
line-by-line code — so they stay true as the implementation evolves.
| Doc | What it is |
|---|---|
| [`spec.md`](./spec.md) | What the app **actually does**, measured performance, the code layout, and an explicit list of deferred features. |
| [`architecture.md`](./architecture.md) | How it works: single-owner concurrency model, channel topology, Frame handoff contract, ownership rules, editor/browser/render internals. |
| [`development_plan.md`](./development_plan.md) | The active plan: completed phases, remaining work, and the on-device observation loop. |
## Package inventory
| Package | Role |
|---------|------|
| `internal/editor` | Chunked buffer, line index, virtualized viewport, IME ops, autosave, logic goroutine, state, Frame |
| `internal/browser` | Directory browsing, search, sort, pagination, browser state machine |
| `internal/ui` | Element tree, frame layout, renderer (op-based), IME wiring, gestures |
| `internal/perf` | Default-off performance profiler (per-logic-frame cadence + scroll state → CSV) |
| `internal/io/pool` | Worker pool (8 workers, 2 priority lanes) + file/dir tasks |
| `internal/test/e2e` | Harness driving the real `Logic` + `Inspect` |
| `cmd/pad` | `main.go` (entry), `impl_android.go` (base path) |
## Documentation policy
1. **Docs describe invariants and contracts, not code lines.** If a document
has to change on every refactor, it is too detailed — delete it or raise
its level of abstraction. Point-in-time implementation plans are deleted
once implemented (the previous `*_implementation_plan.md`,
`touch.md`, `element_model.md`, `layout_rendering.md`,
`virtual_scroll_render_optimization.md`, and `conflict_resolution.md` were
removed in the 2026-08 doc reorganization for this reason).
2. **Unbuilt behavior is not spec'd.** Requirements that are not in the code
live in `spec.md` §7 (deferred), never as if they worked.
3. **Code wins.** When doc and code disagree, fix the doc.
## Build & install (Android, this workstation)
Prereqs on this box (already installed): JDK 17, Go, Android SDK at
`~/android-sdk` (platform-tools, build-tools 35.0.0, emulator, NDK),
`gogio@v0.10.0` in `~/go/bin`, debug keystore at
`~/.android/debug.keystore`. Env vars are set in `~/.bashrc`.
**Build + install with `./scripts/build_emu.sh`** (add `--no-install` to
build only). It is self-contained: checks the prereqs, auto-downloads
apktool v3.0.3 to `~/android-sdk/tools/apktool.jar` if missing, and uses a
temporary work dir. Output: `cmd/pad/pad-emu.apk`.
What it does, and why (gogio cannot inject manifest permissions):
1. `gogio -target android -targetsdk 35 -arch amd64` → raw APK (from `cmd/pad/`)
2. `apktool d` → decode
3. Inject `<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>`
(without it, Android 11+ blocks listing `/storage/emulated/0`)
4. `apktool b` → rebuild
5. `apksigner sign` with the debug key → `cmd/pad/pad-emu.apk`
6. `adb install -r` (skipped with `--no-install`)
## Emulator + on-device debug: `scripts/emu.sh`
All emulator lifecycle and on-device debug operations go through
`scripts/emu.sh` (headless AVD `pad_avd`, API 35): `up` / `down` /
`status`, `app start|stop|restart`, `shot`, `log`, `tap X Y`, `type TEXT`,
`cmd <top|bottom|frac F|dp N>` (one-shot editor debug command),
`perf on|off|pull` (in-app profiler), `push`/`pull` (Notes files). See the
script header for the full list and the device paths it encodes.
Snapshot behavior: the AVD auto-saves an instant-boot snapshot on clean
`down` (restore ~10 s vs ~20 s cold boot). A corrupted snapshot makes the
emulator segfault during restore; `up` detects that and falls back to a
cold boot, and the next `down` re-saves a good snapshot (self-healing).
Always stop with `down` — SIGKILLing the emulator corrupts the snapshot.
App package/activity: `pad.pad / org.gioui.GioActivity`. Default root
directory: `/storage/emulated/0/Notes`.
## On-device observation loop (quick reference)
Gio renders into one GL surface, so the authoritative debug signals are
data, not pixels (use `scripts/emu.sh log|shot|perf|cmd` for the first
four):
- `logcat -s pad.pad` — app log (errors, limits, recovery; the normal path
is quiet by design).
- `input tap|swipe|text` — drive the UI (see `development_plan.md` for the
tap coordinates and IME-tap cadence that works). The first tap right
after launch/open is sometimes swallowed — re-tap.
- Autosave debounce is 1 s: **wait ~1.6 s before reading a file back from
disk** after typing.
- Memory: `adb shell dumpsys meminfo pad.pad` (watch PSS/RSS; the 3.8 GB
emulator OOMs the app above ~2.5 GB RSS).
- Screenshots are an auxiliary check only — state, logcat, and file diffs
are authoritative.