---
gsd_state_version: 1.0
milestone: v1.6
milestone_name: Feature Migration
status: executing
stopped_at: Phase 10 complete (UAT signed agent scope; verifier 7/7 PASS); operator-only D-25 items remain for separate human pass
last_updated: "2026-05-10T20:50:00.000Z"
last_activity: 2026-05-10 -- Phase 10 Wave 7 sign-off + UX-FAIL-PILL-EARLY-RETURN gap closure (commits 08bab96, 1d380e8)
progress:
  total_phases: 7
  completed_phases: 6
  total_plans: 34
  completed_plans: 34
  percent: 86
---

# Project State

## Project Reference

See: .planning/PROJECT.md (updated 2026-04-30 with v1.6 Feature Migration milestone)

**Core value:** Covering the microphone reliably toggles the SteamVR dashboard, invisibly to the rest of VR — no controller beam, no extra hardware, no focus loss.
**Current focus:** Phase 11 — Documentation (next to plan)

## Current Position

Phase: 10 (cutover-cleanup) — COMPLETE (UAT signed agent scope 2026-05-10; verifier 7/7 PASS; operator-only D-25(1 phys, 2, 3, 7, 11, 14) deferred to operator hardware pass)
Next: `/gsd-discuss-phase 11` — Documentation (DOC-01, DOC-02)
Plan: 8 of 8 done on Phase 10; Phase 11 not yet planned
Status: Ready to plan Phase 11
Last activity: 2026-05-10 -- Wave 7 sign-off + UX-FAIL-PILL-EARLY-RETURN gap closure

## Roadmap Summary

7 phases for v1.6 (continues numbering from v1.5 which ended at Phase 4):

| Phase | Name | Requirements | Research Flag |
|-------|------|--------------|---------------|
| 5 | Shared Library Extraction | LIB-01, LIB-02, LIB-03 | STANDARD |
| 6 | Driver-Side Audio Capture Spike | MIG-01 | NEEDS VALIDATION (WASAPI in DLL host) |
| 7 | Driver-Side Detection Thread | MIG-02, MIG-03, MIG-04, MIG-06 | STANDARD threading; NEEDS VALIDATION HMD sleep/wake |
| 8 | IPC Contract Reshape | IPC-01..08, HEALTH-01..07, LIB-04 | STANDARD |
| 9 | Training Migration | TRAIN-01..06, TEST-04 | NEEDS VALIDATION (training UX commit/discard) |
| 10 | Cutover & Cleanup | MIG-05, FAIL-01..05, HEALTH-08, TEST-01, TEST-02, TEST-03, TEST-05, INST-09 | STANDARD |
| 11 | Documentation | DOC-01, DOC-02 | STANDARD |

Coverage: 45/45 v1.6 requirements mapped. No orphans, no duplicates.

## Accumulated Context

### Decisions

Full log lives in PROJECT.md Key Decisions table.

Decisions affecting v1.6 roadmap:

