Skip to content

W-030: ecs-schedule OnStart, errors and re-entrancy (SCH-F03, part 2)

Type: feature · Size: M · Epic: E-schedule-v0 · Target: packages/ecs-schedule · Breaking: no Depends: W-029 Refs: spec SCH-036, SCH-037, SCH-043, SCH-044, SCH-045, SCH-112, SCH-113, SCH-114, SCH-115, SCH-116, SCH-117

Goal

Add once-only OnStart, error propagation, synchronous-system checks, and per-world re-entrancy guards. This item creates the per-world state trait with name, disabled, and onStartDone (SCH-063 shape). Isolation, reset, and state exposure are completed in W-033. The allocation benchmark (SCH-117) is manual.

Steps

  • S1 (SCH-036, SCH-114): OnStart runs once per world on the first run, runPhase, or runPhases that includes it; calls that exclude it do not run or mark it done; files: packages/ecs-schedule/src/state.ts, packages/ecs-schedule/src/on-start.ts, packages/ecs-schedule/tests/on-start.test.ts
  • S2 (SCH-112, SCH-113 partial): onStartDone is set only after the whole OnStart phase completes without throwing; after a throw the phase runs again in full; empty OnStart runs without error (fully-skipped and observable-flag cases deferred to W-031, W-032, W-033); files: packages/ecs-schedule/tests/on-start-done.test.ts
  • S3 (SCH-037, SCH-116): system errors propagate unchanged and skip later systems in that call; a thenable return throws naming the schedule and system and clears the executing marker; files: packages/ecs-schedule/src/run-errors.ts, packages/ecs-schedule/tests/run-errors.test.ts
  • S4 (SCH-043, SCH-044, SCH-045, SCH-115): nested run of the same schedule on the same world throws; the marker is cleared on return or throw; other schedules and worlds may nest; error precedence is phase, then dt, then re-entrancy; files: packages/ecs-schedule/src/reentrancy.ts, packages/ecs-schedule/tests/reentrancy.test.ts
  • S5 (SCH-117 [manual]): benchmark many steady-state run calls with no hooks and check for per-call allocation; files: packages/ecs-schedule/bench/run-alloc.bench.ts
  • S6 (changeset): add .changeset/w-030-ecs-schedule-onstart.md (patch, @workspace/ecs-schedule)

Log

  • 2026-11-01 created from the approved spec split of W-004 (Triage)
  • 2026-11-02 moved from Next to Now, state active (Triage)
  • 2026-11-02 S1 done, Reviewer APPROVED; files add src/state.ts, src/on-start.ts; SCH-061 tests included in on-start.test.ts
  • 2026-11-02 S2 note: onStartDone is set after the last OnStart system runs, must also count when the last system is skipped/disabled (SCH-113)
  • 2026-11-02 S2 narrowed to verifiable scope; fully-skipped and observable-flag cases of SCH-113 deferred to W-031, W-032, W-033 (Triage)
  • 2026-11-02 S2 done, Reviewer APPROVED after 1 fix round; it.todo cases 3 and 4 moved to W-031 S5a and W-032 S3a (Triage)
  • 2026-11-02 S3 done, Reviewer APPROVED after 1 fix round; adds src/run-errors.ts (runSystem); S4 must clear the executing marker on thenable throw
  • 2026-11-02 S4 done, Reviewer APPROVED; adds src/reentrancy.ts (per-schedule WeakSet marker, outside the state trait)
  • 2026-11-02 S6 note: stray .changeset/cool-news-smoke.md exists; rename to w-030-ecs-schedule-onstart.md with W-030 prefix
  • 2026-11-02 S5 benchmark added (bench/run-alloc.bench.ts, bench script); measured ~25 B/call from beginOnStart world.get; user decided to defer the fix to W-033
  • 2026-11-02 S5 done, Reviewer APPROVED (manual SCH-117 check: ~25 B/call, fix deferred to W-033 S5a)
  • 2026-11-02 S6 done, changeset .changeset/w-030-ecs-schedule-onstart.md added, stray cool-news-smoke.md removed
  • 2026-11-02 final Reviewer pass: ref coverage confirmed, changeset verified on disk; moved to review (Triage)
  • 2026-11-02 final Reviewer APPROVED, done (Triage)