Files
open-wc/docs/modules/wmo-scene-resource-finalizer.md
T

11 KiB

WMO Scene Resource Finalizer

Metadata

Field Value
Status Implemented extraction
Target/work package M03 / M03-RND-WMO-SCENE-RESOURCE-FINALIZER-001
Owners Cached WMO PackedScene terminal polling, validation-probe lifetime and scene/missing publication
Last verified Worktree work/sindo-main-codex/m03-wmo-scene-resource-finalizer, 2026-07-18
Profiles/capabilities Profile-independent cached WMO .tscn finalization

Purpose

Finalize pending cached WMO .tscn requests outside StreamingWorldLoader: poll terminal status, retrieve a PackedScene, instantiate one validation probe, apply existing WMOBuilder cache metadata rules, release the probe and publish either the exact scene or the historical missing outcome.

Non-goals

  • Select paths, measure file size or start ResourceLoader requests.
  • Instantiate placed WMO scenes or execute live WMOBuilder fallback.
  • Own cache lifetime, placements, build queues, permits or attached Nodes.
  • Change cache metadata/version rules, fallback order or visible behavior.

Context and boundaries

flowchart LR
    Loader[StreamingWorldLoader] -->|compose and tick| Finalizer[WmoSceneResourceFinalizer]
    Cache[WmoSceneResourceCacheState] -->|pending snapshot| Finalizer
    Finalizer --> ResourceLoader
    Finalizer --> Probe[Temporary Node3D probe]
    Probe --> Validator[WMOBuilder cache validator]
    Finalizer -->|PackedScene or missing| Cache
    Cache --> Fallback[Placed cached scene or live fallback]

The service may depend on ResourceLoader, PackedScene/Node3D lifetime and the injected cache validator. FileAccess, size policy, placement, attached SceneTree, scheduler and application layers remain outside it.

Public API

Symbol Kind Purpose Thread/lifetime Errors
poll_terminal_requests(cache_state) Command/query Poll every pending scene path once and publish terminal outcomes Renderer main thread; stateless between calls Null state returns zero; non-terminal retained
is_scene_cache_current(scene) Command/query Instantiate, validate and release one probe Renderer main thread; call-local Node Null/no validator/wrong root/stale false
load_threaded_get_status(path) Boundary query Read threaded status Renderer main thread; injectable tests ResourceLoader semantics
load_threaded_get(path) Boundary query Retrieve terminal Resource Renderer main thread; injectable tests Null/wrong type rejected

Inputs and outputs

Direction Contract/data Producer Consumer Ownership Thread/lifetime
Input Detached normalized-path to .tscn path Dictionary Scene cache state Finalizer polling Caller-owned copy One pass
Input Opaque load status/terminal Resource ResourceLoader Finalizer Value/borrowed Resource One path
Input Cached WMO PackedScene ResourceLoader Probe validator Borrowed reference One completion
Input Metadata validator Loader composition Finalizer Borrowed Object Finalizer lifetime
Output Exact validated PackedScene Finalizer Scene cache state Cache adopts strong reference Until full clear
Output Missing transition Finalizer Scene cache state Path-only state Until transient clear
Side effect Temporary validation Node PackedScene/finalizer Validator Finalizer-owned Freed before return

Data flow

flowchart TD
    Snapshot[Detached pending snapshot] --> Poll[Poll next status in insertion order]
    Poll --> Terminal{Loaded or failed?}
    Terminal -->|no| Retain[Retain pending]
    Terminal -->|failed| Missing[Complete missing]
    Terminal -->|loaded| Get[Get Resource]
    Get --> Type{PackedScene?}
    Type -->|no| Missing
    Type -->|yes| Instantiate[Instantiate one probe]
    Instantiate --> Root{Node3D root?}
    Root -->|no| FreeRejected[Free rejected Node] --> Missing
    Root -->|yes| Validate[WMOBuilder metadata validation]
    Validate --> Free[Free Node3D probe]
    Free --> Current{Current?}
    Current -->|yes| Adopt[Adopt exact PackedScene]
    Current -->|no| Missing

Lifecycle/state

stateDiagram-v2
    [*] --> Polling
    Polling --> Pending: non-terminal
    Polling --> Probing: loaded PackedScene
    Polling --> Missing: failed/null/wrong type
    Probing --> Missing: wrong root or stale metadata
    Probing --> Cached: current metadata
    Probing --> Released: probe freed before outcome
    Released --> Missing
    Released --> Cached
    Pending --> Polling: later tick

The finalizer retains no request or Node. Cache state owns Pending/Cached/Missing lifetime; every instantiated probe is synchronously released before return.

Main sequence

