Guide3 min read2 sections

Immutable model admission

docs/MODEL_ADMISSION.mdSource updated 2026-10-25
Markdown
On this page 2 sections

Model validation now returns a reusable immutable artifact within one JavaScript realm. The reader records only its own successfully validated, deeply frozen result objects in a private WeakMap. Reusing that exact object skips another JSON snapshot, semantic traversal and checksum pass. An asserted hash, a frozen caller object, a proxy or a structured clone does not carry this admission. Fresh input still passes the complete existing model reader, including original/base identity, geometry, textures, animation, skin and model-detail checks.

The receipt contains canonical byte length, JSON value count, maximum depth and a memoized admission promise. It does not hold a second serialized string, decoded geometry or a GPU resource. The weak registry does not keep a model alive after its actual owners release it. Explicitly retaining a snapshot or model continues to own that data. This is not a hash-addressed global cache, a new memory budget or a cross-worker credential.

#Catalog and ownership rules

snapshotModelTable captures every fresh entry synchronously before any asynchronous admission starts. Later caller mutation cannot alter a pending catalog. Previously admitted entries retain their exact immutable identity. Failed snapshots never become admitted models; a failed read remains a failure.

Catalog admission still enforces 32 entries, the exact 16 MiB canonical JSON byte budget, one million JSON values and depth 64. Every alias counts toward these serialized budgets, even when it shares a model. UTF-8 key encoding, colons, commas and braces are included. The existing canonical encoder and model table admission share the same complexity constants. GPU resource accounting remains independently deduplicated and bounded by the existing catalog/model/device rules.

Authored catalog names retain their existing validation. Presentation tables still require import:<artifact-hash> identities. Streamed place preparation checks the exact expected dependency set and pinned artifact hashes before creating collision/projection data. No artifact, content, world, checkpoint or wire profile changes in this increment.

The renderer, collision preparer and animation/skeleton presentation constructors can reuse an admitted model. Crossing a Worker boundary or loading JSON creates fresh objects and therefore requires validation again. This avoids redundant work inside a worker without trusting unvalidated messages or changing GPU ownership, retirement or recovery.

#Measurement and qualification

Run npm run bench:model-admission -- test-results/model-admission-benchmark.json. It measures the complete prepareModelCatalog operation for both fresh input and an already-admitted artifact, including remaining mesh/index copying and the catalog digest. Three untextured analytic fixture sizes use one warmup and three observations per case, alternating case order.

The same benchmark source was run against an isolated source archive of commit 89a0d885b5d1c610cf83bd8b33c2856c5c79c7cd and the new worktree, sequentially with the same Node/dependency runtime. All three artifact hashes match. For the 66,049-vertex / 391,680-index fixture, the median fresh-catalog time falls from about 1,378 ms to 659 ms; an already-admitted catalog falls from about 1,397 ms to 114 ms. Baseline observations, current observations.

These observations are local CPU evidence, not network startup, FPS, physical GPU, p95 or long-session guarantees. First admission remains substantial, and standalone precomputed variants still add encoded bytes. Independent detail streaming, progressive texture quality, further preparation work and broader device qualification remain open. Acceptance evidence records adversarial ownership/budget checks, the native/full regression suite and browser journeys.

End of Model admission