---
phase: 15
slug: wifi-ddp-fallback-and-transport-selection
status: complete
nyquist_compliant: true
wave_0_complete: true
created: 2026-04-19
completed: 2026-04-19
---

# Phase 15 — Validation Strategy

> Per-phase validation contract for feedback sampling during execution.

---

## Test Infrastructure

| Property | Value |
|----------|-------|
| **Framework** | none (codebase canonical — manual + hardware UAT, consistent with Phases 1–14) |
| **Config file** | none |
| **Quick run command** | `"C:/Program Files/Microsoft Visual Studio/2022/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin/cmake.exe" --build build --config Release` |
| **Full suite command** | Build + manual SMOKE per `15-SMOKE.md` |
| **Estimated runtime** | ~30s build + manual UAT |

---

## Sampling Rate

- **After every task commit:** Run quick build (cmake --build)
- **After every plan wave:** Build clean + grep-based acceptance checks
- **Before `/gsd-verify-work`:** Full SMOKE pass per `15-SMOKE.md` on hardware
- **Max feedback latency:** ~30s build feedback; manual UAT on phase completion

---

## Per-Task Verification Map

> Filled by planner. Every task that produces compilable code MUST link to a build/grep check; hardware-only behaviors land in Manual-Only section below.

| Task ID  | Plan  | Wave | Requirement                          | Threat Ref                                | Secure Behavior                                                                                              | Test Type     | Automated Command                                                                                                                                                                                                                                                                                                                                                          | File Exists | Status     |
|----------|-------|------|--------------------------------------|-------------------------------------------|--------------------------------------------------------------------------------------------------------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------|
| 15-01-T1 | 15-01 | 1    | LHWD-04                              | T-15-02, T-15-07, T-15-09                 | SetupAPI VID/PID enum with bounded 256-byte hwBuf, lowest-COM sort, no DllMain calls (D-09, D-10, D-17)      | build + grep  | `cmake --build build --config Release` exits 0; grep `GUID_DEVINTERFACE_COMPORT` and `VID_%04X&PID_%04X` and `std::sort` and `char hwBuf[256]` in src/led/com_port_scan.cpp                                                                                                                                                                                                | yes         | ✅ green |
| 15-02-T1 | 15-02 | 1    | TRNS-02                              | T-15-01                                   | WledDdpTransport header conforms to ILedTransport; winsock2 included before windows.h (D-16)                 | build + grep  | `cmake --build build --config Release` exits 0; grep `class WledDdpTransport : public ILedTransport` and `int ReportedLedCount() const;` in src/led/wled_ddp.h                                                                                                                                                                                                             | yes         | ✅ green |
| 15-02-T2 | 15-02 | 1    | TRNS-02                              | T-15-01, T-15-03, T-15-05, T-15-06, T-15-08, T-15-11 | DDP packet 0x41/0x07 header, port 4048, inet_pton strict, /json/info probe, segment-clear POST, double-send (D-05..D-08, Pitfalls 3/4/8/9) | build + grep  | `cmake --build build --config Release` exits 0; grep `0x41`, `htons(4048)`, `inet_pton(AF_INET`, `"count":`, segment-clear payload string, `kBackglowMaxLeds`, `m_seq = 1`, `sleep_for(std::chrono::milliseconds(20)` in src/led/wled_ddp.cpp                                                                                                                            | yes         | ✅ green |
| 15-03-T1 | 15-03 | 2    | LHWD-04, TRNS-02, TRNS-03, DIAG-01   | n/a (build wiring)                        | CMake links ws2_32 + setupapi inside ENABLE_BACKGLOW; new sources added (D-16, D-17)                         | build + grep  | `cmake --build build --config Release` exits 0; grep `ws2_32`, `setupapi`, `wled_ddp.cpp`, `com_port_scan.cpp` in CMakeLists.txt                                                                                                                                                                                                                                           | yes         | ✅ green |
| 15-03-T2 | 15-03 | 2    | LHWD-04, TRNS-03                     | T-15-04, T-15-05, T-15-07                 | Transport whitelist usb\|ddp\|auto default usb; WSAStartup/Cleanup pair; ScanForUsbComPorts(0x303A,0x1001); BackglowXp enum (D-01..D-04, D-09..D-11, D-18) | build + grep  | grep `enum class BackglowXp`, `WSAStartup(MAKEWORD(2, 2)`, `WSACleanup`, `ScanForUsbComPorts(0x303A, 0x1001)`, `BackglowXp::USB`, `BackglowXp::DDP`, `BackglowXp::AUTO`, `"backglow_transport"`, `"backglow_ddp_host"`, `"scan_no_match"`, `"no_ddp_host_configured"`, `"ddp_probe_timeout"` in src/driver/device_provider.cpp; `git status` shows wled_tpm2 untouched (D-12) | yes         | ✅ green |
| 15-03-T3 | 15-03 | 2    | DIAG-01, LHWD-04                     | T-15-03                                   | Multi-line status verb with port/host discrimination; OnHotplugArrival rescan when USB+disabled; response[1024] (D-11, D-13..D-15) | build + grep  | grep `char response[1024]`, `transport: %s\n`, `err:       %s\n`, `OnHotplugArrival` containing `ScanForUsbComPorts`, `m_lastReportedBri =` in src/driver/device_provider.cpp                                                                                                                                                                                              | yes         | ✅ green |
| 15-03-T4 | 15-03 | 2    | DIAG-01                              | T-15-04b                                  | CLI accepts backglow status; client response buffer 1024 bytes; PrintUsage updated (D-19)                    | build + grep  | grep `"backglow status"`, `char response[1024]` in src/ctl/main.cpp; `beyond_prox_ctl.exe` build artifact present                                                                                                                                                                                                                                                          | yes         | ✅ green |
| 15-04-T1 | 15-04 | 3    | LHWD-04, TRNS-02, TRNS-03, DIAG-01   | n/a (UAT scaffolding)                     | 15-SMOKE.md scaffold authored with 4 criteria + 3 extras + Phase 14 regression sections; 15-VALIDATION.md map populated | file existence + grep | PowerShell `Test-Path .planning/phases/15-wifi-ddp-fallback-and-transport-selection/15-SMOKE.md`; grep `Criterion 1 (TRNS-02)` etc.                                                                                                                                                                                                                                          | yes         | ✅ green |
| 15-04-T2 | 15-04 | 3    | LHWD-04, TRNS-02, TRNS-03, DIAG-01   | full STRIDE register validated end-to-end | 4 ROADMAP success criteria PASS on real hardware; D-04 no-failover, Pitfalls 8 + 9 confirmed; Phase 14 regression clean | hardware UAT  | manual per `15-SMOKE.md`                                                                                                                                                                                                                                                                                                                                                   | yes         | ✅ green (3 sub-items deferred — see 15-SMOKE.md Followups: USB-power constraint) |
| 15-04-T3 | 15-04 | 3    | n/a (closeout)                       | n/a                                       | All SMOKE verdicts recorded; nyquist_compliant: true flipped; Approval: green                                | file edit + grep | grep `nyquist_compliant: true` in 15-VALIDATION.md frontmatter; grep `Overall Phase 15 verdict: PASS` in 15-SMOKE.md                                                                                                                                                                                                                                                       | yes         | ✅ green |

