---
phase: 13-slider-persistence-hardening
plan: 01
subsystem: driver
tags: [steamvr, lighthouse_console, ipd, persistence, win32, createprocess]

requires:
  - phase: 12-steamvr-ipd-slider-ui
    provides: ApplyIpd shared helper, VREvent_IpdChanged auto-apply, m_fCurrentIpd tracking
provides:
  - IPD persistence to headset flash via lighthouse_console on SteamVR shutdown
  - ENABLE_IPD_PERSIST compile flag for build isolation
  - RunLighthouseCommand static helper following HMDUtility write_to_stdin pattern
affects: []

tech-stack:
  added: []
  patterns: [HMDUtility write_to_stdin pattern for lighthouse_console process spawning]

key-files:
  created: []
  modified:
    - CMakeLists.txt
    - src/driver/device_provider.h
    - src/driver/device_provider.cpp

key-decisions:
  - "Separate process invocations for download and upload (not single session) per HMDUtility pattern"
  - "Stdout ReadFile blocking for synchronization instead of file-polling"
  - "Capture startup IPD on first ApplyIpd call (not just Init) to handle VREvent_IpdChanged arrival"
  - "10s download timeout sufficient (actual ~2.5s observed in testing)"

patterns-established:
  - "RunLighthouseCommand: reusable static helper for any lighthouse_console command"

requirements-completed: [SLIDER-03, SLIDER-04, HARD-03]

duration: 45min
completed: 2026-04-05
---

# Phase 13: Slider Persistence and Hardening Summary

**IPD changes persist to headset flash via lighthouse_console download-modify-upload cycle on SteamVR shutdown, with compile-time isolation behind ENABLE_IPD_PERSIST flag**

## Performance

- **Duration:** ~45 min (including 2 bug-fix iterations and 4 deploy/test cycles)
- **Started:** 2026-04-05T21:40:00Z
- **Completed:** 2026-04-05T22:25:00Z
- **Tasks:** 2
- **Files modified:** 3

## Accomplishments
- PersistIpdToConfig() writes IPD to headset flash via lighthouse_console on SteamVR shutdown
- Change detection skips persistence when IPD unchanged during session
- All persistence code behind #ifdef ENABLE_IPD_PERSIST (builds clean with flag OFF)
- Hardware verified: IPD survives SteamVR restart

## Task Commits

1. **Task 1: Implement IPD persistence with CMake flag and Cleanup hook** - `4a2f5af` (feat)
2. **Task 2: Bug fixes and hardware verification** - `8722008` (fix)

## Files Created/Modified
- `CMakeLists.txt` - ENABLE_IPD_PERSIST option and compile definition
- `src/driver/device_provider.h` - m_fStartupIpd, PersistIpdToConfig, FindLighthouseConsole declarations
- `src/driver/device_provider.cpp` - RunLighthouseCommand helper, PersistIpdToConfig implementation, FindLighthouseConsole, startup IPD capture in ApplyIpd

## Decisions Made
- Rewrote single-process file-polling approach to match HMDUtility's proven write_to_stdin pattern: separate process per command, stdout ReadFile for synchronization, exit command + GetExitCodeProcess polling for cleanup
- Added startup IPD capture in ApplyIpd() (not just Init()) because IPD typically arrives via VREvent_IpdChanged auto-apply, not the Init() property read

## Deviations from Plan

### Auto-fixed Issues

**1. Startup IPD not captured via VREvent_IpdChanged path**
- **Found during:** Hardware testing (first deploy)
- **Issue:** m_fStartupIpd stayed 0 because Init() property read returns 0 before lighthouse driver sets it; actual IPD arrives via VREvent_IpdChanged auto-apply
- **Fix:** Added m_fStartupIpd capture on first successful ApplyIpd call when startup is still 0
- **Files modified:** src/driver/device_provider.cpp
- **Verification:** Log shows startup=0.0620 after fix
- **Committed in:** 8722008

**2. File-polling synchronization failed (downloadconfig timeout)**
- **Found during:** Hardware testing (second deploy)
- **Issue:** Polling for download file existence timed out even at 10s — lighthouse_console hadn't written the file yet because no stdout read was blocking
- **Fix:** Rewrote to use separate process invocations with stdout ReadFile blocking per HMDUtility write_to_stdin pattern
- **Files modified:** src/driver/device_provider.cpp
- **Verification:** Download completes in ~2.5s, upload in ~2.5s, total persistence ~5s
- **Committed in:** 8722008

---

**Total deviations:** 2 auto-fixed (both correctness)
**Impact on plan:** Both fixes necessary for functionality. Architecture changed from single-process to dual-process pattern matching proven HMDUtility reference implementation.

## Issues Encountered
- cmake path changed from BuildTools to Community edition — updated CLAUDE.md

## User Setup Required
None - no external service configuration required.

## Next Phase Readiness
- v2.0 milestone complete — all phases (10-13) shipped
- IPD changes persist across SteamVR restarts via headset flash

---
*Phase: 13-slider-persistence-hardening*
*Completed: 2026-04-05*
