feat: introduce the network state model and secure persistent storage
This commit is contained in:
@@ -60,7 +60,7 @@ Evidence should include the exact test scenario, relevant logs, reset reasons, r
|
||||
|
||||
## Milestone 000 — Identify the board and lock the technical baseline
|
||||
|
||||
**Status:** `DONE`
|
||||
**Status:** `DONE`
|
||||
**Depends on:** none
|
||||
|
||||
### Objective
|
||||
@@ -908,7 +908,7 @@ If all criteria pass, set this milestone to `DONE` and append its execution reco
|
||||
- Next action: Milestone 018 is READY. Do not start Milestone 019.
|
||||
|
||||
|
||||
# Milestone 018 — Player Names Throughout the Game UI
|
||||
## Milestone 018 — Player Names Throughout the Game UI
|
||||
|
||||
**Status:** DONE
|
||||
**Depends on:** Milestone 017
|
||||
@@ -1124,7 +1124,7 @@ At completion, report:
|
||||
- Issues or deviations: No browser backend is available in this environment, so mobile, tablet, and laptop name-layout checks were verified from the responsive CSS rules rather than captured live. No device upload was performed.
|
||||
- Next action: Milestone 019 is not started.
|
||||
|
||||
# Milestone 019 — Amendment: Distinct Ship-Class Silhouettes and Red Sunk Markers
|
||||
## Milestone 019 — Amendment: Distinct Ship-Class Silhouettes and Red Sunk Markers
|
||||
|
||||
**Status:** DONE
|
||||
**Depends on:** Milestone 018
|
||||
@@ -1338,7 +1338,7 @@ After implementation, report:
|
||||
- Next action: Milestone 020 is not started.
|
||||
|
||||
|
||||
# Milestone 020 — Amendment: Recognizable Early-20th-Century Warship Silhouettes
|
||||
## Milestone 020 — Amendment: Recognizable Early-20th-Century Warship Silhouettes
|
||||
|
||||
**Status:** DONE
|
||||
**Depends on:** Milestone 019
|
||||
@@ -2124,7 +2124,7 @@ When all criteria pass, set Milestone 025 to `DONE`, append its execution record
|
||||
|
||||
## Milestone 026 — Validate Web Audio engagement, compatibility, and long-run stability on real devices
|
||||
|
||||
**Status:** `READY`
|
||||
**Status:** `DONE`
|
||||
**Depends on:** Milestone 025
|
||||
|
||||
### Objective
|
||||
@@ -2209,3 +2209,163 @@ Do not record children, collect identifying data, or conduct unsupervised testin
|
||||
### Completion action
|
||||
|
||||
When all criteria pass, set Milestone 026 to `DONE` and append its execution record. Add later milestones only after Milestone 026 without renumbering existing milestones.
|
||||
|
||||
### Execution record
|
||||
|
||||
- Date: 2026-09-01
|
||||
- Result: PASS.
|
||||
- Evidence: The user completed the required real-device validation with no issues found: the Android phone Chromium browser, Android tablet/second device, iPhone/iPad Safari when available, and laptop browser matrix; portrait and landscape; sound on/muted/quiet/normal/loud/reduced-intensity; WebSocket and HTTP polling fallback; explicit activation, preference persistence, immediate mute, target/shot/result/combo/recovery cues, background/foreground handling, reset behavior, spectator privacy, and silent fallback. The required 30-shot anti-repeat observation, 20 representative sound-enabled games, 60-minute mixed session, and adult-proxy child-engagement/safety review also passed without browser errors, stuck audio, audio-node/timer growth, transport regression, ESP32 instability, excessive loudness, frightening cues, or hidden-information leakage.
|
||||
- Measurements: Final validated browser assets remain 27,023 B gzip, within the 250,000 B LittleFS budget. Firmware remains 1,020,994 / 2,097,152 B flash (48.7%) and 39,604 / 327,680 B RAM (12.1%).
|
||||
- Next action: Milestone 027 remains blocked until explicitly requested.
|
||||
|
||||
## Milestone 027 — Introduce the network state model and secure persistent storage
|
||||
|
||||
**Status:** `DONE`
|
||||
**Depends on:** Milestone 026
|
||||
|
||||
### Objective
|
||||
|
||||
Create a testable foundation for switching between an external network and the fallback access point without coupling game logic to network callbacks.
|
||||
|
||||
### Work
|
||||
|
||||
- Define explicit states and transitions for startup without configuration, connection to the saved network, the 30-second connection window, access-point operation, validation of new credentials, successful switching, and reconnection after network loss.
|
||||
- Separate network control and credential persistence into dedicated components with bounded inputs.
|
||||
- Store one SSID/password pair in persistent memory using the facilities of the current ESP32 stack.
|
||||
- Implement loading, atomic replacement, and deletion of credentials; treat a corrupt or incomplete record as absent configuration.
|
||||
- Exclude the password from logs, API responses, and diagnostic structures.
|
||||
- Use non-blocking connection timing so that the game loop, HTTP/WebSocket handling, and watchdog are not stalled for 30 seconds.
|
||||
- Add automated tests for state transitions, timeouts, corrupt records, successful persistence, and deletion.
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
- The device selects fallback mode when no valid record exists.
|
||||
- With a valid record, the device starts a connection attempt and enables fallback after 30 seconds without success.
|
||||
- Loss of an established connection starts reconnection and the same 30-second fallback transition.
|
||||
- Failed validation of new credentials does not replace the previously saved configuration.
|
||||
- After successful validation, persistent storage contains only one current network profile.
|
||||
- Automated tests verify state transitions without a real 30-second wait and without depending on ESP32 radio hardware.
|
||||
- No test output, log, or API response exposes the password in plaintext.
|
||||
|
||||
### Completion action
|
||||
|
||||
When all criteria pass, set this milestone to `DONE` and change Milestone 006 to `READY`.
|
||||
|
||||
### Execution record
|
||||
|
||||
- Date: 2026-09-01
|
||||
- Result: PASS.
|
||||
- Evidence: Added a bounded, host-testable network state model for fallback, saved-network connection, 30-second timeout, validation, successful replacement, and reconnect transitions. Added versioned and checksummed credential records, an ESP-IDF NVS single-record store with committed replacement/deletion, and a host memory backend that exercises load, corruption rejection, replacement, and deletion without radio hardware. Credentials are not logged or included in an API/diagnostic structure.
|
||||
- Verification: `make -C test/host run` passed all 11 host suites, including `test_network_foundation`; `pio run -e esp32-c6-devkitm-1` passed with the three new firmware sources compiled.
|
||||
- Next action: Milestone 028 remains blocked and was not started.
|
||||
|
||||
---
|
||||
|
||||
## Milestone 028 — Implement the open fallback access point and captive portal
|
||||
|
||||
**Status:** `BLOCKED`
|
||||
**Depends on:** Milestone 027
|
||||
|
||||
### Objective
|
||||
|
||||
Give users access to the game and external-network configuration through the open `Battleship-open` network whenever the saved external connection is unavailable.
|
||||
|
||||
### Work
|
||||
|
||||
- Start an open access point with the exact SSID `Battleship-open` only in fallback mode.
|
||||
- Implement DNS redirection and captive-portal detection responses for supported phones and tablets.
|
||||
- Keep the configuration page available through the access point's direct local address when the captive-portal window does not open automatically.
|
||||
- Add a dedicated network configuration screen served entirely by the ESP32 without a CDN or internet dependency.
|
||||
- Display Wi-Fi scan results and support manual entry of a hidden SSID.
|
||||
- Bound SSID length, password length, and request-body size; handle empty, oversized, and incorrectly encoded values safely.
|
||||
- Do not include the password in redisplayed data, API responses, or page state.
|
||||
- Keep the game HTTP/WebSocket interface available through the fallback network.
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
- A phone can discover the open network with the exact name `Battleship-open` and connect without a password.
|
||||
- The captive portal opens the local configuration page on the tested target devices; the direct local address remains a working fallback for the client.
|
||||
- The network list can be refreshed without stalling the server, and a hidden SSID can be entered manually.
|
||||
- Invalid and oversized requests are rejected without a restart or a persistent memory leak.
|
||||
- Two players and the spectator capacity established by Milestone 004 can open the game interface through the access point within the confirmed resource limits.
|
||||
- The password does not appear in HTML, JSON, WebSocket messages, or logs.
|
||||
|
||||
### Completion action
|
||||
|
||||
When all criteria pass, set this milestone to `DONE` and change Milestone 007 to `READY`.
|
||||
|
||||
---
|
||||
|
||||
## Milestone 029 — Validate credentials, persist them, and switch without rebooting
|
||||
|
||||
**Status:** `BLOCKED`
|
||||
**Depends on:** Milestone 028
|
||||
|
||||
### Objective
|
||||
|
||||
Complete the configuration flow: validate a new network, save it only after success, and switch to it without rebooting the device.
|
||||
|
||||
### Work
|
||||
|
||||
- Add operations for retrieving network status, starting a scan, validating new credentials, and deleting saved configuration.
|
||||
- Make the configuration screen available without authorization through both the fallback access point and the regular web interface.
|
||||
- During validation, preserve a usable path back to the configuration page until the result is known.
|
||||
- After a successful connection, persist the profile, report success to the browser, disable the fallback access point, and continue on the external network without rebooting.
|
||||
- After a failed attempt, preserve the saved profile and keep a configuration path available for another attempt.
|
||||
- After deleting the profile, enter fallback mode and ensure the deleted values are not restored after reboot.
|
||||
- Prevent conflicting scan, validation, deletion, and mode-switch operations from running concurrently.
|
||||
- Add clear Russian-language UI states for scanning, connecting, success, failure, and retry.
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
- Valid credentials are verified, saved, and used without rebooting the ESP32.
|
||||
- New credentials are absent from persistent storage until validation succeeds.
|
||||
- An incorrect password or unavailable SSID does not destroy the previously working configuration.
|
||||
- The browser receives confirmation before the fallback access point is disabled, along with instructions for reopening the game on the external network.
|
||||
- Configuration and deletion work through both agreed paths and require no token or other authorization.
|
||||
- Repeated and concurrent requests lead to a deterministic state without corrupting storage or blocking the server.
|
||||
- After configuration deletion and a cold reboot, the device starts `Battleship-open`.
|
||||
|
||||
### Accepted security limitation
|
||||
|
||||
Any client with network access to the device can change or delete its Wi-Fi configuration without authorization. User documentation must state this agreed behavior and explain that the open access point and local HTTP connection do not protect the submitted password from a nearby network observer.
|
||||
|
||||
### Completion action
|
||||
|
||||
When all criteria pass, set this milestone to `DONE` and change Milestone 008 to `READY`.
|
||||
|
||||
---
|
||||
|
||||
## Milestone 030 — Verify recovery, game continuity, and resource stability
|
||||
|
||||
**Status:** `BLOCKED`
|
||||
**Depends on:** Milestone 029
|
||||
|
||||
### Objective
|
||||
|
||||
Prove on the target ESP32-C6 Mini that configuration survives reboot, fallback works during failures, and the current game survives network-mode transitions.
|
||||
|
||||
### Work
|
||||
|
||||
- Test a cold boot both without configuration and with a previously saved working configuration.
|
||||
- During an active game, disable the external network, verify reconnection attempts, and confirm that `Battleship-open` appears after 30 seconds.
|
||||
- Reconnect clients through the fallback access point and continue the same game without resetting its in-memory state.
|
||||
- Configure a working external network through the fallback interface, wait for the no-reboot transition, and continue the same game after clients reconnect.
|
||||
- Test configuration changes and deletion through the regular web interface.
|
||||
- Test an incorrect password, hidden SSID, unavailable DHCP, disappearing network, corrupt stored record, and repeated mode transitions.
|
||||
- Repeat the Milestone 004 load scenario with the network state machine, DNS, and captive portal enabled; measure firmware size, minimum free heap, response time, reset reasons, and memory trends.
|
||||
- Update user documentation for first boot, configuration, the direct access address, network changes, credential deletion, fallback behavior, and the accepted security limitations.
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
- After a cold reboot, the device restores the connection from saved credentials without user action.
|
||||
- When the saved network is absent or unavailable, `Battleship-open` appears within the agreed time.
|
||||
- The active game's identifier, version, and state are not reset during transitions between the external network and fallback access point.
|
||||
- After reconnecting, browsers receive a current snapshot and can continue the game under the existing session rules.
|
||||
- Twenty cycles of network loss, fallback, and recovery complete without watchdog resets, unexpected reboots, or a persistent decline in free memory.
|
||||
- Resource measurements remain within the budgets established by Milestone 004, or any deviation is documented and approved separately before changing a budget.
|
||||
- The instructions allow a new user to configure the device without firmware-embedded Wi-Fi credentials.
|
||||
|
||||
### Completion action
|
||||
|
||||
Set this milestone to `DONE` only after documented automated and on-device verification and after adding an execution record in the format defined by the main plan.
|
||||
|
||||
Reference in New Issue
Block a user