# Phase 14: USB Serial Foundation and LED Control - Discussion Log

> **Audit trail only.** Do not use as input to planning, research, or execution agents.
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.

**Date:** 2026-04-18
**Phase:** 14-usb-serial-foundation-and-led-control
**Areas discussed:** Pipe cmd syntax + format, Serial protocol (Adalight vs TPM2), Brightness ceiling + COM port UX, Hardware validation spike

---

## Pipe cmd syntax + format

### Q: Command prefix — `led` or `backglow`?

| Option | Description | Selected |
|--------|-------------|----------|
| led (Recommended) | Short, matches REQUIREMENTS spec + ARCH doc | |
| backglow | Matches `beyond_backglow_ctl.exe`, VRSettings keys, marketing name | ✓ |

**User's choice:** backglow

### Q: Color value encoding — hex string or decimal RGB triplets?

| Option | Description | Selected |
|--------|-------------|----------|
| Decimal triplets (Recommended) | `led fill 255 0 0`. Matches existing `ipd <mm>` decimal style | |
| Hex strings | `led fill FF0000`. More compact, matches ARCH doc | ✓ |

**User's choice:** Hex strings

### Q: How should multi-LED set work?

| Option | Description | Selected |
|--------|-------------|----------|
| fill (all) + set <i> (one) (Recommended) | Simple primitives covering LCTL-01/02 | |
| Add `led setall <r0> <g0> <b0> ...` | Single-shot full frame for streaming | |
| Both fill/set + setall | Maximum flexibility, more parser surface | |

**User's choice:** "fill + set, but have fill accept either one hex string-->sets all the same, OR ten hex strings-->sets all to different values simultaneously"
**Notes:** Polymorphic `fill` handles both uniform and per-LED. Single command name keeps pipe surface compact for Phase 16 OSC bridge.

### Q: Should a separate `led status` exist now (Phase 14) or wait for Phase 15?

| Option | Description | Selected |
|--------|-------------|----------|
| Defer to Phase 15 (Recommended) | DIAG-01 explicitly mapped to Phase 15. Keeps Phase 14 minimal | ✓ |
| Add minimal `led status` in Phase 14 | Useful for dev debugging | |

**User's choice:** Defer to Phase 15

---

## Serial protocol (Adalight vs TPM2)

### Q: Which serial protocol for per-LED color streaming?

| Option | Description | Selected |
|--------|-------------|----------|
| Adalight (Recommended) | Matches 3 of 4 research docs. Simpler 6-byte header | |
| TPM2 | PITFALLS doc claims better reliability under buffer-full | |
| Both behind ILedTransport | Adalight default, TPM2 selectable via VRSettings | |

**User's choice:** "adalight behind ILedTransport, for now. leave TPM as a stub just in case we need to try it later."
**Notes:** Pragmatic split — go with research consensus, keep escape hatch open with TPM2 stub class.

### Q: Use JSON-over-serial for non-streaming control or fold into binary protocol?

| Option | Description | Selected |
|--------|-------------|----------|
| JSON for ctl, binary for color (Recommended) | ARCH pattern. WLED auto-detects by first byte | ✓ |
| Binary-only (Adalight + brightness pre-baked into RGB) | Simpler firmware contract; loses access to WLED `bri` field | |

**User's choice:** JSON for ctl, binary for color

### Q: Baud rate — stay at 115200 or push higher?

| Option | Description | Selected |
|--------|-------------|----------|
| 115200 fixed (Recommended) | Plenty for 10 LEDs at 30fps. Avoids handshake. ESP32-C3 USB CDC ignores baud anyway | ✓ |
| Configurable via VRSettings (default 115200) | Future-proof for higher LED counts | |

**User's choice:** 115200 fixed

### Q: How is the writer thread driven — condition variable wakes or fixed 33ms tick?

| Option | Description | Selected |
|--------|-------------|----------|
| Condition variable + 33ms timeout (Recommended) | Wakes immediately on update, periodic tick fallback | ✓ |
| Fixed 33ms polling sleep | Simpler, always 0–33ms latency | |
| Fire-on-update only (no periodic tick) | Lowest CPU, no heartbeat | |

**User's choice:** Condition variable + 33ms timeout

---

## Brightness ceiling + COM port UX

### Q: How does user adjust the brightness ceiling?

| Option | Description | Selected |
|--------|-------------|----------|
| VRSettings only (Recommended) | `backglow.brightness_ceiling = 50`. No pipe command. Forces deliberate change | ✓ |
| Pipe command + VRSettings | `backglow ceiling <0-255>` for live tuning | |
| Pipe command only | Live-only, resets on driver reload | |

