ece7724a28
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
225 lines
10 KiB
Markdown
225 lines
10 KiB
Markdown
# M2 Runtime Mesh Rebuild Classifier
|
|
|
|
## Metadata
|
|
|
|
| Field | Value |
|
|
|---|---|
|
|
| Status | Implemented extraction |
|
|
| Target/work package | M03 / `M03-RND-M2-RUNTIME-REBUILD-CLASSIFIER-001` |
|
|
| Owners | Billboard/UV-rotation rebuild decision and per-path memoization |
|
|
| Last verified | Worktree `work/sindo-main-codex/m03-m2-runtime-rebuild-classifier`, 2026-07-17 |
|
|
| Profiles/capabilities | Existing M2 material-refresh path; profile-independent |
|
|
|
|
## Purpose
|
|
|
|
Determine whether a stale cached M2 mesh must be rebuilt in memory from raw M2
|
|
data to restore billboard custom attributes or UV-rotation material inputs. The
|
|
first decision is memoized by normalized relative path for the current map/
|
|
runtime-cache lifetime.
|
|
|
|
## Non-goals
|
|
|
|
- Read M2 files or invoke `M2Loader`/`M2Builder`.
|
|
- Own cached Meshes, scenes, materials, Nodes or RIDs.
|
|
- Select cache paths, perform ResourceLoader transitions or consume permits.
|
|
- Change refresh/cache format versions or shader behavior.
|
|
- Classify animation, particles, ribbons or general visual fidelity.
|
|
|
|
## Context and boundaries
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
Cache[Stale cached M2 Mesh] --> Finalizer[M2RuntimeMeshFinalizer]
|
|
Loader[StreamingWorldLoader] --> Raw[M2Loader raw Dictionary]
|
|
Raw --> Classifier[M2RuntimeMeshRebuildClassifier]
|
|
Classifier --> Decision[Memoized rebuild boolean]
|
|
Decision --> Finalizer
|
|
Finalizer -->|true| Builder[M2Builder rebuild]
|
|
Finalizer -->|false| Refresh[Mark material refresh version]
|
|
```
|
|
|
|
Allowed dependencies are Dictionary/Array, `PackedInt32Array`, `Vector4` and
|
|
scalar math. Files, ResourceLoader, parser/builder classes, SceneTree,
|
|
WorkerThreadPool, Mesh/Node/RID ownership and other layers are forbidden.
|
|
|
|
## Public API
|
|
|
|
| Symbol | Kind | Purpose | Thread/lifetime | Errors |
|
|
|---|---|---|---|---|
|
|
| `needs_runtime_mesh_rebuild(normalized_relative_path, raw_m2_data)` | Memoized query | Detect billboard or referenced UV rotation requirements | Renderer main thread; cached until clear | Invalid variants/indices are skipped; first path decision wins |
|
|
| `clear()` | Command | Drop all memoized path decisions | Main thread; map reset/shutdown | Idempotent |
|
|
| `cached_path_count()` | Query | Return memoized path count | Main thread | None |
|
|
| `diagnostic_snapshot()` | Query | Return detached path/decision map | Main thread; caller-owned | None |
|
|
|
|
## Inputs and outputs
|
|
|
|
| Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime |
|
|
|---|---|---|---|---|---|
|
|
| Input | Normalized M2 relative path | Loader cache lookup | Classifier cache key | String value copied | Until clear |
|
|
| Input | Raw M2 batches/transforms/combos Dictionary | Native `M2Loader` adapter | Classifier | Borrowed; not mutated | First classification call per path |
|
|
| Output | Rebuild-required boolean | Classifier | Runtime Mesh finalizer | Scalar | Memoized until clear |
|
|
| Output | Detached decision Dictionary | Classifier | Verifier/future diagnostics | Caller-owned copy | Snapshot lifetime |
|
|
|
|
Side effects are limited to inserting and clearing boolean memoization entries.
|
|
|
|
## Data flow
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
Query[path + raw M2 data] --> Cached{Path cached?}
|
|
Cached -->|yes| Return[Return first decision]
|
|
Cached -->|no| Billboard{Any billboard flag or positive vertex count?}
|
|
Billboard -->|yes| StoreTrue[Store true]
|
|
Billboard -->|no| Inputs{Transforms and combos present?}
|
|
Inputs -->|no| StoreFalse[Store false]
|
|
Inputs -->|yes| Batch[For each Dictionary batch]
|
|
Batch --> Stage[Inspect at most four referenced stages]
|
|
Stage --> Rotation{Non-identity rotation or speed above epsilon?}
|
|
Rotation -->|yes| StoreTrue
|
|
Rotation -->|no| StoreFalse
|
|
StoreTrue --> Return
|
|
StoreFalse --> Return
|
|
```
|
|
|
|
## Lifecycle/state
|
|
|
|
Each path moves from unknown to one immutable cached boolean. Clear returns all
|
|
paths to unknown; no resource lifecycle participates.
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> Unknown
|
|
Unknown --> RebuildRequired: billboard or referenced UV rotation
|
|
Unknown --> RebuildNotRequired: no relevant metadata
|
|
RebuildRequired --> RebuildRequired: repeated query
|
|
RebuildNotRequired --> RebuildNotRequired: repeated query
|
|
RebuildRequired --> Unknown: clear
|
|
RebuildNotRequired --> Unknown: clear
|
|
```
|
|
|
|
## Main sequence
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Loader as StreamingWorldLoader
|
|
participant Native as M2Loader
|
|
participant Finalizer as M2RuntimeMeshFinalizer
|
|
participant Classifier as M2RuntimeMeshRebuildClassifier
|
|
participant Builder as M2Builder
|
|
Loader->>Native: load_m2(normalized path)
|
|
Native-->>Loader: raw Dictionary
|
|
Loader->>Finalizer: finalize_mesh(path, mesh, data, dir)
|
|
Finalizer->>Classifier: needs_runtime_mesh_rebuild(path, data)
|
|
Classifier-->>Finalizer: memoized boolean
|
|
alt rebuild required
|
|
Finalizer->>Builder: rebuild mesh from raw data
|
|
else no rebuild required
|
|
Finalizer->>Finalizer: stamp material refresh version
|
|
end
|
|
```
|
|
|
|
## Dependency diagram
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
Loader[StreamingWorldLoader] --> Finalizer[M2RuntimeMeshFinalizer]
|
|
Finalizer --> Classifier[M2RuntimeMeshRebuildClassifier]
|
|
Loader --> Native[M2Loader]
|
|
Loader --> Builder[M2Builder]
|
|
Loader --> Cache[M2 Mesh/Scene caches]
|
|
Classifier -. no dependency .-> Native
|
|
Classifier -. no dependency .-> Builder
|
|
Classifier -. no dependency .-> Cache
|
|
```
|
|
|
|
## Ownership, threading and resources
|
|
|
|
- The classifier owns only normalized-path boolean entries.
|
|
- The finalizer owns classifier lifetime, rebuild decisions and refresh metadata.
|
|
- The loader owns raw loading, cache/resource selection and Mesh adoption.
|
|
- Raw Dictionaries are borrowed and never retained; only the computed boolean is cached.
|
|
- Current calls and clears are serialized on the renderer main thread.
|
|
- No Node, Resource, Mesh, material or RID reference crosses into the classifier.
|
|
|
|
## Errors, cancellation and recovery
|
|
|
|
| Failure | Detection | Behavior | Diagnostic | Recovery |
|
|
|---|---|---|---|---|
|
|
| Non-Dictionary batch/transform | Type guard | Skip entry or use identity defaults | Synthetic verifier | Correct parser data on next cleared lifetime |
|
|
| Missing transforms/combos | Empty guard | No UV-driven rebuild | Synthetic verifier | Billboard classification still applies |
|
|
| Invalid combo/transform index | Bounds guard | Skip stage | Synthetic verifier | Correct raw data and clear |
|
|
| Repeated path with changed data | Cache hit | Preserve first decision | Memoization fixture | Map/reset clear recomputes |
|
|
| Load/build failure | Outside classifier | Existing mesh fallback remains | Loader diagnostics | Existing reload/fallback path |
|
|
|
|
## Configuration and capabilities
|
|
|
|
| Setting/capability | Default | Profile | Runtime mutable | Effect |
|
|
|---|---|---|---|---|
|
|
| Maximum texture stages inspected | `4` | Existing M2 material path | No | Preserves historical four-stage shader boundary |
|
|
| UV rotation-speed epsilon | `0.000001` exclusive | Existing M2 material path | No | Larger absolute speed requires rebuild |
|
|
| `MATERIAL_REFRESH_VERSION` | Finalizer constant `2` | All | Code version | Gates whether classifier is called |
|
|
|
|
## Persistence, cache and migration
|
|
|
|
Memoized booleans are runtime-only and are cleared at the two historical loader
|
|
reset/shutdown sites. No persisted cache version or rebuild instruction changes.
|
|
|
|
## Diagnostics and observability
|
|
|
|
- Logs: none.
|
|
- Metrics: `cached_path_count` is contract-level only and not added to runtime logs.
|
|
- Debug views: detached path-to-boolean snapshot.
|
|
- Correlation IDs: normalized M2 relative path.
|
|
|
|
## Verification
|
|
|
|
- `verify_m2_runtime_mesh_rebuild_classifier.gd`: billboard flag/count, invalid
|
|
variants, identity/non-identity rotation, positive/negative speed, exact
|
|
epsilon, four-stage cap, invalid indices, memoization, clear, source boundary
|
|
and 100-by-256 timing.
|
|
- Existing M2 builder/material verifiers cover downstream shader/cache behavior.
|
|
- Fidelity evidence is exact predicate/cache extraction. No new asset-backed or
|
|
original-client parity claim is made.
|
|
- Performance budget: 25,600 classifications and clears under one second.
|
|
|
|
## Extension points
|
|
|
|
- A typed raw M2 material descriptor may replace the Dictionary only with parser
|
|
fixtures and a compatibility adapter.
|
|
- Mesh request/cache/finalization state can be extracted separately without
|
|
changing this rebuild predicate.
|
|
|
|
## Capability status
|
|
|
|
| Capability | Status | Evidence | Gap/next step |
|
|
|---|---|---|---|
|
|
| Billboard rebuild classification | Implemented extraction | Flag/count fixtures | Asset-backed cache refresh timing pending |
|
|
| UV-rotation rebuild classification | Implemented extraction | Combo/stage/threshold fixtures | More build-12340 material fixtures pending |
|
|
| Runtime memoization lifetime | Implemented extraction | First-decision/clear/source fixtures | Byte/count runtime metric not exposed |
|
|
| Runtime Mesh finalization | Implemented extraction | Finalizer transition/rebuild fixtures | Asset-backed material comparison pending |
|
|
|
|
## Known gaps and risks
|
|
|
|
- Raw parser data remains Dictionary-based.
|
|
- The first decision wins even if different raw data is passed for the same path;
|
|
this intentionally preserves prior cache behavior.
|
|
- Only four texture stages are inspected, matching current material support.
|
|
- No private asset traversal, descriptor-pressure, p95/p99 or paired visual run is included.
|
|
|
|
## Source map
|
|
|
|
| Path | Responsibility |
|
|
|---|---|
|
|
| `src/render/m2/m2_runtime_mesh_rebuild_classifier.gd` | Predicate, thresholds and boolean memoization |
|
|
| `src/scenes/streaming/streaming_world_loader.gd` | Raw loading, Mesh rebuild/adoption, refresh version and clear calls |
|
|
| `addons/mpq_extractor/loaders/m2_builder.gd` | Mesh/material rebuild implementation |
|
|
| `src/tools/verify_m2_runtime_mesh_rebuild_classifier.gd` | Synthetic predicate/cache/boundary/timing regression |
|
|
|
|
## Related decisions and references
|
|
|
|
- [`m2-build-batch-planner.md`](m2-build-batch-planner.md)
|
|
- [`m2-placement-grouper.md`](m2-placement-grouper.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)
|