---
phase: 12-steamvr-ipd-slider-ui
plan: 01
subsystem: driver
tags: [openvr, ipd, steamvr-slider, hmd-serial, beyond1-detection, component-probing]

requires:
  - phase: 11-live-ipd-change
    provides: "HandleIpdSet pipeline with SetDisplayEyeToHead, lighthouse config loading, cached rotation matrices"
  - phase: 11.1-proximity-sensor-app-compat
    provides: "Deferred component creation pattern (TryCreateProximityComponent) on HMD container"
provides:
  - "HMD serial parsing (tag 0x08) and Beyond 1 vs Beyond 2 detection"
  - "ApplyIpd shared helper with loop guard for reuse by auto-apply and pipe commands"
  - "VREvent_IpdChanged auto-apply with Beyond 1 gating"
  - "Track B native slider property activation spike (IpdUIRange + DriverDisplaysIPDChanges)"
  - "Track B component-based IPD handle probing spike (/input/ipd/value, ipd_adjust, eye_distance)"
  - "Beyond 1 gating on all IPD pipe commands"
affects: [12-02-settings-tab-fallback]

tech-stack:
  added: []
  patterns: [deferred-init-with-guard, apply-helper-refactor, loop-guard-pattern, component-handle-probing]

key-files:
  created: []
  modified:
    - src/hid/user_signature.h
    - src/hid/user_signature.cpp
    - src/driver/device_provider.h
    - src/driver/device_provider.cpp

key-decisions:
  - "Refactored HandleIpdSet body into ApplyIpd shared helper for reuse by auto-apply and pipe commands"
  - "Loop guard in ApplyIpd prevents infinite VREvent_IpdChanged feedback (fabsf < 0.0001f threshold)"
  - "Removed duplicate Euler angle logging from HandleIpdSet (already logged in ReadEyeToHeadFromConfigFile)"
  - "Three component probes attempted for Track B: /input/ipd/value, /input/ipd_adjust/value, /input/eye_distance/value"

patterns-established:
  - "Beyond 1 gating: m_bIsBeyond1 flag checked before any IPD operation"
  - "Deferred serial check: CheckHmdSerial follows TryCreateProximityComponent pattern in RunFrame"

requirements-completed: [SLIDER-01, SLIDER-02, HARD-04]

duration: 3min
completed: 2026-03-28
---

# Phase 12 Plan 01: IPD Slider Infrastructure Summary

**HMD serial-based Beyond 1/2 detection, ApplyIpd refactor with loop guard, VREvent_IpdChanged auto-apply, and Track B native slider spike (properties + component probing)**

## Performance

- **Duration:** 3 min
- **Started:** 2026-03-28T11:24:59Z
- **Completed:** 2026-03-28T11:28:01Z
- **Tasks:** 1
- **Files modified:** 4

## Accomplishments
- HMD serial parsed from user flash TLV tag 0x08, enabling Beyond 1 vs Beyond 2 detection via BS1 prefix
- Refactored IPD application into shared ApplyIpd helper with loop guard preventing VREvent_IpdChanged feedback
- VREvent_IpdChanged now auto-applies IPD through the full SetDisplayEyeToHead pipeline (gated by Beyond 1 check)
- Track B native slider spike: IpdUIRange properties, DriverDisplaysIPDChanges=false, and three component-based handle probes attempted on HMD container
- All IPD pipe commands (ipd, ipd?) gated for Beyond 1 headsets

## Task Commits

Each task was committed atomically:

1. **Task 1: Add HMD serial parsing and Beyond 1 detection infrastructure** - `f076ef8` (feat)

## Files Created/Modified
- `src/hid/user_signature.h` - Added HmdSerial=0x08 to SigTag enum and hmd_serial[32] field to CalibrationData
- `src/hid/user_signature.cpp` - Added tag 0x08 TLV parsing block mirroring tag 0x09 pattern
- `src/driver/device_provider.h` - Added m_bIsBeyond1, m_bHmdSerialChecked, m_bSliderPropsAttempted flags; CheckHmdSerial, TrySetSliderProperties, ApplyIpd declarations
- `src/driver/device_provider.cpp` - Implemented CheckHmdSerial, ApplyIpd, TrySetSliderProperties; updated RunFrame with deferred calls; refactored HandleIpdSet to delegate to ApplyIpd; added Beyond 1 gating on ipd/ipd? pipe commands; updated VREvent_IpdChanged to auto-apply

## Decisions Made
- Refactored HandleIpdSet into ApplyIpd to avoid code duplication between pipe command and auto-apply paths
- Removed duplicate Euler angle diagnostic logging from HandleIpdSet (already present in ReadEyeToHeadFromConfigFile)
- Loop guard threshold 0.0001f in meters (~0.1mm) prevents infinite feedback from SetFloatProperty triggering VREvent_IpdChanged
- Three different component path names probed for Track B to maximize discovery chance

## Deviations from Plan

None - plan executed exactly as written.

## Issues Encountered

None.

## User Setup Required

None - no external service configuration required.

## Next Phase Readiness
- Infrastructure for slider-driven IPD is complete
- Track B spike results will be evaluated at runtime (property/component errors logged)
- Plan 02 (settings tab fallback) can proceed regardless of Track B outcome
- Beyond 1 gating ensures all IPD functionality is safely disabled for non-supported headsets

---
*Phase: 12-steamvr-ipd-slider-ui*
*Completed: 2026-03-28*
