Files
open-wc/docs/modules/m2-mesh-resource-cache-state.md
T
sindoring 7b0e1eac5f refactor(M03): extract M2 mesh resource traversal
Work-Package: M03-RND-M2-MESH-RESOURCE-EXTRACTOR-001
Agent: sindo-main-codex
Tests: 36 headless renderer/coordinate contracts pass; checkpoint dry-run 7/7; documentation and coordination gates pass
Fidelity: preserves first-Mesh preorder and temporary PackedScene cleanup; no visual parity claim
2026-07-17 13:02:40 +04:00

9.2 KiB

M2 Mesh Resource Cache State

Metadata

Field Value
Status Implemented extraction
Target/work package M03 / M03-RND-M2-MESH-RESOURCE-CACHE-001
Owners Prepared static M2 Mesh resource references by normalized path
Last verified Worktree work/sindo-main-codex/m03-m2-mesh-resource-cache, 2026-07-17
Profiles/capabilities Existing static M2 cached and raw fallback paths

Purpose

Own the runtime cache of prepared static M2 Mesh references outside StreamingWorldLoader. The loader remains responsible for finding, loading, extracting, refreshing and materializing each Mesh.

Non-goals

  • Own the shared M2 missing-path, prototype or animated-scene caches.
  • Call ResourceLoader/FileAccess or select .tscn/.glb paths.
  • Extract a Mesh from a Resource or Node.
  • Refresh materials, rebuild Meshes or create MultiMesh instances.
  • Add eviction, persistence, cache versions or quality-profile behavior.

Context and boundaries

flowchart LR
    Need[Static M2 mesh lookup] --> Loader[StreamingWorldLoader]
    Loader --> Cache[M2MeshResourceCacheState]
    Cache -->|cached Mesh or null| Loader
    Loader --> Pipeline[M2MeshLoadPipelineState]
    Pipeline --> IO[ResourceLoader]
    IO --> Extract[M2MeshResourceExtractor]
    Extract --> Prepare[Loader runtime preparation]
    Prepare --> Cache
    Loader --> Build[M2 MultiMesh materialization]

The cache may retain Mesh resources and copied normalized-path Strings. It has no Node, ResourceLoader, filesystem, worker, scheduler, missing-state, builder, gameplay, network or editor dependency.

Public API

Symbol Kind Purpose Thread/lifetime Errors
store_mesh(path, mesh) Command/query Retain or replace one prepared Mesh Renderer main thread; final shutdown Empty path/null Mesh rejected
has_mesh(path) Query Test whether a Mesh is retained Renderer main thread Empty/unknown false
find_mesh(path) Query Borrow exact retained Mesh reference Renderer main thread Empty/unknown null
mesh_count() Query Return retained entry count Diagnostics/tests None
normalized_paths_snapshot() Query Copy insertion-order path keys Diagnostics/tests Never exposes Mesh references
clear() Command Release every retained Mesh reference Final shutdown after async drain Idempotent

Inputs and outputs

Direction Contract/data Producer Consumer Ownership Thread/lifetime
Input Normalized relative M2 path Loader normalization adapter Cache key Copied String Cache lifetime
Input Prepared static Mesh Loader finalizer or synchronous fallback Cache value Strong reference retained Until replacement/clear
Output Borrowed exact Mesh Cache lookup Static M2 batch builder Cache retains reference One build/materialization pass
Output Detached normalized paths Cache diagnostics Verifier/future metrics Caller-owned Strings Snapshot lifetime

Store and clear mutate only the cache Dictionary and Resource reference counts.

Data flow

flowchart TD
    Lookup[Lookup normalized M2 path] --> Cached{Mesh cached?}
    Cached -->|yes| Return[Return retained Mesh]
    Cached -->|no| Missing{Shared missing state?}
    Missing -->|yes| Null[Return null]
    Missing -->|no| Load[Loader request or synchronous fallback]
    Load --> Prepare[Loader extracts and prepares Mesh]
    Prepare --> Valid{Prepared Mesh valid?}
    Valid -->|yes| Store[Store or replace cache entry]
    Valid -->|no| MarkMissing[Loader updates shared missing state]
    Store --> Return

Lifecycle/state

stateDiagram-v2
    [*] --> Absent
    Absent --> Cached: store valid Mesh
    Cached --> Cached: replace Mesh reference
    Cached --> Absent: final shutdown clear

Map/world refresh retains cached Meshes. Only the existing final runtime-cache release clears them after asynchronous shutdown drain.

Main sequence

