Skip to content

W-033: ecs-schedule per-world state and isolation (SCH-F05)

Type: feature · Size: M · Epic: E-schedule-v0 · Target: packages/ecs-schedule · Breaking: no Depends: W-030, W-031 Refs: spec SCH-060, SCH-061, SCH-062, SCH-063, SCH-064, SCH-065, SCH-113, SCH-117, SCH-125, SCH-151

Goal

Complete the per-world state trait that W-030 started: name, disabled, and onStartDone with lazy add, the readonly schedule.state property, and the reset behaviour. Enforce isolation between worlds and between schedules, and check that importing the package has no side effects. Unknown names in disabled are ignored.

Steps

  • S1 (SCH-063, SCH-151): state trait fields exactly name, disabled (factory default), onStartDone; schedule.state is readonly with stable identity; added lazily, so world.has is false until first use; name equals schedule.name; files: packages/ecs-schedule/src/state.ts, packages/ecs-schedule/src/schedule.ts, packages/ecs-schedule/tests/state-shape.test.ts
  • S2 (SCH-060, SCH-061): one schedule on two worlds keeps enabled and OnStart state separately; files: packages/ecs-schedule/tests/state-worlds.test.ts
  • S3 (SCH-062, SCH-064): two schedules on one world do not share state; importing the package has no side effects and no module-level mutable state; files: packages/ecs-schedule/tests/state-schedules.test.ts, packages/ecs-schedule/tests/import-side-effects.test.ts
  • S4 (SCH-065, SCH-125): after world.reset() all systems are enabled and OnStart runs again, with the trait re-added under the same name; names in disabled that match no system are ignored silently; files: packages/ecs-schedule/tests/state-reset.test.ts
  • S4a (SCH-113): empty and fully skipped OnStart leave schedule.state.onStartDone true after the call; files: packages/ecs-schedule/tests/state-on-start-done.test.ts
  • S5a (SCH-117): remove the per-call allocation in beginOnStart (src/on-start.ts: koota world.get on the state trait allocates ~25 B/call); use a per-schedule WeakSet as the hot-path started check while keeping the state trait observable; re-run packages/ecs-schedule/bench/run-alloc.bench.ts and confirm ~0 B/call; files: packages/ecs-schedule/src/on-start.ts, packages/ecs-schedule/bench/run-alloc.bench.ts
  • S5 (changeset): add .changeset/w-033-ecs-schedule-state.md (patch, @workspace/ecs-schedule)

Log

  • 2026-11-01 created from the approved spec split of W-004 (Triage)
  • 2026-11-02 S4a added for SCH-113 (empty and fully skipped OnStart state), taken from the deferred W-030 S2 cases (Triage)
  • 2026-11-02 S5a added for SCH-117 (per-call allocation in beginOnStart), moved from W-030 S5 follow-up (Triage)