Files
open-wc/docs/modules/m2-build-batch-planner.md
T

9.7 KiB

M2 Build Batch Planner

Metadata

Field Value
Status Implemented
Target/work package M03 / M03-RND-M2-BUILD-BATCH-PLANNER-001
Owners Pure static/animated M2 batch sizing and group cursor progression
Last verified Worktree work/sindo-main-codex/m03-m2-build-batch-planner, 2026-07-17
Profiles/capabilities Existing static MultiMesh and animated-instance build paths

Purpose

Select the effective per-tick M2 batch limit, cap it to remaining transforms and plan the next group offset without accessing loader state or renderer resources.

Non-goals

  • Own M2 build jobs, queues, tile state, retries or cancellation.
  • Decide whether an animated prototype or static mesh is ready.
  • Rotate queues or consume RenderBudgetScheduler permits.
  • Create or modify Nodes, MultiMesh, Mesh, materials or RIDs.
  • Introduce spatial cells or change profile batch limits.

Context and boundaries

flowchart LR
    Groups[M2PlacementGrouper transform arrays] --> Loader[Loader build loop]
    Limits[Animated/static batch limits] --> Planner[M2BuildBatchPlanner]
    Loader --> Planner
    Planner --> Plan[Detached batch plan]
    Plan --> Loader
    Loader --> Dispatch[M2BuildDispatchPlanner]
    Dispatch --> Materialize[Animated or MultiMesh materialization]
    Loader --> Budget[RenderBudgetScheduler permit]

Allowed dependencies are integer/boolean scalar math and a fresh Dictionary. Node, SceneTree, RenderingServer, ResourceLoader, WorkerThreadPool, mutexes, renderer caches, gameplay, network, editor UI and files are forbidden.

Public API

Symbol Kind Purpose Thread/lifetime Errors
plan_batch(transform_count, current_offset, has_animated_prototype, animated_batch_limit, static_batch_limit) Pure query Return the selected batch size/count and next group cursor Any thread; call-local result Non-positive selected limit clamps to one; empty/past-end range completes

Inputs and outputs

Direction Contract/data Producer Consumer Ownership Thread/lifetime
Input Transform count Grouped transform array Planner remaining-count formula Scalar copy One plan
Input Current group offset Loader build job Planner cursor formula Scalar copy One plan
Input Animated prototype availability Loader resource selection Planner limit selector Scalar copy One plan
Input Animated/static raw limits Renderer profile/exports Planner clamp Scalar copy One plan
Output effective_batch_size Planner Tests/diagnostics Detached integer One plan
Output batch_count Planner Loader materialization adapter Detached integer One plan
Output next_offset Planner Loader build-job cursor Detached integer Until next batch
Output group_complete Planner Loader group-index progression Detached boolean One plan

The output Dictionary is newly allocated and caller-owned. The planner retains no reference to it or any input.

Data flow

flowchart TD
    Select{Animated prototype?} -->|yes| Animated[animated_batch_limit]
    Select -->|no| Static[static_batch_limit]
    Animated --> Clamp[max 1]
    Static --> Clamp
    Clamp --> Remaining[max 0 of transform_count - current_offset]
    Remaining --> Count[min effective limit, remaining]
    Count --> Complete{count <= 0 or offset + count >= total?}
    Complete -->|yes| Done[group_complete true; next_offset 0]
    Complete -->|no| Continue[group_complete false; next_offset offset + count]

Lifecycle/state

The planner is stateless. It has no initialization, reset, cancellation, recovery or shutdown work. Each call returns a complete detached value plan.

Main sequence

sequenceDiagram
    participant Loader as StreamingWorldLoader build loop
    participant Planner as M2BuildBatchPlanner
    participant Materializer as Animated/MultiMesh adapter
    participant Scheduler as RenderBudgetScheduler
    Loader->>Planner: plan_batch(count, offset, path kind, limits)
    Planner-->>Loader: batch_count, next_offset, group_complete
    Loader->>Loader: resolve/request prototype or mesh
    Loader->>Materializer: materialize selected transform slice
    Loader->>Loader: adopt cursor/group completion
    Loader->>Scheduler: consume M2_BUILD permit

