# Terrain driving and measured suspension

Status: accepted for the locally recorded scenarios; both real Jev videos verified. Action: implement. 2026-09-23.

## Context and evidence

The requested outcome is a more dynamic Jev driving demonstration on uneven
ground, including visible suspension response. The baseline is the dirty
Driving V1 implementation documented in [DRIVING](DRIVING.md), based on
`e1dc2c0d5f38231054325dba67a9ea3344ea7ea5`. This work authorizes local code,
isolated worlds and recordings; it does not deploy a shared persistent world.

The baseline physically simulates raycast suspension but estimates rendered
wheel travel from terrain height. Its road compiler produces level slabs.
Neither flat-road footage nor swapping the model establishes terrain handling.

## Alternatives and selection

| Option | Preconditions and benefit | Cost, affected surface and recovery | Decision |
| --- | --- | --- | --- |
| Retain the flat-road baseline and measure | Preserves compatibility; diagnoses limitations but cannot satisfy uneven-ground driving | Recording cost only; no new capability | Used for baseline, insufficient as delivery |
| Animate body bounce over the flat road | Cheap presentation; no physical or perception evidence | Renderer-only change would leave authoritative handling unchanged | Reject |
| Measured wheels plus an admitted terrain corridor | Reuses Physics, terrain collision, Package lifecycle and authoritative driving | Bounded wire, physics and renderer changes; explicit capabilities, recipe identity and fresh-world validation | Implement |
| Replace the solver with full multibody suspension and tire dynamics | Broader fidelity with a new calibrated vehicle model | Solver integration, calibration, new recovery contract and substantially broader validation | Defer pending a measured limitation |

The implementation leaves authored paved roads intact. An explicitly marked
`terrain_following` road is a horizontal navigation corridor. Its reference Y
does not claim a paved surface; live terrain and installed collision determine
height. `pajama-package trail` takes a road plus validated terrain parameters and
produces semantic route data and non-colliding orange boundary posts. Matching
terrain belongs to the world; publishing a trail neither writes terrain nor
adds a hidden flat collision plane. Moving the trail or subsequently editing
terrain may require republishing its decorative posts. There is no new
publication or direct agent mutation path. Terrain corridors require
`gameplay.driving-trail-v1` in addition to the existing road feature.

## Ownership and execution

- Rapier exports four wheel samples at the chassis publication barrier:
  suspension length, steering, spin, contact and applied suspension force.
- Replication sends at most 64 visible vehicles per connection in a separate
  transient `VehicleWheels` message, after the corresponding entity update.
  These samples never enter Packages or checkpoints. Stale incarnation/physics
  sequences, malformed samples and unknown entities are rejected by the client;
  removal and a new server snapshot clear the cache.
- Both native and headless presentation bind wheels to the chassis-local
  suspension axis. The old terrain estimate is a fallback for peers that do not
  publish wheel data. No client calculates authoritative traction or movement.
- A bounded 16 m terrain lookahead uses 27 height queries to measure longitudinal and transverse grade and roughness along the lane.
  The server limits speed for grade, roughness, curvature and reduced contact,
  adds gravity feed-forward from current body pitch and gravity reported by Physics (the current world uses 18 m/s²), and brakes for unstable attitude.
  This is a game controller, not a certified traversability or vehicle model.
- Jev receives this feedback in optional `DrivingObservationV1.terrain` and may
  choose `cautious` or resume `cruise`. The server still owns continuous control,
  validation, stopping and expired-intent braking. Fixture decisions remain
  explicitly labeled and cannot stand in for live Jev inference evidence.
- The optional recording chase camera follows replicated poses only. It adds
  neither authority nor additional interest visibility. Windows stay on the
  selected left/right monitors.

## Execution and acceptance

