Work-Package: M03-RND-M2-RUNTIME-MESH-FINALIZER-001 Agent: sindo-main-codex Tests: 37 headless renderer/coordinate contracts pass; checkpoint dry-run 7/7; documentation and coordination gates pass Fidelity: preserves refresh version 2, classifier, rebuild and fallback transitions; no visual parity claim
9.8 KiB
M2 Runtime Mesh Finalizer
Metadata
| Field | Value |
|---|---|
| Status | Implemented extraction |
| Target/work package | M03 / M03-RND-M2-RUNTIME-MESH-FINALIZER-001 |
| Owners | Stale Mesh refresh version, rebuild classification, M2Builder rebuild and fallback |
| Last verified | Worktree work/sindo-main-codex/m03-m2-runtime-mesh-finalizer, 2026-07-17 |
| Profiles/capabilities | Static cached and prototype M2 runtime material preparation |
Purpose
Finalize an extracted static M2 Mesh for runtime use by accepting already-loaded
raw M2 data, preserving material refresh version 2, rebuilding only billboard/
UV-rotation cases and returning the historical original-Mesh fallback.
Non-goals
- Read raw
.m2files or call ClassDB/FileAccess/ResourceLoader. - Own request/finalize queues, Mesh/missing/prototype caches or MultiMeshes.
- Select cache paths or extract a Mesh from the originally loaded Resource.
- Change classifier predicates, builder materials, refresh version or profiles.
Context and boundaries
flowchart LR
Extractor[M2MeshResourceExtractor] --> Loader[StreamingWorldLoader]
Loader -->|is raw data required?| Finalizer[M2RuntimeMeshFinalizer]
Loader --> Raw[M2Loader raw Dictionary]
Raw --> Finalizer
Finalizer --> Classifier[M2RuntimeMeshRebuildClassifier]
Finalizer --> Builder[M2Builder]
Builder --> Subtree[M2MeshResourceExtractor]
Finalizer -->|prepared Mesh| Cache[M2MeshResourceCacheState]
The finalizer may use Mesh metadata, raw value Dictionaries, M2Builder and the two existing scene-free M2 services. Raw-file I/O, cache state, render permits, Nodes outside temporary rebuild roots and other application layers are forbidden.
Public API
| Symbol | Kind | Purpose | Thread/lifetime | Errors |
|---|---|---|---|---|
requires_raw_data_for_refresh(mesh) |
Query | Tell loader whether stale Mesh needs raw-file lookup | Renderer main thread | Null/current false |
finalize_mesh(path, mesh, raw_data, extracted_directory) |
Command/query | Return current, marked, rebuilt or fallback Mesh | Renderer main thread; one finalize operation | Null Mesh returns null; invalid rebuild falls back |
clear() |
Command | Clear memoized classifier decisions | Map reset/final shutdown | Idempotent |
cached_rebuild_decision_count() |
Diagnostic query | Expose memoized path-decision count | Tests/diagnostics | None |
Inputs and outputs
| Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime |
|---|---|---|---|---|---|
| Input | Extracted Mesh and normalized M2 path | Loader/extractor adapter | Finalizer | Borrowed Mesh reference/String copy | One call |
| Input | Already-loaded raw M2 Dictionary | Loader raw-file boundary | Classifier/M2Builder | Caller-owned value container | One call |
| Input | Extracted directory path | Loader configuration | M2Builder texture resolution | Copied String | One rebuild |
| Output | Original or rebuilt current Mesh | Finalizer | Cache/prototype adapter | Borrowed/new Resource reference | Cache may retain |
Side effects are Mesh refresh metadata, classifier memoization and temporary M2Builder prototype creation/destruction during required rebuilds.
Data flow
flowchart TD
Mesh[Extracted Mesh] --> Current{Refresh version >= 2?}
Current -->|yes| ReturnOriginal[Return original unchanged]
Current -->|no| NeedRaw[Loader supplies raw M2 data]
NeedRaw --> HasData{Raw data available?}
HasData -->|no| Mark[Mark original version 2]
HasData -->|yes| Classify{Billboard or UV rotation?}
Classify -->|no| Mark
Classify -->|yes| Build[M2Builder temporary prototype]
Build --> Extract[M2MeshResourceExtractor first Mesh]
Extract --> Rebuilt{Rebuilt Mesh exists?}
Rebuilt -->|yes| ReturnRebuilt[Return rebuilt Mesh]
Rebuilt -->|no| Mark
Mark --> ReturnOriginal
Lifecycle/state
stateDiagram-v2
[*] --> Current: Mesh metadata >= 2
[*] --> Stale: Mesh metadata < 2
Stale --> Current: empty/ordinary data marks original
Stale --> Rebuilding: classifier requires rebuild
Rebuilding --> Current: rebuilt Mesh returned
Rebuilding --> Current: failure marks original fallback
Current --> Current: later preparation is no-op
Classifier decisions are memoized per normalized path until either existing
map/reset clear site calls clear().
Main sequence
sequenceDiagram
participant Loader as StreamingWorldLoader
participant Finalizer as M2RuntimeMeshFinalizer
participant Raw as M2Loader boundary
participant Classifier as RebuildClassifier
participant Builder as M2Builder
Loader->>Finalizer: requires_raw_data_for_refresh(mesh)
alt current Mesh
Finalizer-->>Loader: false; reuse Mesh
else stale Mesh
Finalizer-->>Loader: true
Loader->>Raw: load raw Dictionary
Loader->>Finalizer: finalize_mesh(path, mesh, raw, extracted dir)
Finalizer->>Classifier: needs_runtime_mesh_rebuild(path, raw)
opt rebuild required
Finalizer->>Builder: build(raw, extracted dir)
Finalizer->>Finalizer: extract first Mesh; free prototype
end
Finalizer-->>Loader: rebuilt or marked fallback Mesh
end
Dependency diagram
flowchart TB
Loader[StreamingWorldLoader] --> Finalizer[M2RuntimeMeshFinalizer]
Finalizer --> Classifier[M2RuntimeMeshRebuildClassifier]
Finalizer --> Extractor[M2MeshResourceExtractor]
Finalizer --> Builder[M2Builder]
Loader --> Raw[FileAccess / ClassDB M2Loader]
Loader --> Cache[M2MeshResourceCacheState]
Finalizer -. no dependency .-> Raw
Finalizer -. no dependency .-> Cache
Ownership, threading and resources
- Renderer main thread executes metadata changes and M2Builder work.
- Loader owns raw M2 file existence/load calls and supplies value data.
- Finalizer owns classifier memoization and temporary rebuild prototype lifetime.
- M2Builder owns construction rules; extractor selects the first rebuilt Mesh.
- Cache/prototype adapters decide where the returned Mesh reference is retained.
Errors, cancellation and recovery
| Failure/state | Detection | Behavior | Diagnostic | Recovery |
|---|---|---|---|---|
| Null Mesh | Guard | Return null | Contract verifier | Caller marks missing |
| Current Mesh | Metadata query | Return exact reference; no raw load | Contract verifier | None needed |
| Raw file/parse unavailable | Empty Dictionary from loader | Mark/reuse original | Existing renderer behavior | Source/cache repair |
| Ordinary stale Mesh | Classifier false | Mark/reuse original | Classifier verifier | None needed |
| Builder produces no Mesh | Extractor null | Mark/reuse original | Finalizer fallback fixture | Source/builder repair |
| Reset/shutdown | Loader lifecycle | Clear classifier decisions | Source/clear verifier | Recompute next session |
Configuration and capabilities
MATERIAL_REFRESH_VERSION remains 2 and is now owned by this finalizer.
Finalize permits, cache paths, extracted directory configuration and quality
profiles remain unchanged in the loader.
Persistence, cache and migration
No new format is serialized. Existing Mesh metadata key
wow_m2_material_refresh_version, M2Builder MATERIAL_FORMAT_VERSION == 2 and
.tscn/.glb caches are unchanged; no migration or rebake is introduced.
Diagnostics and observability
cached_rebuild_decision_count exposes only a scalar count. Existing renderer
logs/queue metrics are unchanged. Normalized M2 path remains the correlation key.
Verification
verify_m2_runtime_mesh_finalizer.gd: null/current/raw requirement, empty and ordinary marking, synthetic triangle billboard rebuild, rebuild failure fallback, refresh metadata, classifier clear, source boundary and 100-by-256 bounded finalization.- Classifier/extractor/cache/pipeline/material/shutdown/M2 build regressions cover adjacent behavior. No asset-backed or original-client visual claim is made.
Extension points
- Raw M2 file loading may later move behind a dedicated repository without changing the finalizer's value-data contract.
- Refresh versions above
2require explicit cache/fidelity evidence and docs.
Capability status
| Capability | Status | Evidence | Gap/next step |
|---|---|---|---|
| Runtime Mesh refresh/fallback | Implemented extraction | Synthetic transition/rebuild verifier | Asset-backed corrupt/stale cache pending |
| Rebuild predicate | Implemented extraction dependency | Classifier fixtures | Original-client material comparison pending |
| Raw M2 refresh I/O | Existing loader-owned | Source boundary | Separate repository extraction optional |
Known gaps and risks
- Required rebuild remains synchronous main-thread work behind existing permits.
- Synthetic geometry proves transition/build behavior, not full asset materials.
- No proprietary M2 traversal, descriptor-pressure/leak, p95/p99 or paired original-client capture is included.
Source map
| Path | Responsibility |
|---|---|
src/render/m2/m2_runtime_mesh_finalizer.gd |
Refresh version, classification, rebuild and fallback |
src/scenes/streaming/streaming_world_loader.gd |
Raw-file I/O and returned-Mesh adoption |
src/render/m2/m2_runtime_mesh_rebuild_classifier.gd |
Memoized billboard/UV-rotation predicate |
src/render/m2/m2_mesh_resource_extractor.gd |
First rebuilt-Mesh selection |
src/tools/verify_m2_runtime_mesh_finalizer.gd |
Transition/rebuild/boundary/timing regression |