Ownership, threading and resources

  • The planner owns only call-local scalar values and the returned Dictionary.
  • M2BuildQueue owns typed jobs, FIFO ordering, serial numbers and group/offset cursors. M2BuildDispatchPlanner owns the pure resource-state action decision; the loader owns tile checks, resource observation/retry and adoption calls.
  • Materializers own main-thread Node/MultiMesh construction under loader roots.
  • The scheduler owns the frame-local M2_BUILD counter.
  • Pure planning is thread-safe, though the current adapter calls it on main thread.

Errors, cancellation and recovery

Failure Detection Behavior Diagnostic Recovery
Zero/negative selected limit Scalar clamp Effective size becomes one Contract fixture Correct profile value later
Empty transform group Remaining count zero Count zero; group completes Contract fixture Loader advances group
Offset at/past end Remaining count clamp Count zero; offset resets Contract fixture Loader advances group
Negative offset No new validation Historical arithmetic is preserved Contract fixture Loader inputs should remain valid
Resource pending/missing Outside planner Loader rotates or advances as before Existing cache/build diagnostics Resource loader retry/fallback
Tile cancelled Outside planner Loader cancels job before planning/materialization Existing lifecycle gates Eligible tile may requeue

Configuration and capabilities

The planner introduces no setting. It consumes existing m2_animated_instances_per_tick and m2_multimesh_batch_size values after the loader determines whether an animated prototype is available.

Persistence, cache and migration

No persistence, schema or cache format participates. ADT/M2 cache versions, quality presets and rebuild instructions are unchanged.

Diagnostics and observability

The planner emits no logs. Its verifier covers deterministic formula/source boundaries and records bounded 20,000-plan timing. Existing loader metrics retain queue depth, build activity and hitch observability.

Verification

  • verify_m2_build_batch_planner.gd: static/animated selection, invalid-limit clamp, remaining cap, exact completion, empty/past-end and negative-offset behavior, loader/dependency source boundaries and bounded timing.
  • Grouper, transform resolver, unique registry/dedupe, facade, internal-access, manifest, shutdown, scheduler, streaming, coordinate, documentation and coordination regressions remain required.
  • Fidelity evidence is formula extraction only. Asset-backed frame pacing and visual output require the renderer checkpoint/performance workflow.

Extension points

  • A later package may extract resource observation/request orchestration while retaining the dispatch and typed build-job/FIFO contracts.
  • Spatial-cell batching must use measured culling/performance evidence and must not silently change this model-path batch cursor.

Capability status

Capability Status Evidence Gap/next step
Static/animated batch cursor planning Implemented extraction Contract/source/timing verifier Asset-backed p95/p99 pending
Typed build queue/cursor state Implemented extraction M2 build queue lifecycle verifier Asset-backed traversal pending
Resource dispatch decision Implemented extraction M2 build dispatch planner verifier Asset-backed traversal pending
Resource observation/requests Remains in loader Existing lifecycle regressions Stateful extraction pending
Spatial-cell batching Planned Renderer roadmap Culling evidence/design pending

Known gaps and risks

  • The planner result remains a Dictionary; M2BuildQueue adopts its scalar cursor values through one explicit progress call.
  • Negative offsets are preserved rather than rejected to avoid a hidden behavior change.
  • Planning timing does not measure resource loading or materialization.
  • Private asset-backed p95/p99 and visual comparison remain unavailable.

Source map

Path Responsibility
src/render/m2/m2_build_batch_planner.gd Pure limit/count/cursor planning
src/render/m2/m2_build_dispatch_planner.gd Pure observed-state action/transition planning
src/render/m2/m2_build_queue.gd Typed pending jobs, FIFO order and cursor ownership
src/scenes/streaming/streaming_world_loader.gd Tile checks, resource readiness, progress adoption, materializer adapters and budgets
src/render/m2/m2_static_batch_materializer.gd Planned static-slice MultiMesh construction and attachment
src/render/m2/m2_animation_playback_controller.gd Animated-instance phase/selection/native/imported playback
src/render/m2/m2_animated_instance_materializer.gd Planned animated-slice duplication, playback startup and attachment
src/render/m2/m2_placement_grouper.gd Produces grouped transform arrays
src/tools/verify_m2_build_batch_planner.gd Formula, source and timing regression