# WMO Render Resource Finalizer

## Metadata

| Field | Value |
|---|---|
| Status | Implemented extraction |
| Target/work package | M03 / `M03-RND-WMO-RENDER-RESOURCE-FINALIZER-001` |
| Owners | Lightweight WMO terminal status polling, Resource validation and cache/missing publication |
| Last verified | Worktree `work/sindo-main-codex/m03-wmo-render-resource-finalizer`, 2026-07-18 |
| Profiles/capabilities | Profile-independent lightweight WMO render-cache finalization |

## Purpose

Finalize pending lightweight WMO `.res` cache requests outside
`StreamingWorldLoader`: poll terminal status, retrieve a loaded Resource, enforce
exact script/current-format validation and publish either the exact Resource or
the historical missing outcome.

## Non-goals

- Select normalized WMO/cache paths or start threaded requests.
- Finalize cached WMO PackedScenes or live WMOBuilder prototypes.
- Own cache lifetime, placements, build queues, scheduler permits or Nodes.
- Change `WMOStreamingResource.FORMAT_VERSION`, fallback or visible behavior.

## Context and boundaries

```mermaid
flowchart LR
    Loader[StreamingWorldLoader] -->|compose and tick| Finalizer[WmoRenderResourceFinalizer]
    Cache[WmoRenderResourceCacheState] -->|pending snapshot| Finalizer
    Finalizer --> ResourceLoader
    Finalizer -->|validated Resource or missing| Cache
    Cache --> Build[WMO render build queue]
```

The service may depend on `ResourceLoader`, the injected expected Script and the
render Resource cache-state API. File selection, FileAccess, SceneTree, WMOBuilder,
placement, scheduler and application layers remain outside it.

## Public API

| Symbol | Kind | Purpose | Thread/lifetime | Errors |
|---|---|---|---|---|
| `poll_terminal_requests(cache_state)` | Command/query | Poll all pending paths once and publish terminal outcomes | Renderer main thread; stateless between calls | Null state returns zero; non-terminal retained |
| `is_current_render_resource(resource)` | Query | Enforce exact injected Script and minimum format | Renderer main thread; stateless | Null/wrong/stale false |
| `load_threaded_get_status(path)` | Boundary query | Read opaque threaded status | Renderer main thread; injectable in tests | ResourceLoader semantics |
| `load_threaded_get(path)` | Boundary query | Retrieve terminal Resource | Renderer main thread; injectable in tests | Null accepted as failed outcome |

## Inputs and outputs

| Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime |
|---|---|---|---|---|---|
| Input | Detached normalized-path to `.res` path Dictionary | Render cache state | Finalizer polling | Caller-owned copy | One poll pass |
| Input | Opaque ResourceLoader status | ResourceLoader | Finalizer | Integer value | One path poll |
| Input | Terminal Resource | ResourceLoader | Validator | Borrowed reference | One completion |
| Input | Expected Script/minimum format | Loader composition | Validator | Borrowed/value | Finalizer lifetime |
| Output | Exact validated Resource | Finalizer | Render cache state | Cache adopts strong reference | Until full clear |
| Output | Missing transition | Finalizer | Render cache state | Path-only state | Until transient clear |

## Data flow

```mermaid
flowchart TD
    Snapshot[Detached pending snapshot] --> Next[Next path in insertion order]
    Next --> Poll[Poll ResourceLoader status]
    Poll --> Terminal{Loaded or failed?}
    Terminal -->|no| Retain[Retain pending]
    Terminal -->|failed| Missing[Complete as missing]
    Terminal -->|loaded| Get[Get terminal Resource]
    Get --> Validate{Exact script and format current?}
    Validate -->|yes| Adopt[Complete with exact Resource]
    Validate -->|no| Missing
    Retain --> Next
    Adopt --> Next
    Missing --> Next
```

## Lifecycle/state

```mermaid
stateDiagram-v2
    [*] --> Polling
    Polling --> Pending: non-terminal status
    Polling --> Missing: failed/null/wrong/stale
    Polling --> Cached: exact script and current format
    Pending --> Polling: later tick
    Missing --> [*]
    Cached --> [*]
```

The finalizer retains no per-path state. The sibling cache state owns all
Pending/Cached/Missing lifetime and reset transitions.

## Main sequence

```mermaid
sequenceDiagram
    participant Loader as StreamingWorldLoader
    participant Finalizer as WmoRenderResourceFinalizer
    participant Cache as WmoRenderResourceCacheState
    participant RL as ResourceLoader
    Loader->>Finalizer: poll_terminal_requests(Cache)
    Finalizer->>Cache: request_paths_snapshot()
    loop insertion-ordered paths
        Finalizer->>RL: load_threaded_get_status(cache path)
        alt non-terminal
            Finalizer->>Finalizer: retain request
        else failed
            Finalizer->>Cache: complete_request_as_missing(path)
        else loaded
            Finalizer->>RL: load_threaded_get(cache path)
            Finalizer->>Finalizer: exact Script and format validation
            Finalizer->>Cache: complete with Resource or missing
        end
    end
```

