render: extract static M2 build resource observer
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
| M2 build batch planner | Implemented extraction | [`m2-build-batch-planner.md`](m2-build-batch-planner.md) |
|
||||
| M2 build dispatch planner | Implemented extraction | [`m2-build-dispatch-planner.md`](m2-build-dispatch-planner.md) |
|
||||
| M2 build resource snapshot | Implemented extraction | [`m2-build-resource-snapshot.md`](m2-build-resource-snapshot.md) |
|
||||
| M2 static build resource observer | Implemented extraction | [`m2-static-build-resource-observer.md`](m2-static-build-resource-observer.md) |
|
||||
| M2 build queue | Implemented extraction | [`m2-build-queue.md`](m2-build-queue.md) |
|
||||
| M2 static batch materializer | Implemented extraction | [`m2-static-batch-materializer.md`](m2-static-batch-materializer.md) |
|
||||
| M2 runtime mesh rebuild classifier | Implemented extraction | [`m2-runtime-mesh-rebuild-classifier.md`](m2-runtime-mesh-rebuild-classifier.md) |
|
||||
|
||||
@@ -187,9 +187,9 @@ queue/hitch metrics remain unchanged.
|
||||
|
||||
## Extension points
|
||||
|
||||
A later resource-observation service may produce this snapshot while moving
|
||||
ResourceLoader/cache request ownership out of the loader. The value contract
|
||||
must remain independent of that service and of generic callback frameworks.
|
||||
`M2StaticBuildResourceObserver` now produces the static phase. A later animated
|
||||
observer may produce the first phase. The value contract remains independent of
|
||||
both producers and of generic callback frameworks.
|
||||
|
||||
## Capability status
|
||||
|
||||
@@ -197,7 +197,8 @@ must remain independent of that service and of generic callback frameworks.
|
||||
|---|---|---|---|
|
||||
| Typed per-step M2 resource observation | Implemented extraction | Identity/adoption/lifetime/source/timing verifier | Asset-backed traversal pending |
|
||||
| Dispatch decision | Implemented separately | Dispatch planner verifier | Asset-backed traversal pending |
|
||||
| Resource lookup/request execution | Loader-owned | Cache/pipeline regressions | Service extraction pending |
|
||||
| Static lookup/request execution | Implemented separately | Static observer verifier | Asset-backed traversal pending |
|
||||
| Animated lookup/request execution | Loader-owned | Animation regressions | Service extraction pending |
|
||||
| Engine lifetime/materialization | Loader/materializer-owned | Lifetime/materializer regressions | GPU/p95/p99 evidence pending |
|
||||
|
||||
## Known gaps and risks
|
||||
@@ -213,7 +214,8 @@ must remain independent of that service and of generic callback frameworks.
|
||||
|---|---|
|
||||
| `src/render/m2/m2_build_resource_snapshot.gd` | Typed per-step resource observations and diagnostics |
|
||||
| `src/render/m2/m2_build_dispatch_planner.gd` | Snapshot-to-action planning |
|
||||
| `src/scenes/streaming/streaming_world_loader.gd` | Resource observation/request execution and materializer borrowing |
|
||||
| `src/render/m2/m2_static_build_resource_observer.gd` | Static snapshot production and requests |
|
||||
| `src/scenes/streaming/streaming_world_loader.gd` | Animated observation/request execution and materializer borrowing |
|
||||
| `src/tools/verify_m2_build_resource_snapshot.gd` | Identity/adoption/lifetime/boundary/timing regression |
|
||||
|
||||
## Related decisions and references
|
||||
|
||||
@@ -206,7 +206,8 @@ rebuild policy are unchanged; no migration or rebake is required.
|
||||
| Capability | Status | Evidence | Gap/next step |
|
||||
|---|---|---|---|
|
||||
| Static M2 request/finalize state | Implemented extraction | Contract/source/timing verifier | Asset-backed long traversal pending |
|
||||
| ResourceLoader I/O | Existing loader-owned | Shutdown/material regressions | I/O adapter extraction optional |
|
||||
| Static request admission I/O | Implemented in observer | Observer/shutdown regressions | Asset-backed traversal pending |
|
||||
| Static request polling/finalize I/O | Existing loader-owned | Shutdown/material regressions | Finalize extraction optional |
|
||||
| Mesh cache | Implemented extraction | Mesh resource cache state verifier | Asset-backed memory/leak run pending |
|
||||
| First-Mesh extraction | Implemented extraction | Resource/order/lifetime verifier | Asset-backed corrupt-scene fixture pending |
|
||||
| Mesh preparation | Implemented extraction | Runtime finalizer transition/rebuild verifier | Asset-backed material comparison pending |
|
||||
|
||||
@@ -186,7 +186,7 @@ the historical Mesh cache had no queue contribution or log site.
|
||||
| Capability | Status | Evidence | Gap/next step |
|
||||
|---|---|---|---|
|
||||
| Prepared static M2 Mesh cache | Implemented extraction | Contract/source/timing verifier | Asset-backed memory/leak run pending |
|
||||
| M2 Mesh request lifecycle | Implemented extraction | Pipeline state verifier | ResourceLoader I/O remains loader-owned |
|
||||
| M2 Mesh request lifecycle | Implemented extraction | Pipeline state verifier | Finalize polling remains loader-owned |
|
||||
| M2 Mesh extraction | Implemented extraction | Resource/order/lifetime verifier | Asset-backed corrupt-scene fixture pending |
|
||||
| M2 Mesh preparation | Implemented extraction | Runtime finalizer transition/rebuild verifier | Asset-backed material comparison pending |
|
||||
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
# M2 Static Build Resource Observer
|
||||
|
||||
## Metadata
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Status | Implemented extraction |
|
||||
| Target/work package | M03 / `M03-RND-M2-STATIC-BUILD-RESOURCE-OBSERVER-001` |
|
||||
| Owners | Static build Mesh lookup, request selection and missing transition |
|
||||
| Last verified | Worktree `work/sindo-main-codex/m03-m2-static-build-resource-observer`, 2026-07-18 |
|
||||
| Profiles/capabilities | Existing static MultiMesh M2 build path |
|
||||
|
||||
## Purpose
|
||||
|
||||
Produce the static phase of `M2BuildResourceSnapshot`: reuse a prepared Mesh,
|
||||
wait for an existing request, start the first eligible cache request, or record
|
||||
a terminal missing model while preserving historical path and GLB rules.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Observe animated/native prototypes or finalize threaded loads.
|
||||
- Own/free Meshes, Nodes, cache entries or snapshot lifetime.
|
||||
- Materialize instances, plan batches, rotate queues or consume permits.
|
||||
- Change cache format, candidate order, profiles or visible output.
|
||||
|
||||
## Context and boundaries
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Loader[StreamingWorldLoader] --> Observer[M2StaticBuildResourceObserver]
|
||||
MeshCache[M2MeshResourceCacheState] --> Observer
|
||||
Missing[M2PrototypeCacheState] --> Observer
|
||||
Pipeline[M2MeshLoadPipelineState] --> Observer
|
||||
Observer --> Snapshot[M2BuildResourceSnapshot]
|
||||
Snapshot --> Dispatch[M2BuildDispatchPlanner]
|
||||
```
|
||||
|
||||
## Public API
|
||||
|
||||
| Symbol | Kind | Purpose | Errors |
|
||||
|---|---|---|---|
|
||||
| `observe(snapshot, path, cache_dir, mesh_cache, prototype_cache, pipeline)` | Command/query | Adopt cached/pending/requested/missing static result | Invalid inputs return `rejected` |
|
||||
| `cache_resource_paths(cache_dir, path, extensions)` | Pure query | Return unique historical nested/lowercase/basename candidates | Empty values yield fewer/empty candidates |
|
||||
| `glb_animation_schema(path)` | Read query | Read OpenWC schema marker from GLB JSON | Invalid/missing GLB returns empty String |
|
||||
| `OUTCOME_*` | Constants | Stable diagnostic transition identifiers | None |
|
||||
|
||||
## Inputs and outputs
|
||||
|
||||
| Direction | Data | Producer | Consumer | Ownership/lifetime |
|
||||
|---|---|---|---|---|
|
||||
| Input | Normalized M2 path/cache directory | Loader | Observer | Copied Strings; one observation |
|
||||
| Input | Mesh/missing/request states | M2 state services | Observer | Borrowed services; map/session |
|
||||
| Input/output | Resource snapshot | Loader | Observer/dispatch/materializer | Borrowed; one build operation |
|
||||
| Output | Cached Mesh or missing/pending values | Observer | Snapshot | Exact borrowed Mesh/scalars |
|
||||
| Output | Threaded request record | Observer | Mesh pipeline | Pipeline-owned path record |
|
||||
| Output | Outcome StringName | Observer | Tests/future diagnostics | Immutable scalar |
|
||||
|
||||
## Data flow
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start[Observe static path] --> Cached{Mesh cached?}
|
||||
Cached -->|yes| AdoptMesh[Adopt exact Mesh; cached]
|
||||
Cached -->|no| Missing{Already missing?}
|
||||
Missing -->|yes| AdoptMissing[Adopt missing]
|
||||
Missing -->|no| Pending{Request pending?}
|
||||
Pending -->|yes| AdoptPending[Adopt unresolved; pending]
|
||||
Pending -->|no| Candidates[Generate tscn then glb candidates]
|
||||
Candidates --> Eligible{Exists and not pivot-prefix GLB?}
|
||||
Eligible -->|yes| Request[Threaded request]
|
||||
Request -->|OK or busy| Remember[Remember request; requested]
|
||||
Eligible -->|none/error| MarkMissing[Mark/adopt missing]
|
||||
```
|
||||
|
||||
## Lifecycle/state
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Observing
|
||||
Observing --> Cached
|
||||
Observing --> Pending
|
||||
Observing --> Requested
|
||||
Observing --> Missing
|
||||
Observing --> Rejected
|
||||
Cached --> [*]
|
||||
Pending --> [*]
|
||||
Requested --> [*]
|
||||
Missing --> [*]
|
||||
Rejected --> [*]
|
||||
```
|
||||
|
||||
## Main sequence
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant L as StreamingWorldLoader
|
||||
participant O as StaticBuildResourceObserver
|
||||
participant C as Mesh/prototype cache state
|
||||
participant P as MeshLoadPipelineState
|
||||
participant R as ResourceLoader
|
||||
participant S as M2BuildResourceSnapshot
|
||||
L->>O: observe(snapshot, path, cache_dir, states)
|
||||
O->>C: cached/missing lookup
|
||||
alt cache hit or missing
|
||||
O->>S: adopt static observation
|
||||
else pending
|
||||
O->>P: has_request
|
||||
O->>S: adopt unresolved observation
|
||||
else request candidate
|
||||
O->>R: exists + load_threaded_request
|
||||
O->>P: remember_request
|
||||
O->>S: adopt unresolved observation
|
||||
end
|
||||
```
|
||||
|
||||
## Dependency diagram
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
Observer[M2StaticBuildResourceObserver] --> ResourceLoader
|
||||
Observer --> FileAccess[GLB header/JSON read]
|
||||
Observer --> MeshCache[M2MeshResourceCacheState]
|
||||
Observer --> PrototypeCache[M2PrototypeCacheState]
|
||||
Observer --> Pipeline[M2MeshLoadPipelineState]
|
||||
Observer --> Snapshot[M2BuildResourceSnapshot]
|
||||
Observer -. no dependency .-> SceneTree
|
||||
Observer -. no dependency .-> Materializers
|
||||
Observer -. no dependency .-> Scheduler
|
||||
```
|
||||
|
||||
## Ownership, threading and resources
|
||||
|
||||
- Observer retains no request, cache, snapshot or engine reference.
|
||||
- Cache/pipeline services retain their existing state and resource ownership.
|
||||
- Snapshot borrows the exact cached Mesh; observer never frees it.
|
||||
- Resource existence/request and GLB inspection run on renderer main thread.
|
||||
- Finalization and Mesh preparation remain in the loader drain path.
|
||||
|
||||
## Errors, cancellation and recovery
|
||||
|
||||
| State | Behavior | Recovery |
|
||||
|---|---|---|
|
||||
| Invalid dependency/path | Return `rejected`; no mutation | Correct composition |
|
||||
| Existing request | Return `pending`; no duplicate request | Retry when queue rotates |
|
||||
| Pivot-prefix GLB | Skip as static candidate | Continue next candidate |
|
||||
| Request error | Stop historical search and mark missing | Later reset/new session |
|
||||
| No candidate | Mark/adopt terminal missing | Cache content becomes available in new session |
|
||||
| Tile cancellation | Observer retains nothing | Loader/queue cancellation remains authoritative |
|
||||
|
||||
## Configuration and capabilities
|
||||
|
||||
The observer consumes existing `m2_cache_dir`. It adds no profile, cache version,
|
||||
batch, visibility, shadow or scheduler setting.
|
||||
|
||||
## Persistence, cache and migration
|
||||
|
||||
No new persistence is introduced. Existing `.tscn/.glb` layout, pipeline records
|
||||
and missing-cache lifetime are unchanged; no rebake is required.
|
||||
|
||||
## Diagnostics and observability
|
||||
|
||||
Returned outcomes distinguish rejected/cached/pending/requested/missing without
|
||||
logging. Existing queue and hitch metrics remain unchanged.
|
||||
|
||||
## Verification
|
||||
|
||||
- Dedicated verifier covers invalid, cached identity, missing, pending, path
|
||||
order/deduplication, absent GLB schema, source ownership and bounded timing.
|
||||
- Snapshot/dispatch/pipeline/cache/shutdown/facade/internal-access/checkpoint
|
||||
regressions protect adjacent behavior.
|
||||
- No original-client visual claim is made; this is bookkeeping/I/O extraction.
|
||||
|
||||
## Extension points
|
||||
|
||||
Animated/native observation may become a separate producer of the animation
|
||||
phase. Shared cache candidate/GLB inspection can later be reused without adding
|
||||
a generic resource framework.
|
||||
|
||||
## Capability status
|
||||
|
||||
| Capability | Status | Evidence | Gap |
|
||||
|---|---|---|---|
|
||||
| Static build lookup/request production | Implemented extraction | Lifecycle/path/source/timing verifier | Asset-backed traversal pending |
|
||||
| Static finalize/preparation | Existing loader-owned | Pipeline/finalizer regressions | Later extraction |
|
||||
| Animated observation | Existing loader-owned | Animation regressions | Separate producer pending |
|
||||
|
||||
## Known gaps and risks
|
||||
|
||||
- Successful request behavior is protected by source plus existing pipeline
|
||||
tests; starting an undrained asynchronous request in the unit fixture would leak.
|
||||
- GLB schema parser reads synchronously, matching the previous loader behavior.
|
||||
- Private traversal, p95/p99, leak and visual evidence remain unavailable.
|
||||
|
||||
## Source map
|
||||
|
||||
| Path | Responsibility |
|
||||
|---|---|
|
||||
| `src/render/m2/m2_static_build_resource_observer.gd` | Static cache/request/missing observation |
|
||||
| `src/render/m2/m2_build_resource_snapshot.gd` | Typed observation result |
|
||||
| `src/scenes/streaming/streaming_world_loader.gd` | Composition, finalize drain and action execution |
|
||||
| `src/tools/verify_m2_static_build_resource_observer.gd` | Lifecycle/path/boundary/timing regression |
|
||||
|
||||
## Related decisions and references
|
||||
|
||||
- [`m2-build-resource-snapshot.md`](m2-build-resource-snapshot.md)
|
||||
- [`m2-mesh-load-pipeline-state.md`](m2-mesh-load-pipeline-state.md)
|
||||
- [`m2-mesh-resource-cache-state.md`](m2-mesh-resource-cache-state.md)
|
||||
- [`world-renderer.md`](world-renderer.md)
|
||||
- [`../../RENDER.md`](../../RENDER.md)
|
||||
@@ -142,6 +142,7 @@ from externally reading/writing loader-private queue, task, cache and tile-state
|
||||
| `M2BuildBatchPlanner.plan_batch` | Internal pure M2 service | Selects static/animated batch count and next group cursor | Main/any thread; stateless | Non-positive selected limit clamps to one; empty range completes |
|
||||
| `M2BuildDispatchPlanner.plan_step` | Internal pure M2 service | Selects wait, animated/static materialization or no-Node advancement from observed resource state | Main/any thread; stateless | Pending animation has priority; unresolved static Mesh waits |
|
||||
| `M2BuildResourceSnapshot` | Internal M2 value contract | Carries per-step normalized path, animated/static references and pending/missing observations | Renderer main thread; one build operation | Values retained exactly; release never frees resources |
|
||||
| `M2StaticBuildResourceObserver.observe` | Internal M2 I/O service | Produces cached/pending/requested/missing static snapshot phase | Renderer main thread; stateless | Invalid composition rejected; no candidate marks missing |
|
||||
| `M2BuildQueue` / `M2BuildJob` | Internal M2 pending-state service | Own typed root/groups/cursor jobs and FIFO/stale tile keys | Renderer main thread; map session | Invalid enqueue rejected; stale keys drain independently of jobs |
|
||||
| `M2StaticBatchMaterializer.materialize_batch` | Internal M2 scene-materialization service | Builds and attaches one prepared-Mesh MultiMesh transform slice | Renderer main thread; stateless after each call | Invalid/empty input returns null; bounds are caller precondition |
|
||||
| `M2RuntimeMeshRebuildClassifier` | Internal memoized M2 service | Detects billboard/UV-rotation metadata requiring stale cached-mesh rebuild | Renderer main thread; cached until reset | Invalid variants/indices skipped; first path decision wins |
|
||||
@@ -393,9 +394,10 @@ sequenceDiagram
|
||||
without controlling engine lifetime.
|
||||
`M2BuildQueue` owns typed pending jobs, FIFO/stale keys, grouped-transform
|
||||
references and group/offset/serial cursors without freeing engine objects.
|
||||
`M2StaticBatchMaterializer` owns static MultiMesh construction/attachment;
|
||||
the loader retains resource observation/requests, action execution,
|
||||
cursor adoption, root cleanup, budgets and Editor ownership.
|
||||
`M2StaticBuildResourceObserver` owns static Mesh lookup/request admission and
|
||||
snapshot adoption. `M2StaticBatchMaterializer` owns static MultiMesh
|
||||
construction/attachment; the loader retains animated observation/requests,
|
||||
action execution, cursor adoption, root cleanup, budgets and Editor ownership.
|
||||
- `WmoPlacementResolver` is stateless and owns only call-local cache-key,
|
||||
identity and transform values. `WmoPlacementRegistry` owns only placement-key
|
||||
reference sets. `WmoRenderBuildStepPlanner` owns only a call-local operation
|
||||
@@ -416,15 +418,17 @@ sequenceDiagram
|
||||
for billboard/UV-rotation material refresh and is composed by the runtime Mesh
|
||||
finalizer. The raw repository loads value data; loader retains Mesh adoption.
|
||||
- `M2MeshLoadPipelineState` owns static M2 pending Resource paths, opaque
|
||||
terminal statuses and completion-order finalize FIFO. The loader retains cache
|
||||
path selection, ResourceLoader calls, permits and adoption decisions; prototype
|
||||
cache state owns shared missing outcomes.
|
||||
terminal statuses and completion-order finalize FIFO. The static observer owns
|
||||
cache path selection, request admission and initial snapshot adoption. The
|
||||
loader retains ResourceLoader polling/finalize, permits and terminal adoption;
|
||||
prototype cache state owns shared missing outcomes.
|
||||
- `M2MeshResourceCacheState` owns prepared static Mesh references and releases
|
||||
them at the existing final-shutdown site. Prototype state and materialization
|
||||
belong to the sibling cache service and loader respectively.
|
||||
- `M2MeshResourceExtractor` owns depth-first first-Mesh selection and temporary
|
||||
PackedScene instance destruction. The loader retains ResourceLoader I/O,
|
||||
cache/missing adoption and materialization.
|
||||
PackedScene instance destruction. The static observer admits ResourceLoader
|
||||
requests and initial cache/missing adoption; the loader retains polling,
|
||||
terminal adoption and materialization.
|
||||
- `M2RuntimeMeshFinalizer` owns refresh version `2`, classifier lifetime,
|
||||
M2Builder rebuild and original-Mesh fallback. The loader loads raw data only
|
||||
after the finalizer reports that a cached Mesh is stale.
|
||||
@@ -579,6 +583,7 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
|
||||
| M2 build batch planner | Implemented extraction | Scene-free limit/count/cursor/source/timing contract | Spatial cells and asset-backed p95/p99 remain pending |
|
||||
| M2 build dispatch planner | Implemented extraction | Scene-free priority/action/transition/source/timing contract | Resource observation/orchestration and asset-backed traversal remain pending |
|
||||
| M2 build resource snapshot | Implemented extraction | Typed identity/adoption/lifetime/source/timing contract | Resource observation service and asset-backed traversal remain pending |
|
||||
| M2 static build resource observer | Implemented extraction | Cache/pending/path/request/source/timing contract | Asset-backed traversal and finalize extraction pending |
|
||||
| M2 build queue | Implemented extraction | Typed lifecycle/FIFO/progress/lifetime/source/timing contract | Resource dispatch and asset-backed traversal remain pending |
|
||||
| M2 animation load pipeline state | Implemented extraction | Synthetic lifecycle/FIFO/source/timing contract | Asset-backed traversal/leak/animation-fidelity/p95/p99 pending |
|
||||
| M2 animated scene finalizer | Implemented extraction | Synthetic type/lifetime/material/player/source/timing contract | Asset-backed GLB traversal/material/animation comparison pending |
|
||||
@@ -652,6 +657,7 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
|
||||
| `src/render/m2/m2_static_batch_materializer.gd` | Static MultiMesh construction, render setup and attachment |
|
||||
| `src/render/m2/m2_build_dispatch_planner.gd` | M2 wait/materializer/advance action priority and transition plan |
|
||||
| `src/render/m2/m2_build_resource_snapshot.gd` | Typed per-step animated/static observations and borrowed references |
|
||||
| `src/render/m2/m2_static_build_resource_observer.gd` | Static Mesh lookup/request/missing snapshot production |
|
||||
| `src/render/m2/m2_build_job.gd` | M2 root/groups references and group/offset/serial progress |
|
||||
| `src/render/m2/m2_build_queue.gd` | Keyed pending jobs and FIFO/stale tile-key lifecycle |
|
||||
| `src/render/m2/m2_mesh_load_pipeline_state.gd` | Static M2 pending Resource paths, terminal statuses and finalize FIFO |
|
||||
@@ -682,6 +688,7 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
|
||||
| `src/tools/verify_m2_static_batch_materializer.gd` | Static M2 node/Mesh/render/attachment/boundary/timing regression |
|
||||
| `src/tools/verify_m2_build_dispatch_planner.gd` | M2 dispatch priority/action/transition/boundary/timing regression |
|
||||
| `src/tools/verify_m2_build_resource_snapshot.gd` | M2 observation identity/adoption/lifetime/boundary/timing regression |
|
||||
| `src/tools/verify_m2_static_build_resource_observer.gd` | Static lookup/request/path/boundary/timing regression |
|
||||
| `src/tools/verify_m2_build_queue.gd` | M2 job/FIFO/progress/lifetime/boundary/timing regression |
|
||||
| `src/tools/verify_m2_mesh_load_pipeline_state.gd` | Static M2 request/terminal/FIFO/boundary/timing regression |
|
||||
| `src/tools/verify_m2_mesh_resource_cache_state.gd` | Static M2 Mesh cache ownership/lifetime/boundary/timing regression |
|
||||
|
||||
Reference in New Issue
Block a user