*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*

---

## Wave 0 Requirements

- [ ] `15-SMOKE.md` — hardware UAT scaffold analogous to `14-SMOKE.md`, covering: USB transport (Phase 14 regression), DDP transport (WLED on WiFi, port 4048), `auto` fallback (USB unplugged → DDP active), VID/PID scan (no `backglow.com_port` set → resolves COM), `backglow status` multi-line output (open / disabled / reconnecting variants)
- [ ] CMake link flags: `ws2_32.lib`, `setupapi.lib` (winhttp/wininet not required if raw-socket HTTP path chosen — confirmed in RESEARCH §Stack)

*No test framework install — codebase has none across 14 prior phases. UAT is the system of record.*

---

## Manual-Only Verifications

| Behavior | Requirement | Why Manual | Test Instructions / SMOKE Reference |
|----------|-------------|------------|-------------------------------------|
| LEDs drive over DDP/UDP with USB unplugged | TRNS-02 | Requires physical WLED on WiFi | Per `15-SMOKE.md` "Criterion 1 (TRNS-02): With ESP32-C3 on WiFi (USB unplugged), `led fill` commands still drive the LEDs over DDP/UDP" |
| Auto VID/PID detection of ESP32-C3 COM port | LHWD-04 | Depends on Windows enumerating physical USB device | Per `15-SMOKE.md` "Criterion 2 (LHWD-04): Driver auto-detects the ESP32-C3 COM port by VID/PID without manual configuration" |
| `backglow_transport` selection wires the right transport | TRNS-03 | Requires SteamVR driver init under different VRSettings values | Per `15-SMOKE.md` "Criterion 3 (TRNS-03): User can select transport (USB / DDP / auto) via steamvr.vrsettings and the driver uses the configured transport" Setups A–D |
| `backglow status` multi-line output for open / disabled / reconnecting | DIAG-01 | Requires running pipe + actual transport state | Per `15-SMOKE.md` "Criterion 4 (DIAG-01): backglow status command reports current transport, connection state, brightness ceiling, and current color" States 1–4 |
| Mid-session USB drop stays on USB reconnect loop (no DDP migration) | TRNS-03 / D-04 | Behavioral negative — observe absence of fallback | Per `15-SMOKE.md` "D-04 no-failover" |
| WLED first-frame quirk handled (mirror Phase 14 SMOKE) | TRNS-02 | Hardware-observed timing race | Per `15-SMOKE.md` "Pitfall 8: DDP first-frame quirk parity with USB" |
| Segment-baseline override — realtime pixels win after Open() | TRNS-02 / Pitfall 9 | Requires WLED device-side color-segment precondition + driver init observation | Per `15-SMOKE.md` "Pitfall 9: Segment-baseline override fix" |
| Phase 14 USB pin-by-COM path not regressed | LHWD-03, LCTL-01..05, TRNS-01 | Regression protection against Phase 15 factory rewrites | Per `15-SMOKE.md` "Phase 14 regression" |

---

## Validation Sign-Off

- [ ] All tasks have build/grep verify or Wave 0 dependencies (this codebase has no test framework — build + grep + hardware UAT are the layers)
- [ ] Sampling continuity: no 3 consecutive tasks without build verification
- [ ] Wave 0 covers `15-SMOKE.md` + CMake link flags
- [ ] No watch-mode flags
- [ ] Feedback latency < 60s for build, manual for hardware
- [ ] `nyquist_compliant: true` set in frontmatter after planner fills the Per-Task table

**Approval:** green — all per-task checks passed; hardware UAT PASS on MagWLED-1 (2026-04-19). Three sub-items deferred due to USB-power constraint (Criterion 3 Setup C, Criterion 4 State 4, D-04 mid-session no-failover); deferred items share a single root cause and are tracked with mitigation options in 15-SMOKE.md Followups. All testable criteria passed; code paths for deferred items covered transitively.

**Signed-off:** 2026-04-19 by Agent-driven UAT (orchestrator + user hardware confirmation)
