Bundle Entry:
docs/spec/HOST_RUNTIME_BUNDLE_v0.1.md
XR Host Runtime v0.1
Status: normative for deterministic XR runtime behavior.
Goal
Define deterministic WebXR-aligned capability behavior that runs consistently across:
- native host CI/runtime (first-party XR runtime),
- WASI/wasm-host bridge profile lanes,
- browser-facing wasm execution paths.
XR ABI Families
Baseline families:
gfx/xr::session-opengfx/xr::frame-pollgfx/xr::input-pollgfx/xr::hands-pollgfx/xr::hit-testgfx/xr::spatial-mesh-pollgfx/xr::anchor-creategfx/xr::anchor-updategfx/xr::anchor-destroygfx/xr::layer-creategfx/xr::layer-updategfx/xr::layer-destroygfx/xr::haptics-pulsegfx/xr::submit-framegfx/xr::session-close
These ops are first-party deterministic by default and can be explicitly bridge-routed via per-op bridge policy (bridge_cmd or wasi_bridge_profile response mapping). In addition, a dedicated WebXR device lane is available via xr_backend = "webxr-device" with explicit bridge transport. Artifact-backed production policy loads classify this backend and every haptics and advanced-feature policy field through GenesisCode authority protocol v0.19. The host consumes only the installed result and retains matching, bound enforcement, deterministic runtime state, bridge/adapter execution, replay, and resource lifecycle.
Runtime Contract
First-party XR runtime exposes deterministic identity fields:
:backend = "xr-first-party-runtime":adapter = "xr-headless-sim"
WebXR device runtime lane (xr_backend = "webxr-device") exposes:
:backend = "xr-webxr-device-runtime":adapter = "webxr-device"(or bridge-provided adapter if set)- deterministic
:replay-envelopemap::schema = :gfx/xr-webxr-device-replay-envelope.v1:capture-seqmonotonically increasing deterministic capture index per runtime process:source = :webxr-device:opoperation symbol:deterministic = true
WebXR device lane policy requirements:
- per-op
xr_backend = "webxr-device" - explicit bridge profile (
bridge_cmdorwasi_bridge_profile+ deterministic bridge response mapping) - fail-closed policy error if
xr_backend = "webxr-device"is configured without bridge transport. - production aliases and production runtime-profile fallback require the GenesisCode-composed bridge-active decision and otherwise return the stable
gfx/xr-policy-disabledenvelope. - canonical template:
docs/policies/xr_webxr_device_caps_v0.1.toml
Browser-native conformance lane:
- CI job:
webxr_browser_conformancein.github/workflows/ci.yml - checker:
scripts/check_webxr_browser_conformance.sh - runtime harness:
scripts/webxr_browser_conformance.mjs - artifact:
.genesis/perf/webxr_browser_conformance_report.json - explicit artifact producer:
scripts/update_webxr_browser_conformance_report.sh - CI invokes the explicit producer because it uploads the report; the checker always uses a private temporary output.
- conformance scope:
- real browser
navigator.xrsession open (inline) + reference-space request - deterministic render-layer initialization (
XRWebGLLayer) before frame probe - frame callback with bounded classification; functional pass requires
frame.status = ok - real input-source snapshot from
session.inputSources - real haptics attempt on available actuators, or deterministic
no-haptics-sourceclassification - session-close functional proof:
session.end()resolved close (status = closed), or- deterministic close-recovery proof (
status = closed-quiesced) when browser runtime leavessession.end()unresolved but old-session frames quiesce and reopen+frame succeeds
- deterministic replay assertion using capture hash equivalence across two independent runs
- real browser
Session lifecycle contract:
session-openreturns a deterministic session id and normalized mode/reference-space metadata.frame-pollincrements deterministic frame index and emits deterministic frame envelopes.input-pollemits deterministic controller/input envelopes with bounded:max-inputs.hands-pollemits deterministic left/right hand joint envelopes with policy-bounded joint counts.hit-testemits deterministic hit vectors and pose envelopes with policy-bounded result counts.spatial-mesh-pollemits deterministic mesh metadata envelopes with policy-bounded mesh/vertex counts.anchor-create/anchor-update/anchor-destroymaintain deterministic anchor lifecycle state per session.layer-create/layer-update/layer-destroymaintain deterministic compositor layer lifecycle state per session.haptics-pulseapplies deterministic bounded haptic intents for a session/input lane.submit-framerecords deterministic accepted/submitted counters.session-closeseals the session and deterministically rejects further use via stable error codes.
Haptics policy gate contract (gfx/xr::haptics-pulse):
Artifact-backed production loads preserve these defaults and effect-use errors through the closed GenesisCode XR decision. A malformed haptics field cannot change unrelated XR operations or reject the capability file early.
- required per-op
allow_haptics_inputs = ["<input-id>" ...]allowlist. - optional per-op
max_haptics_amplitudeinteger (1..1000, default1000). - optional per-op
max_haptics_duration_msinteger (>0, default250). - requests outside policy bounds fail closed with deterministic
core/caps/policy-errorenvelopes.
Advanced XR policy gate contract:
GenesisCode trims these allowlists, removes empty entries, preserves order and duplicates, and ASCII-lowercases anchor-space and layer-type values. The strict host decoder rejects noncanonical output before installing policy state; no first-party XR operation rereads raw TOML.
gfx/xr::hands-poll- optional per-op
allow_hand_tracking(bool, defaulttrue) - optional per-op
max_hand_joints(int > 0, default25)
- optional per-op
gfx/xr::hit-test- optional per-op
allow_hit_test(bool, defaulttrue) - optional per-op
max_hit_results(int > 0, default8)
- optional per-op
gfx/xr::spatial-mesh-poll- optional per-op
allow_spatial_mesh(bool, defaulttrue) - optional per-op
max_meshes(int > 0, default4) - optional per-op
max_mesh_vertices(int > 0, default4096)
- optional per-op
gfx/xr::anchor-create- optional per-op
allow_anchor_spaces(array, default ["local","local-floor","bounded-floor","viewer"]) - optional per-op
max_anchors(int > 0, default64)
- optional per-op
gfx/xr::layer-create/gfx/xr::layer-update- optional per-op
allow_layer_types(array, default ["quad","cylinder","equirect"]) - optional per-op
max_layers(int > 0, default16) - optional per-op
max_layer_opacity(int > 0, default1000)
- optional per-op
- requests outside these policy bounds fail closed with deterministic
core/caps/policy-errorenvelopes.
Determinism + Replay
- First-party XR runtime state is process-local deterministic state (session table, frame counters, submit counters).
haptics-pulseemits deterministic:pulse-idand cumulative:submitted-hapticscounters.- WebXR device lane emits deterministic per-op replay envelopes (
:replay-envelope) that are hashed in run/replay equivalence checks. - Browser-native WebXR lane enforces deterministic capture-replay equivalence:
hash(run_a_capture) == hash(run_b_capture)- replay rule persisted in
.genesis/perf/webxr_browser_conformance_report.json.
runandreplayproduce identical value hashes for the same program/log pair.- Native/WASI lane parity is enforced by
scripts/check_agent_workflow_runtime_parity.shvia the shared gauntlet workflow set.