# 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 ```mermaid 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 --> Prepare[Loader extraction and 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 ```mermaid 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 ```mermaid 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 ```mermaid 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 ```mermaid 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. - The loader owns missing/prototype/animated state and all Nodes/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/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/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 | ## Related decisions and references - [`m2-mesh-load-pipeline-state.md`](m2-mesh-load-pipeline-state.md) - [`m2-runtime-mesh-rebuild-classifier.md`](m2-runtime-mesh-rebuild-classifier.md) - [`world-renderer.md`](world-renderer.md) - [`../../RENDER.md`](../../RENDER.md) - [`../../targets/roadmap/02-rendering-and-graphics.md`](../../targets/roadmap/02-rendering-and-graphics.md)