# BEHAVIOR source video and state conversion

This recipe converts one official MIT-licensed simulated human demonstration. It does not execute OmniGibson, acquire its encrypted 3D Data Bundle, restore a 3D world or reproduce a task score. Phone testing is deferred; desktop playback is the current scope.

Use the clean site commit identified by the downloaded recipe's `build.metadata.commit`. The source dataset is `behavior-1k/2026-challenge-demos` at `4f50b44796641a4d526a19d9aeadc8aa51e2f2c2`. The ten-file selection, byte limits and SHA-256 hashes are in `scripts/worlds/locks/behavior/radio-demo.json` (706,407,125 bytes). Raw HDF5 and the encrypted Data Bundle are not inputs to this conversion.

The v3.9.2 reference reader at `b1979916ec1549b10a4e65e630bc6504a9af1b00` postdates the dataset. It is a channel/protocol reference, not an exact historical producer pin. The LeRobot episode is 0, task `turning_on_radio`, raw episode id 10 and task instance 1. These identifiers are not interchangeable with a reset seed.

## Prepare the converter

From the site checkout, with Python 3.12 on Linux x86-64:

```sh
python3.12 -m venv .cache/behavior-replay/env
.cache/behavior-replay/env/bin/python -m pip install -r scripts/worlds/locks/behavior/requirements.txt
.cache/behavior-replay/env/bin/python -m pip install imageio-ffmpeg==0.6.0
.cache/behavior-replay/env/bin/python - <<'PY'
import hashlib, json, shutil
from pathlib import Path
import imageio_ffmpeg
source = Path(imageio_ffmpeg.get_ffmpeg_exe())
expected = json.loads(Path('worlds/behavior/radio/evidence.json').read_text())['ffmpeg_sha256']
assert hashlib.sha256(source.read_bytes()).hexdigest() == expected, 'FFmpeg binary differs from reviewed 7.0.2-static'
shutil.copyfile(source, '.cache/behavior-replay/ffmpeg')
Path('.cache/behavior-replay/ffmpeg').chmod(0o755)
PY
```

## Acquire, encode, compare and publish

Existing valid source files are reused after hash verification. Incomplete `.part` downloads are retained and cause a retry to stop. Encoding and verification require new output directories; use new names for each attempt. Publication writes the generated BEHAVIOR files in the checkout.

```sh
.cache/behavior-replay/env/bin/python scripts/worlds/behavior_demo.py --cache .cache/behavior-replay/dataset acquire
.cache/behavior-replay/env/bin/python scripts/worlds/behavior_demo.py --cache .cache/behavior-replay/dataset inspect
.cache/behavior-replay/env/bin/python scripts/worlds/behavior_demo.py --cache .cache/behavior-replay/dataset encode --output .cache/behavior-replay/reproduce-encoded --ffmpeg .cache/behavior-replay/ffmpeg
.cache/behavior-replay/env/bin/python scripts/worlds/behavior_demo.py --cache .cache/behavior-replay/dataset verify-media --encoded .cache/behavior-replay/reproduce-encoded --output .cache/behavior-replay/reproduce-verification --ffmpeg .cache/behavior-replay/ffmpeg
PYTHONPATH=scripts .cache/behavior-replay/env/bin/python -m worlds.behavior_publish --cache .cache/behavior-replay/dataset --encoded .cache/behavior-replay/reproduce-encoded --verification .cache/behavior-replay/reproduce-verification
PYTHONPATH=scripts python3 -m worlds.behavior_publish --check
```

Each camera retains all 1,956 original frames. H.264 encoding uses libx264, CRF 18, medium preset, 15-frame GOP, disabled scene-cut insertion, yuv420p and faststart, with two encoder threads. Every published packet timestamp is checked, including the entire published clip (no extra trailing frames). All decoded source/publication frame pairs are compared; dimensions and a minimum 35 dB frame PSNR are checked. Reviewed minima were head 43.93 dB, left wrist 43.69 dB and right wrist 44.25 dB. Preserve the MIT notice with derived media.

The published media hashes are in each manifest camera and `worlds/behavior/radio/evidence.json`. Source row conversion preserves all 61 state channels, 23 action channels, three camera poses and next-transition fields. The selected-samples digest binds the complete extracted stream; original parquet and metadata hashes bind its upstream inputs. No observation is shifted against its action or next-transition fields. Float32 row timestamps remain unchanged; media timestamps use exact frame index / 30.

The source annotation covers 1,776 frames rather than 1,956. Skill labels remain unsynchronized until their mapping is established. `next_terminated=true` is a source transition flag, not independent success. Summary success and return remain unknown. No placeholder root pose, qpos, geometry or benchmark result is fabricated.

## Desktop verification

The Worker serves the three pinned MP4 files with single-byte-range support and fixed response lengths. The production Static Assets binding returned full `200` responses to range requests; that allowed playback but prevented reliable seeking. The range handler streams the requested interval from the asset binding, discards any preceding chunks and cancels the unused tail. It does not buffer a complete video. A late seek can still read the preceding bytes from the binding; it is not an indexed storage read.

The desktop probe runs the actual Worker and its Static Assets binding through `wrangler dev --local`, then checks `HEAD`, exact `206` response bytes, playback and exports. The binding omits `Content-Length` internally; the manifest supplies the bound and the streamed output still must have exactly the declared byte count. `tests/test_behavior_media_workerd.mjs` separately verifies the response length and range bytes in workerd. A plain local HTTP range server is insufficient to verify this delivery contract.

After `bash scripts/sync-worker-public.sh`, run `node scripts/viewer/verify-behavior-replay.mjs .cache/behavior-replay/desktop-review-001` from the checkout. The tool owns its ephemeral server and browser and writes a report, screenshots and actual UI downloads to a new output directory. For production verification, use `node scripts/viewer/verify-behavior-replay.mjs OUTPUT_DIRECTORY https://botlandscape.com/ MERGED_COMMIT`. Run the shared player regressions and the integrated desktop check with one browser/video process at a time. The default Chromium profile and the Intel Arc graphics profile with `--disable-accelerated-video-decode` use FFmpeg software video decoding. The forced Intel hardware-video-decoder profile failed with `PIPELINE_ERROR_DISCONNECTED`; hardware decoding is not claimed to pass. Metadata and recipe downloads must identify the selected, presented sample and the clean published site commit.

Native OmniGibson remains a separate acceptance item under issue #150. Its NVIDIA RTX requirement was unavailable on this Intel Arc host. The MIT demo publication does not confer extraction or redistribution rights for the separate restricted 3D Data Bundle. No bundle/key was acquired and no bundle licence was accepted for this work.