- **Phase numbering continues from v1.5.** v1.5 ended at Phase 4 (Installer); v1.6 starts at Phase 5 — no reset.
- **Phase 5 must be first.** Shared lib is the keystone refactor; without it every later phase duplicates code or breaks the `mic_test.exe` headless invariant.
- **Phase 6 isolates the highest-risk unknown.** WASAPI inside vrserver DLL host is validated once in sister project `bey-closer-t1` but not in this driver — real-hardware spike on Bigscreen Beyond + Win11 Pro is mandatory before Phase 7. Behind `enableDriverAudio` flag, default OFF.
- **Driver-as-sole-writer for `config.json` and `training_data.bin`.** File-watching from the driver rejected (Pitfall 5 — torn reads, no rejection path). Settings flow exclusively through `PUT /settings`.
- **`POST /button` and `IDriverClient::tap()` survive until Phase 10.** Provides rollback path during phased migration; deletion is the cutover.
- **v1.5 SVR-05 invariant preserved.** HTTP-thread → CommandQueue → RunFrame is still the only path that touches OpenVR API. Detection thread becomes a new producer for the same CommandQueue; the boundary is unchanged.
- **Phase 5 (Documentation) carryover from v1.5 rolled into v1.6 as Phase 11** — DOC-01/DOC-02 re-scoped against the post-migration architecture.
- 06-01: Wave 0 RED scaffold uses skip-on-NOT-EXISTS lint branch + EXISTS-gated test source list so cmake configure stays clean while build-time missing-include diagnostic remains the Nyquist gate
- 06-02: AudioWorker class — Pitfall 1 apartment-trick (D-04) by constructing WASAPIAudioCapture on the worker thread; weak_ptr<State> alive-flag callback (Pitfall 13/D-15/D-16); 2 s watchdog Stop() (D-13); RPC_E_CHANGED_MODE distinct log line (D-06/SC2)
- 06-02: SafeDriverLog Rule-3 fix — guard on vr::VRDriverContext() before vr::VRDriverLog() so headless tests do not crash before VR_INIT_SERVER_DRIVER_CONTEXT
- 06-03: forward-decl class AudioWorker in device_provider.hpp rather than including audio_worker.hpp — mirrors HttpServer/CommandQueue pattern; complete type only needed in device_provider.cpp where ~DeviceProvider is defined
- 06-03: AudioWorker construction LAST in Init (after httpServer_->Start) and audioWorker_.reset() FIRST in Cleanup (before httpServer_->Stop) — D-13 reverse-order teardown enforced by explicit Cleanup() sequence not by member declaration order
- 06-03: D-14 fail-soft semantics — AudioWorker::Start() failure resets the unique_ptr but Init still returns VRInitError_None so the v1.5 HTTP/CommandQueue/HMD trigger path stays alive even when audio capture cannot start
- 06-04 Task 1: scaffold .planning/phases/06-driver-side-audio-capture-spike/06-UAT.md from PLAN interfaces template (Tested 2026-05-02, Driver SHA 8ace4e7, Rig/Operator placeholders); toggle default.vrsettings.driver_micmap.enable_driver_audio false → true for D-17(1)-(3) live runs (Task 3 restores to false per D-19/D-20 — shipped default OFF on main)
- 09-04: vendored dr_wav v0.14.6 @ 243e26ffa (public-domain / MIT-0) under vendor/dr_wav/; landed apps/mic_test/src/wav_replay.{hpp,cpp} (decode + downmix + linear-resample + JSON output, headless, kBlockFrames=480, dt-pure D-34 determinism); 9 replay CLI flags via tryRunReplayCli() short-circuit at top of WinMain (mic_test stays Win32 GUI binary); seed corpus (3 WAVs + manifest + README + tools/gen-replay-corpus.py); mic_test_replay_corpus ctest registered in tests/CMakeLists.txt Wave 1 (09-04) block; AssertReplayNoVrApi clean
- 09-04 deviation: T-09-04-01 declared-duration DoS gate (peekWavHeader pre-scan recovers declared chunk size before dr_wav clamps to file size — closes the truncated-1-hour-header attack)
- 09-04 deviation: profile-deferred CI corpus invocation — positive_001's 1-trigger expectation requires a trained profile; current ctest does NOT pass --expect-triggers-from; manifest stays in repo as contract for future plan that ships seed_profile.bin
- 09-03: SINGLE-WRITER CUTOVER — deleted v1.5 client-side training body in apps/micmap/main.cpp (members isTraining/trainingSampleCount; audio-callback addTrainingSample block; shutdown saveTrainingData; entire 953-1034 Training UI section); inserted endpoint-driven Training pane (Train/Cancel/Recompute/Confirm/Discard buttons) consuming IDriverApi training methods; wired GET /health full-envelope poll (driverAudioEnabled + driverTrainingActive atomics) onto the existing 1Hz pollDriverHealth tick; added 5Hz GET /training/progress poll with canonical finalize-success path (state==finalized → optimistic detector->loadTrainingData + "Profile saved" toast, ≤200ms latency); Discard Profile destructive modal under WR-03/WR-07 audioMutex; AssertNoClientTraining ctest GO-LIVE in tests/CMakeLists.txt Wave-3 block
- 09-03 deviation: Rule-3 lint narrowing — IDriverApi::startTraining shares its name with the v1.5 PatternTrainer::startTraining; the original AssertNoClientTraining bare-token regex `[^a-zA-Z0-9_]startTraining` matched both call surfaces. Tightened to `detector->X` qualifier-prefixed regex for all four entry points (addTrainingSample/finishTraining/startTraining/saveTrainingData) so the new driverClient->startTraining call is permitted while detector->startTraining remains forbidden. Sanity-checked: synthetic `void f() { detector->startTraining(); }` still FATALs; apps/mic_test/ allowlist still works