sequenceDiagram
    participant Loader as StreamingWorldLoader
    participant Cache as M2MeshResourceCacheState
    participant Pipeline as M2MeshLoadPipelineState
    Loader->>Cache: find/has normalized path
    alt cache miss
        Loader->>Pipeline: request/poll/finalize record
        Loader->>Loader: ResourceLoader get + extract + prepare
        Loader->>Cache: store_mesh(path, prepared Mesh)
    end
    Cache-->>Loader: exact retained Mesh
    Loader->>Loader: materialize static M2 batch

Dependency diagram

flowchart TB
    Loader[StreamingWorldLoader] --> Cache[M2MeshResourceCacheState]
    Loader --> Pipeline[M2MeshLoadPipelineState]
    Loader --> Classifier[M2RuntimeMeshRebuildClassifier]
    Loader --> Builder[M2Builder and MultiMesh]
    Cache --> Mesh[Godot Mesh Resource]
    Cache -. no dependency .-> Pipeline
    Cache -. no dependency .-> Classifier
    Cache -. no dependency .-> Builder

Ownership, threading and resources

  • Renderer main-thread adapters serialize every cache operation.
  • The cache owns normalized-path Strings and strong Mesh references.
  • Borrowed Mesh lookups do not transfer ownership or duplicate resources.
  • M2MeshResourceExtractor owns first-Mesh selection and temporary PackedScene instances. The loader owns missing/prototype/animated state and MultiMeshes.
  • The loader drains asynchronous work before the final cache clear.

Errors, cancellation and recovery

Failure/state Detection Behavior Diagnostic Recovery
Empty path or null Mesh Cache guard Reject unchanged Contract verifier Correct caller input
Unknown lookup Membership query Return null Existing loader path Request/load or missing decision
Replacement Existing key Retain new exact reference Contract verifier Normal subsequent lookup
Load/preparation failure Loader boundary Do not store; loader marks missing Existing renderer behavior Cache/source correction and reload
Final shutdown Loader lifecycle Clear releases references Shutdown/source verifier New loader starts empty

Configuration and capabilities

The module adds no setting, budget or profile branch. Cache path order, M2_MATERIAL_REFRESH_VERSION, finalize permits and batching remain loader-owned.

Persistence, cache and migration

The state is runtime-only and serializes nothing. Existing .tscn/.glb formats, import caches and material refresh metadata are unchanged; no migration or rebake is required.

Diagnostics and observability

mesh_count and normalized_paths_snapshot expose scalar ownership diagnostics without Mesh references. Existing renderer metrics/logging are unchanged because the historical Mesh cache had no queue contribution or log site.

Verification

  • verify_m2_mesh_resource_cache_state.gd: invalid input, exact reference, replacement, lookup, detached path snapshot, idempotent clear, loader source ownership and 100-by-256 bounded timing.
  • Mesh pipeline/classifier/material/shutdown/M2 build/facade regressions cover adjacent behavior.
  • Fidelity evidence is exact cache/lifetime extraction; no original-client visual-parity or asset-backed performance claim is made.

Extension points

  • A separate M2 Mesh resource finalizer may later return a prepared Mesh for store_mesh without changing cache ownership.
  • Eviction requires measured memory pressure and explicit lifetime semantics.

Capability status

Capability Status Evidence Gap/next step
Prepared static M2 Mesh cache Implemented extraction Contract/source/timing verifier Asset-backed memory/leak run pending
M2 Mesh request lifecycle Implemented extraction Pipeline state verifier ResourceLoader I/O remains loader-owned
M2 Mesh extraction Implemented extraction Resource/order/lifetime verifier Asset-backed corrupt-scene fixture pending
M2 Mesh preparation Existing loader-owned Material/classifier regressions Separate finalizer extraction next

Known gaps and risks

  • Strong Mesh references intentionally remain until final shutdown.
  • Shared missing state cannot move here without also redesigning prototype and animated lookup behavior.
  • No proprietary M2 traversal, leak/descriptor-pressure, p95/p99 or paired original-client capture is included.

Source map

Path Responsibility
src/render/m2/m2_mesh_resource_cache_state.gd Prepared Mesh references and final clear
src/render/m2/m2_mesh_resource_extractor.gd First-Mesh selection and temporary PackedScene lifetime
src/scenes/streaming/streaming_world_loader.gd Normalization, I/O, preparation, missing state and materialization
src/render/m2/m2_mesh_load_pipeline_state.gd Pending request and terminal finalize records
src/tools/verify_m2_mesh_resource_cache_state.gd Cache ownership/lifetime/boundary/timing regression