**User's choice:** VRSettings only

### Q: Semantics of `backglow bri <N>` relative to the ceiling?

| Option | Description | Selected |
|--------|-------------|----------|
| Clamps to ceiling, sent as WLED master `bri` (Recommended) | Driver clamps then sends `{"bri":clamped}` | ✓ |
| Clamps to ceiling, applied client-side to RGB | Driver multiplies RGB before Adalight | |
| Refuses values above ceiling (returns error) | Forces explicit ceiling change | |

**User's choice:** Clamps to ceiling, sent as WLED master `bri`

### Q: COM port config UX in Phase 14?

| Option | Description | Selected |
|--------|-------------|----------|
| VRSettings required, no scan (Recommended) | `backglow.com_port = COM5`. If absent or fails: log + disabled state | ✓ |
| VRSettings preferred, fall back to scan all COM ports | Pulls Phase 15 work forward | |
| Always scan, VRSettings = override only | Largest scope expansion | |

**User's choice:** VRSettings required, no scan

### Q: What happens when LED subsystem is disabled or COM port missing at startup?

| Option | Description | Selected |
|--------|-------------|----------|
| Silent disable + log INFO + recheck on hotplug (Recommended) | RegisterDeviceNotification, retry on plug | ✓ |
| Silent disable + log INFO, no recheck | User restarts SteamVR after plugging | |
| Retry connect every 5s in background | Polling, mirrors HidDevice cadence | |

**User's choice:** Silent disable + log INFO + recheck on hotplug

---

## Hardware validation spike

### Q: When to validate the two hardware risks (GPIO3, CDC framing)?

| Option | Description | Selected |
|--------|-------------|----------|
| Dedicated spike plan first (Recommended) | Plan 14.1: throwaway code, findings doc before main impl | ✓ |
| Inline in first impl plan | Build directly, treat first run as spike | |
| Skip — trust research | Accept risk of mid-phase rework | |

**User's choice:** Dedicated spike plan first

### Q: Spike scope — what specifically to verify? (multiSelect)

| Option | Description | Selected |
|--------|-------------|----------|
| WLED `'v'` round-trip + version parse | ~5 lines, confirms device + WLED responding | ✓ |
| Adalight 10-LED frame — visible color change | End-to-end proof; catches GPIO3 conflict | ✓ |
| Unplug/replug recovery (USB hotplug) | Validates ERROR_OPERATION_ABORTED handling | ✓ |
| JSON `{"bri":50}` over same port | Validates first-byte protocol detection | ✓ |

**User's choice:** All four

### Q: Spike artifacts — keep code or throw away?

| Option | Description | Selected |
|--------|-------------|----------|
| Throwaway in src/spike/ + findings doc (Recommended) | Mirrors existing src/spike/ pattern | ✓ |
| Productionize spike code into WledSerialTransport | Faster but risks shortcuts becoming load-bearing | |

**User's choice:** Throwaway in src/spike/ + findings doc

### Q: Plan 14.1 (spike) needed regardless, or fold spike into Plan 14.0 if scope is tiny?

| Option | Description | Selected |
|--------|-------------|----------|
| Separate Plan 14.1 spike (Recommended) | Atomic commit, parallels v2.0 Phase 10/10.1 | ✓ |
| Fold into Plan 14.0 | Less ceremony, mixes throwaway + production | |

**User's choice:** Separate Plan 14.1 spike

---

## Claude's Discretion

The following were not asked but are explicitly delegated to Claude / planning agents:
- Exact thread-shutdown ordering on `Cleanup()` (off frame → join writer thread vs. join → final off via main thread).
- Specific error code → log message mapping for serial errors.
- Whether the spike uses `FILE_FLAG_OVERLAPPED` from the start or starts synchronous.
- Internal `MAX_LEDS` constant location (controller header vs shared config header).
- Pipe response wording (e.g. `OK fill=FF8000 leds=10`).
- VRSettings key naming format under `driver_BeyondProximity` section.

## Deferred Ideas

User mentioned during discussion close:

- **Camera stream for agent-in-the-loop UAT during the v3.0 milestone.** View URL: https://vdo.ninja/?view=JYMW97gq. Captured in CONTEXT.md `<specifics>` and saved to project memory. Particularly useful for Plan 14.1 spike "visible color change" verification.

The following were already mapped to other phases by ROADMAP and not re-discussed:
- `backglow status` command → Phase 15
- VID/PID COM port auto-detect → Phase 15
- WiFi/DDP fallback → Phase 15
- VRChat OSC bridge → Phase 16
- Avatar prefab + reference world → Phase 17
