Summary
On Windows, an ESP32-C6 full-flash deploy reached the external esptool subprocess and then caused the fbuild daemon to disappear without returning actionable diagnostics to the client. The board and COM port remained healthy, and the next fbuild daemon status started a new daemon PID.
This blocks FastLED hardware-in-the-loop validation because a failed flash is indistinguishable at the caller from a dropped daemon connection, and the device must be retried without knowing whether the child exited, timed out, or triggered a daemon crash.
Reproduction
Environment:
- Windows, fbuild 2.5.18
- ESP32-C6 on COM9 (USB VID:PID
303A:1001)
- FastLED AutoResearch deploy command:
bash autoresearch esp32c6 --parlio --lanes 1 --strip-sizes 100 --tight-timing --upload-port COM9 --timeout 120s --skip-lint
Observed daemon log sequence:
build completed in 328.7s
Flash: 2,469,437 / 4,194,304 bytes
RAM: 73,936 / 327,680 bytes
verified device differs
flashing .../firmware.bin to COM9 via esptool (esp32c6)
The log ends immediately after the final line. The client eventually exited 1 with no stdout explaining the flash result. COM9 remained present and healthy. A subsequent fbuild daemon status started a new daemon (PID 54588), confirming that the daemon handling the deploy was no longer alive.
Expected behavior
An external flash-tool exit, timeout, cancellation, or I/O failure must remain contained to the deploy operation:
- the daemon stays alive;
/api/deploy returns a structured non-success response;
- the response and daemon log preserve the child exit status and bounded stdout/stderr, or clearly identify a timeout/cancellation;
- the serial port is released so a retry can proceed.
Current code path
On current main (fdd824131fd1756c2d960ee3397b251ad1f12707):
crates/fbuild-deploy/src/esp32/deployer.rs logs flashing ... via esptool and calls run_command(..., Some(Duration::from_secs(120))) for a full flash.
crates/fbuild-core/src/subprocess.rs starts a contained Tokio child and wait_and_capture should convert completion or timeout into a ToolOutput/FbuildError.
crates/fbuild-cli/src/daemon_client.rs gives deploy a 30-minute HTTP budget.
crates/fbuild-daemon/src/handlers/operations/deploy.rs owns the daemon-side deploy operation.
The observed daemon disappearance violates that containment contract. The cutoff does not establish whether the initiating fault is subprocess/job containment, a panic, process termination, or daemon supervision; preserving the terminal child/handler diagnostic is part of the required fix.
Related issues (not duplicates)
Acceptance criteria
- Add a focused RED integration test that drives the external ESP flash child through abnormal exit/termination (and, if needed, handler cancellation) and reproduces the dropped response or daemon death.
- Make the test GREEN: the daemon remains alive and accepts a follow-up status/request.
/api/deploy returns a structured actionable failure containing the child exit status plus bounded stdout/stderr, or an explicit 120-second timeout/cancellation reason.
- The child/process-tree and COM port are released after every failure path.
- Add or extend an ignored ESP32-C6 HIL full-flash test. On COM9, record the daemon PID before and after the exact deploy; it must remain stable, and success/failure must be explicit at the client.
- Verify the original FastLED AutoResearch command can retry over the same USB port without replugging the board.
Decisions
- Repository: FastLED/fbuild, because the daemon lifecycle and deploy response fail below FastLED's AutoResearch wrapper.
- Priority:
priority: p1; this blocks reliable HIL work but has a reproducible retry path and no evidence of data loss.
- Scope: external ESP esptool full-flash containment and daemon diagnostics. AutoResearch stack sizing is separate.
- Deploy path: retain the sanctioned fbuild deploy pipeline; do not work around it with raw esptool invocations.
- Proof standard: require both a deterministic integration regression and a real C6 full-flash run, because the current unit/HIL coverage verifies C6 images but does not exercise daemon survival across full flash.
Open diagnostic question
What terminates the daemon after the child starts: Windows contained-process/job behavior, a panic or abort in the deploy task, daemon supervision/restart, or another process-level failure? The fix should capture enough terminal state to answer this on the first failing run.
Summary
On Windows, an ESP32-C6 full-flash deploy reached the external
esptoolsubprocess and then caused the fbuild daemon to disappear without returning actionable diagnostics to the client. The board and COM port remained healthy, and the nextfbuild daemon statusstarted a new daemon PID.This blocks FastLED hardware-in-the-loop validation because a failed flash is indistinguishable at the caller from a dropped daemon connection, and the device must be retried without knowing whether the child exited, timed out, or triggered a daemon crash.
Reproduction
Environment:
303A:1001)Observed daemon log sequence:
The log ends immediately after the final line. The client eventually exited 1 with no stdout explaining the flash result. COM9 remained present and healthy. A subsequent
fbuild daemon statusstarted a new daemon (PID 54588), confirming that the daemon handling the deploy was no longer alive.Expected behavior
An external flash-tool exit, timeout, cancellation, or I/O failure must remain contained to the deploy operation:
/api/deployreturns a structured non-success response;Current code path
On current
main(fdd824131fd1756c2d960ee3397b251ad1f12707):crates/fbuild-deploy/src/esp32/deployer.rslogsflashing ... via esptooland callsrun_command(..., Some(Duration::from_secs(120)))for a full flash.crates/fbuild-core/src/subprocess.rsstarts a contained Tokio child andwait_and_captureshould convert completion or timeout into aToolOutput/FbuildError.crates/fbuild-cli/src/daemon_client.rsgives deploy a 30-minute HTTP budget.crates/fbuild-daemon/src/handlers/operations/deploy.rsowns the daemon-side deploy operation.The observed daemon disappearance violates that containment contract. The cutoff does not establish whether the initiating fault is subprocess/job containment, a panic, process termination, or daemon supervision; preserving the terminal child/handler diagnostic is part of the required fix.
Related issues (not duplicates)
Acceptance criteria
/api/deployreturns a structured actionable failure containing the child exit status plus bounded stdout/stderr, or an explicit 120-second timeout/cancellation reason.Decisions
priority: p1; this blocks reliable HIL work but has a reproducible retry path and no evidence of data loss.Open diagnostic question
What terminates the daemon after the child starts: Windows contained-process/job behavior, a panic or abort in the deploy task, daemon supervision/restart, or another process-level failure? The fix should capture enough terminal state to answer this on the first failing run.