Add-Content C:\Users\decid\Documents\projects\sauna\.gitignore "spikes/**/*.raw"; cd C:\Users\decid\Documents\projects\sauna; git add -A; git status --short

Ignore raw frames, stage changes


warning: in the working copy of '.gitignore', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'PLAN.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'spikes/s2-vulkan-direct/s2_nvapi.cpp', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'spikes/s3-distortion-truth/FINDINGS.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'spikes/s3-distortion-truth/make_warped_grid.py', LF will be replaced by CRLF the next time Git touches it
M  .gitignore
M  PLAN.md
M  spikes/s2-vulkan-direct/s2_nvapi.cpp
M  spikes/s3-distortion-truth/FINDINGS.md
A  spikes/s3-distortion-truth/make_warped_grid.py
A  spikes/s3-distortion-truth/preview.png


PowerShell

cd C:\Users\decid\Documents\projects\sauna; git commit -m @'
Spike S3 eyes-in PASS: pre-warped grid validated through the lens on enlyzeam

make_warped_grid.py renders the verified poly3 warp into a static pre-distorted
test frame (per-channel CA pre-correction, up-marker triangle, left-eye marker)
from a unit config JSON. s2_nvapi gains --image: loads a raw B8G8R8X8 frame
into the DM surfaces via CopyTextureRegion (RGBA swizzle fallback; 10/16-bit
flavors rejected) and presents it statically, skipping the animated pattern.

Eyes-in results (two 120 s runs at 5088x2544@75, 74.99 fps): grid rectilinear
both eyes, CA stable (residual fringing is generator aliasing, not warp error),
triangle up (v=0 = top), left-eye marker correct (left half = left eye). Stereo
convergence absent as expected - no IPD/canting compensation in the test image
(M2 scope). Spike ladder complete 3/3.

Incidental M1 finding recorded: doffing the headset kills vsync and the present
loop free-runs at 5000+ fps with zero errors - compositor needs prox/power
handling and free-run detection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'@; git push

Commit and push eyes-in PASS


[main 479bf71] Spike S3 eyes-in PASS: pre-warped grid validated through the lens on enlyzeam
 6 files changed, 273 insertions(+), 33 deletions(-)
 create mode 100644 spikes/s3-distortion-truth/make_warped_grid.py
 create mode 100644 spikes/s3-distortion-truth/preview.png
To https://github.com/FEAT-HER3/sauna.git
   df66b07..479bf71  main -> main


Sending commune to psyche — spike ladder milestone.


Write

Spike S3 PASS both gates — **spike ladder complete 3/3**. Repo main @ 479bf71, clean, pushed.

