# MVP release and acceptance guide This guide is the reproducible handoff for the ESP32-C6 Battleship MVP. It does not replace the locked rules in [MVP.md](MVP.md), the HTTP contract in [API_CONTRACT.md](API_CONTRACT.md), or the resource limits in [RESOURCE_BUDGET.md](RESOURCE_BUDGET.md). ## Release prerequisites - Target environment: `esp32-c6-devkitm-1` from `platformio.ini`. - ESP32-C6FH4, revision v0.2, 4 MB flash; no PSRAM is assumed. - PlatformIO Core 6.1.19, `espressif32` 7.0.1, ESP-IDF 6.0.1, and `esp_littlefs` 1.20.4. - USB serial device: normally `/dev/ttyACM0`; confirm with `pio device list` before an upload. - No firmware-embedded Wi-Fi credentials are required. On first boot, join the open `Battleship-open` network and open `http://192.168.4.1/setup` if the captive portal does not appear. ## Build and upload From the repository root, run the automated release checks: ```sh make -C test/host run pio run -e esp32-c6-devkitm-1 -t buildfs pio run -e esp32-c6-devkitm-1 ``` Confirm the build remains within the limits in `RESOURCE_BUDGET.md`, then connect only the intended board and upload the browser assets before firmware: ```sh pio run -e esp32-c6-devkitm-1 -t uploadfs --upload-port /dev/ttyACM0 pio run -e esp32-c6-devkitm-1 -t upload --upload-port /dev/ttyACM0 ``` Replace `/dev/ttyACM0` when `pio device list` identifies another device. Do not use erase targets for this release procedure. After boot, obtain the DHCP address from the router or serial log, then open `http:///`. The web application and API must be used only on the local network. The API health check is: ```sh curl http:///api/health ``` The response includes free/minimum heap, largest free block, connection count, rejected input count, Wi-Fi state, and reset reason. It must not contain Wi-Fi credentials or session tokens. ## Network configuration and local-security limitation The `/setup` screen and `/api/network/*` routes are intentionally unauthenticated so a new device can be configured through either the fallback AP or its regular local address. Any client that can reach the device can change or delete the saved Wi-Fi configuration. The open AP and plain local HTTP do not protect a submitted password from a nearby network observer. Configure the board only on a network you trust, and do not use this feature for credentials that require strong confidentiality. ## MVP acceptance checklist Record the observed result, device address, browser/device model, and any deviation for every item. A `PASS` requires all thirteen checks. | MVP criterion | Required physical check | | --- | --- | | 1 | Cold boot, Wi-Fi join, and Russian interface load from LittleFS. | | 2 | Two phones complete a human-versus-human game. | | 3 | One phone completes a human-versus-ESP32 game, including delayed bot turns. | | 4–6 | Verify fleet rules, rejected duplicate/out-of-turn shots, and role-safe views. | | 7 | Connect at least two spectators during a game; confirm controls stay unavailable. Repeat to the eight-spectator target. | | 8 | Interrupt WebSocket connectivity; confirm two-second HTTP fallback and WebSocket recovery. | | 9 | Refresh each player and a spectator; confirm token-based role/state recovery. | | 10–11 | Finish, inspect winner and statistics, rematch, then confirm fresh fleets and preserved cumulative totals. | | 12 | Check narrow-phone and tablet portrait/landscape views, including tabs and side-by-side boards. | | 13 | Complete 20 representative consecutive games with no reset, hang, or material heap decline. | For the final load run, keep two players and eight spectators connected and sample `/api/health` before, during, and after the run. The final report must compare minimum free heap, largest free block, reset reason, and observed state/delivery latency with the hard limits in `RESOURCE_BUDGET.md`. ## Recovery and incident handling - A player refreshes the page to resume with the token stored in browser `localStorage`; a reboot intentionally invalidates all tokens and resets game/statistics state. - If WebSocket is unavailable, leave the page open: the browser uses HTTP state polling and retries WebSocket at 1, 2, 5, then 10 seconds. - If the board has a new DHCP address, use the router/serial information and open the new local URL. No fixed IP or external service is required. - If LittleFS assets fail to load, repeat `uploadfs` for the confirmed target port before reflashing firmware. Do not format LittleFS automatically. - Capture `/api/health`, reset reason, and the exact source revision before reporting a failure. Never capture or publish tokens or Wi-Fi credentials. ## Release record template Complete this only after all physical checks pass: ```text Source revision: PlatformIO / ESP-IDF / esp_littlefs: Firmware bytes / LittleFS bytes: RAM bytes / minimum heap / largest free block: Largest state payload / maximum observed delivery latency: Reset reason before and after run: 20-game result: 2-player + 8-spectator result: MVP criteria 1–13: PASS / FAIL with evidence: Release decision: PASS ``` Post-MVP work begins only after this record is complete and Milestone 017 is marked `DONE`.