chore: checkpoint before lint autofix

This commit is contained in:
Sebastien L
2026-02-12 04:44:17 +00:00
parent 41c3056184
commit df225c120c
14 changed files with 795 additions and 14 deletions

View File

@@ -0,0 +1,44 @@
# Contract Test Template
Use this template when adding/refactoring tests to ensure they are refactor-resilient.
## Metadata
- Test ID:
- Module/Boundary:
- Priority (`P0`/`P1`/`P2`):
- Platform scope (`host`, `all`, `i2s`, `muse`, `squeezeamp`, etc.):
## Contract
Describe what externally visible behavior must remain true.
## Invariant(s)
List invariant properties this test protects.
## Inputs/Preconditions
- Required setup:
- Input variants:
- Fault conditions (if any):
## Expected Behavior
- Success conditions:
- Error conditions:
- Bounds/time/resource expectations:
## Non-goals
State what this test intentionally does not verify (to avoid implementation coupling).
## Refactor Resilience Check
- Would this still pass if internals were reorganized but behavior unchanged? (`yes`/`no`)
- If `no`, explain why coupling is unavoidable.
## Regression Linkage
- Related issue/bug (if regression test):
- Why this boundary was chosen:

View File

@@ -0,0 +1,130 @@
# Hardware Test Matrix
Date: 2026-02-12
Scope: Platform-specific stability and release validation for `squeezelite-esp32`.
## Purpose
Define a practical hardware-focused test strategy that complements host/unit tests and acknowledges embedded uncertainty under real-world load.
This matrix is designed to:
- maximize platform stability
- prioritize high-impact failures first
- provide clear release gates per hardware profile
Use together with:
- `documentation/TESTING_CHARTER.md`
- `documentation/CONTRACT_TEST_TEMPLATE.md`
## Platforms
Mapped to build profiles used in this repo:
- `i2s` -> `build-scripts/I2S-4MFlash-sdkconfig.defaults`
- `muse` -> `build-scripts/Muse-sdkconfig.defaults`
- `squeezeamp` -> `build-scripts/SqueezeAmp-sdkconfig.defaults`
## Priority Levels
- `P0`: release blocking, must pass
- `P1`: strong confidence tests, expected to pass before release
- `P2`: extended coverage/soak, required for nightly and milestone validation
## Execution Tiers
- PR smoke: fast subset (`P0` only, selected `P1`)
- Nightly: full `P0 + P1` and selected `P2`
- Pre-release: full matrix, all `P0/P1`, mandatory `P2` soak and fault-injection
## Core Hardware Matrix
| ID | Area | Test Path | Priority | Platforms | Pass Criteria |
|---|---|---|---|---|---|
| HW-BOOT-001 | Boot | Cold boot to operational state | P0 | all | boots successfully within target time budget; no panic/reset loop |
| HW-BOOT-002 | Boot | Warm reboot (`esp_restart`) loop x50 | P0 | all | no stuck boot, no boot partition confusion, stable counters |
| HW-BOOT-003 | Boot identity | Platform profile and key GPIO map sanity | P0 | all | expected `FW_PLATFORM_NAME`, expected peripheral init paths |
| HW-STOR-001 | Storage/NVS | NVS read/write/reset cycle | P0 | all | persisted values survive reboot, reset restores defaults |
| HW-STOR-002 | Storage/NVS | Corrupt/partial NVS handling | P1 | all | graceful recovery path, no crash, defaults restored or fallback used |
| HW-STOR-003 | SPIFFS | SPIFFS mount + defaults file read | P0 | all | mount succeeds, required files loaded, clear error if missing |
| HW-NET-001 | Wi-Fi | AP connect + DHCP + DNS | P0 | all | connected state reached, IP assigned, DNS query success |
| HW-NET-002 | Wi-Fi resilience | AP loss/recovery reconnect | P0 | all | reconnect within SLA, no task deadlock or watchdog |
| HW-NET-003 | Service discovery | mDNS announce/discover | P1 | all | service visible on LAN; no crash if mDNS unavailable |
| HW-NET-004 | Ethernet | Link up/down + DHCP + traffic | P1 | ethernet-capable | state transitions handled cleanly; no memory growth trend |
| HW-AUD-001 | Audio output | Start/stop playback, no signal path errors | P0 | all | successful init and playback lifecycle, no panic |
| HW-AUD-002 | Audio behavior | Format/rate transitions during playback | P1 | all | transitions without hard fault; bounded glitch behavior |
| HW-AUD-003 | Audio resilience | Underrun/rebuffer recovery | P1 | all | playback recovers, no runaway CPU or deadlock |
| HW-AUD-004 | Controls | Volume/mute/jack/speaker path checks | P1 | platform-specific | control actions reflected correctly in output state |
| HW-UI-001 | Inputs | Button/rotary/IR event mapping | P1 | platform-specific | expected commands dispatched; no ghost/repeat storm |
| HW-UI-002 | Display | Display init + update loop | P1 | display-capable | stable render/update path, no crash under repeated updates |
| HW-PWR-001 | Battery/charger | Battery telemetry and status logic | P1 | battery-capable | values in expected range; no invalid-state loop |
| HW-BT-001 | Bluetooth | Pair/connect/disconnect cycles | P1 | bt-enabled | stable lifecycle across repeated cycles |
| HW-BT-002 | Bluetooth resilience | BT stack restart/recovery | P2 | bt-enabled | stack recovers without reboot or hard fault |
| HW-OTA-001 | OTA | Happy-path OTA update | P0 | all | new image boots and reports expected version |
| HW-OTA-002 | OTA failure | Interrupted OTA (network/power cut) | P0 | all | safe fallback/rollback path works; device recoverable |
| HW-OTA-003 | Recovery partition | Recovery boot and exit path | P0 | all | recovery mode entry/exit consistent and deterministic |
| HW-PWRF-001 | Power fault | Brownout/power-cut during write/OTA | P0 | all | no bricking; deterministic recovery behavior |
| HW-SOAK-001 | Soak | 12h playback + periodic reconnect | P2 | all | no crash/reset; memory trend within threshold |
| HW-SOAK-002 | Soak | 24h mixed load (stream/control/network churn) | P2 | all | no regressions in responsiveness and stability |
## Platform-Specific Focus
## `i2s` (generic baseline)
- Emphasize:
- audio path stability under varied sample rates
- generic GPIO/peripheral defaults
- OTA + recovery baseline behavior
- Required:
- all `P0`
- `HW-AUD-002`, `HW-AUD-003`, `HW-SOAK-001`
## `muse` (portable/battery-centric)
- Emphasize:
- battery telemetry, charger events, low-power edge conditions
- UI/display responsiveness under battery/network churn
- Wi-Fi reconnect after sleep-like or low-power transitions
- Required:
- all `P0`
- `HW-PWR-001`, `HW-UI-001`, `HW-UI-002`, `HW-SOAK-001`
## `squeezeamp` (amp/control-centric)
- Emphasize:
- amplifier-related controls, output routing, jack/speaker transitions
- thermal/long-play stability proxies (extended playback)
- network resilience during active playback
- Required:
- all `P0`
- `HW-AUD-004`, `HW-NET-002`, `HW-SOAK-001`, `HW-SOAK-002`
## Release Gates
A release is eligible only if:
- every target platform passes all `P0` tests
- no unresolved regression in previously passing `P1` tests
- at least one `P2` soak run per platform completed within release window
- OTA/recovery tests (`HW-OTA-001/002/003`) pass on all platforms
## Observability Requirements During Tests
Collect at minimum:
- reset reason, panic reason, boot count, recovery boot count
- heap free/minimum and largest block trend
- task stack high-water marks for critical tasks
- network reconnect counters and durations
- OTA stage/result events
A test can be marked "pass with warning" only for non-`P0` tests and only with a filed follow-up issue and owner.
## Failure Triage Rules
- `P0` fail: immediate release block
- repeated `P1` fail on same platform: treat as release risk, escalate to block unless waived
- any soak fail with crash/reset: open defect with logs and reproduction steps before next release candidate
## Suggested First Implementation Wave
1. Automate all `P0` checks for each platform profile.
2. Add nightly `P1` network/audio/UI subset.
3. Add 12h soak (`HW-SOAK-001`) with telemetry capture and trend thresholds.
4. Expand to full pre-release matrix once stable signal quality is established.

