Skip to content

flake: RSC runtime generation activation can wedge or go permanently stale after a repair rebuild (Node 24 CI, 2x on 2026-08-29) #38

Description

@ScriptedAlchemy

Two Verify (Node 24) failures on 2026-08-29 share one signature: after a source edit, the fixture compiler finishes a successful rebuild, but the Workbench page never observes a new data-runtime-generation — no runtime.generation.activated (and no .failed) ever reaches the client.

Occurrences

  1. Main, merge of fix: stop watched-file write races in e2e suites and host message drops in the Runtime App relay #35 (cf02915d)run 33266629560: runtime-playground-capture.test.ts timed out at 600s with zero output (the capture child had no overall deadline; opaque). Node 22.19/26 passed.
  2. PR test: fail the runtime capture fast with phase attribution instead of an opaque timeout #37 branch (same tree + capture watchdog)run 33271302280: runtime-playground-hmr.e2e.test.ts > activates an edited RSC generation and replays the selected hook without replacing the document failed at expect.poll(generation).not.toBe(failedGeneration) after 120s. Log timeline:
    • 19:43:51 broken write compiles, fails (expected; page shows failure, last-good retained)
    • 19:43:53 repair write lands (staged rename verified on disk by the test)
    • 19:43:54 ready built in 0.44s (widget) / ready built in 0.95s (rsc) — rebuild succeeded
    • next 119s: no second compile cycle, no activated/failed event, page generation never changes

Analysis

The wedge is inside the activation pipeline in examples/rsc-agent-runtime/src/dev/rsbuild-runtime-session.ts (#activate), between the compiler's after-hook and the runtime.generation.activated emit. Candidate mechanisms, in suspicion order:

  1. Hang in materializeRuntimeGeneration or #mcpRegistry.prepareActivationReconcile — neither is bounded; a wedged MCP server restart on a contended 2-core runner emits nothing, and the page has no recovery trigger. This also explains occurrence 1: fixture.close() awaits #providerTail, so a wedged activation can hang cleanup, which the capture script (pre-test: fail the runtime capture fast with phase attribution instead of an opaque timeout #37) surfaced as a silent 600s timeout.
  2. Spurious permanent supersession#activationGuard.check() fails if any live attempt with a higher sequence exists in the window between guard.wait() returning and check() running. A no-op attempt (duplicate watch event compiling identical content) settles without raising the cohort revision and without producing its own candidate; if it also classifies cohortChanged=false against the plugin's capturedCohort before the superseded activation's failure callback resets it (rsbuild.config.ts line ~150), nothing ever activates and there is no retry. (Less likely for occurrence 2: the log shows no second compile cycle.)

Suggested next steps

  • Bound materializeRuntimeGeneration + prepareActivationReconcile (or make them #closed-aware) and emit runtime.generation.failed on expiry so the page recovers via its existing bootstrap path.
  • Make the plugin's same-revision dedup (capturedCohort) confirmed-only (set on activated outcome) so a no-op rebuild racing a failed activation re-captures instead of dropping the cohort permanently.
  • test: fail the runtime capture fast with phase attribution instead of an opaque timeout #37's capture watchdog will attribute the wedge phase on the next capture-test occurrence; consider a burn-in of runtime-playground-hmr.e2e.test.ts on Node 24 to reproduce.

Both occurrences were Node 24 only; the same commits passed Node 22.19 and Node 26, and the full parallel integration pool passes locally on a many-core machine — consistent with a contention-sensitive race, not a Node 24 incompatibility.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions