Files
keyrelay/.agents/phases/todo/01_verification_gate/02_hardware_contract.md
T
ducoterra 56aa97d60d chore(agent): phase roadmap from TODO.md, 5 phases
The four open items in TODO.md become an executable pipeline: 01 the
verification gate (host suites + sanitiser + both firmware envs, and the
hardware contract so no unit blocks on a board nobody is holding), 02 HTTPS
and wss:// with an identity the board generates itself into NVS, 03 session
takeover that always lands disarmed, 04 a responsive page whose safety
statements are pinned before they are trimmed, 05 the phone as a controller
(press-and-hold pad, soft keyboard, modifier latches over a new Q= frame).

TODO.md is cleared to its empty title; the items live in .agents/phases/ now.
AGENTS.md gains the five protocol rules and nothing else.

LLM-Generated: true
2026-11-08 23:28:25 -05:00

4.3 KiB
Raw Blame History

Task 02 — The hardware contract: what the gate cannot see

Phase: 01_verification_gate · Source: TODO.md — (foundation; AGENTS.md "Verification standard": "A feature that lives on the device is not done when the source builds — it is done when the device is running it and something observed it.") Story: n/a

Objective

Make the device-only half of this roadmap explicit, runnable and non-blocking: a probe that reports what hardware is reachable right now, and a file that pairs every device-only claim with the exact command that would confirm it — so a unit running unattended never hangs on a board and never claims a device result it did not observe.

Work

  1. .agents/HW_VERIFICATION.md — three sections:
    • Baseline (measured, from task 01's gate run): bridge RAM 26.7% (87 592 B) / Flash 36.1% (1 135 293 B), console RAM 16.8% (55 200 B) / Flash 33.6% (1 056 081 B), 3406 host checks. Later phases quote a delta against these numbers.
    • Claims that need hardware, each with its command and its expected observation, at least: keystroke/chord delivery and which keys a chord really was (python3 tools/watch_target.py on the target); served-page byte agreement (curl -sk https://keyrelay.local/ | wc -c vs the gate's page count — http until phase 02 lands, https -k after); TLS handshake + the SHA-256 fingerprint printed once on the serial console; takeover actually releasing the incumbent's held keys (watch_target.py must show key-up before the new session's first key); the mobile soft keyboard and touch pad (a phone on the board's AP, watch_target.py for both the characters and the pointer deltas).
    • The blocking rule: a unit attempts a device step at most once, wrapped in timeout, and writes the outcome — ok, skipped (no device), or failed: … — with the command it ran into the section's table. It never loops on a port, never re-flashes to "see if it works", and never leaves the board in ROM download mode without saying so in the report (tools/to_bootloader.py drops it there deliberately; a power cycle is the only way back and nobody may be there to do it).
  2. tools/hw_probe.sh (executable, set -uo pipefail, no side effects) — prints one line per fact and always exits 0 (it informs, it does not gate): /dev/ttyACM*//dev/ttyUSB* present?; keyrelay.local resolves?; https reachable (curl -sk -m 2 -o /dev/null -w '%{http_code}')?; http reachable and does it redirect?; uv on PATH?; node on PATH?; is a watch_target.py-capable evdev device visible (informational only). Nothing is opened on a serial port except a test -e/test -r check — opening it toggles DTR/RTS and resets the board, so the probe must not.
  3. .agents/validate.sh — append bash tools/hw_probe.sh as the last, non-affecting line (its exit status is deliberately not folded into rc), with a comment saying why: it is context for whoever reads the gate output, not a check.
  4. README.md — no behaviour change yet; only if the "End-to-end verification" section contradicts what the probe just printed, fix the stale line. Do not restructure it here.
  • ASSUMPTION: at execution time a board may be attached and reachable but nobody is watching it, so "board available" is treated as best-effort. Any phase that needs an on-target second machine (watch_target.py) records skipped (no device) rather than inventing a result. This is the user-facing cost of running the roadmap unattended; the file is where they pick those checks up.

Testing & Quality

  • bash tools/hw_probe.sh exits 0 with and without a board, with and without uv, from any cwd; it never blocks (every probe has a -m/timeout).
  • The gate still passes with the probe line added, and its output cannot flip rc.
  • shellcheck-clean if shellcheck is installed; otherwise -n syntax check in the report.

Completion Criteria

  • bash tools/hw_probe.sh prints the six facts and exits 0 (paste its output).
  • .agents/HW_VERIFICATION.md covers every phase 02–05 device claim listed above, each with command + expected observation + the rule about one attempt.
  • bash .agents/validate.sh still exits 0.
  • Full test suite green; no firmware source touched.