# M2 Raw Model Repository ## Metadata | Field | Value | |---|---| | Status | Implemented extraction | | Target/work package | M03 / `M03-RND-M2-RAW-MODEL-REPOSITORY-001` | | Owners | Native M2Loader availability, file existence and raw Dictionary loading | | Last verified | Worktree `work/sindo-main-codex/m03-m2-raw-model-repository`, 2026-07-17 | | Profiles/capabilities | Static and native-animated raw M2 reads | ## Purpose Provide one stateless boundary between renderer orchestration and the optional native `M2Loader`. The repository resolves an extracted path and returns the raw static or animated Dictionary consumed by existing builders and classifiers. ## Non-goals - Normalize relative paths or choose `.tscn`/`.glb` cache fallbacks. - Cache successful data, missing paths, Meshes, Nodes or animation decisions. - Build geometry/materials, own queues or attach renderer objects. - Change native parsing, cache formats, retry policy or visible behavior. ## Context and boundaries ```mermaid flowchart LR Loader[StreamingWorldLoader] --> Repository[M2RawModelRepository] Repository --> File[Extracted M2 file] Repository --> Native[ClassDB M2Loader] Native --> Raw[Raw Dictionary] Raw --> Loader Loader --> Builder[Existing M2 builders/finalizer] ``` Allowed dependencies are `ProjectSettings`, `FileAccess` and `ClassDB` for the native file boundary. Resource caches, builders, SceneTree types, worker pools, renderer policy and other application layers are forbidden. ## Public API | Symbol | Kind | Purpose | Thread/lifetime | Errors | |---|---|---|---|---| | `load_static_model_data(extracted_directory, normalized_relative_path)` | Query | Invoke native `load_m2` for one existing extracted file | Synchronous; stateless | Returns `{}` for rejected/unavailable/invalid result | | `load_animated_model_data(extracted_directory, normalized_relative_path)` | Query | Invoke native `load_m2_animated` for one existing extracted file | Synchronous; stateless | Returns `{}` for rejected/unavailable/invalid result | ## Inputs and outputs | Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime | |---|---|---|---|---|---| | Input | Extracted directory String | Loader configuration | Repository path resolution | Copied value | One call | | Input | Already-normalized relative M2 path String | Loader normalization | Repository | Copied value | One call | | Input | Extracted `.m2` bytes | Local legal extraction | Native M2Loader | File-owned | Native call | | Output | Static raw M2 Dictionary | Native `load_m2` | Loader/finalizer/M2Builder | Fresh native result | One caller operation | | Output | Animated raw M2 Dictionary | Native `load_m2_animated` | Loader/animated builder | Fresh native result | One caller operation | | Output | Empty Dictionary | Repository guards | Loader fallback and prototype outcome adapter | Fresh value | One failed call | Side effects are limited to file-existence inspection, synchronous native file parsing and creation of one temporary native loader instance per accepted call. ## Data flow ```mermaid flowchart TD Request[Directory plus normalized path] --> Empty{Path empty?} Empty -->|yes| Reject[Return empty Dictionary] Empty -->|no| Class{M2Loader registered?} Class -->|no| Reject Class -->|yes| Resolve[globalize directory/path join] Resolve --> Exists{File exists?} Exists -->|no| Reject Exists -->|yes| Instance[Instantiate M2Loader] Instance --> Method{Instance and method available?} Method -->|no| Reject Method -->|yes| Parse[Call static or animated method] Parse --> Type{Dictionary result?} Type -->|no| Reject Type -->|yes| Return[Return raw Dictionary] ``` ## Lifecycle/state ```mermaid stateDiagram-v2 [*] --> Ready: construct repository Ready --> Resolving: load request Resolving --> Ready: rejected input/unavailable dependency Resolving --> Parsing: file and native method available Parsing --> Ready: Dictionary or empty result returned Ready --> [*]: caller releases reference ``` No request, result or failure state survives a call. ## Main sequence ```mermaid sequenceDiagram participant Loader as StreamingWorldLoader participant Repo as M2RawModelRepository participant File as FileAccess participant Native as M2Loader Loader->>Repo: load static/animated(directory, path) Repo->>File: file_exists(globalized joined path) alt dependency or file unavailable Repo-->>Loader: empty Dictionary else available Repo->>Native: instantiate and call exact native method Native-->>Repo: Variant Repo-->>Loader: Dictionary or empty Dictionary end ``` ## Dependency diagram ```mermaid flowchart TB Loader[StreamingWorldLoader] --> Repository[M2RawModelRepository] Repository --> ProjectSettings Repository --> FileAccess Repository --> ClassDB ClassDB --> Native[M2Loader extension] Loader --> Finalizer[M2RuntimeMeshFinalizer] Loader --> StaticBuilder[M2Builder] Loader --> AnimatedBuilder[M2NativeAnimatedBuilder] Repository -. no dependency .-> Finalizer Repository -. no dependency .-> StaticBuilder Repository -. no dependency .-> Cache[Renderer caches/queues] ``` ## Ownership, threading and resources - The repository owns only call-local path, native instance and result values. - The loader owns path normalization and fallback selection; `M2PrototypeCacheState` owns prototype/negative adoption. - Native `M2Loader` owns parsing behavior and returns a new Dictionary value. - Calls are synchronous on the caller's thread; current renderer callers use the main thread. The module starts no tasks and touches no SceneTree objects. - No file handle, native instance, Dictionary or engine Resource is retained. ## Errors, cancellation and recovery | Failure | Detection | Behavior | Diagnostic | Recovery | |---|---|---|---|---| | Empty normalized path | String guard | Return `{}` | Dedicated verifier | Correct caller normalization | | Native extension absent | `ClassDB.class_exists` | Return `{}` | Existing renderer fallback | Install/load extension and retry | | Extracted file absent | `FileAccess.file_exists` | Return `{}` | Prototype cache records historical missing state through loader | Restore extraction and start a new loader session | | Instance/method absent | Null/`has_method` guard | Return `{}` | Source contract verifier | Repair extension registration | | Parse/non-Dictionary result | Result type check | Return `{}` | Existing loader fallback | Repair asset/parser and retry | | Cancellation requested | Not supported inside synchronous native call | Call completes | None | Caller controls whether to start call | ## Configuration and capabilities | Setting/capability | Default | Profile | Runtime mutable | Effect | |---|---|---|---|---| | Native class name | `M2Loader` | All | No | Exact GDExtension registration | | Static method | `load_m2` | All | No | Existing static parser path | | Animated method | `load_m2_animated` | Experimental animated path | No | Existing native animation parser | | Extracted directory | Loader `extracted_dir` | Scene configuration | Yes, caller-owned | Root used for path join | ## Persistence, cache and migration The module adds no persistence or cache. Native methods, normalized relative paths and `.tscn/.glb`/material versions are unchanged, so no migration or rebake is required. ## Diagnostics and observability - Logs: none; loader retains existing fallback and debug output. - Metrics: none; rejected-input timing is verifier-only. - Debug views: none. - Correlation ID: normalized relative M2 path in the caller. ## Verification - `verify_m2_raw_model_repository.gd` covers empty/missing/repeated failures, exact static/animated method ownership, three loader delegations, forbidden dependencies and 10,000 empty-path rejects under one second. - Adjacent finalizer/extractor/cache/pipeline/animation/material/shutdown tests protect caller behavior and ownership. - Fidelity evidence is structural: exact path join/globalization and native method names are preserved. No proprietary M2 or original-client visual claim is made by this extraction. ## Extension points Future asset-backed verification may add a legal fixture around these value contracts. Caching, asynchronous I/O and parser replacement require separate measured work packages rather than expansion of this repository. ## Capability status | Capability | Status | Evidence | Gap/next step | |---|---|---|---| | Static raw M2 read | Implemented extraction | Source/invalid/missing verifier | Legal success fixture pending | | Native animated raw M2 read | Implemented extraction | Exact method/source contract | Legal animated fixture pending | | Stateless failure behavior | Verified synthetic | Repeated missing call and source boundary | Asset-backed corrupt input pending | ## Known gaps and risks - Native parsing remains synchronous and has no mid-call cancellation. - The repository deliberately does not distinguish missing dependency, missing file and parser failure; loader fallback behavior historically treats them alike. - Proprietary asset traversal, descriptor pressure, p95/p99 and visual comparison remain outside this structural extraction. ## Source map | Path | Responsibility | |---|---| | `src/render/m2/m2_raw_model_repository.gd` | Stateless native class/file/method boundary | | `src/render/m2/m2_prototype_cache_state.gd` | Prototype and negative-result retention | | `src/scenes/streaming/streaming_world_loader.gd` | Path normalization, fallback decisions and result consumers | | `src/native/src/m2_loader.cpp` | Native static/animated parsing implementation | | `src/tools/verify_m2_raw_model_repository.gd` | Rejected-input/source/dependency/timing regression | ## Related decisions and references - [`m2-runtime-mesh-finalizer.md`](m2-runtime-mesh-finalizer.md) - [`m2-mesh-resource-cache-state.md`](m2-mesh-resource-cache-state.md) - [`m2-mesh-load-pipeline-state.md`](m2-mesh-load-pipeline-state.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)