Files
open-wc/docs/modules/m2-build-resource-snapshot.md
T

12 KiB

M2 Build Resource Snapshot

Metadata

Field Value
Status Implemented extraction
Target/work package M03 / M03-RND-M2-BUILD-RESOURCE-SNAPSHOT-001
Owners Per-build-step observed M2 resource references and outcome flags
Last verified Worktree work/sindo-main-codex/m03-m2-build-resource-snapshot, 2026-07-18
Profiles/capabilities Existing static MultiMesh and animated-instance build paths

Purpose

Carry the resource observations for one M2 build operation as a typed contract: normalized path, optional animated prototype, pending-animation state, optional static Mesh and terminal missing-model state. The snapshot never owns engine lifetime.

Non-goals

  • Locate, request, load, validate or cache M2 resources.
  • Decide dispatch action, batch count, queue order or permit consumption.
  • Create, attach or free Nodes, Meshes, MultiMeshes or animated instances.
  • Change animation allowlists, native candidate rules or cache paths/formats.
  • Persist observations beyond one build operation.

Context and boundaries

flowchart LR
    Native[M2NativeAnimationResourceObserver] --> Snapshot[M2BuildResourceSnapshot]
    Cached[M2CachedAnimationResourceObserver] --> Snapshot
    Static[M2StaticBuildResourceObserver] --> Snapshot
    Snapshot --> Dispatch[M2BuildDispatchPlanner]
    Snapshot --> Loader
    Loader --> Animated[M2AnimatedInstanceMaterializer]
    Loader --> Static[M2StaticBatchMaterializer]

The snapshot depends only on RefCounted, String, booleans and borrowed Node3D/ Mesh references. ResourceLoader, cache/pipeline state, SceneTree mutation, RenderingServer/RIDs, files, workers, mutexes, gameplay, network and Editor APIs are forbidden.

Public API

Symbol Kind Purpose Thread/lifetime Errors
Constructor (normalized_path, animated_prototype, animation_pending) Command Capture first-phase animation observation Main thread; one build operation Values retained exactly
normalized_relative_path() Query Return observed normalized path Snapshot lifetime None
animated_prototype() Query Borrow exact animated prototype Main thread; no ownership transfer May be null
has_animated_prototype() Query Report prototype availability Any serialized caller None
animation_request_pending() Query Report pending animation request Any serialized caller None
adopt_static_observation(mesh, missing) Command Replace second-phase static observation Main thread Values retained exactly, including contradictory inputs
static_mesh() Query Borrow exact prepared Mesh Main thread; no ownership transfer May be null
has_static_mesh() Query Report static Mesh availability Any serialized caller None
static_model_missing() Query Report terminal missing outcome Any serialized caller None
diagnostic_snapshot() Query Return detached path/availability flags Any serialized caller Omits engine references

Inputs and outputs

Direction Contract/data Producer Consumer Ownership Thread/lifetime
Input Normalized relative path Loader path adapter Snapshot/diagnostics Copied String Snapshot lifetime
Input Optional animated prototype Native/cached animation observer Snapshot/materializer adapter Borrowed exact Node3D reference One build operation
Input Animation request pending Cached animation observer Snapshot/dispatch planner Boolean copy One build operation
Input Optional prepared static Mesh Mesh cache/request path Snapshot/materializer adapter Borrowed exact Mesh reference One build operation
Input Static model terminally missing Prototype cache state Snapshot/dispatch planner Boolean copy One build operation
Output Availability/pending/missing values Snapshot Dispatch planner Scalar reads One dispatch plan
Output Borrowed prototype or Mesh Snapshot Loader materializer adapter No ownership transfer One materialization call
Output Detached diagnostics Snapshot Tests/future metrics Caller-owned Dictionary Call result

The snapshot is released after the build-loop operation. Releasing or replacing it never frees the borrowed Node3D or Mesh.

Data flow

flowchart TD
    Path[Normalized M2 path] --> Construct[Create snapshot]
    Animated[Animated prototype or null] --> Construct
    Pending[Animation request pending] --> Construct
    Construct --> PendingCheck{Animation pending?}
    PendingCheck -->|yes| Dispatch[Dispatch planner]
    PendingCheck -->|no| Batch[Batch planner]
    Batch --> StaticNeeded{Positive static batch?}
    StaticNeeded -->|yes| Adopt[Adopt Mesh and missing observation]
    StaticNeeded -->|no| Dispatch
    Adopt --> Dispatch
    Dispatch --> Borrow[Loader borrows selected resource]

Lifecycle/state

stateDiagram-v2
    [*] --> AnimationObserved: construct
    AnimationObserved --> AnimationObserved: animation pending or animated path
    AnimationObserved --> StaticObserved: adopt static result
    StaticObserved --> StaticObserved: replace static result
    AnimationObserved --> Released: operation ends
    StaticObserved --> Released: operation ends
    Released --> [*]

Main sequence

