M2 Animation Load Pipeline State
Metadata
| Field |
Value |
| Status |
Implemented extraction |
| Target/work package |
M03 / M03-RND-M2-ANIMATION-LOAD-PIPELINE-001 |
| Owners |
Animated M2 threaded request records and terminal finalize FIFO |
| Last verified |
Worktree work/sindo-main-codex/m03-m2-animation-load-pipeline, 2026-07-17 |
| Profiles/capabilities |
Existing optional cached-GLB animated M2 path |
Purpose
Own cross-frame bookkeeping between a successful animated M2 ResourceLoader
request, terminal polling and budgeted main-thread scene finalization. This is
an exact state extraction; animation eligibility and loading remain in
StreamingWorldLoader, while scene finalization and retained Node lifecycle
belong to M2AnimatedSceneFinalizer and M2PrototypeCacheState.
Non-goals
- Select cache paths, interpret ResourceLoader statuses or perform I/O.
- Decide animated/static fallback or own prototype Nodes.
- Instantiate PackedScenes, repair materials or consume render permits.
- Merge the distinct animated and static-Mesh pipelines.
Context and boundaries
Allowed dependencies are value containers, Strings and opaque integer statuses.
ResourceLoader, workers, scheduler, Node/Resource/Mesh ownership and other
renderer services are forbidden.
Public API
| Symbol |
Kind |
Purpose |
Thread/lifetime |
Errors |
remember_request(normalized_relative_path, resource_path) |
Command/query |
Insert one pending request |
Renderer main thread; until transition/clear |
Empty/duplicate false |
has_request(path) |
Query |
Pending-request dedupe |
Main thread |
Empty/unknown false |
request_records_snapshot() |
Query |
Detached pending records in insertion order |
Main thread; caller-owned |
None |
complete_request(path, terminal_status) |
Command/query |
Move copied record into completion FIFO |
Main thread after poll |
Unknown false |
discard_request(path) |
Command/query |
Remove without finalization |
Main thread |
Unknown false |
has_finalize_record() / pop_finalize_record() |
Query/command |
Drain completion-order FIFO |
Main-thread budget drain |
Empty pop returns {} |
total_work_count() |
Query |
Pending plus finalize metric |
Main thread |
None |
pending_request_count() / finalize_record_count() |
Query |
Stage diagnostics |
Main thread |
None |
clear() |
Command |
Drop bookkeeping after caller I/O drain/reset |
Main thread |
Idempotent; no I/O drain |
diagnostic_snapshot() |
Query |
Detached paths/status records |
Main thread |
No Resources exposed |
Inputs and outputs
| Direction |
Contract/data |
Producer |
Consumer |
Ownership |
Thread/lifetime |
| Input |
Normalized M2 path and GLB Resource path |
Loader request adapter |
Pending map |
Copied Strings |
Until completion/discard/clear |
| Input |
Opaque terminal status |
Loader polling adapter |
Finalize FIFO |
Integer value |
Until pop/clear |
| Output |
Detached pending records |
State |
Loader poll/shutdown adapter |
Caller-owned copies |
One pass |
| Output |
Oldest completion record |
State |
Loader finalizer |
Transferred Dictionary |
One finalize attempt |
| Output |
Detached diagnostics |
State |
Verifier/future metrics |
Caller-owned copies |
Snapshot lifetime |
Side effects are limited to collection mutation and retaining String/integer values.
Data flow
Lifecycle/state
Main sequence
Ownership, threading and resources
- Main thread serializes all mutation.
- State owns only request/finalize Dictionaries with copied paths and statuses.
- Loader drains pending ResourceLoader paths before orderly shutdown clear.
- Loader owns PackedScene instantiation and material repair; prototype state owns
accepted detached Node references and static-only outcomes.
Dependency diagram
Errors, cancellation and recovery
| Failure |
Detection |
Behavior |
Diagnostic |
Recovery |
| Empty/duplicate request |
State guard |
Reject unchanged |
Contract verifier |
Correct caller or request later |
| Request start/cache miss |
Loader |
No insertion; mark static |
Existing loader path |
Cache correction/reload |
| Non-terminal status |
Loader |
Keep pending |
Existing metric |
Poll next frame |
| Failed terminal load |
Popped status |
Loader marks static |
Existing behavior |
Future map/session reload |
| Empty defensive path |
Loader poll |
Discard and mark static |
Source contract |
Correct producer |
| Shutdown |
Loader drains pending paths |
Clear state |
Source/shutdown regressions |
New loader starts empty |
Configuration and capabilities
| Setting/capability |
Default |
Profile |
Runtime mutable |
Effect |
enable_m2_animated_instances |
true |
Existing renderer profile |
Yes |
Enables caller request path |
m2_animation_finalize_ops_per_tick |
1 |
Quality/custom |
Yes |
Bounds caller FIFO drain |
| Animated allow/deny/primitive rules |
Existing values |
Existing renderer profile |
Yes |
Filter before state insertion |
Persistence, cache and migration
State is not serialized. Cache formats and prototype lifetimes are unchanged;
no rebake or migration is required.
Diagnostics and observability
total_work_count() preserves all three historical m2_animation metrics.
- Snapshots expose only paths and opaque statuses, never Resources or Nodes.
- Normalized M2 path is the correlation key; existing loader logs are unchanged.
Verification
verify_m2_animation_load_pipeline_state.gd covers validation, dedupe,
insertion order, completion FIFO, opaque status, discard, detached snapshots,
source boundaries and 100-by-256 timing.
- Adjacent renderer, scheduler, prototype and shutdown regressions cover callers.
- Fidelity evidence is exact state/lifecycle extraction; no visual 3.3.5a parity
or proprietary asset-backed claim is made.
- Performance budget: 25,600 request/complete/pop transitions under one second.
Extension points
ResourceLoader polling may later move behind a separate adapter without
changing this value-only state contract. Animated-scene finalization is now a
sibling service.
Capability status
| Capability |
Status |
Evidence |
Gap/next step |
| Animated request/finalize state |
Implemented extraction |
Synthetic contract/source/timing verifier |
Asset-backed traversal/leak/p95/p99 pending |
| ResourceLoader and GLB selection |
Existing loader-owned |
Adjacent renderer tests |
I/O adapter extraction optional |
| Animated prototype outcomes |
Implemented extraction |
Prototype cache verifier |
Asset-backed animation fidelity pending |
Known gaps and risks
- Dictionary records preserve the existing dynamic ResourceLoader boundary.
clear() does not drain I/O; caller ordering remains mandatory.
- No private asset traversal, leak/descriptor-pressure or paired-client run is included.
Source map
| Path |
Responsibility |
src/render/m2/m2_animation_load_pipeline_state.gd |
Pending records, completion FIFO and metrics |
src/render/m2/m2_animated_scene_finalizer.gd |
Candidate instantiation, material repair and player validation |
src/render/m2/m2_prototype_cache_state.gd |
Animated prototype/static-only outcomes |
src/scenes/streaming/streaming_world_loader.gd |
Eligibility, I/O, permits, instantiation and adoption |
src/tools/verify_m2_animation_load_pipeline_state.gd |
Lifecycle/boundary/timing regression |
Related decisions and references