# 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
    MeshFinalizer[M2MeshResourceFinalizer] --> Repository[M2RawModelRepository]
    Loader[StreamingWorldLoader] --> Repository
    Observer[M2NativeAnimationResourceObserver] --> Repository
    Repository --> File[Extracted M2 file]
    Repository --> Native[ClassDB M2Loader]
    Native --> Raw[Raw Dictionary]
    Raw --> MeshFinalizer
    Raw --> Loader
    Raw --> Observer
    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` | Mesh resource finalizer/M2Builder | Fresh native result | One caller operation |
| Output | Animated raw M2 Dictionary | Native `load_m2_animated` | Native animation observer/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 Caller as Loader or NativeAnimationObserver
    participant Repo as M2RawModelRepository
    participant File as FileAccess
    participant Native as M2Loader
    Caller->>Repo: load static/animated(directory, path)
    Repo->>File: file_exists(globalized joined path)
    alt dependency or file unavailable
        Repo-->>Caller: empty Dictionary
    else available
        Repo->>Native: instantiate and call exact native method
        Native-->>Repo: Variant
        Repo-->>Caller: Dictionary or empty Dictionary
    end
```

## Dependency diagram

```mermaid
flowchart TB
    Loader[StreamingWorldLoader] --> Repository[M2RawModelRepository]
    Observer[M2NativeAnimationResourceObserver] --> Repository
    Repository --> ProjectSettings
    Repository --> FileAccess
    Repository --> ClassDB
    ClassDB --> Native[M2Loader extension]
    Loader --> Finalizer[M2RuntimeMeshFinalizer]
    Loader --> StaticBuilder[M2Builder]
    Observer --> 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; the Mesh resource
  finalizer owns static refresh reads, while the native observer owns the
  animated raw-read/build decision;
  `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_mesh_resource_finalizer.gd` | Static refresh repository consumer |
| `src/render/m2/m2_native_animation_resource_observer.gd` | Animated raw-data consumer and builder adapter |
| `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)