The first physical run failed its upright-body assertion at 42.23 m. The new optional mass-offset feature moves the SUV centre of mass 75 cm down inside the unchanged collision hull; box inertia remains an approximation. Absent mass offset preserves legacy physical behavior. Transverse grade now also limits speed. A second run stopped at 16.54 m: using lookahead grade for gravity compensation commanded insufficient throttle before a crest. The controller now uses current body pitch for gravity compensation, while lookahead terrain limits pace. The Package can additionally declare a front/rear drive-force split; the initial demonstration used equal four-wheel drive and 8 m/s² authored drive acceleration (later raised to 12 m/s² for hill restarts). A 55 cm offset passed the conservative crawl, but failed when the approach-speed profile allowed normal acceleration between rough sections; the final 75 cm offset passed the same route without relaxing the upright, lane or stop assertions. The approach profile now brakes towards each upcoming surface speed rather than imposing the worst lookahead speed everywhere.

The physical fixture uses the imported 1,500 kg SUV, a 34 cm suspension travel
parameter and a winding route over the same analytic terrain parameters as the
recording. Required measurements: finish near the route endpoint, stop below
0.3 m/s, lane error below 0.8 m, elevation change above 1 m, pitch above 0.06 rad,
roll above 0.025 rad and wheel suspension span above 2 cm without overturning.
Flat driving, input rejection, timeout, replication and recovery remain checks.
The native recording must show the exact five Package model parts and measured
wheel articulation on both clients; the video must decode completely.

The initial continuous-driving test traversed 58.00 m, with 2.35 m of elevation variation,
29.30° peak pitch, 17.88° peak roll, 20.80 cm wheel suspension span and 0.613 m
maximum lane error. It stopped below 0.04 m/s. Both terrain and existing paved
closed-loop tests passed. These are measurements from the physical fixture,
not substitutes for a live Jev recording. The final recording uses a 56 m Z-extent corridor (the fixture uses 64 m),
retaining the same hills and critical 42 m section. A 60 m recording route
put the parked car just beyond the second observer's 60 m interest radius
after accounting for its spawn offset. Shortening the final segment by 4 m
keeps the finish visible without changing interest policy or terrain.

The first live provider rehearsal remained stationary because the old `stop`
criterion also said to stop when no crossing was present. Its 93 submitted
decisions were all `stop`; 7 other calls failed or timed out. The recording
correctly failed rather than presenting this as a driving success. The criterion
now restricts stopping to occupied crossings and the route endpoint, and the
model receives an explicit route-progress objective. A second run hit provider
timeouts during cold startup and also remained safely stopped. Allowing requests
to finish for up to 5 seconds did not solve the latency tail: all four returned
answers in that rehearsal were correctly discarded as stale. The final adapter
sends only driving semantics (rounded to two decimal places); opaque session IDs
and package pins remain in the director. On a clear, stable terrain corridor Jev
chooses between `cruise` and `cautious`; traffic, endpoint and unstable-contact
states restore the full maneuver menu. Server safety checks run for either menu.
Requests now stop at 700 ms, and replies older than 1 second are still discarded.
A stationary recording exits after 15 seconds; a terrain run has a 90-second,
160-request bound. Provider timeouts still expire the server intent; there is no
fixture fallback. The preparatory calls and failed attempts remain evidence of
the provider's latency variation, rather than being counted as successful drives.

A subsequent live drive completed with 45 accepted Jev decisions, but its
150-second, 12 fps native recording exceeded the per-camera 16 GiB staging
budget. That driving trace is retained as diagnostic evidence, not a verified
video. Driving preflight now caps each camera at 1,000 requested frames; the
150-second pair uses the previous demos' 5 fps capture cadence. Video encoding
preserves wall-clock timing and does not claim 30 distinct captured frames per
second merely because the output container is 30 fps.

