# Original warehouse and first Nav2 mission

This publication contains one source warehouse, its original forklift and one recorded mission. It is a native navigation recording, not a learned-policy evaluation, physical pallet-manipulation demonstration or hardware-throughput measurement. The original mission dispatcher completes two Nav2 legs and two ten-second wall-clock waits. Its optional VLM client remains in the source workload, but no model server or inference result is claimed.

Source: [Open Navigation workload benchmark at 991b41b](https://github.com/open-navigation/opennav_robotics_workload_benchmark/tree/991b41bad4eafab0b28c80b2b7b8fc9258ca2f26). The source/asset lock is `worlds/opennav/source-lock.json`. Code is Apache-2.0; model terms are separately recorded in the scene descriptor and source page, including CC BY-NC and CC BY-NC-ND. Do not infer asset terms from the code licence. Original geometry stays at its versioned upstream URLs.

## Original source acquisition

The verifier seals all 441 original Git blobs and 42 Fuel cache files. Three
upstream historical ROS-log symlinks are checked as literal Git blobs without
following their unavailable targets. The isolated Fuel cache also needs two
lookup aliases: `fuel.ignitionrobotics.org` → `fuel.gazebosim.org`, and
`openrobotics/models/casual female` → `casual%20female` within that server cache.
Both aliases must resolve inside the cache. Original source files remain intact.
Unexpected cache files or version directories fail verification, because the
source's unversioned references could otherwise select a newer model.

Gazebo Fuel's CLI follows the latest release even when passed a numeric version.
The acquired cache versions were therefore checked against numeric file URLs.
All meshes and textures matched byte for byte. Four archive SDF files have
different formatting from their HTTP file representations; two also expand a
`model://` reference to the same numeric Fuel file. The lock retains both source
hashes and the exact XML differences. It does not silently replace either file.

## Original runtime

The recorder checks these existing Docker image identities before starting:

- Simulation: `sha256:f46d200aae7cbd2352798844b9ff64b68f1d17a230a78c0688ba3c110959d23c`
- Workload: `sha256:736792ec678d37b592b2da3c5456302b314f180f5e9b16ea72eb0e78b10d6eeb`

These are local captured image identities, not downloadable public tags. The original images are prerequisites for the exact recorder; this recipe does not promise that rebuilding floating apt dependencies will recreate those image IDs. A different runtime requires a fresh reviewed recording and evidence.

The runtime is ROS Jazzy, Gazebo Sim 8.15.0, Common 5.9.0 and DART at 10 ms physics steps. The source physics profile name `tpe` is not treated as the actual engine. The source dispatcher uses seed 42; the native world seed is 0. The observer retains native Pose_V timestamps, body transforms and camera messages. DDS socket minimums are lowered from 10 MB to 4 MB inside the isolated containers; host settings are unchanged. Source physics, geometry and sensors are retained. The broadcaster runs without the GUI while preserving its original full-world output.

The original output receipt is `worlds/opennav/native/recording.json`; the source mission receipt is `worlds/opennav/native/mission.json`. Native producer hashes, original timestamps, scene bytes and input closure hashes remain in `episode-evidence.json`. That file describes the publication preparation stage; subsequent desktop component evidence is in `desktop-camera.json`.

## Reproduction on the audited runtime

Run from the site checkout. Populate `.cache/opennav-warehouse/source` at the exact source pin and `.cache/opennav-warehouse/fuel-cache` with the files and aliases listed in the lock. These commands verify existing inputs; they do not bulk-download the source corpus, install Docker or create the two required images.

```sh
PYTHONPATH=scripts python3 -m worlds.opennav_source \
  --source .cache/opennav-warehouse/source \
  --fuel-cache .cache/opennav-warehouse/fuel-cache

PYTHONPATH=scripts python3 scripts/worlds/record_opennav_episode.py \
  --source .cache/opennav-warehouse/source \
  --fuel-cache .cache/opennav-warehouse/fuel-cache \
  --output .cache/opennav-warehouse/recipe-native \
  --wall-seconds 1800
```

The recorder is invoked as a script because its sealed imports are script-relative. Use a new output directory for every run. Its wall-clock limit is a recording resource limit, not a source episode-step horizon. A later native run can have different asynchronous sample timing and count. Strict publication checks intentionally reject changed evidence rather than label it identical.

For host-side message parsing, provide the matching Gazebo messages 10 Python protobuf modules in `.cache/opennav-warehouse/protobuf-python`. Export the original source assembly and measured body samples with:

```sh
PYTHONPATH=scripts:.cache/opennav-warehouse/protobuf-python \
  python3 -m worlds.export_opennav_scene \
  --recording .cache/opennav-warehouse/recipe-native \
  --source .cache/opennav-warehouse/source \
  --fuel-cache .cache/opennav-warehouse/fuel-cache \
  --output .cache/opennav-warehouse/recipe-display
```

Provide the audited FFmpeg 7.0.2-static executable at the path below. The camera index retains its exact binary hash and all encode/decode/quality commands:

```sh
PYTHONPATH=scripts:.cache/opennav-warehouse/protobuf-python \
  python3 -m worlds.export_opennav_camera \
  --cache .cache/opennav-warehouse \
  --recording .cache/opennav-warehouse/recipe-native \
  --output .cache/opennav-warehouse/recipe-camera \
  --ffmpeg .cache/opennav-warehouse/ffmpeg-7.0.2
```

## Geometry, body and camera checks

`scripts/worlds/capture_opennav_meshes.py` builds a sealed CMake capture against Common 5.9.0 in the audited simulation image. `audit_opennav_meshes.py` compares original triangles, transformed normals, UVs, texture bindings and materials with the browser imports. `prepare_opennav_spatial.py` derives conservative spatial bounds from those original native mesh vertices. Bounds do not replace, simplify or rehost the meshes.

The original full scene has 1,388 models, 1,405 links and 2,249 visuals. Its 28 mesh/material/texture files total 40,168,724 bytes. The compiled hierarchy has 5,043 links. Static instancing and 63 spatial regions share original geometry; visited source assets are retained until the world closes. No simplified LOD is provided or claimed.

The published body recording has 11,847 samples and 19 body channels over 191.81 seconds. It is split into 186 chunks, with at most 64 samples per chunk. `qpos` and `qvel` are empty, `action` is null and `action_applied` is false. Separately timestamped Twist observations are retained without inventing physics-step action alignment. `terminated` marks the completed mission recording, not a Gym flag. No source episode-step horizon exists to infer from recording length.

The optional whole-episode line overlay retains its 2,048-sample limit and is
unavailable for this longer recording. Timeline playback and frame selection
retain all 11,847 original body samples.

The camera has 960 original 640×480 RGB observations, starting at episode time 0.01 s and ending at 191.78 s. The first observed interval is irregular. All H.264 presentation timestamps match source differences from the camera origin. H.264/YUV420 is lossy; minimum per-frame PSNR is 46.03 dB against original RGB converted to YUV420. PNG paths in the index are local audit inputs, not served files.

The body timeline selects the latest observed camera image at or before the displayed body time. It preserves the native image timestamp and age rather than treating the camera as uniformly sampled. Before the first image, no camera frame is asserted. A presented-frame callback confirms the selected encoded image; exports retain the receipt. The freely movable inspection camera is separate from the recorded sensor.

`verify_opennav_browser.mjs` checks all 900,372 body/basis points and native mesh imports. `verify_opennav_lifecycle.mjs` checks inspection, graphics-context loss/recovery, resource cancellation and repeated close/reopen cycles. `verify_opennav_camera.mjs` additionally checks the actual warehouse adapter, pinned scene/bounds, camera index, 41 paired seeks, playback, looping and disposal. Its `software-codec` mode uses hardware WebGL and explicitly disables accelerated video decoding. Default headless Chrome passed functionally with SwiftShader; forced hardware decoder overrides failed. Those modes are not combined into a hardware-decoding or live-network timing claim.

Publication requires fresh site integration checks, applicable desktop regressions, review and production verification. The native capture, component check, full page behavior and production transport are distinct evidence. Physical-phone testing is deferred.

The full explorer check is `scripts/worlds/verify_opennav_site.mjs`. After staging
the site, run it on a desktop X display with Chrome installed (or through
`xvfb-run` with Xvfb and Xauth available):

```sh
xvfb-run -a node scripts/worlds/verify_opennav_site.mjs \
  .cache/opennav-warehouse/new-desktop-site
```

It uses a fresh Chrome profile, the default CDP context without foreground-focus
emulation, live upstream mesh requests and actual camera-video decoding. The
local server invokes the actual Worker against an asset binding that returns
complete files and ignores byte-range requests, matching production behavior.
The Worker streams the requested camera interval and cancels the source reader
at its end or on disconnect; it does not buffer the entire clip. The desktop
checks include paired seeks and downloads, idle rendering, graphics-context
recovery, trusted background/freeze/resume events, rapid seeking, default-scene
handoff and repeated world changes. Hardware WebGL and software H.264 decoding
are reported separately. An optional second argument selects the live site
origin for the same checks. The profile and owned browser are closed afterward.

## Source geometry and publication procedure

The native mesh capture is now reproducible from repository scripts. It uses
the identity-checked local simulation image offline, verifies all original
source/Fuel files and thirteen mesh inputs, and requires Gazebo Common 5.9.0
through CMake's exact-version check. Its release resolves to
[`442a7ab4f213e435c3ca93947004216f26ec728d`](https://github.com/gazebosim/gz-common/tree/442a7ab4f213e435c3ca93947004216f26ec728d).
The C++ observer saves original MeshManager attributes; these local audit
outputs are not public mesh replacements. Each capture binds its image,
producer files, scene and output digests. A fresh capture passed all thirteen
browser mesh comparisons, including original material coefficients and texture
assignments. An earlier attempt stopped at a nonexistent pkg-config lookup;
its incomplete receipt remains separate from the successful CMake-checked run.

```sh
PYTHONPATH=scripts python3 -m worlds.capture_opennav_meshes \
  --source .cache/opennav-warehouse/source \
  --fuel-cache .cache/opennav-warehouse/fuel-cache \
  --scene .cache/opennav-warehouse/mission-display-003/warehouse-first-mission.scene.json \
  --output .cache/opennav-warehouse/new-native-mesh-capture

PYTHONPATH=scripts python3 -m worlds.audit_opennav_meshes \
  --cache .cache/opennav-warehouse \
  --display .cache/opennav-warehouse/mission-display-003 \
  --capture .cache/opennav-warehouse/desktop-spatial-003 \
  --native .cache/opennav-warehouse/new-native-mesh-capture \
  --output .cache/opennav-warehouse/new-native-browser-mesh-audit.json
```

The desktop preparation now batches repeated original static meshes in 16-metre
cells without changing their source hierarchy, material, or geometry. The
unbatched overview required 4,632 draw calls; eager batching required 448.
Spatial acquisition assembles 63 regions on demand, retains each region at most
once within the viewer's fixed source closure, and releases that closure on
close. A source inspection camera near the forklift loaded 5 regions and
12,643,585 source bytes; opening the full warehouse loaded all 63 regions and
40,168,724 bytes. The full spatially loaded scene used 473 draw calls. These are
hash-checked local interception measurements, not live-network timings or GPU
elapsed-time measurements. No mesh LOD or simplified geometry is substituted.

Bounds are derived from the sealed native MeshManager vertex capture and
original SDF mesh scales. They include a 20-micrometre conservative margin and
remain separate from the source scene. Queue changes discard obsolete pending
regions; active source acquisition uses the viewer's abort signal. Static
regions remain inspectable through their original links before acquisition.
The starting view is an inspection composition, not a native sensor camera.
All 900,372 native body/basis comparisons and thirteen source mesh comparisons
pass with spatial loading enabled.

```sh
PYTHONPATH=scripts python3 -m worlds.prepare_opennav_spatial \
  --cache .cache/opennav-warehouse \
  --display .cache/opennav-warehouse/mission-display-003 \
  --native .cache/opennav-warehouse/native-mesh-capture-003 \
  --output .cache/opennav-warehouse/new-spatial-bounds.json

node scripts/worlds/verify_opennav_browser.mjs \
  .cache/opennav-warehouse .cache/opennav-warehouse/mission-display-003 \
  .cache/opennav-warehouse/native-local-pose-reference-001.json.gz \
  .cache/opennav-warehouse/new-desktop-spatial spatial-loading full \
  .cache/opennav-warehouse/new-spatial-bounds.json

node scripts/worlds/verify_opennav_lifecycle.mjs \
  .cache/opennav-warehouse .cache/opennav-warehouse/mission-display-003 \
  .cache/opennav-warehouse/new-spatial-bounds.json \
  .cache/opennav-warehouse/new-spatial-lifecycle
```

`scripts/worlds/publish_opennav_episode.py` prepares the measured mission as an
episode in a fresh review directory. It rereads the native log, checks every
exported pose and observed command, regenerates the scene and spatial bounds,
and requires matching desktop, native mesh and lifecycle evidence. The prepared
episode has 11,847 samples over 191.81 seconds in 186 bounded chunks. Its explicit
`body-poses` representation has zero qpos/qvel/applied-action channels and no
fixed frame skip. Native Twist observations stay separately timestamped in task
metadata. Both navigation legs and handling waits completed; this protocol has
no fixed episode-step horizon. Preparing these files does not register a public
world or complete camera synchronization.

```sh
PYTHONPATH=scripts:.cache/opennav-warehouse/protobuf-python \
python3 -m worlds.publish_opennav_episode \
  --cache .cache/opennav-warehouse \
  --display .cache/opennav-warehouse/mission-display-003 \
  --recording .cache/opennav-warehouse/native-mission-002 \
  --desktop .cache/opennav-warehouse/desktop-spatial-003 \
  --mesh-audit .cache/opennav-warehouse/mesh-attributes-spatial-003.json \
  --lifecycle .cache/opennav-warehouse/desktop-spatial-lifecycle-001 \
  --spatial .cache/opennav-warehouse/warehouse-spatial-bounds-001.json \
  --native-meshes .cache/opennav-warehouse/native-mesh-capture-003 \
  --reference .cache/opennav-warehouse/native-local-pose-reference-001.json.gz \
  --camera .cache/opennav-warehouse/camera-export-001 \
  --output .cache/opennav-warehouse/new-publication-preparation
```

The component preparation, source packaging, full desktop page and production transport require separate validation. Physical-phone checks are owner-deferred.
