mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2026-03-15 15:02:55 +03:00
chore: checkpoint before lint autofix
This commit is contained in:
@@ -1,14 +1,19 @@
|
||||
{
|
||||
"BasedOnStyle": "LLVM",
|
||||
"UseTab": "Never",
|
||||
"IndentWidth": 4,
|
||||
"TabWidth": 4,
|
||||
"ColumnLimit": 150,
|
||||
"PointerAlignment": "Left",
|
||||
"AlignAfterOpenBracket": "DontAlign",
|
||||
"BreakBeforeBraces": "Attach",
|
||||
"AllowShortIfStatementsOnASingleLine": true,
|
||||
"AllowShortFunctionsOnASingleLine": "All",
|
||||
"IndentCaseLabels": false,
|
||||
"SpacesBeforeTrailingComments": 1
|
||||
}
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
UseTab: Never
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
ColumnLimit: 150
|
||||
PointerAlignment: Right
|
||||
ReferenceAlignment: Pointer
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
BreakBeforeBraces: Attach
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
IndentCaseLabels: false
|
||||
SortIncludes: false
|
||||
SpaceBeforeParens: Never
|
||||
ReflowComments: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
|
||||
16
.clang-format-ignore
Normal file
16
.clang-format-ignore
Normal file
@@ -0,0 +1,16 @@
|
||||
# Third-party/vendor code
|
||||
components/codecs/inc/**
|
||||
components/esp-dsp/**
|
||||
components/esp_http_server/**
|
||||
components/spotify/cspot/**
|
||||
components/squeezelite/**
|
||||
components/telnet/libtelnet/**
|
||||
components/tjpgd/**
|
||||
managed_components/**
|
||||
|
||||
# Generated web artifacts
|
||||
components/wifi-manager/webapp/dist/**
|
||||
components/wifi-manager/webapp/src/js/proto/**
|
||||
|
||||
# Build outputs
|
||||
build/**
|
||||
33
.github/pull_request_template.md
vendored
Normal file
33
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
## Summary
|
||||
|
||||
- What changed:
|
||||
- Why it changed:
|
||||
|
||||
## Test Strategy Check (Required)
|
||||
|
||||
- [ ] I validated behavior at contract/module boundaries (not private implementation details).
|
||||
- [ ] New tests are refactor-resilient (should survive internal reorganization with identical behavior).
|
||||
- [ ] For bug fixes, I added at least one regression test at the highest stable boundary.
|
||||
- [ ] I avoided brittle assertions on internals (private helper call order, private layout, incidental log text), unless behavior-critical.
|
||||
|
||||
## Validation Performed
|
||||
|
||||
- [ ] Host/unit tests
|
||||
- [ ] Hardware/HIL tests (if applicable)
|
||||
- [ ] Platform profile(s) validated: `i2s` / `muse` / `squeezeamp` / N/A
|
||||
|
||||
Commands and results:
|
||||
```bash
|
||||
# paste exact commands used
|
||||
```
|
||||
|
||||
## Risk and Rollback
|
||||
|
||||
- Risk level: low / medium / high
|
||||
- Potential regressions:
|
||||
- Rollback plan:
|
||||
|
||||
## Related Docs
|
||||
|
||||
- [ ] `documentation/TESTING_CHARTER.md` reviewed
|
||||
- [ ] `documentation/HARDWARE_TEST_MATRIX.md` reviewed (if platform impact)
|
||||
32
.github/workflows/style-lint.yml
vendored
Normal file
32
.github/workflows/style-lint.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Style Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "refactoring"
|
||||
- "main"
|
||||
- "master-cmake"
|
||||
pull_request:
|
||||
branches:
|
||||
- "refactoring"
|
||||
- "main"
|
||||
- "master-cmake"
|
||||
|
||||
jobs:
|
||||
clang-format:
|
||||
name: clang-format
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install clang-format
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends clang-format
|
||||
|
||||
- name: Check style
|
||||
run: |
|
||||
build-scripts/lint_style.sh check
|
||||
94
AGENTS.md
Normal file
94
AGENTS.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# AGENTS.md
|
||||
|
||||
This file is the default startup brief for Codex sessions in this repository.
|
||||
Keep it short, directive, and high-signal.
|
||||
|
||||
## Mission
|
||||
|
||||
- Preserve platform behavior and stability.
|
||||
- Prefer small, reversible changes over broad rewrites.
|
||||
- Keep behavior unchanged unless a request explicitly asks for behavior changes.
|
||||
|
||||
## Working Scope
|
||||
|
||||
- Primary source code: `components/`, `main/`, `test/`.
|
||||
- Build and release scripts: `build-scripts/`, `docker/`, `.github/workflows/`.
|
||||
- Documentation: `documentation/`.
|
||||
|
||||
## Engineering Priorities
|
||||
|
||||
1. Correctness and safety.
|
||||
2. Backward-compatible behavior.
|
||||
3. Maintainability and clarity.
|
||||
4. Build/test reproducibility.
|
||||
5. Performance and footprint optimization.
|
||||
|
||||
Optimize in this order unless the task explicitly changes priorities.
|
||||
|
||||
## Do Not Edit By Default
|
||||
|
||||
- Vendor/external code:
|
||||
- `components/esp-dsp/`
|
||||
- `components/spotify/cspot/`
|
||||
- `components/telnet/libtelnet/`
|
||||
- `managed_components/`
|
||||
- Build outputs and generated artifacts:
|
||||
- `build/`
|
||||
- `components/wifi-manager/webapp/dist/`
|
||||
|
||||
Only modify these paths when the task explicitly requires it.
|
||||
|
||||
## Behavioral Invariants
|
||||
|
||||
- Treat OTA/recovery reliability as a product-level contract.
|
||||
- Treat partition layout as a fixed contract unless explicitly requested otherwise.
|
||||
- Do not introduce platform-specific compile-time branches when runtime/config solutions are sufficient.
|
||||
- Avoid unrelated churn; keep patches tightly scoped to the request.
|
||||
|
||||
## Standard Workflow
|
||||
|
||||
1. Read the request and identify touched modules and contracts.
|
||||
2. Inspect current code and existing patterns in those modules.
|
||||
3. Implement the smallest coherent patch that preserves contracts.
|
||||
4. Run targeted validation commands.
|
||||
5. Report changes, validation evidence, and residual risks.
|
||||
|
||||
## Validation Commands
|
||||
|
||||
- Style check: `build-scripts/lint_style.sh check`
|
||||
- Style normalize: `build-scripts/lint_style.sh format`
|
||||
- Firmware build (example): `idf.py build`
|
||||
- Recovery footprint (platform-specific): `build-scripts/build_recovery_size.sh <platform|defaults-file> [build-dir]`
|
||||
|
||||
Use targeted checks first; avoid full-matrix builds unless requested.
|
||||
|
||||
## Testing Rule (Grounding)
|
||||
|
||||
- Tests should validate behavior contracts and invariants, not implementation details.
|
||||
- Prefer module-boundary and regression tests over private-internal assertions.
|
||||
- Every bug fix should include a regression test at the highest stable boundary possible.
|
||||
- Use:
|
||||
- `documentation/TESTING_CHARTER.md`
|
||||
- `documentation/CONTRACT_TEST_TEMPLATE.md`
|
||||
- `documentation/HARDWARE_TEST_MATRIX.md`
|
||||
|
||||
## Style Baseline
|
||||
|
||||
- Use repository formatting/lint settings as the source of truth.
|
||||
- Do not introduce style-only churn outside task scope unless requested.
|
||||
- During refactors, normalization is acceptable when intentionally planned.
|
||||
|
||||
## Frontend Context (Required)
|
||||
|
||||
- For any UI/API work involving `components/wifi-manager/webapp/` or `components/wifi-manager/http_server_handlers.c`, read:
|
||||
- `documentation/agents/frontend_requirements_context.md`
|
||||
- Treat that file as requirements-first context and keep it current.
|
||||
- When frontend payload, routes, or protobuf contract changes, run:
|
||||
- `build-scripts/ui_footprint_snapshot.sh`
|
||||
- Then update `documentation/agents/frontend_requirements_context.md` in the same change.
|
||||
|
||||
## Agent Docs Layout
|
||||
|
||||
- Keep this file concise and policy-focused.
|
||||
- Put detailed playbooks under `documentation/agents/`.
|
||||
- Add module-specific guidance in local `AGENTS.md` files when needed (closest file to changed code takes precedence).
|
||||
@@ -6,6 +6,7 @@ ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
clang-format \
|
||||
curl \
|
||||
git \
|
||||
git-lfs \
|
||||
|
||||
75
build-scripts/lint_style.sh
Normal file
75
build-scripts/lint_style.sh
Normal file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: build-scripts/lint_style.sh [check|format]
|
||||
|
||||
Commands:
|
||||
check Verify C/C++ style with clang-format (default)
|
||||
format Apply clang-format in place
|
||||
EOF
|
||||
}
|
||||
|
||||
MODE="${1:-check}"
|
||||
if [[ "$MODE" != "check" && "$MODE" != "format" ]]; then
|
||||
usage
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if ! command -v clang-format >/dev/null 2>&1; then
|
||||
echo "clang-format is required but was not found in PATH." >&2
|
||||
exit 127
|
||||
fi
|
||||
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
declare -a PATHSPECS=(
|
||||
"*.c"
|
||||
"*.h"
|
||||
"*.cc"
|
||||
"*.cpp"
|
||||
"*.hpp"
|
||||
":(exclude)build/**"
|
||||
":(exclude)managed_components/**"
|
||||
":(exclude)components/codecs/inc/**"
|
||||
":(exclude)components/esp-dsp/**"
|
||||
":(exclude)components/esp_http_server/**"
|
||||
":(exclude)components/spotify/cspot/**"
|
||||
":(exclude)components/squeezelite/**"
|
||||
":(exclude)components/telnet/libtelnet/**"
|
||||
":(exclude)components/tjpgd/**"
|
||||
":(exclude)components/wifi-manager/webapp/dist/**"
|
||||
":(exclude)components/wifi-manager/webapp/src/js/proto/**"
|
||||
)
|
||||
|
||||
mapfile -t FILES < <(git ls-files -- "${PATHSPECS[@]}" | grep -E '^(components|main|test)/.*\.(c|h|cc|cpp|hpp)$' || true)
|
||||
|
||||
if [[ ${#FILES[@]} -eq 0 ]]; then
|
||||
echo "No C/C++ files matched lint scope."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$MODE" == "format" ]]; then
|
||||
printf '%s\0' "${FILES[@]}" | xargs -0 -r clang-format -i
|
||||
echo "Formatted ${#FILES[@]} file(s)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
declare -a FAILING=()
|
||||
for file in "${FILES[@]}"; do
|
||||
if ! clang-format --dry-run --Werror "$file" >/dev/null 2>&1; then
|
||||
FAILING+=("$file")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#FAILING[@]} -gt 0 ]]; then
|
||||
echo "Style check failed in ${#FAILING[@]} file(s)."
|
||||
echo "First failing files:"
|
||||
printf ' - %s\n' "${FAILING[@]:0:30}"
|
||||
echo "Run: build-scripts/lint_style.sh format"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Style check passed for ${#FILES[@]} file(s)."
|
||||
45
build-scripts/ui_footprint_snapshot.sh
Normal file
45
build-scripts/ui_footprint_snapshot.sh
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(git rev-parse --show-toplevel)"
|
||||
DIST_DIR="$ROOT/components/wifi-manager/webapp/dist"
|
||||
|
||||
if [[ ! -d "$DIST_DIR" ]]; then
|
||||
echo "dist directory not found: $DIST_DIR" >&2
|
||||
echo "Build webapp first (e.g. npm run build in components/wifi-manager/webapp)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python - "$DIST_DIR" <<'PY'
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
from datetime import datetime, timezone
|
||||
|
||||
dist = sys.argv[1]
|
||||
|
||||
def rel(p):
|
||||
return os.path.relpath(p, start=os.getcwd())
|
||||
|
||||
all_files = [p for p in glob.glob(os.path.join(dist, "**", "*"), recursive=True) if os.path.isfile(p)]
|
||||
ship_files = [p for p in all_files if p.endswith(".gz") or p.endswith(".png")]
|
||||
|
||||
all_files_sorted = sorted([(os.path.getsize(p), p) for p in all_files], reverse=True)
|
||||
ship_sorted = sorted([(os.path.getsize(p), p) for p in ship_files], reverse=True)
|
||||
|
||||
print(f"Snapshot UTC: {datetime.now(timezone.utc).isoformat(timespec='seconds')}")
|
||||
print(f"Dist dir: {rel(dist)}")
|
||||
print("")
|
||||
print(f"All dist files: {len(all_files)}")
|
||||
print(f"All dist bytes: {sum(s for s, _ in all_files_sorted)}")
|
||||
print(f"Shipped files (*.gz + *.png): {len(ship_sorted)}")
|
||||
print(f"Shipped bytes: {sum(s for s, _ in ship_sorted)}")
|
||||
print("")
|
||||
print("Top 15 dist files:")
|
||||
for size, path in all_files_sorted[:15]:
|
||||
print(f"{size:9d} {rel(path)}")
|
||||
print("")
|
||||
print("Shipped files:")
|
||||
for size, path in ship_sorted:
|
||||
print(f"{size:9d} {rel(path)}")
|
||||
PY
|
||||
21
components/wifi-manager/webapp/AGENTS.md
Normal file
21
components/wifi-manager/webapp/AGENTS.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# AGENTS.md (Web UI)
|
||||
|
||||
Local guidance for work under `components/wifi-manager/webapp/`.
|
||||
|
||||
## Required Context
|
||||
|
||||
- Read `documentation/agents/frontend_requirements_context.md` before making UI/API changes.
|
||||
- Treat that document as the active requirements context (not just historical notes).
|
||||
|
||||
## Scope Rules
|
||||
|
||||
- Prioritize behavior and contract clarity over framework churn.
|
||||
- Do not edit `dist/` files manually.
|
||||
- Keep generated protobuf artifacts and API usage aligned with the active request/response contract.
|
||||
|
||||
## Maintenance Rules
|
||||
|
||||
- If routes, payload contracts, or shipped web asset sizes change:
|
||||
1. Run `build-scripts/ui_footprint_snapshot.sh`.
|
||||
2. Update `documentation/agents/frontend_requirements_context.md`.
|
||||
3. Add/update the decision log entry in that file.
|
||||
44
documentation/CONTRACT_TEST_TEMPLATE.md
Normal file
44
documentation/CONTRACT_TEST_TEMPLATE.md
Normal 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:
|
||||
130
documentation/HARDWARE_TEST_MATRIX.md
Normal file
130
documentation/HARDWARE_TEST_MATRIX.md
Normal 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.
|
||||
64
documentation/TESTING_CHARTER.md
Normal file
64
documentation/TESTING_CHARTER.md
Normal 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.
|
||||
20
documentation/agents/README.md
Normal file
20
documentation/agents/README.md
Normal 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`.
|
||||
201
documentation/agents/frontend_requirements_context.md
Normal file
201
documentation/agents/frontend_requirements_context.md
Normal 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?
|
||||
Reference in New Issue
Block a user