288 lines
15 KiB
Markdown
288 lines
15 KiB
Markdown
# ESP32 Battleship Implementation Plan
|
||
|
||
## Purpose of the initial milestones
|
||
|
||
Before implementing the complete game, experimentally verify that the specific ESP32-C6 Mini board:
|
||
|
||
- can be flashed and run reliably with the selected PlatformIO and Arduino stack;
|
||
- can connect to the home Wi-Fi network;
|
||
- can store and serve the web interface from LittleFS;
|
||
- can support HTTP, WebSocket, and HTTP polling fallback;
|
||
- has enough flash, RAM, and processing capacity for one game, two players, and up to eight spectators;
|
||
- can provide role-specific state without exposing hidden game data.
|
||
|
||
Full MVP implementation may begin only after Milestone 004 is completed with a documented **Go** decision.
|
||
|
||
## Codex execution rules
|
||
|
||
This file is an ordered execution queue for Codex.
|
||
|
||
1. Work on milestones strictly in numerical order.
|
||
2. In one task, execute only the first milestone whose status is `READY`.
|
||
3. Do not start the next milestone during the same task unless the user explicitly requests it.
|
||
4. A milestone may become `READY` only after all milestones listed under `Depends on` are `DONE`.
|
||
5. Before implementation, change the selected milestone status from `READY` to `IN PROGRESS`.
|
||
6. Do not mark a milestone `DONE` until every acceptance criterion has objective evidence.
|
||
7. If a criterion cannot be met, set the status to `BLOCKED` and record the reason, evidence, and proposed next action in that milestone's execution record.
|
||
8. If implementation changes the plan, preserve the intent and acceptance criteria of already completed milestones.
|
||
9. Add future milestones only at the end of this file. Do not insert or renumber milestones after work has started.
|
||
10. Never edit files under `sources/`; they are read-only reference material.
|
||
11. Never store Wi-Fi credentials or other secrets in tracked project files.
|
||
|
||
Allowed statuses:
|
||
|
||
- `BLOCKED` — work cannot proceed until a recorded issue is resolved;
|
||
- `READY` — all dependencies are complete and the milestone may be executed;
|
||
- `IN PROGRESS` — this is the milestone currently being executed;
|
||
- `DONE` — all acceptance criteria have passed and evidence is recorded.
|
||
|
||
At most one milestone may have the status `IN PROGRESS`.
|
||
|
||
## Execution record format
|
||
|
||
When completing or blocking a milestone, append an execution record inside that milestone using this format:
|
||
|
||
```text
|
||
Execution record
|
||
- Date:
|
||
- Board model and revision:
|
||
- Toolchain and library versions:
|
||
- Result: PASS | FAIL | BLOCKED
|
||
- Evidence:
|
||
- Measurements:
|
||
- Issues or deviations:
|
||
- Next action:
|
||
```
|
||
|
||
Evidence should include the exact test scenario, relevant logs, reset reasons, resource measurements, and paths to created project files. A statement such as “works in general” is not sufficient.
|
||
|
||
---
|
||
|
||
## Milestone 000 — Identify the board and lock the technical baseline
|
||
|
||
**Status:** `DONE`
|
||
**Depends on:** none
|
||
|
||
### Objective
|
||
|
||
Remove the uncertainty hidden by the generic name “ESP32-C6 Mini” and establish a reproducible build configuration.
|
||
|
||
### Work
|
||
|
||
- Record the manufacturer, exact board model, and revision from the physical markings and authoritative documentation.
|
||
- Record the ESP32-C6 module variant, flash size, presence and size of PSRAM, USB connection type, and built-in LED.
|
||
- Locate the schematic or pinout and identify pins used by USB, UART, flash, and the built-in LED.
|
||
- Select the exact PlatformIO `board` identifier. If no exact profile exists, select the closest ESP32-C6 profile and explicitly configure flash and partition parameters.
|
||
- Pin the PlatformIO, Espressif 32 platform, and Arduino Core versions.
|
||
- Define an initial partition layout that provides space for both the application and LittleFS.
|
||
- Create a short board passport containing a photo of the markings, documentation links, and confirmed specifications.
|
||
|
||
### Deliverables
|
||
|
||
- A board passport in the project documentation.
|
||
- An initial `platformio.ini` with pinned versions.
|
||
- A documented memory map and selected partition layout.
|
||
|
||
### Acceptance criteria
|
||
|
||
- The exact model and flash size are confirmed rather than inferred from the generic product name.
|
||
- The build configuration does not depend on floating package versions.
|
||
- The partition layout includes both an application partition and LittleFS.
|
||
- Every unknown board parameter is either resolved or recorded as a specific risk to test in Milestone 001.
|
||
|
||
### Blocking conditions
|
||
|
||
- The flash size or a safe flashing configuration cannot be determined.
|
||
- The available toolchain has no usable ESP32-C6 support for this board.
|
||
|
||
### Completion action
|
||
|
||
If all criteria pass, set this milestone to `DONE`, append its execution record, and change Milestone 001 from `BLOCKED` to `READY`.
|
||
|
||
### Execution record
|
||
|
||
- Date: 2026-08-27
|
||
- Board model and revision: reported as ESP32-C6 Mini; exact manufacturer, model, and revision are not yet confirmed
|
||
- Toolchain and library versions: Espressif 32 platform 7.0.1; ESP-IDF 6.0.1; esptool.py 4.11.0; RISC-V toolchain 15.2.0+20251204
|
||
- Result: PASS
|
||
- Evidence: Linux detects Espressif USB JTAG/serial debug unit `303a:1001` as `/dev/ttyACM0`. VS Code PlatformIO completed two uploads through esptool 4.11.0, identified `ESP32-C6FH4 (QFN32) revision v0.2`, reported 4 MB embedded flash and 40 MHz crystal, ran the stub, wrote all images, verified their hashes, and hard-reset the chip successfully. Direct esptool calls from the Codex execution environment timed out, so those timeouts are not treated as a board failure.
|
||
- Measurements: the clean build used 10,964 / 327,680 bytes of RAM (3.3%) and 155,504 / 1,048,576 bytes of the configured application partition (14.8%). It completed successfully in 46.86 seconds. The earlier `Expected 4MB, found 2MB` warning is no longer present.
|
||
- Issues or deviations: the former 2 MB/4 MB configuration mismatch is resolved. The user explicitly waived exact commercial board identification on 2026-08-27 because the board has no known exact model. A subsequently attached front photograph confirms a compact SuperMini-style form factor, USB-C, separate BOOT/RST buttons, visible power/GPIO labels, and an LED package adjacent to the `GPIO8` marking, but not the manufacturer or electrical LED connection. Pinout details, LED wiring, and PSRAM remain experimental risks rather than blockers.
|
||
- Next action: begin Milestone 001. Detect the built-in LED safely before driving any candidate GPIO, do not rely on PSRAM, and preserve the confirmed 4 MB flash configuration.
|
||
|
||
---
|
||
|
||
## Milestone 001 — Prove build, flashing, and stable basic operation
|
||
|
||
**Status:** `IN PROGRESS`
|
||
**Depends on:** Milestone 000
|
||
|
||
### Objective
|
||
|
||
Prove that the configuration selected in Milestone 000 works reliably on the physical board.
|
||
|
||
### Work
|
||
|
||
- Create a minimal firmware project with serial logging and reports for chip information, flash size, reset reason, and available heap.
|
||
- Flash the board and test startup after a manual reset, a full power cycle, and several repeated flashing cycles.
|
||
- Test the built-in LED if present and confirm that its pin does not conflict with USB or flash operation.
|
||
- Add uptime and periodic free-heap reporting.
|
||
- Run the firmware continuously for at least two hours without Wi-Fi and record every reset reason.
|
||
|
||
### Required measurements
|
||
|
||
- Firmware size and flash usage.
|
||
- Free heap immediately after startup and minimum free heap during the run.
|
||
- Boot and reset reasons.
|
||
- Any errors, watchdog resets, or unexpected restarts.
|
||
|
||
### Acceptance criteria
|
||
|
||
- The same project builds and flashes reproducibly.
|
||
- The board starts correctly after reset and full power loss.
|
||
- The two-hour run completes without a hang, watchdog reset, or unexpected restart.
|
||
- Free heap does not show a persistent downward trend.
|
||
- The detected flash size matches the configuration established in Milestone 000.
|
||
|
||
### Failure path
|
||
|
||
- First verify the board profile, USB mode, flash frequency, and partition layout.
|
||
- If Arduino Core is unstable on this board, repeat only this bring-up test with ESP-IDF before rejecting the board.
|
||
|
||
### Completion action
|
||
|
||
If all criteria pass, set this milestone to `DONE`, append its execution record, and change Milestone 002 from `BLOCKED` to `READY`.
|
||
|
||
---
|
||
|
||
## Milestone 002 — Prove the Wi-Fi, LittleFS, and HTTP vertical slice
|
||
|
||
**Status:** `BLOCKED`
|
||
**Depends on:** Milestone 001
|
||
|
||
### Objective
|
||
|
||
Prove the MVP's basic delivery path: home Wi-Fi, LittleFS, and HTTP served directly by the ESP32.
|
||
|
||
### Work
|
||
|
||
- Connect the board to a predefined home Wi-Fi network in station mode.
|
||
- Keep Wi-Fi credentials in a local configuration file excluded from version control.
|
||
- Implement automatic reconnection after a temporary Wi-Fi outage without a manual reset.
|
||
- Mount LittleFS and upload test `index.html`, CSS, and JavaScript files.
|
||
- Implement `GET /`, static asset delivery, and `GET /api/health`.
|
||
- Return uptime, Wi-Fi state, RSSI, free heap, minimum free heap, and build version from `/api/health`, without exposing secrets.
|
||
- Open the page from at least one phone and one tablet or second client device on the same network.
|
||
- Verify MIME types, gzip delivery for static assets, and appropriate cache headers.
|
||
|
||
### Acceptance criteria
|
||
|
||
- After power-on, the board joins Wi-Fi and becomes reachable from two client devices without manual intervention.
|
||
- The page and all assets load locally without a CDN or internet access.
|
||
- After the router or Wi-Fi connection is interrupted and restored, the board becomes reachable again without reflashing or a user-triggered reset.
|
||
- `/api/health` remains responsive during repeated page reloads.
|
||
- A LittleFS mount failure is visible in the serial log and does not cause an endless reboot loop.
|
||
- Measured firmware, filesystem, and heap usage are recorded.
|
||
|
||
### Blocking conditions
|
||
|
||
- Wi-Fi or HTTP repeatedly hangs and cannot recover in software.
|
||
- The filesystem cannot hold the minimum interface while retaining safe space for firmware growth.
|
||
|
||
### Completion action
|
||
|
||
If all criteria pass, set this milestone to `DONE`, append its execution record, and change Milestone 003 from `BLOCKED` to `READY`.
|
||
|
||
---
|
||
|
||
## Milestone 003 — Prove real-time transport, fallback, and state isolation
|
||
|
||
**Status:** `BLOCKED`
|
||
**Depends on:** Milestone 002
|
||
|
||
### Objective
|
||
|
||
Prove that the selected server stack works on ESP32-C6 and validate WebSocket delivery, HTTP fallback, versioning, and role-specific state before implementing game logic.
|
||
|
||
### Work
|
||
|
||
- Select and pin an HTTP/WebSocket library version compatible with the pinned Arduino Core and ESP32-C6.
|
||
- Implement a test state containing a monotonically increasing `version`, public data, and simulated hidden data.
|
||
- Add WebSocket endpoint `/ws`, role-specific state snapshots, and `GET /api/state?version=N`.
|
||
- In the test page, retry WebSocket after 1, 2, 5, and 10 seconds and poll HTTP every 2 seconds while WebSocket is unavailable.
|
||
- Connect two player clients and at least two spectator clients simultaneously.
|
||
- Deliberately interrupt WebSocket, verify the transition to HTTP polling, and then restore WebSocket.
|
||
- Inspect player and spectator traffic to confirm that simulated hidden data is absent.
|
||
- Limit incoming message size and reject malformed JSON without crashing or leaking memory.
|
||
|
||
### Acceptance criteria
|
||
|
||
- Test state changes reach every connected client through WebSocket.
|
||
- While WebSocket is unavailable, clients receive current state through HTTP within approximately one polling interval.
|
||
- After WebSocket recovers, polling stops and each client receives the current `version` without losing state.
|
||
- Hidden data is absent from HTTP responses, WebSocket messages, and client-side source files.
|
||
- Malformed and oversized messages are rejected while the server remains responsive.
|
||
- A 30-minute run with four clients completes without hangs, restarts, or a persistent downward trend in free heap.
|
||
|
||
### Fallback path
|
||
|
||
If the asynchronous server library is unstable with the pinned Arduino Core, repeat only this vertical slice with ESP-IDF and `esp_http_server`. Keep the protocol and acceptance criteria unchanged.
|
||
|
||
### Completion action
|
||
|
||
If all criteria pass, set this milestone to `DONE`, append its execution record, and change Milestone 004 from `BLOCKED` to `READY`.
|
||
|
||
---
|
||
|
||
## Milestone 004 — Prove MVP capacity and make the Go/No-Go decision
|
||
|
||
**Status:** `BLOCKED`
|
||
**Depends on:** Milestone 003
|
||
|
||
### Objective
|
||
|
||
Test the expected worst-case MVP workload before investing in the complete game engine and user interface.
|
||
|
||
### Work
|
||
|
||
- Create a compact mock state for one game: two 10 × 10 boards, 20 ships, two player sessions, eight spectator sessions, statistics, and protocol metadata.
|
||
- Generate separate safe views for player 1, player 2, and spectators without keeping a complete JSON copy for every client at the same time.
|
||
- Connect two client devices and eight spectator connections. A local load script may simulate some spectator connections.
|
||
- Simulate a game start and at least 200 state changes with WebSocket broadcasts and HTTP polling from a subset of clients.
|
||
- Run at least 20 consecutive simulated games without rebooting the board.
|
||
- Record firmware and LittleFS sizes, current and minimum free heap, maximum JSON message size, state generation and delivery time, reconnection count, and reset reasons.
|
||
- Test recovery after Wi-Fi loss, client reconnections, and a sequence of malformed requests.
|
||
- Document a **Go**, **Go with constraints**, or **No-Go** decision.
|
||
|
||
### Resource budgets
|
||
|
||
Before running the capacity test, define numerical limits based on the board specifications and evidence from Milestones 000–003 for:
|
||
|
||
- maximum firmware and static asset size;
|
||
- minimum acceptable free-heap reserve;
|
||
- maximum HTTP or WebSocket message size;
|
||
- maximum API response and update-delivery time;
|
||
- acceptable error and restart count.
|
||
|
||
Do not adjust a threshold after seeing the result unless the execution record contains an explicit justification.
|
||
|
||
### Acceptance criteria
|
||
|
||
- Two players and eight spectators simultaneously receive the state intended for their roles.
|
||
- No client receives hidden opponent cells before the simulated game ends.
|
||
- Twenty simulated games complete without a hang, watchdog reset, or manual restart.
|
||
- After the tests, measured flash and heap reserves remain sufficient for `GameEngine`, `FleetGenerator`, `BotPlayer`, and the complete interface.
|
||
- Minimum free heap does not show a persistent game-to-game decline.
|
||
- State delivery recovers after Wi-Fi and WebSocket interruptions without rebooting the board.
|
||
|
||
### Decision rules
|
||
|
||
- **Go:** all acceptance criteria pass with sufficient measured resource reserves. Full game-engine implementation may begin.
|
||
- **Go with constraints:** the MVP is feasible only after reducing a nonessential target such as the spectator limit or interface size. Update `MVP.md` explicitly before further implementation.
|
||
- **No-Go for the current stack:** the board works, but the Arduino/server stack is unstable. Evaluate the ESP-IDF fallback.
|
||
- **No-Go for the board:** the fallback stack also fails the stability or resource criteria. Select a different board before implementing the complete game.
|
||
|
||
### Completion action
|
||
|
||
Set this milestone to `DONE` only for a documented **Go** decision. For any other decision, set it to `BLOCKED` and record the required scope or platform decision. Append every future milestone after this section without renumbering Milestones 000–004.
|