View File

@@ -0,0 +1,64 @@
# Testing Charter
Date: 2026-02-12
Scope: `squeezelite-esp32` test design and review policy.
## Objective
Keep tests stable across refactors by validating behavior contracts and invariants, not implementation details.
## Grounding Rule
Tests must verify behavior that is expected to remain true after refactoring.
Tests should be rejected in review if they mainly assert internals that can change without changing user-visible or system-visible behavior.
## Contract-First Principles
1. Test module boundaries
- public function behavior
- state machine transitions
- error semantics
- resource/timing bounds where relevant
2. Prefer invariants over internals
- "must never crash on malformed input"
- "illegal state transition is rejected"
- "retry is bounded"
- "idempotent operation remains safe when repeated"
3. Avoid implementation coupling
- do not assert private helper call order unless behavior-critical
- do not assert exact logs/strings unless contractually required
- do not assert private data layout
4. Fixes require regression tests
- every production bug fix should add a regression test at the highest stable boundary that catches it
5. Embedded + host split
- host-native tests for deterministic logic
- hardware/HIL tests for timing, drivers, memory layout, OTA/recovery, power fault behavior
## Review Gate
Reviewers should ask:
1. What contract does this test protect?
2. Would this test still pass after a clean internal refactor with identical behavior?
3. Does this test provide failure signal that matters to users/platform stability?
If answers are weak, request a contract-level test instead.
## Minimum PR Expectations
- New behavior: at least one contract-level test
- Bug fix: at least one regression test
- Refactor-only PR: existing contract tests still pass, no new implementation-coupled tests added
## Mapping to Hardware Matrix
Use this charter with:
- `documentation/HARDWARE_TEST_MATRIX.md`
The charter governs *how* tests are written.
The matrix governs *where/what* is validated per hardware platform.

