# Streaming Target Planner ## Metadata | Field | Value | |---|---| | Status | Implemented | | Target/work package | `M03-RND-STREAMING-PLANNER-001` | | Owners | Renderer workstream / M03 integrator | | Last verified | `work/sindo-main-codex/m03-streaming-target-planner`, 2026-07-15 | | Profiles/capabilities | Runtime and Editor preview ADT target selection; profile values supplied by caller | ## Purpose Calculate which available ADT tiles are wanted and retained for one typed focus without accessing the SceneTree, worker tasks, renderer queues, caches or GPU resources. Runtime planning preserves prewarm, hysteresis and boundary-prefetch behavior; editor planning preserves the square preview radius. ## Non-goals - Mutate load/finalize/eviction queues. - Prioritize queued tile paths by world distance. - Calculate chunk or tile LOD levels after a tile is loaded. - Own the available WDT tile catalog or cache paths. - Create, cancel or await jobs. - Implement M2, WMO, liquid or terrain attachment. ## Context and boundaries ```mermaid flowchart LR Focus[GodotWorldPosition] --> Planner[StreamingTargetPlanner] Policy[StreamingTargetPolicy] --> Planner Catalog[Available tile keys from WDT/directory] --> Planner Planner --> Plan[StreamingTargetPlan] Plan --> Streamer[StreamingWorldLoader queue/state apply] Streamer --> Queue[Tile load queue] ``` Allowed dependencies: - typed coordinate values and `CoordinateMapper`; - immutable planner policy/result contracts; - read-only available-tile key membership. Forbidden dependencies: - `Node`, SceneTree and viewport/camera discovery; - `WorkerThreadPool`, `ResourceLoader` and filesystem access; - `RenderingServer`, meshes, materials, nodes and RIDs; - gameplay, network, UI, editor UI or server adapters; - streamer queues, tile states and cache dictionaries. ## Public API | Symbol | Kind | Purpose | Thread/lifetime | Errors | |---|---|---|---|---| | `StreamingTargetPlanner.plan_runtime` | Pure method | Builds wanted/retained sets with edge/corner prefetch | Any thread if caller does not mutate catalog concurrently; call-scoped | Empty catalog produces empty sets | | `StreamingTargetPlanner.plan_editor` | Pure method | Builds identical editor wanted/retained square sets | Same as runtime planning | Negative radius clamps to zero | | `StreamingTargetPolicy` | Immutable value | Captures radius margins and boundary threshold for one plan | Caller-owned, shareable | Values retain scene input; effective margins/threshold are clamped | | `visible_tile_radius` | Pure query | Resolves chunk-radius versus tile-radius visibility | Any thread/value lifetime | No failure | | `load_tile_radius` | Pure query | Adds non-negative prewarm margin | Any thread/value lifetime | No failure | | `retained_tile_radius` | Pure query | Adds non-negative hysteresis margin | Any thread/value lifetime | No failure | | `StreamingTargetPlan` | Immutable value | Holds focus tile and read-only wanted/retained key sets | Caller-owned plan lifetime | No failure | | `wanted_tile_keys` | Read-only query | Returns immutable wanted set | Plan lifetime | Mutation is rejected by Godot read-only Dictionary | | `retained_tile_keys` | Read-only query | Returns immutable retained set | Plan lifetime | Mutation is rejected by Godot read-only Dictionary | ## Inputs and outputs | Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime | |---|---|---|---|---|---| | Input | `GodotWorldPosition` | `WorldRenderFacade`/streamer focus adapter | Planner | Immutable caller value | One plan | | Input | Available `_` keys | `StreamingWorldLoader` WDT/directory catalog | Planner membership checks | Loader-owned, read-only during call | Map session | | Input | `StreamingTargetPolicy` | Streamer configuration snapshot | Planner | Immutable caller value | One or more plans | | Input | Editor preview radius | Editor scene configuration | Planner | Scalar copy | One plan | | Output | `StreamingTargetPlan.focus_tile` | Planner/`CoordinateMapper` | Streamer diagnostics | Immutable typed coordinate | Plan lifetime | | Output | Wanted tile-key set | Planner | Streamer queue/state apply | Plan-owned read-only Dictionary | Plan lifetime | | Output | Retained tile-key set | Planner | Streamer hysteresis/state apply | Plan-owned read-only Dictionary | Plan lifetime | Side effects: - none; - no input mutation; - no logging, I/O, task submission, cache access, SceneTree or GPU work. ## Data flow ```mermaid flowchart TD Position[GodotWorldPosition] --> Tile[CoordinateMapper.godot_to_adt_tile] Position --> Local[CoordinateMapper.godot_to_adt_tile_local] Policy[StreamingTargetPolicy] --> Radii[load and retained radii] Policy --> Threshold[clamped boundary threshold] Tile --> Centers[base prefetch center] Local --> Centers Threshold --> Centers Centers --> Wanted[available keys within load radius] Centers --> Retained[available keys within retained radius] Catalog[Available tile keys] --> Wanted Catalog --> Retained Wanted --> Plan[StreamingTargetPlan] Retained --> Plan Tile --> Plan ``` ## Lifecycle/state The planner is stateless. A call creates local center/set dictionaries, freezes the result dictionaries in `StreamingTargetPlan`, returns the plan and retains no reference to inputs or output. There is no retry, cancellation or shutdown state machine. ## Main sequence ```mermaid sequenceDiagram participant Stream as StreamingWorldLoader participant Planner as StreamingTargetPlanner participant Mapper as CoordinateMapper participant Plan as StreamingTargetPlan Stream->>Planner: plan_runtime(catalog, typed focus, policy) Planner->>Mapper: focus tile and tile-local position Mapper-->>Planner: typed coordinates Planner->>Planner: prefetch centers and available key sets Planner->>Plan: freeze focus/wanted/retained result Plan-->>Stream: immutable target plan Stream->>Stream: apply queues, LOD and detail state ``` ## Ownership, threading and resources - `StreamingWorldLoader` owns the available catalog and must not mutate it during a planning call. - `StreamingTargetPolicy` and typed focus remain caller-owned immutable values. - The planner owns temporary center/set values only until plan construction. - `StreamingTargetPlan` owns its read-only result dictionaries. - The planner creates no Node, Resource, RID, thread, mutex or task. - Current runtime calls occur on the main thread; scene-free contracts permit a future worker call only after catalog publication/ownership is explicit. ## Errors, cancellation and recovery | Failure | Detection | Behavior | Diagnostic | Recovery | |---|---|---|---|---| | Empty/unavailable catalog | No membership matches | Valid plan with empty sets | Streamer retains existing missing-data diagnostics | Load a valid WDT/directory catalog and replan | | Focus outside catalog/grid | Typed coordinate does not match keys | Valid focus tile with filtered empty/partial sets | Caller diagnostic if required | Supply valid focus/map or catalog | | Negative prewarm/retain margin | Policy effective-radius query | Margin clamps to zero | Contract test | Correct configuration if negative value was unintended | | Boundary threshold outside range | Policy query | Clamp to `0.0..0.49` | Contract test | Correct configuration or accept safe clamp | | Plan no longer current | New focus/config/catalog revision | Caller discards ephemeral plan | Streamer refresh diagnostics | Replan from current inputs | Cancellation is not applicable: planning is synchronous, bounded and owns no external work. A returned stale plan is simply not retained by the planner. ## Configuration and capabilities | Setting/capability | Default source | Profile | Runtime mutable | Effect | |---|---|---|---|---| | `lod2_radius_chunks` | Streamer scene/profile | Renderer | Yes at composition/debug boundary | Converts chunk coverage to minimum ADT radius | | `lod2_tile_radius` | Streamer scene/profile | Renderer | Yes | Minimum visible ADT radius | | `warm_tile_margin` | Streamer scene/profile | Renderer | Yes | Extends chunk-derived visible radius | | `prewarm_tile_margin` | Streamer scene/profile | Renderer | Yes | Extends wanted/load radius | | `retain_tile_margin` | Streamer scene/profile | Renderer | Yes | Extends retained hysteresis radius | | `boundary_prefetch_threshold` | Streamer scene/profile | Renderer | Yes | Adds adjacent/corner prefetch centers near tile boundaries | | Editor preview radius | Editor scene | Authoring preview | Yes | Square wanted/retained preview set | The planner does not select `Blizzlike335` or `Enhanced`; it applies the values already selected by renderer composition. ## Persistence, cache and migration - Planner contracts are runtime-only and are not serialized. - Existing tile keys and cache paths are unchanged. - No cache/resource/schema version bump or migration is required. ## Diagnostics and observability - Logs remain emitted by `StreamingWorldLoader` after applying a plan. - `StreamingTargetPlan` exposes focus/wanted/retained data for deterministic tests. - Dedicated verifier reports case count, iteration count, total time and average plan time. - No correlation ID is required for synchronous ephemeral plans. ## Verification - Unit/contract: `src/tools/verify_streaming_target_planner.gd` covers center radii, edge/corner cross product, catalog filtering, clamps, editor behavior, input/result ownership and scene-free dependencies. - Integration: streamer source gate confirms both runtime/editor delegation and removal of `_predictive_focus_tiles` from the monolith. - Fidelity evidence: expected sets encode the pre-extraction formulas; renderer checkpoint dry-run must retain all seven checkpoint plans. - Performance budget: 250 synthetic High-like corner plans average at most `4.0 ms` each on the headless regression runner; measured result is recorded in test output. - Manual diagnostics: unchanged `StreamingWorld` focus/wanted/queued log. ## Extension points - Direction/velocity/frustum priority can extend policy/input only with fixtures and a compatibility-safe default reproducing the current position-only plan. - Multi-focus planning may union additional typed centers without giving the planner ownership of queues or consumers. - Queue ordering remains a separate scheduler/application responsibility. ## Capability status | Capability | Status | Evidence | Gap/next step | |---|---|---|---| | Runtime wanted/retained sets | Implemented | Center/corner/catalog fixtures | Add paired traversal performance evidence | | Boundary prefetch centers | Implemented | Edge/corner cross-product fixture | Direction/velocity prediction not implemented | | Editor preview set | Implemented | Negative/radius-one fixtures | Editor viewport integration remains existing adapter | | Scene-free deterministic execution | Implemented | Dependency/source gate and 250-iteration run | Worker execution is unnecessary today | | Queue priority/LOD | Not in module | Preserved in streamer | Separate extraction packages | ## Known gaps and risks - Tile-key sets preserve the streamer's internal string representation; a typed catalog migration is deferred until it can remove, rather than duplicate, that source of truth. - Planner time scales with the union of square radii/prefetch centers. The current bounded regression covers High-like corner input but not pathological custom radii. - Exact p95/p99 frame impact still requires renderer baseline runs with local assets. - Direction, velocity and camera frustum do not influence target selection yet. ## Source map | Path | Responsibility | |---|---| | `src/render/streaming/streaming_target_planner.gd` | Pure runtime/editor set calculation and boundary centers | | `src/render/streaming/streaming_target_policy.gd` | Immutable radius/threshold snapshot and effective clamps | | `src/render/streaming/streaming_target_plan.gd` | Immutable typed focus and read-only result sets | | `src/scenes/streaming/streaming_world_loader.gd` | Planner composition and plan application to queues/state | | `src/tools/verify_streaming_target_planner.gd` | Asset-free behavior/dependency/performance regression | ## Related decisions and references - [`world-renderer.md`](world-renderer.md) - [`../../targets/03-renderer-facade.md`](../../targets/03-renderer-facade.md) - [`../../targets/roadmap/02-rendering-and-graphics.md`](../../targets/roadmap/02-rendering-and-graphics.md) - [`../GODOT_BEST_PRACTICES.md`](../GODOT_BEST_PRACTICES.md) - [`../CODING_STANDARD.md`](../CODING_STANDARD.md)