e887c3bad5
Work-Package: M03-RND-STREAMING-PLANNER-001 Agent: sindo-main-codex Tests: planner/facade/focus/coordinate/manifest/shutdown contracts, seven-checkpoint dry-run, repository gates Fidelity: preserves wanted/retained radii, boundary prefetch, editor preview, queue priority and cache/render behavior
240 lines
12 KiB
Markdown
240 lines
12 KiB
Markdown
# 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 `<tile_x>_<tile_y>` 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)
|