View File

@@ -0,0 +1,20 @@
# Agent Documentation
Store long-form guidance for coding agents here.
## Suggested Files
- `documentation/agents/architecture.md`: subsystem boundaries, data flow, invariants.
- `documentation/agents/build-and-test.md`: canonical commands, fast checks, CI mapping.
- `documentation/agents/style-and-lint.md`: formatting policy, lint severity, suppression rules.
- `documentation/agents/refactor-playbook.md`: safe refactor steps, rollout strategy, risk controls.
- `documentation/agents/frontend_requirements_context.md`: requirements-first UI context, size budgets, and migration constraints.
- `documentation/agents/module-notes/<module>.md`: module-level constraints and edge cases.
## Writing Rules
- Keep files operational and concrete.
- Prefer checklists and explicit commands.
- Record known pitfalls and non-obvious invariants.
- Link back from `AGENTS.md` only to docs that are actively maintained.
- When frontend payload/routes/contracts change, refresh the snapshot with `build-scripts/ui_footprint_snapshot.sh` and update `frontend_requirements_context.md`.

View File

@@ -0,0 +1,201 @@
# Frontend Requirements Context (Living)
Status: Active
Last reviewed: 2026-02-12
Review scope: `components/wifi-manager/webapp`, `components/wifi-manager/http_server_handlers.c`, `components/wifi-manager/wifi_manager_http_server.c`, `spiffs_src/CMakeLists.txt`
## Purpose
This document captures reverse-engineered **product requirements** for the embedded web UI, with measurable constraints.
It is intentionally not an implementation walkthrough.
Use this as session handoff context for UI refactoring and footprint control.
## Snapshot Findings (Current State)
### 1. What actually ships to firmware
SPIFFS packaging currently copies only:
- `components/wifi-manager/webapp/dist/*.gz`
- `components/wifi-manager/webapp/dist/*.png`
Evidence: `spiffs_src/CMakeLists.txt`.
Current shipped web payload:
- Total shipped bytes: `219741` (`~214.6 KiB`, `~0.21 MiB`)
- Largest asset: `dist/js/node_vendors.bundle.js.gz` (`166729` bytes)
### 2. What looks large but is not currently shipped
- `dist/` total is about `4.5M`, dominated by source maps (`*.map`).
- Source maps are large in repo artifacts, but not copied to SPIFFS by current packaging.
### 3. Major technical debt signal
- UI source references many legacy endpoints (`/status.zzz`, `/messages.zzz`, `/commands.zzz`, etc.).
- Active server registration in `wifi_manager_http_server.c` is centered on `/data.bin` + static handlers; many legacy handlers are commented out.
This indicates API/contract drift and unclear migration state.
### 4. Modularity and proto usage signal
- Main UI logic is largely monolithic in `src/js/custom.ts` (~2.5k LOC).
- `index.ts` imports generated protobuf bundle (`configuration_pb.js`) up front.
- `dist/js/index.bundle.js` includes many generated proto message definitions, not only request/response minimum set.
Implication: upfront JS parse/execute and bundle weight are likely higher than needed.
## Reverse-Engineered Product Requirements
These are the requirements we should preserve while refactoring.
### RQ-UI-001 Captive Portal Bootstrap
The UI must reliably open and render from AP/captive-portal entry points with no manual URL knowledge.
Acceptance:
- Landing page reachable from captive portal probes.
- First meaningful controls visible without requiring cloud services.
### RQ-UI-002 Network Onboarding and Recovery
Users must be able to scan APs, join/disconnect Wi-Fi, and understand current link mode (Wi-Fi vs Ethernet) with clear status.
Acceptance:
- Scan, connect, disconnect workflows remain available and understandable.
- Connection state transitions are visible and unambiguous.
### RQ-UI-003 Runtime Observability
Users must see operational status and logs needed for diagnosis (network, playback, OTA progress, errors).
Acceptance:
- Status view remains available in normal and recovery mode.
- Error and warning paths are visible in UI without dev tools.
### RQ-UI-004 Safe Configuration Editing
Users must be able to view/edit/apply configuration with guardrails (validation feedback, clear commit/apply behavior).
Acceptance:
- Config edit path supports both selective and global update actions.
- Validation errors are explicit before/after submit.
### RQ-UI-005 OTA Operations
Users must be able to trigger firmware update by URL or upload, with progress and failure feedback.
Acceptance:
- OTA action always yields deterministic status progression or explicit terminal error.
- Recovery path remains accessible if normal OTA path fails.
### RQ-UI-006 Advanced Control Access
Power-user controls (commands/NVS/diagnostics) must exist but should not degrade common-task UX.
Acceptance:
- Advanced functions remain accessible.
- Main tasks are not blocked by advanced UI complexity.
### RQ-UI-007 Backward Compatibility Envelope
The UI must support currently deployed firmware API variants during migration (legacy and protobuf-era endpoints), with explicit deprecation strategy.
Acceptance:
- Contract compatibility matrix is documented and tested.
- Legacy paths have clear sunset criteria.
### RQ-UI-008 Embedded Footprint Discipline
Web assets must stay within explicit firmware budget and be measurable in CI.
Acceptance:
- Shipping budget exists and is enforced.
- Size regressions fail checks unless explicitly approved.
## Non-Functional Budgets (Proposed)
These are targets, not yet enforced:
- `NB-001` Shipped web payload (`*.gz` + `*.png` in `dist/`) <= `180 KiB` target, `220 KiB` hard cap.
- `NB-002` Main JS gzip <= `120 KiB` target.
- `NB-003` Vendor JS gzip <= `120 KiB` target.
- `NB-004` No runtime dependency on external CDNs for critical UI function.
- `NB-005` One canonical API transport for new features (`/data.bin` protobuf), with compatibility shim for legacy endpoints during migration only.
## UX + Footprint Improvement Directions
Prioritized by impact/risk.
### P1 Contract Unification (High impact, medium risk)
- Define one frontend API client contract around protobuf request/response.
- Treat legacy `.zzz` paths as compatibility layer, not primary path.
- Add explicit compatibility table (firmware version -> supported endpoints).
### P2 Modularization by Capability (High impact, medium risk)
- Split monolithic UI logic into capability modules:
- onboarding
- status/logs
- config editor
- OTA
- advanced
- Lazy-load non-critical modules (advanced, release browser, heavy editors).
Expected result: lower startup JS cost and clearer ownership boundaries.
### P3 Proto Surface Minimization (High impact, medium risk)
- Stop importing broad generated config surface on initial load.
- Create thin protobuf DTO layer for startup-critical flows.
- Load heavy schema modules only when entering related screens.
### P4 UI Responsiveness and Clarity (Medium impact, low risk)
- Replace mixed polling patterns with a single scheduler and explicit backoff policy.
- Standardize in-progress/error/success state rendering across all actions.
- Reduce ambiguous icon-only cues with text fallback in constrained/offline contexts.
### P5 Build Output Hygiene (Medium impact, low risk)
- Keep generating sourcemaps for dev/debug if needed, but separate from shipping artifact workflow.
- Enforce shipped-size budget on what SPIFFS actually receives, not raw `dist/`.
## Living Maintenance Protocol
This file must be updated when any of the following changes:
- web routes/endpoints
- protobuf request/response schema used by UI
- shipped asset packaging rules
- significant UI feature flow
Required update steps:
1. Run `build-scripts/ui_footprint_snapshot.sh`.
2. Update Snapshot Findings and budget deltas in this file.
3. Update compatibility notes if API contract changed.
4. Add an entry to Decision Log.
## Decision Log
| Date | Decision | Why | Follow-up |
|------|----------|-----|-----------|
| 2026-02-12 | Treat this file as requirements-first context, not implementation notes | Reduce drift and speed up session handoffs | Add CI size gate and API contract checks |
## Open Questions
- Are legacy `.zzz` endpoints still required for deployed firmware versions, and for which versions exactly?
- Is the intended long-term model pure protobuf over `/data.bin` for all dynamic data?
- What startup latency target is acceptable on AP-mode captive portal connections?