Context
The useOrchestratorState hook uses a rAF-based buffered flush mechanism to batch rapid-fire orchestrator events into single React state updates. A race condition was discovered and fixed where post-flush event handlers would fall back to a stale initial closure, reverting already-loaded PVM states to pre-loadProgram defaults. This caused false divergence when enabling/disabling the second PVM.
The fix (adding a lastFlushedSnapshots ref) is in place, but the existing E2E tests cannot reliably trigger the race condition since both web workers typically respond within the same animation frame.
Proposed work
Add unit tests for useOrchestratorState that mock requestAnimationFrame and orchestrator events to deterministically test:
- Post-flush event preservation — after PVM A's
pvmStateChanged is flushed via rAF, PVM B's event should build on A's flushed state, not the stale initial
- Multiple flush cycles — accumulated state survives across multiple rAF flush boundaries
- Orchestrator switch cleanup — when the orchestrator changes,
lastFlushedSnapshots and pendingSnapshots are properly reset, preventing cross-orchestrator state leakage
- Concurrent PVM loading — simulating
loadProgram where workers respond at different times across rAF boundaries
Technical notes
- Vitest's
vi.useFakeTimers() doesn't mock rAF by default; may need explicit vi.stubGlobal('requestAnimationFrame', ...) or --environment jsdom
- The hook depends on
OrchestratorContext — tests will need a mock orchestrator (EventEmitter implementing OrchestratorEvents) wrapped in the provider
- Pre-existing issue: many unit tests fail with
document is not defined due to missing jsdom environment config — fixing that would be a prerequisite
Related
- Fix commit on branch
td-fix-pvm-disable-diverge
- File:
apps/web/src/hooks/useOrchestratorState.ts
Context
The
useOrchestratorStatehook uses a rAF-based buffered flush mechanism to batch rapid-fire orchestrator events into single React state updates. A race condition was discovered and fixed where post-flush event handlers would fall back to a staleinitialclosure, reverting already-loaded PVM states to pre-loadProgramdefaults. This caused false divergence when enabling/disabling the second PVM.The fix (adding a
lastFlushedSnapshotsref) is in place, but the existing E2E tests cannot reliably trigger the race condition since both web workers typically respond within the same animation frame.Proposed work
Add unit tests for
useOrchestratorStatethat mockrequestAnimationFrameand orchestrator events to deterministically test:pvmStateChangedis flushed via rAF, PVM B's event should build on A's flushed state, not the staleinitiallastFlushedSnapshotsandpendingSnapshotsare properly reset, preventing cross-orchestrator state leakageloadProgramwhere workers respond at different times across rAF boundariesTechnical notes
vi.useFakeTimers()doesn't mock rAF by default; may need explicitvi.stubGlobal('requestAnimationFrame', ...)or--environment jsdomOrchestratorContext— tests will need a mock orchestrator (EventEmitter implementingOrchestratorEvents) wrapped in the providerdocument is not defineddue to missing jsdom environment config — fixing that would be a prerequisiteRelated
td-fix-pvm-disable-divergeapps/web/src/hooks/useOrchestratorState.ts