Round 4 of adversarial review found that the previous commit's overlap
guard, keyed off state.gen.state, produced false refusals: Export, Save to
Media bin and Render Final all set state.gen to "running" for their own
entirely local work, so clicking H3 Combo Sweep's "Run sweep" button while
any of those was in progress got refused with a message borrowed from that
unrelated job ("Stopped at ...: Exporting 3 clips…") -- not silent, but
actively misleading about the real cause.
Switching the check to GenerateBridge's own run.state.phase (considered as
the obvious fix) would have reopened the very race round 3 closed: phase
stays "idle" for the whole check() network round trip, before run.start()
ever fires, so a second call could still slip through during that window.
Fixed with `_genRunActive`, a flag dedicated to exactly one question --
"does GenerateBridge have a run of this page's making in flight" -- set
synchronously the instant a call is accepted (before any await, so two
calls fired back to back still serialize) and cleared either by the
terminal-phase subscription (covers a run that actually started, click or
adopted) or by _generateRun's own `finally` (covers a run refused before
ever leaving "idle", which that subscription never sees).
Live-verified: a state.gen "running" left over from an unrelated job no
longer blocks a real generate() call, while two genuinely concurrent
generate() calls still correctly serialize (one proceeds, one is refused
with the accurate reason). 691/692 JS tests and 548/548 Python tests pass
(the one JS failure is the pre-existing, unrelated projects.test.js
import-race flake).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>