Failure Boundary: 6,400 Rollouts in 126 Seconds
Part 2. The harness passed its equivalence gate, so now it gets to produce a dataset. See Part 1: The Gate That Kept Failing.
Aug 13: Pilot
148 rollouts, zero divergences. Enough to see the shape before committing to the full grid.
Findings:
- Boundary sits somewhere around 75 to 150% of bodyweight depending on friction.
- μ=0.10 is a walk-barely-possible regime. It falls at a 10% bodyweight nudge.
- Non-monotonic friction effect at 100%BW: μ=0.7 gave 1/4 survival, μ=1.0 gave 3/4. Four seeds. Unresolved, parked.
Broke: local deserialization of the pilot’s return value. Numpy scalars, and my local venv had no numpy. The run itself was fine; I pulled the manifest off the Volume. Added numpy to local dev deps since I need it for track analysis anyway.
Aug 13: The vmap bug
Building the full-sweep executor, first attempt vmapped the whole mjx model across the friction axis and broke mjx internals.
The fix: batch the single leaf that actually varies. geom_friction gets batched on the model pytree; the in_axes tree is None everywhere else. Obvious in retrospect. Most of an afternoon otherwise.
Aug 13: Full sweep
μ from 0.05 to 1.00 in steps of 0.05, push from 10 to 200% bodyweight in steps of 10. Sixteen seeds per cell. 6,400 rollouts.
126 seconds wall on one A100-80GB. Zero divergences.
Chunk walls: 99.3s for the first (includes compile), then 8.6, 9.1, 8.7. One compiled step reused across chunks, 1600 rollouts per chunk. The compile amortizes over the run, which is the whole reason it’s two minutes instead of twenty.
What the data says
The result picked its own framing, which I prefer to picking one and then finding support for it:
- A smooth diagonal band where fall-onset climbs from 50 to 110%BW as friction goes 0.15 to 1.00.
- A transition zone two to four cells wide. Not a threshold.
- A sharp ice cliff below μ 0.15.
Nine cells of the grid, one push, synchronized at t=2s. Friction increases bottom to top, push magnitude left to right.
The boundary sits inside the map on every edge, so I’m not clipping the interesting region. The pilot’s non-monotonicity resolved as seed noise once there were 16 seeds instead of 4.
Threshold freeze
Failure is torso below 0.15 m or tilt past 60 degrees, whichever comes first. Derived from the nominal walking distribution and frozen before the sweep is analyzed, so I can’t tune the definition until the picture looks good.
Rollouts that survive the full five seconds are censored, not counted as failures at t=5. That’s why the per-cell estimate is Kaplan-Meier rather than a mean. Counting survivors as late failures would bias the whole surface downward.
Left an empty sweep directory on the Volume from a failed first attempt’s mkdir. Nothing on the Volume gets deleted casually. Noting it here so nobody wonders what it is.