# 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 `.m2` files 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

```mermaid
flowchart LR
    ResourceFinalizer[M2MeshResourceFinalizer] -->|is raw data required?| Finalizer[M2RuntimeMeshFinalizer]
    ResourceFinalizer --> Raw[M2RawModelRepository]
    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 | Mesh resource finalizer | Finalizer | Borrowed Mesh reference/String copy | One call |
| Input | Already-loaded raw M2 Dictionary | `M2RawModelRepository` through resource finalizer | 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

```mermaid
flowchart TD
    Mesh[Extracted Mesh] --> Current{Refresh version >= 2?}
    Current -->|yes| ReturnOriginal[Return original unchanged]
    Current -->|no| NeedRaw[Repository supplies raw M2 data through loader]
    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

```mermaid
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

```mermaid
sequenceDiagram
    participant ResourceFinalizer as M2MeshResourceFinalizer
    participant Finalizer as M2RuntimeMeshFinalizer
    participant Raw as M2Loader boundary
    participant Classifier as RebuildClassifier
    participant Builder as M2Builder
    ResourceFinalizer->>Finalizer: requires_raw_data_for_refresh(mesh)
    alt current Mesh
        Finalizer-->>ResourceFinalizer: false; reuse Mesh
    else stale Mesh
        Finalizer-->>ResourceFinalizer: true
        ResourceFinalizer->>Raw: load static raw Dictionary
        ResourceFinalizer->>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-->>ResourceFinalizer: rebuilt or marked fallback Mesh
    end
```

## Dependency diagram

```mermaid
flowchart TB
    ResourceFinalizer[M2MeshResourceFinalizer] --> Finalizer[M2RuntimeMeshFinalizer]
    Finalizer --> Classifier[M2RuntimeMeshRebuildClassifier]
    Finalizer --> Extractor[M2MeshResourceExtractor]
    Finalizer --> Builder[M2Builder]
    ResourceFinalizer --> Raw[M2RawModelRepository]
    ResourceFinalizer --> Cache[M2MeshResourceCacheState]
    Finalizer -. no dependency .-> Raw
    Finalizer -. no dependency .-> Cache
```

## Ownership, threading and resources

- Renderer main thread executes metadata changes and M2Builder work.
- `M2RawModelRepository` owns raw M2 file/native calls; the Mesh resource
  finalizer supplies its value result.
- 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

- Asset-backed fixture coverage can be added without changing the finalizer's
  value-data contract.
- Refresh versions above `2` require 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 | Implemented repository dependency | Repository source/invalid verifier | Legal success fixture pending |

## 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/render/m2/m2_raw_model_repository.gd` | Raw-file/native I/O and Dictionary result |
| `src/render/m2/m2_mesh_resource_finalizer.gd` | Repository call and returned-Mesh adoption |
| `src/scenes/streaming/streaming_world_loader.gd` | Service composition, permits and materialization |
| `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 |

## Related decisions and references

- [`m2-runtime-mesh-rebuild-classifier.md`](m2-runtime-mesh-rebuild-classifier.md)
- [`m2-mesh-resource-extractor.md`](m2-mesh-resource-extractor.md)
- [`m2-mesh-resource-cache-state.md`](m2-mesh-resource-cache-state.md)
- [`m2-raw-model-repository.md`](m2-raw-model-repository.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)
