diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-18 21:10:37 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-18 21:10:37 +0200 |
| commit | b70cde45b67e1f6bb65d598d25c1a5184bdab520 (patch) | |
| tree | 2460f861600912b4ab18eb7f672ab559729dd5cf /docs/DEVELOPER_GUIDE.md | |
| parent | 773df56883b9961b607a1994920f5ef5299423b8 (diff) | |
docs: add developer, testing and performance guides; record M0 resultsv0.1.0
- DEVELOPER_GUIDE: workflow, how the tooling works (verified simulator
behaviour), conventions and how to add devices.
- TESTING and PERFORMANCE: test layers, M0 results and measured numbers.
- FEASIBILITY: what M0 verified (watchdog 120k/240k, 10 MB storage in
device profiles, unreliable monkeydo exit code, icon sizes).
- README status, new make targets and layout; CHANGELOG 0.1.0.
- Author/Summary headers on every document, including the original brief.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docs/DEVELOPER_GUIDE.md')
| -rw-r--r-- | docs/DEVELOPER_GUIDE.md | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/docs/DEVELOPER_GUIDE.md b/docs/DEVELOPER_GUIDE.md new file mode 100644 index 0000000..e6f53a9 --- /dev/null +++ b/docs/DEVELOPER_GUIDE.md @@ -0,0 +1,91 @@ +<!-- + Author: cirakg & claude ai + Summary: How to build, test and debug OTP Wallet in Docker, how the tooling works, and the coding conventions. +--> +# Developer guide + +Everything runs in Docker through the `Makefile`; the host needs only Docker and make. This guide covers the daily workflow, how the tooling works underneath, and the conventions every change follows. The design and the build plan are in the [README](../README.md). + +## First-time setup + +1. Docker access: your user must be in the `docker` group (log out and in after joining, or run `newgrp docker` in a terminal). +2. `make image` builds the development image (about 1.1 GB; it needs the network). +3. `make sdk` is interactive: you accept Garmin's agreements, log in, and the SDK (9.2.0) plus the device files of all 72 products download into `.cache/home` (about 1.1 GB). The login token is deleted at the end. +4. `make key` creates the developer key in `.cache/keys/`. Back that folder up; see [README 15.6](../README.md#156-developer-key). + +## Daily workflow + +| Task | Command | +| --- | --- | +| Build for one device | `make build DEVICE=fr70` | +| Run the app and watch it in your browser | `make sim DEVICE=fr70`, then open http://127.0.0.1:6080/vnc.html | +| Unit tests (Python tools and Monkey C, 4 devices) | `make test` | +| All static checks | `make lint` | +| Screenshots against the approved images | `make screenshots` | +| Accept changed screens after reviewing build/screenshots/ | `make screenshots-approve` | +| Start-up time and memory budgets | `make perf`, `make memtest` | +| Signed package for the Store beta | `make package` | +| Everything, in order | `make ci` | +| A shell in the container | `make shell` | + +Use other devices with `TEST_DEVICES="fr70 venu3"` on any target that takes a device list. Every target runs serially, even under `make -j`. + +## Repository layout + +| Path | Content | +| --- | --- | +| `source/` | The watch app (Monkey C), one folder per module (README section 5) | +| `test/` | Monkey C unit tests (`(:test)` functions), compiled only into test builds | +| `test/golden/` | Approved simulator screenshots, one per test device | +| `resources/` | Strings, the default launcher icon and, from M7, the settings | +| `resources-icons/`, `icons.jungle` | Launcher icons at each size the products need, generated by `make icons` | +| `manifest.xml`, `monkey.jungle`, `test.jungle` | App manifest and build configuration | +| `docker/` | Images (`Dockerfile`, `docs.Dockerfile`), hash-locked dependencies, and the container scripts | +| `tools/` | Python tools (test-log judge, screenshot checker, linters, icon generator) and their tests | +| `docs/` | This guide and the other documents | +| `.cache/`, `build/` | Git-ignored: SDK, device files, key; build outputs | + +## How the tooling works + +### Builds + +`docker/scripts/build-app.sh` compiles one device in one mode: + +- `debug`: what `make build`, `make sim`, `make perf` and `make screenshots` use. It contains the `(:debug)` diagnostics. +- `release`: `monkeyc -r` removes every `(:debug)` declaration; used by `make package`. +- `test`: adds `test.jungle` and `--unit-test`. + +Every build uses strict type checking (`-l 3`) and fails on any compiler warning. The launcher icon is the classic source of warnings: the compiler warns when it has to scale an icon, so every product gets an icon of exactly its size through `icons.jungle`. After adding a product to the manifest, run `make sdk` (device files) and then `make icons`. + +### The headless simulator + +The simulator is a GTK program. The scripts start it on a virtual display (Xvfb on `:99`) with the openbox window manager, so its window can be found for screenshots. Behaviour verified with SDK 9.2.0: + +- It accepts `monkeydo` on TCP port 1234; the scripts wait until that port listens (read from `/proc/net/tcp`). +- It keeps a single-instance lock file, `~/Sim-dev`, holding its process ID. That file survives in `.cache/home`, and a later container often reuses the process ID for something else, so the simulator would believe it's already running. `ciq_start_simulator` deletes the stale lock first. +- `monkeydo` exits with 1 even when every unit test passed, so `tools/ciq_test_report.py` judges the console output instead. +- For a normal (non-test) run, `monkeydo` blocks while the app runs and streams the app's `System.println` output. Quotes in that output arrive escaped, which is why the diagnostics use plain `key=value` pairs. + +### Screenshots + +`tools/sim_screenshot.py` doesn't assume where the watch is drawn in the simulator window. It searches for the device drawing (named in the device's `simulator.json`) in the window capture, comparing only the bezel, because the app draws inside the display area. The match is near-exact (mean difference below 0.3 out of 255); the drawing sits at offset (1, 26) because of the window border and the menu bar. The display rectangle from `simulator.json` is then cut out, round screens get their corners blacked out, and the result is compared with `test/golden/<device>.png`. + +### Performance and memory + +Debug builds print `DIAG first_frame startup_ms=... mem_used=... mem_total=...` after their first frame (`source/util/Diag.mc`). `docker/scripts/app-diag.sh` adds a `HARNESS first_frame wall_ms=...` line, the wall-clock time from launching `monkeydo` until that first frame. `tools/check_budgets.py` compares both with `tools/budgets.json`. See [PERFORMANCE.md](PERFORMANCE.md) for the numbers and their limits. + +## Conventions + +- **Headers**: every file starts with `Author: cirakg & claude ai` and a one-line `Summary:` in its comment syntax. JSON files use `author`/`_author` and `description`/`_summary` keys, and PNG images use Author and Description text chunks. Only `docker/docs/package-lock.json`, which npm rewrites, is exempt. `make lint` enforces this (rule HDR001). +- **Comments**: every module, class and non-trivial function explains its purpose, inputs, outputs, errors and security implications. +- **No logging**: `System.println` is allowed only in `source/util/Diag.mc`, and only in `(:debug)` code. Secrets, codes and entry names never go to a log. +- **No network**: `manifest.xml` requests no permissions and no code uses `Toybox.Communications`. `make lint` enforces both. +- **Secrets**: no real secrets anywhere in the repository; test data is fake and says so. +- **Small functions, named constants**, strict typing in Monkey C (`-l 3`) and Python (`mypy --strict`), and warnings treated as errors in the compiler, pytest and the linters. +- **Commits**: [Conventional Commits](https://www.conventionalcommits.org/) on `main`, one finished and verified unit per commit, with `CHANGELOG.md` updated. + +## Adding things + +- **A device**: add `<iq:product id="..."/>` to `manifest.xml`, then `make sdk` (downloads its files), `make icons` and `make products` (checks it meets the target rule: a watch, API 5.0 or newer, at least 512 KB). +- **A test device**: add it to `TEST_DEVICES` in the `Makefile`, run `make screenshots`, review `build/screenshots/<device>.png` and run `make screenshots-approve`. +- **A barcode symbology** (from M6): one encoder module under `source/codes/`, its validator, unit tests with reference patterns, and the checks in [README 12.4](../README.md#124-how-each-symbology-is-proven-scannable). |