Numeric gate: `DISTORT_POLY3` settled empirically against one sanctioned SteamVR run on
the enlyzeam Beyond (LHR-599F3B91): **direct** polynomial `d = 1+k1r²+k2r⁴+k3r⁶` (NOT
Monado's reciprocal), output rescale `0.5/(1+grow)`, **no undistort_r2_cutoff clamp** —
evaluator matches `ComputeDistortion` to 0.0002 px max (65×65×3ch×2eyes). Found via
9-param free fit (analyze.py) after all 4 closed-form hypotheses failed; fitted coeffs +
center reproduced config values to 5 decimals. The clamp was the only bug in the
otherwise-correct hypothesis.

Eyes-in gate: pre-warped grid (make_warped_grid.py) presented via new `s2_nvapi --image`
static-frame path at native 5088×2544@75. User eyeball on enlyzeam: rectilinear both
eyes, CA stable (residual fringing = generator aliasing, not warp), triangle-up confirms
v=0=top, left-eye marker confirms left half = left eye. Stereo convergence absent as
expected (no IPD/canting comp in test image — M2 scope).

Load-bearing M2 facts from the dump (all in spikes/s3-distortion-truth/FINDINGS.md):
- Driver reports eye_to_head = IDENTITY + ±ipd/2; canting is folded into asymmetric
  GetProjectionRaw (config `parallel_render_cameras: true`). M2 must replicate the fold
  (closed form underivable so far — fitted per-eye offset/scale archived as ground
  truth) or render genuinely canted cameras with consistent warp math. NOT mix.
- IPD translation = user setting (`driver_BeyondSteamVR.ipd_mm` 62.0), not config
  ipd.default_mm (69). v1: config default + user override.
- center_x = −K[0][2], center_y = +K[1][2] convention confirmed.
- M1 hazard: doffed headset → prox kills panels → vsync gone → present loop free-runs
  5000+ fps with ZERO errors. Compositor needs prox/power handling + free-run detection.

Ops notes: OpenVR IPC refuses SSH logon sessions — `schtasks /it` trick runs dump in
interactive session. SteamVR-cached lighthouse configs on enlyzeam include ~47 stale
factory units; serial cross-check in verify.py guards mismatches.

Next queue: (1) local 4090 rig S2 visual re-verify with fixed build — user must be
physically at local rig, currently at enlyzeam; (2) M1 first light: S1 IMU reader + S2
presenter glued, head-locked test pattern from cold boot.


File created successfully at: C:\Users\decid\Documents\projects\sauna\.claude\solar-commune.md (file state is current in your context — no need to Read it back)

Spike S3 PASS both gates — **spike ladder complete 3/3**. Repo main @ 479bf71, clean, pushed.

Numeric gate: `DISTORT_POLY3` settled empirically against one sanctioned SteamVR run on
the enlyzeam Beyond (LHR-599F3B91): **direct** polynomial `d = 1+k1r²+k2r⁴+k3r⁶` (NOT
Monado's reciprocal), output rescale `0.5/(1+grow)`, **no undistort_r2_cutoff clamp** —
evaluator matches `ComputeDistortion` to 0.0002 px max (65×65×3ch×2eyes). Found via
9-param free fit (analyze.py) after all 4 closed-form hypotheses failed; fitted coeffs +
center reproduced config values to 5 decimals. The clamp was the only bug in the
otherwise-correct hypothesis.

Eyes-in gate: pre-warped grid (make_warped_grid.py) presented via new `s2_nvapi --image`
static-frame path at native 5088×2544@75. User eyeball on enlyzeam: rectilinear both
eyes, CA stable (residual fringing = generator aliasing, not warp), triangle-up confirms
v=0=top, left-eye marker confirms left half = left eye. Stereo convergence absent as
expected (no IPD/canting comp in test image — M2 scope).

Load-bearing M2 facts from the dump (all in spikes/s3-distortion-truth/FINDINGS.md):
- Driver reports eye_to_head = IDENTITY + ±ipd/2; canting is folded into asymmetric
  GetProjectionRaw (config `parallel_render_cameras: true`). M2 must replicate the fold
  (closed form underivable so far — fitted per-eye offset/scale archived as ground
  truth) or render genuinely canted cameras with consistent warp math. NOT mix.
- IPD translation = user setting (`driver_BeyondSteamVR.ipd_mm` 62.0), not config
  ipd.default_mm (69). v1: config default + user override.
- center_x = −K[0][2], center_y = +K[1][2] convention confirmed.
- M1 hazard: doffed headset → prox kills panels → vsync gone → present loop free-runs
  5000+ fps with ZERO errors. Compositor needs prox/power handling + free-run detection.

Ops notes: OpenVR IPC refuses SSH logon sessions — `schtasks /it` trick runs dump in
interactive session. SteamVR-cached lighthouse configs on enlyzeam include ~47 stale
factory units; serial cross-check in verify.py guards mismatches.

Next queue: (1) local 4090 rig S2 visual re-verify with fixed build — user must be
physically at local rig, currently at enlyzeam; (2) M1 first light: S1 IMU reader + S2
presenter glued, head-locked test pattern from cold boot.


**S3 closed — spike ladder 3/3 complete.** Pushed as 479bf71, commune sent to psyche.

Final state:
- **Numeric gate:** evaluator = OpenVR ground truth to 0.0002 px. Formula locked: direct poly, `0.5/(1+grow)` rescale, no r² clamp.
- **Eyes-in gate:** rectilinear both eyes, CA stable (fringing = generator aliasing — M2's shader sampling fixes free), v-orientation + eye assignment confirmed.
- Your stereo read is right and quantified: dump shows SteamVR achieves fusion via cant folded into asymmetric projections + 62 mm user IPD — test image had neither. M2 work, fully specified by the captured ground truth.

Remaining queue:
1. **Local 4090 rig S2 eyeball re-verify** — needs you physically back at HFENDULEAM. Bonus: new `--image` path means you could also run the warped-grid eyes-in there with the local unit's config (LHR-1F8E25F1, cached) — one session, both checks.
2. **M1 first light** — S1 IMU + S2 presenter glued, head-locked pattern from cold boot. All architecture-blocking unknowns now resolved.

Say the word when you want M1 started — it doesn't need you at any particular rig until the eyeball stage.


please explain in no more than 15 points how you derived the steamvr compositor's warp mesh formulae


<owl_reachability_notice>
You have an active owl perch. When spawning subagents or doing work, use run_in_background: true so you stay reachable for incoming messages.
</owl_reachability_notice>


CAVEMAN MODE ACTIVE (full). Drop articles/filler/pleasantries/hedging. Fragments OK. Code/commits/security: write normal.


1. Start point: device config JSON holds per-channel `DISTORT_POLY3` coeffs, but sign history was ambiguous — EVT/DVT units shipped `DISTORT_DPOLY3` with **negative** leading coeffs, production ships **positive**. Public Vive evaluators (Monado) use reciprocal form. Direction unknowable from configs alone.

2. Only authority on the real mapping: Valve's closed lighthouse driver. Its `ComputeDistortion(eye, u, v)` returns, per output-panel UV, the source UVs to sample for R/G/B. Compositor builds its warp mesh by sampling exactly that function. So dump it once = ground truth.

3. Dumped 65×65 UV grid per eye, per channel (`dump_openvr.py`, pyopenvr, SteamVR running with enlyzeam Beyond). Also grabbed `GetProjectionRaw` tangents and `GetEyeToHeadTransform` per eye in same dump — free cross-check data.

4. First attempt: 4 closed-form hypotheses — {direct poly `d=1+k1r²+k2r⁴+k3r⁶` vs reciprocal `d=1/(1+…)`} × {output rescale `0.5/(1+grow_for_undistort)` vs plain `0.5`}. All four FAILED, hundreds of px error. Model space too narrow.

5. Failure analysis from the cross-checks: dump frustum (`GetProjectionRaw`) ≠ intrinsics-derived frustum (−1.40 vs −0.70 tangent, asymmetric), and dump `eye_to_head` = identity rotation, not config's canted matrix. Conclusion: source-UV space isn't what I assumed — it's defined relative to the **raw projection frustum**, and the driver folds canting in somewhere.

6. So stopped guessing, let data speak: converted every ground-truth source UV into frustum tangent space (`tan = L + u_src·(R−L)`, `T + v_src·(B−T)`).

7. Fit a general 9-parameter radial model per eye per channel (`analyze.py`, scipy least_squares): `tan = a + s⊙(t−c)·d(r²)`, free center `c`, free offset `a`, free signed scale `s`, free coeffs `k1..k3`, with `t = 2·uv−1`. Both d-forms tried.

8. Direct-poly fit converged to **0.000 px residual** at all 4225 points — and fitted `c` and `k1..k3` equaled the config values to 5 decimals, all 3 channels, both eyes. Proves: coeffs used verbatim, direct polynomial, radial-affine mapping exact (no homography, no extra terms).

9. Reciprocal fit left ~1 px rms with mangled coeffs (~−0.21 leading) — distinguishably wrong, but its near-fit explains the EVT-era negative coeffs: `1/(1+0.21r²) ≈ 1−0.21r²+…`. Same optics, opposite fit direction. Historical confusion resolved.

10. Then reverse-engineered the fitted nuisance params into closed form. Scale: `s_x/(R−L) = 0.31250 = 0.5/(1+0.6)` exactly — the grow rescale. Offset: `(a_x−L)/(R−L) = 0.5 + c_x·0.3125` exactly. Both axes, both eyes.

11. Substituting back: in source-UV space the formula is exactly the Monado shape — `uv_src = 0.5 + ((t−c)·d + c)·0.5/(1+grow)` — with direct `d`. Meaning my original hypothesis #1 had the right formula all along.

12. So why did step 4 fail? One bug: I clamped r² at `undistort_r2_cutoff` (1.0) like Monado does. Ground truth follows the polynomial unclamped out to panel corners (r²≈2.1). The free fit had no clamp — that's why it succeeded where the closed form failed. Removed clamp → hypothesis test gave 0.0002 px max. Cutoff field gates something else, not `ComputeDistortion`.

13. Validation rigor: `verify.py --selftest` first proved on synthetic data the 4 hypotheses are mutually distinguishable (hundreds of px apart), so a sub-pixel winner is unambiguous, not a tie-break.

14. Independent physical confirmation: rendered grid straight in source space through the recovered warp, presented on the actual panels, eyeballed through the lens — rectilinear, CA stable, orientation/eye markers correct. Math and optics agree.

15. Residual 0.0002 px = float32 rounding in OpenVR's return path; effectively exact. One caveat stays open: formula validated for `DISTORT_POLY3` only — DPOLY3 direction never tested (moot, all production units are POLY3).