Uh oh!
There was an error while loading. Please reload this page.
fix(web): warn when dashboard is stuck reconnecting after a silent crash - #332
Merged
Jason Robert (jrob5756) merged 2 commits intoJul 21, 2026
Merged
Conversation
The dashboard's WebSocket client retries forever with exponential backoff on disconnect, but workflowStatus stays 'running' the whole time and the only feedback was a small spinner in the status bar. A silently crashed conductor process (e.g. --web-bg) was indistinguishable from a healthy long-running workflow until the page was refreshed. - workflow-store.ts: track wsDisconnectedSince (timestamp of the first drop from 'connected', preserved through the connecting/reconnecting backoff churn, cleared on reconnect) since wsStatus itself oscillates and can't be timed directly. Also capture bg_stderr_log/bg_stdout_log/ log_file from the root workflow_started event's `system` metadata (already emitted by the engine, previously unused by the frontend). - lib/reconnect.ts: pure, unit-tested isReconnectStuck() threshold check (60s default). - hooks/use-reconnect-warning.ts: ticking wrapper around the pure check. - components/layout/ReconnectWarningBanner.tsx: new banner telling the user the workflow may have silently failed, pointing at the best available log location. Wired into WorkflowGraph.tsx. Fixes#330 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… follow-up) Code review on PR #332 found that system.log_file was mislabeled everywhere (comments, AGENTS.md, and the banner's user-facing copy) as tied to the --log-file debug-output flag. It's actually the always-on structured JSONL event log (*.events.jsonl) written by EventLogSubscriber for every run, unrelated to --log-file. Corrected the wording in workflow-store.ts, ReconnectWarningBanner.tsx (including the visible "Check the event log" string), types/events.ts (dropped the inaccurate `| null` — the backend always sends a string, defaulting to ""), and AGENTS.md. Normalized systemLogFile's empty-string default to null with `||` instead of `??` to match the corrected type. Also added the two regression tests flagged by review: - a nested subworkflow_started event no longer clobbers the root workflow's captured log paths - wsDisconnectedSince stays null across connecting -> disconnected -> reconnecting when the socket has never once reached connected Updated the existing system-metadata test fixtures to use a realistic log_file value (an .events.jsonl path, and "" instead of null for the "unset" case) matching the real backend contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes#330.
The dashboard's WebSocket client (
use-websocket.ts) retries forever with exponential backoff on disconnect.workflowStatusstays'running'the whole time, and the only feedback is a small spinner in the status bar — so a silently crashed conductor process (e.g. a--web-bgprocess that dies) is indistinguishable from a healthy, still-running workflow, indefinitely, until the page is refreshed.Changes
workflow-store.ts: tracks a newwsDisconnectedSincetimestamp — set only on a fresh drop from'connected', preserved through the connecting/reconnecting backoff churn, and cleared once reconnected. This is necessary becausewsStatusitself oscillates between'reconnecting'/'connecting'on every retry cycle and can't be timed directly (a naive "reconnecting for N seconds" timer would reset every cycle). Also capturesbg_stderr_log/bg_stdout_log/log_filefrom the rootworkflow_startedevent'ssystemmetadata — this was already emitted by the engine but never read by the frontend.lib/reconnect.ts(new): pure, unit-testedisReconnectStuck()comparing elapsed disconnected time against a 60s threshold, gated onworkflowStatus === 'running'and notreplayMode.hooks/use-reconnect-warning.ts(new): ticks once a second (mirrorsStatusBar's existingidleSecondspattern) to re-evaluate the pure check.components/layout/ReconnectWarningBanner.tsx(new): amber banner warning the user the workflow may have silently crashed, pointing at the best available log location —bg_stderr_log/bg_stdout_log(--web-bgruns) →--log-filedebug log → generic hint to check the launching terminal. Only clears on an actual reconnect, not on a timer. Wired intoWorkflowGraph.tsxalongside the existing success/failure banners.AGENTS.md: documents the new behavior.Testing
npm run test(vitest): 48/48 passing, including newlib/reconnect.test.ts(table-driven threshold/gating tests) and new cases inworkflow-store.test.ts(timestamp tracking through backoff churn, system metadata capture).npm run build(tsc -b && vite build): typechecks clean, rebuilt and committed thestatic/bundle.🤖 Generated with GitHub Copilot CLI