# Phase 01 — Verification gate and hardware contract **Source:** `TODO.md` — (foundation, no TODO line). Required before the four TODO items can be executed by subprocesses behind a pass/fail gate. **Story:** `n/a` **Context:** `PLAN.md` "Validation / Verification Workflow"; `tests/run_tests.sh`; `AGENTS.md` "Build, test, flash" ## Objective Give this repository a `.agents/validate.sh` that actually fails when keyrelay is broken — host suites (including the sanitiser run and the page suite) plus **both** firmware builds — and write down the hardware contract so that no later unit ever blocks waiting for a board that nobody is holding. ## Dependencies - — (none) ## Tasks 1. `01_adapt_validate_sh.md` — author `.agents/validate.sh` with keyrelay's real checks and the template's repo-hygiene gates, and prove it fails on a deliberately broken tree. 2. `02_hardware_contract.md` — `.agents/HW_VERIFICATION.md` + `tools/hw_probe.sh`: what can only be checked on hardware, how to check it, the baseline RAM/flash numbers, and the rule that a unit attempts a device step once, with a timeout, and records the outcome. ## Testing & Quality - Unit/integration: the gate itself is the artifact. It must pass on a healthy tree **and** fail on each injected fault: a failing C++ assertion, a page-suite id mismatch, a firmware compile error in `src/main.cpp`, and a tracked `*.pem`. - Coverage: n/a for shell scripts; >90% applies only to any Python added (`tools/hw_probe.sh` is shell, not Python). - `.agents/validate.sh` must run the **full** suite — a partial gate defeats the "no phase commits unless 100% passing" guarantee. ## Completion Criteria - [ ] `bash .agents/validate.sh` exits 0 on the untouched tree and prints, per check: the suite results (`RESULT: all suites passed`), the two build results, and the hygiene verdict. - [ ] `SANITIZE=1` is exercised by the gate (or by a documented, gate-called second pass) and passes. - [ ] The gate contains no `pio … -t upload`, no `curl` to a device, no network fetch. - [ ] Each of the four injected faults makes the gate exit non-zero (demonstrated in the task's report, then reverted). - [ ] `.agents/HW_VERIFICATION.md` exists and names, for every device-only claim in this roadmap, the command that observes it (`tools/watch_target.py`, the serial console, `curl -k https://keyrelay.local/status`). - [ ] Full test suite green; `git status` shows only planning artifacts.