### Pending Todos

None — Phase 5 ready to plan.

### Blockers/Concerns

None blocking. Open questions to address during phase planning:

- **Phase 6 spike outcome:** if WASAPI fails inside the vrserver DLL host, escalate before Phase 7 begins. The whole architecture migration is predicated on this working.
- **Phase 9 training UX:** commit/discard pattern designed from first principles (no v1.5 prior art); validate with a real training session on hardware.
- **Phase 10 hmd_button_test.exe decision:** TEST-05 keeps it as a developer tool; confirm before cutover that this is still the right call given TEST-02 `--debug-trigger` overlap.
- **cpp-httplib v0.14.3 → v0.20.1 (CVE-2025-46728):** deferred to a standalone deps-refresh plan inside Phase 5; risk to wire format is low but non-zero.

## Deferred Items

Items carried forward from v1.5 that are NOT in v1.6 scope (see PROJECT.md and REQUIREMENTS.md "Future Requirements"):

| Category | Item | Status | Reason |
|----------|------|--------|--------|
| Backlog | OBS-01 — unified rotating log file (one file shared across driver+client) | candidate | Partially addressed by LIB-04 + TEST-03 (separate files); unification deferred |
| Backlog | HEALTH-D1 — per-component health badges with hover tooltips | deferred | Future GUI revamp milestone |
| Backlog | HEALTH-D2 — trigger-history sparkline | deferred | Future milestone |
| Backlog | TRAIN-D2 — A/B threshold preview | deferred | Future milestone |
| Backlog | TEST-D2 — `/debug/snapshot` driver endpoint | deferred | Future milestone |
| Backlog | UX-01 (in-app auto-start toggle), UX-02 (in-VR settings overlay) | deferred | Out of v1.6 scope — settings UX work belongs to a later milestone |
| Backlog | DIST-01/02/03 (installer launch checkbox, silent-install docs, non-default Steam path) | deferred | Out of v1.6 scope |
| Backlog | DET-01/02 (detection accuracy in noisy environments) | deferred | Out of v1.6 scope — orthogonal to migration |
| Backlog | cpp-httplib v0.14.3 → v0.20.1 bump (CVE-2025-46728) | candidate | Deferred to standalone deps-refresh plan |

## Session Continuity

Last session: 2026-05-10T08:53:07.045Z
Stopped at: Phase 10 context gathered
Resume file: .planning/phases/10-cutover-cleanup/10-CONTEXT.md

**Next action:** `/gsd-discuss-phase 10` — gather context for Cutover & Cleanup (MIG-05, FAIL-01..05, HEALTH-08, TEST-01..03/05, INST-09).

**Phase 6 spike outcome:** GO. WASAPI capture inside `vrserver.exe` DLL host on Bigscreen Beyond + Win11 Pro is feasible.
**Phase 7 outcome:** GO 2026-05-04 — in-process detection trigger path validated; HMD sleep/wake clean.
**Phase 8 outcome:** Done 2026-05-08 — UAT D-27 + D-28 signed; new IPC surface live; driver is sole `config.json` writer.
**Phase 9 outcome:** Done 2026-05-09 — driver is sole training writer; `mic_test --replay` corpus harness shipped.

**Phase 10 open question:** confirm `hmd_button_test.exe` retention (TEST-05) vs `--debug-trigger` overlap (TEST-02) before cutover.
