[GH-ISSUE #5429] bug(hopper): startup cancellation replaces an observed launcher exit #3290

Closed
opened 2026-10-31 00:38:50 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @XiaoBinGan on GitHub (Oct 20, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5429

Before submitting

  • I searched open and closed issues and related PRs. #340 covers Hopper cancellation, timeout, mutation readback, and shutdown verification as a broader check; this report is a narrower, reproducible defect in the startup outcome projection. #4227 tracks the lifecycle audit; #5393, #5388, #5385 and #5292 are the same precedence family in other owners.
  • This report contains no credentials, private target samples, or sensitive values.

Area

Bugs

Observed behavior

HopperClient.start() reports HopperCancelledError when the caller aborts after the owned launcher process has already exited with a failing status. The otherwise identical no-abort control reports the physical startup failure (HopperProcessError, exitCode: 3, stage: "launch").

Reproduction

  1. Build a HopperClient with a BridgeLauncher whose launch spawns process.execPath -e "process.exit(3)" and returns { ownsProcessLifetime: true, providerLifetime: "launcher-process", shutdownMode: "bridge-request" }.
  2. Register an exit listener on that child that schedules controller.abort(reason) with setImmediate, so the supervisor observes the exit before the abort.
  3. Call client.start(controller.signal).

Observed: HopperCancelledError.
Control without the abort: HopperProcessError with exitCode: 3 and stage: "launch".

Expected behavior

A launcher exit the owned process already holds stays primary when the interruption arrives afterwards; a cancellation observed before any exit stays a cancellation. Diagnostics, launcherFailure, provider state and cleanup ownership keep their behaviour.

Impact and scope

Startup failures from the launcher become indistinguishable from caller cancellation, so an operator who aborts a slow launch loses the launcher's exit status and diagnostic. The projection sites are #connect in src/hopper/HopperClient.ts, which converts an interrupted wait into #startupInterruption without consulting the launch the owner already holds.

Originally created by @XiaoBinGan on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5429 ### Before submitting - [x] I searched open and closed issues and related PRs. #340 covers Hopper cancellation, timeout, mutation readback, and shutdown verification as a broader check; this report is a narrower, reproducible defect in the startup outcome projection. #4227 tracks the lifecycle audit; #5393, #5388, #5385 and #5292 are the same precedence family in other owners. - [x] This report contains no credentials, private target samples, or sensitive values. ### Area Bugs ### Observed behavior `HopperClient.start()` reports `HopperCancelledError` when the caller aborts after the owned launcher process has already exited with a failing status. The otherwise identical no-abort control reports the physical startup failure (`HopperProcessError`, `exitCode: 3`, `stage: "launch"`). ### Reproduction 1. Build a `HopperClient` with a `BridgeLauncher` whose launch spawns `process.execPath -e "process.exit(3)"` and returns `{ ownsProcessLifetime: true, providerLifetime: "launcher-process", shutdownMode: "bridge-request" }`. 2. Register an `exit` listener on that child that schedules `controller.abort(reason)` with `setImmediate`, so the supervisor observes the exit before the abort. 3. Call `client.start(controller.signal)`. Observed: `HopperCancelledError`. Control without the abort: `HopperProcessError` with `exitCode: 3` and `stage: "launch"`. ### Expected behavior A launcher exit the owned process already holds stays primary when the interruption arrives afterwards; a cancellation observed before any exit stays a cancellation. Diagnostics, `launcherFailure`, provider state and cleanup ownership keep their behaviour. ### Impact and scope Startup failures from the launcher become indistinguishable from caller cancellation, so an operator who aborts a slow launch loses the launcher's exit status and diagnostic. The projection sites are `#connect` in `src/hopper/HopperClient.ts`, which converts an interrupted wait into `#startupInterruption` without consulting the launch the owner already holds.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3290
No description provided.