The next live repeat exposed a separate physical gap: intent expiry stopped the
vehicle near 42.5 m on the ridge, after which it slid sideways and overturned.
The old 8 m/s² brake capacity was insufficient against this world's 18 m/s²
gravity with fewer than four grounded wheels. An optional authored
`brake_deceleration_mps2` now supports 8–40 m/s² and requires
`physics.wheeled-brake-capacity-v1`. Omission preserves the old 8 m/s² behavior.
The off-road SUV uses 24 m/s² capacity and 12 m/s² drive capacity for hill
restarts; ordinary closed-loop brake demand is scaled to that capacity, while
expired intent requests full braking. There is no transform or velocity reset.
The new regression stops for five seconds on the ridge before resuming.
`terrain.ground_speed_mps` measures horizontal speed magnitude, including
rollback and sideways sliding; recording acceptance no longer treats clamped
forward speed as sufficient proof of a stop.

The brake change deliberately adds an admitted, bounded recipe capability.
Raising braking for every vehicle would change legacy tuning; freezing velocity
or pose would bypass tire contact and hide sliding. Both alternatives were
rejected. Full braking still applies wheel impulses subject to contact and
friction. The new physical hold-and-restart test passed at 58.07 m, with 29.99°
peak pitch, 17.53° peak roll, 23.15 cm suspension span and 0.783 m maximum lane
error. Its five-second ridge hold stayed within a 0.5 m displacement bound,
then the vehicle resumed and stopped below 0.04 m/s at the route end.

Keeping the same player connected for the entire capture tail exposed another
solver defect: steering assistance used persistent `add_torque` in every 250 Hz
substep. That accumulated yaw input and eventually rotated a parked car away
from the lane, despite having ample wheel braking. V4 applies a time-scaled
torque impulse only while drive force is present; braking and coasting add no
artificial yaw input. The ridge-hold regression is extended to 60 seconds.
This changes simulation results, so the runtime identity advances to
`pajama.physics.rapier-world-v4-driving`. Old V3 checkpoints are not silently
resumed; all new recordings use fresh V4 worlds. Migration remains separate work.

V4 also models bounded static tire shear while fully braking at low speed on
fixed ground with at least three wheel contacts. A transient anchor measures
small chassis displacement; position and contact-point velocity feedback apply tangential
impulses at the actual wheel contacts. Each supplemental impulse is limited by both its share of authored brake
capacity and the measured suspension load times tire friction. This is not a
calibrated combined-slip friction budget shared with Rapier's wheel controller. Motion, contact loss, moving ground or brake release discard the
anchor. Displacement beyond 20 cm also releases it. This approximation does not
set pose or velocity; its correction remains force-limited. It addresses
numerical creep in the raycast wheel solver without claiming full tire dynamics.

The first V4 live drive completed, but its long tail exposed short parking
oscillations (up to 0.48 m/s). Contact damping now includes angular velocity
at each tire, and this SUV's authored suspension damping is 20 (previously 8).
The added regression drives to two different stopping slopes and checks at
least 60 seconds below 0.2 m/s after the normal intent lease expires. It retains
the 0.8 m lane bound and the original 60-second ridge hold and restart test.
These are game-physics tuning values, not calibrated production-vehicle data.

The authorized rollout is local, isolated worlds and native recordings. Both
Packages use the existing cold-stage/admission/publication/tick-activation path;
failed or ambiguous publication is inspected by release ID rather than replayed
as another mutation. No shared persistent world is upgraded. The current runtime
recipe rejects older checkpoints; migration needs a separately measured case.

Recording resource bounds are 160 model calls per terrain run, a 700 ms provider
timeout, a 90-second driving window and at most 1,000 native frames per camera.
The selected capture uses 750 frames per camera and a 150-second observation
window. Failure of lane, contact, stop, publication, frame-gap or exact asset
draw assertions rejects the run. Revalidate when terrain, mass, tires, solver,
provider route or collision streaming changes; this finite corridor is not
evidence of arbitrary-world autonomous navigation. Exact dirty-source, binary,
Package, environment and validation-receipt hashes belong to the final evidence
folder, alongside the native runner and provider results.

Executable entry points:

```powershell
$env:CARGO_TARGET_DIR='target\offroad-brake-validation'
cargo test -p pajama-world -p pajama-content -p pajama-physics
cargo test -p pajama-server --lib driving::tests -- --nocapture
cargo test -p pajama-server --test e2e driving::
cargo test -p pajama-client --features catalog-v2-process-e2e,retained-presentation-wire-v1 wheel_physics_is_transient
cargo build -p pajama-server --bins -p pajama-client --features pajama-client/catalog-v2-process-e2e,pajama-client/retained-presentation-wire-v1
node --test scripts/system-one/driving-director.test.mjs scripts/system-one/system-one.test.mjs scripts/authoring/driving-recording.test.mjs scripts/authoring/generative-recording.test.mjs scripts/authoring/recording-evidence.test.mjs
node scripts/authoring/record-driving-trail.mjs --bins target/offroad-v4-contact-binaries --character-cache COMPLETED_CACHE --out target/NEW_RUN --seconds 150 --fps 5 --ffmpeg FFMPEG_PATH
# Explicit live inference: --driving-provider openrouter (or typesafe).
# Read the corresponding API key from the environment, or use --key-stdin.
# Interrupted decisions: record-driving-trail-fault.mjs with the same arguments.
# Both recordings, with the recovered credential supplied only in the process environment:
node scripts/authoring/record-driving-demos.mjs --terrain --provider openrouter --bins target/offroad-v4-contact-binaries --character-cache COMPLETED_CACHE --out target/NEW_SUITE --seconds 150 --fps 5 --ffmpeg FFMPEG_PATH
```

## Outcome and reuse

The final candidate is recorded in
[`driving-terrain-v4-20260923`](evidence/driving-terrain-v4-20260923/).
Both scenario journal entries and native results are `verified`. All four
native recordings completed with 750 frames each; the delivered clips passed
capture-gap validation and full decode. Final telemetry overlay frames were
visually inspected. The two real-time videos are:

- [Adaptive terrain driving](../target/driving-terrain-20260923-r9/trail/whitepaper/driving-trail-realtime.mp4)
- [Inference interruption on the ridge](../target/driving-terrain-20260923-r9/trail-fault/whitepaper/driving-trail-fault-realtime.mp4)

The suite is `target/driving-terrain-20260923-r9`, using the
`target/offroad-v4-contact-binaries` executables and fresh V4 worlds.

| Measured live result | Adaptive terrain | Deliberate inference interruption |
| --- | ---: | ---: |
| Accepted real Jev decisions | 50 | 35 |
| Provider failures | 0 | 0 |
| Median returned latency | 293.8 ms | 228.1 ms |
| Driving distance | 49.81 m | 40.18 m |
| Peak speed | 19.73 km/h | 20.05 km/h |
| Maximum lane error while driving | 0.477 m | 0.485 m |
| Peak absolute pitch / roll | 29.17° / 18.49° | 25.45° / 18.42° |
| Maximum measured wheel span | 17.94 cm | 17.91 cm |
| Lowest wheel contact count | 3 | 3 |
| Maximum horizontal speed during the parking tail | 0.0963 m/s | 0.0064 m/s |

These two completed driving traces have no fixture fallback. The interruption
scenario stops inference while retaining the connected driver's seat and
session, exercising the server's expired-intent brake. It does not establish
player-disconnection or whole-server-failure behavior. Failed earlier rehearsals
remain available and are not counted among the 85 accepted decisions above.

The narrow validation receipts contain 499 passing Rust tests (one additional
world test ignored) and 41 passing JavaScript checks. They cover world/content
schemas and compilation, Physics, four actual vehicle-control cases, driving
network E2E, transient wheel-state rejection and recording/provider acceptance.
Native validation additionally checks exact Package parts, physics-to-render
wheel positions and complete video decode. Recorded frames are 5 fps with real
wall-clock timing; 30 fps encoding does not add captured motion samples.

Unsupported claims include rock crawling, arbitrary steep
slopes, tire deformation, calibrated tire slip curves, airborne stunt control,
traffic routing at junctions, and a completed live model run without a provider
receipt. Raycast wheels have finite travel and cannot climb arbitrary vertical
steps. The existing server collision-readiness corridor remains bounded.