sequenceDiagram
    participant L as StreamingWorldLoader
    participant S as M2BuildResourceSnapshot
    participant B as M2BuildBatchPlanner
    participant D as M2BuildDispatchPlanner
    participant M as M2 materializer
    L->>L: delegate native animated prototype observation
    L->>S: construct native result
    opt no native prototype
        L->>L: delegate cached animation observer
        L->>S: receive cached/pending snapshot
    end
    alt animation not pending
        L->>B: plan batch using snapshot availability
        opt positive static batch
            L->>L: lookup/request static Mesh
            L->>S: adopt_static_observation
        end
    end
    L->>D: plan_step(batch count, snapshot)
    D-->>L: action plan
    opt materialization action
        L->>S: borrow prototype or Mesh
        L->>M: materialize selected slice
    end

Dependency diagram

flowchart TB
    Loader[StreamingWorldLoader] --> Snapshot[M2BuildResourceSnapshot]
    Dispatch[M2BuildDispatchPlanner] --> Snapshot
    Snapshot --> Values[String and booleans]
    Snapshot --> Borrowed[Borrowed Node3D and Mesh]
    Snapshot -. no dependency .-> IO[ResourceLoader / FileAccess]
    Snapshot -. no dependency .-> State[Cache / pipeline / queue / scheduler]
    Snapshot -. no dependency .-> Mutation[SceneTree / RenderingServer]

Ownership, threading and resources

  • Snapshot owns only copied scalar state and temporary references.
  • Prototype/cache services retain resource state; the native observer owns its phase while loader owns native-first ordering among resource observers.
  • Scene roots remain loader/tile-owned; Mesh lifetime follows cache/resource refs.
  • Dispatch planner reads only snapshot accessors and never mutates the snapshot.
  • Current construction/adoption occurs on renderer main thread.

Errors, cancellation and recovery

Failure/state Detection Behavior Diagnostic Recovery
Empty path Exact String retained No validation or hidden normalization Contract fixture Loader already normalizes input
Null prototype/Mesh Availability accessor false Dispatch uses pending/missing state Contract fixture Loader request/cache path retries
Mesh and missing both true Exact adoption Both retained; dispatch gives ready Mesh priority Contradiction fixture Loader normally prevents combination
Static observation replaced Explicit adoption Latest Mesh/missing values win Replacement fixture None required
Borrowed Node externally freed Outside snapshot Loader validity/lifecycle gates remain authoritative Shutdown regressions Tile may cancel/requeue
Tile cancellation Outside snapshot Ephemeral snapshot releases references Queue/shutdown regressions Eligible tile may rebuild

Configuration and capabilities

The snapshot adds no setting. Existing animation enable/allow/deny rules, batch limits, cache paths, render settings and scheduler permits remain external.

Persistence, cache and migration

No observation is serialized. No ADT/M2 cache version changes and no rebake or migration are required.

Diagnostics and observability

diagnostic_snapshot() exposes normalized path and four availability/outcome flags without Node/Mesh references. The module emits no logs. Existing loader queue/hitch metrics remain unchanged.

Verification

  • verify_m2_build_resource_snapshot.gd covers exact path/reference identity, defaults, static adoption/replacement/clear, contradictory flags, detached diagnostics, engine lifetime, loader/dispatch boundaries and bounded timing.
  • Dispatch, queue, batch, materializer, cache/pipeline, shutdown, facade, internal-access and checkpoint regressions protect adjacent behavior.
  • Fidelity evidence is exact observation transfer only; no private asset or original-client visual claim is made.

Extension points

M2CachedAnimationResourceObserver produces the cached animated phase and M2StaticBuildResourceObserver produces the static phase. Native animation is produced by M2NativeAnimationResourceObserver. The value stays independent of all producers and of generic callback frameworks.

Capability status

Capability Status Evidence Gap/next step
Typed per-step M2 resource observation Implemented extraction Identity/adoption/lifetime/source/timing verifier Asset-backed traversal pending
Dispatch decision Implemented separately Dispatch planner verifier Asset-backed traversal pending
Static lookup/request execution Implemented separately Static observer verifier Asset-backed traversal pending
Cached animated lookup/request execution Implemented separately Cached observer verifier Asset-backed traversal pending
Native animated lookup/build execution Implemented observer extraction Native observer lifecycle/source verifier Asset-backed traversal pending
Engine lifetime/materialization Loader/materializer-owned Lifetime/materializer regressions GPU/p95/p99 evidence pending

Known gaps and risks

  • Static observation is mutable during its short two-phase construction.
  • Raw Node3D/Mesh references remain necessary for current materializer APIs.
  • Native parsing/build remains synchronous; loader still owns terminal polling.
  • Synthetic timing does not measure resource, Node or GPU work.

Source map

Path Responsibility
src/render/m2/m2_build_resource_snapshot.gd Typed per-step resource observations and diagnostics
src/render/m2/m2_build_dispatch_planner.gd Snapshot-to-action planning
src/render/m2/m2_static_build_resource_observer.gd Static snapshot production and requests
src/render/m2/m2_cached_animation_resource_observer.gd Cached animated snapshot production and requests
src/render/m2/m2_native_animation_resource_observer.gd Native prototype observation producer
src/scenes/streaming/streaming_world_loader.gd Observer ordering and materializer borrowing
src/tools/verify_m2_build_resource_snapshot.gd Identity/adoption/lifetime/boundary/timing regression