M2 Cached Animation Resource Observer
Metadata
| Field |
Value |
| Status |
Implemented extraction |
| Target/work package |
M03 / M03-RND-M2-CACHED-ANIMATION-RESOURCE-OBSERVER-001 |
| Owners |
Cached animated M2 eligibility, request admission and initial snapshot |
| Last verified |
Worktree work/sindo-main-codex/m03-m2-cached-animation-resource-observer, 2026-07-18 |
| Profiles/capabilities |
Existing optional cached-GLB animated M2 path |
Purpose
Produce the cached-animation phase of M2BuildResourceSnapshot: reuse an exact
animated prototype, wait for a pending request, admit the first safe GLB request,
or record a terminal static-only animation outcome without changing behavior.
Non-goals
- Load/build native GryphonRoost animation or emit its diagnostics.
- Poll/finalize threaded Resources or instantiate/fix imported scenes.
- Own/free prototype Nodes, snapshots, pipeline entries or cache state.
- Materialize instances, consume permits or change animation policy defaults.
- Change GLB layout, cache format, batching, profiles or visible output.
Context and boundaries
Public API
| Symbol |
Kind |
Purpose |
Failure behavior |
observe(path, cache_dir, max_primitives, allow, deny, prototype_state, pipeline_state, debug) |
Command/query |
Produce cached prototype/pending/static-only snapshot |
Invalid input returns empty non-pending snapshot |
find_eligible_glb_cache_path(...) |
I/O query |
Select first existing safe historical candidate |
Returns empty String |
is_animation_path_allowed(path, allow, deny) |
Pure query |
Apply stripped case-insensitive substring policy |
Empty path/allowlist rejects; deny wins |
cache_resource_paths(cache_dir, path) |
Pure query |
Return nested/lowercase/basename GLB candidates |
Empty values yield fewer candidates |
glb_cache_is_safe_for_runtime_animation(path, max, debug) |
I/O query |
Validate animations, primitive limit and schema |
Invalid/missing GLB rejects |
read_glb_json(path) |
I/O query |
Read version-2 GLB JSON chunk |
Returns empty Dictionary |
glb_primitive_count(gltf) |
Pure query |
Count primitives across meshes |
Invalid entries contribute zero |
glb_animation_schema(gltf) |
Pure query |
Read OpenWC schema marker |
Missing marker returns empty String |
Inputs and outputs
| Direction |
Data |
Producer |
Consumer |
Ownership/lifetime |
| Input |
Normalized M2 path/cache directory |
Loader |
Observer |
Copied Strings; one observation |
| Input |
Primitive cap and allow/deny patterns |
Loader exports |
Observer |
Copied/read-only call values |
| Input |
Prototype and request states |
M2 state services |
Observer |
Borrowed services; map/session |
| Input |
Existing GLB cache file |
Offline cache pipeline |
Observer |
Read-only file access |
| Output |
Resource snapshot |
Observer |
Loader/dispatch/materializer |
Caller-owned snapshot; one build step |
| Output |
Borrowed exact prototype |
Prototype state |
Snapshot/materializer |
No ownership transfer |
| Output |
Threaded request record |
Observer |
Animation pipeline |
Pipeline-owned copied paths |
| Output |
Static-only transition |
Observer |
Prototype state |
State-owned copied path |
Data flow
Lifecycle/state
Main sequence
Dependency diagram
Ownership, threading and resources
- Observer retains no service, request, snapshot, Resource or Node reference.
- Prototype state retains accepted Nodes and static-only paths until shutdown.
- Pipeline state retains copied request paths until terminal polling/finalize.
- Snapshot borrows the exact cached prototype; observer never frees it.
- Resource existence/request and synchronous GLB JSON inspection run on the
renderer main thread, matching the previous loader behavior.
- The sibling native observer owns the native build attempt and the animation
resource finalizer owns terminal polling/finalize. Loader retains permits,
material lookup, materialization and SceneTree mutation.
Errors, cancellation and recovery
| Failure/state |
Behavior |
Recovery |
| Empty path/dependency |
Return empty non-pending snapshot without mutation |
Correct composition |
| Cached prototype |
Return exact reference immediately |
None |
| Existing request |
Return pending without duplicate admission |
Retry after terminal drain |
| Disallowed/denied path |
Mark static-only |
New loader session/configuration |
| Missing/invalid/unsafe GLB |
Continue candidates, then mark static-only |
Repair/rebake cache and restart session |
| Request error |
Mark static-only |
New loader session/cache repair |
| Tile cancellation |
Observer retains nothing |
Loader queue remains authoritative |
| Shutdown |
Loader drains requests before state clear |
New loader starts empty |
Configuration and capabilities
The service consumes existing m2_cache_dir, m2_animated_max_primitives,
m2_animated_allowlist_patterns, m2_animated_denylist_patterns and debug flag.
It adds no setting and preserves runtime mutability and defaults.
Persistence, cache and migration
No persistence or cache format changes are introduced. Existing .glb candidate
layout and OpenWC schema markers are read unchanged; no rebake is required.
Diagnostics and observability
Unsupported non-empty schemas preserve the historical optional
M2_ANIM_REJECT debug line. Snapshot and pipeline diagnostics remain detached;
queue and hitch metrics are unchanged.
Verification
- Dedicated verifier covers invalid/cached identity/static/pending/missing
lifecycle, allow/deny semantics, exact path order, generated GLB header/JSON,
animation presence, primitive cap, accepted/rejected schemas, source boundaries
and bounded timing.
- Snapshot, dispatch, pipeline, prototype, shutdown, facade, internal-access and
checkpoint regressions protect adjacent behavior.
- Fidelity evidence is exact policy/I/O extraction. No original-client visual or
animation parity claim is made.
Extension points
Native and cached observation remain sibling services. Terminal ResourceLoader
polling/finalization uses the dedicated finalizer while retaining pipeline state.
Capability status
| Capability |
Status |
Evidence |
Gap/next step |
| Cached animation observation/request |
Implemented extraction |
Lifecycle/policy/GLB/source/timing verifier |
Asset-backed traversal pending |
| Native animation observation |
Implemented sibling extraction |
Native observer lifecycle/source verifier |
Asset-backed traversal pending |
| Animated finalize/preparation |
Implemented finalizer extraction |
Pipeline/finalizer regressions |
Asset-backed traversal pending |
Known gaps and risks
- A successful asynchronous request is not started by the unit fixture because
leaving it undrained leaks process work; source and pipeline tests cover admission.
- Generated GLB metadata fixtures validate policy, not Godot import fidelity.
- Private traversal, leak/descriptor pressure, p95/p99 and paired visuals remain
unavailable without private assets.
Source map
| Path |
Responsibility |
src/render/m2/m2_cached_animation_resource_observer.gd |
Cached GLB policy, request and snapshot production |
src/render/m2/m2_build_resource_snapshot.gd |
Typed per-step observation value |
src/render/m2/m2_animation_load_pipeline_state.gd |
Pending request/finalize state |
src/render/m2/m2_animation_resource_finalizer.gd |
Terminal polling/load/finalize outcomes |
src/render/m2/m2_prototype_cache_state.gd |
Prototype and static-only outcomes |
src/render/m2/m2_native_animation_resource_observer.gd |
Native-first candidate/read/build/cache observation |
src/scenes/streaming/streaming_world_loader.gd |
Composition, fallback order, finalize and execution |
src/tools/verify_m2_cached_animation_resource_observer.gd |
Lifecycle/policy/GLB/boundary/timing regression |
Related decisions and references