## Dependency diagram

```mermaid
flowchart TB
    Loader[StreamingWorldLoader] --> Finalizer[WmoRenderResourceFinalizer]
    Loader --> Cache[WmoRenderResourceCacheState]
    Finalizer --> Cache
    Finalizer --> ResourceLoader
    Finalizer --> Script[WMOStreamingResource Script contract]
    Finalizer -. no dependency .-> FileAccess
    Finalizer -. no dependency .-> WMOBuilder
    Finalizer -. no dependency .-> Node
    Finalizer -. no dependency .-> Scheduler
```

## Ownership, threading and resources

- Renderer main thread serializes polling and cache-state publication.
- Finalizer owns no Resource, request, Node, RID or file lifetime.
- Cache state adopts accepted exact Resource references until its full clear.
- Loader owns request admission, fallback/build orchestration and shutdown order.
- Detached snapshots allow terminal cache-state mutation during iteration.

## Errors, cancellation and recovery

| Failure/state | Detection | Behavior | Diagnostic | Recovery |
|---|---|---|---|---|
| Null cache state | Guard | Return zero | Contract verifier | Correct composition |
| Non-terminal request | Status | Retain pending | Pending count | Poll next tick |
| Failed request | Terminal status | Complete missing | Negative cache | Transient reset/rebuilt cache |
| Null/wrong-script Resource | Validation | Complete missing | Synthetic fixture | Rebuild cache and reset |
| Stale format | Format below injected minimum | Complete missing | Synthetic fixture | Rebuild cache and reset |
| Shutdown | Loader lifecycle | Drain then cache clear | Shutdown verifier | New loader starts absent |

## Configuration and capabilities

The loader injects the exact `WMOStreamingResource` Script and its
`FORMAT_VERSION`. The service introduces no setting, profile, permit or cache
format. WMO cache paths and build budgets remain loader-owned.

## Persistence, cache and migration

The module serializes nothing and changes no cache format. It only enforces the
existing script identity and current-or-newer format rule before runtime cache
adoption, so no migration or rebake is introduced.

## Diagnostics and observability

- `poll_terminal_requests` returns terminal completion count for tests/future metrics.
- Existing cache pending count and renderer `wmobuild` metrics are unchanged.
- The service emits no logs; normalized relative path remains the correlation key.

## Verification

- `verify_wmo_render_resource_finalizer.gd`: null/non-terminal, insertion order,
  failed/load boundary, null/wrong/stale rejection, current/newer identity,
  source ownership and 1,000 terminal polls under one second.
- Cache-state, WMO queue/planner/registry/resolver, shutdown, facade,
  internal-access and baseline regressions protect adjacent behavior.
- Fidelity evidence is exact orchestration extraction; no asset-backed visual or
  original-client parity claim is made.

## Extension points

- A legal current/stale `.res` fixture can extend validation evidence unchanged.
- PackedScene finalization remains separate because it instantiates a probe Node
  and uses WMOBuilder metadata rather than script/format Resource fields.

## Capability status

| Capability | Status | Evidence | Gap/next step |
|---|---|---|---|
| Lightweight WMO terminal polling | Implemented extraction | Status/order/source/timing verifier | Asset-backed traversal pending |
| Script/format validation | Implemented extraction | Wrong/stale/current/newer fixtures | Legal serialized fixture pending |
| Resource/missing publication | Implemented extraction | Exact identity/negative-state fixtures | Asset-backed lifetime/leak run pending |
| WMO materialization | Loader-owned | Existing build regressions | Further safe extraction pending |

## Known gaps and risks

- ResourceLoader status/get remains synchronous main-thread boundary polling.
- No proprietary WMO corpus, serialized corrupt-version fixture, leak run,
  traversal p95/p99 or paired original-client capture is included.

## Source map

| Path | Responsibility |
|---|---|
| `src/render/wmo/wmo_render_resource_finalizer.gd` | Terminal polling, validation and publication |
| `src/render/wmo/wmo_render_resource_cache_state.gd` | Resource/missing/request ownership and resets |
| `src/scenes/streaming/streaming_world_loader.gd` | Composition, request admission, fallback and build orchestration |
| `src/resources/wmo_streaming_resource.gd` | Serialized cache contract and format version |
| `src/tools/verify_wmo_render_resource_finalizer.gd` | Terminal-I/O/validation/source/timing regression |

## Related decisions and references

- [`wmo-render-resource-cache-state.md`](wmo-render-resource-cache-state.md)
- [`wmo-render-build-queue.md`](wmo-render-build-queue.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)