sequenceDiagram
    participant Loader as StreamingWorldLoader
    participant Finalizer as WmoSceneResourceFinalizer
    participant Cache as WmoSceneResourceCacheState
    participant RL as ResourceLoader
    participant Validator as WMOBuilder validator
    Loader->>Finalizer: poll_terminal_requests(Cache)
    Finalizer->>Cache: request_paths_snapshot()
    loop insertion-ordered paths
        Finalizer->>RL: load_threaded_get_status(path)
        alt failed
            Finalizer->>Cache: complete_request_as_missing(path)
        else loaded
            Finalizer->>RL: load_threaded_get(path)
            Finalizer->>Finalizer: instantiate Node3D probe
            Finalizer->>Validator: is_scene_cache_current(probe)
            Finalizer->>Finalizer: free probe
            Finalizer->>Cache: complete with exact scene or missing
        else non-terminal
            Finalizer->>Finalizer: retain request
        end
    end

Dependency diagram

flowchart TB
    Loader[StreamingWorldLoader] --> Finalizer[WmoSceneResourceFinalizer]
    Loader --> Cache[WmoSceneResourceCacheState]
    Finalizer --> Cache
    Finalizer --> ResourceLoader
    Finalizer --> PackedScene
    Finalizer --> Node3D
    Finalizer --> Validator[WMOBuilder cache validator]
    Finalizer -. no dependency .-> FileAccess
    Finalizer -. no dependency .-> Placement
    Finalizer -. no dependency .-> Scheduler

Ownership, threading and resources

  • Renderer main thread serializes polling, instantiation and cache publication.
  • Finalizer owns every call-local validation probe and frees it before return.
  • Non-Node3D rejected roots are also freed, closing the prior leak edge.
  • Cache state adopts accepted exact PackedScene references until full clear.
  • Loader owns admission/size policy, live fallback, placed Nodes and shutdown order.

Errors, cancellation and recovery

Failure/state Detection Behavior Diagnostic Recovery
Null cache state Guard Return zero Contract verifier Correct composition
Non-terminal Status Retain pending Pending count Poll later
Failed/null/wrong Resource Status/type Complete missing Synthetic fixture Reset/rebuild cache
Non-Node3D root Probe type Free probe; complete missing Type/lifetime fixture Rebuild cache
Stale metadata Injected validator Free probe; complete missing Validation fixture Rebuild/reset
Shutdown Loader lifecycle Drain then clear cache Shutdown verifier New loader starts absent

Configuration and capabilities

The loader injects the existing WMOBuilder cache validator. wmo_cache_dir, wmo_max_runtime_scene_mb, debug logging, request timing and WMO budgets remain loader-owned. No setting, profile or cache version is added.

Persistence, cache and migration

No data is serialized. Existing WMOBuilder metadata/version acceptance is called unchanged before adoption. The rejected-root lifetime fix needs no migration or rebake and does not alter accepted cache output.

Diagnostics and observability

  • Poll returns terminal completion count for tests/future metrics.
  • Existing pending count and renderer wmobuild metrics remain unchanged.
  • No logs are emitted; oversize debug logging remains at loader admission.
  • Normalized WMO relative path remains the correlation key.

Verification

  • verify_wmo_scene_resource_finalizer.gd: null/non-terminal, insertion order, failed/load boundary, null/wrong/non-Node3D/stale rejection, current exact identity, accepted/rejected probe release, source ownership and timing.
  • Scene cache, render finalizer/cache, WMO queue/planner/registry/resolver, shutdown, facade, internal-access and baseline regressions cover neighbors.
  • Fidelity evidence is exact orchestration extraction plus rejected-root leak repair; no asset-backed visual or original-client parity claim is made.

Extension points

  • Legal current/stale serialized .tscn fixtures can extend evidence unchanged.
  • Placed-scene preparation stays separate because it mutates an attached WMO instance rather than a call-local validation probe.

Capability status

Capability Status Evidence Gap/next step
Cached WMO scene terminal polling Implemented extraction Status/order/source/timing verifier Asset-backed traversal pending
Probe validation/lifetime Implemented extraction Current/stale/type/free fixtures Serialized fixture pending
Scene/missing publication Implemented extraction Exact identity/negative fixtures Asset-backed lifetime/leak run pending
File-size admission/live fallback Loader-owned Existing scene-cache regressions Separate extraction if justified

Known gaps and risks

  • PackedScene instantiation/metadata validation remains synchronous main-thread work.
  • No proprietary WMO corpus, serialized stale/oversize fixture, long leak run, traversal p95/p99 or paired original-client capture is included.

Source map

Path Responsibility
src/render/wmo/wmo_scene_resource_finalizer.gd Terminal polling, probe validation/lifetime and publication
src/render/wmo/wmo_scene_resource_cache_state.gd Scene/missing/request ownership and resets
src/scenes/streaming/streaming_world_loader.gd Admission/size policy, live fallback and placed Node ownership
addons/mpq_extractor/loaders/wmo_builder.gd Existing cache metadata/version validation
src/tools/verify_wmo_scene_resource_finalizer.gd Terminal/probe/lifetime/source/timing regression