Skip to content

fix(fleet): don't kill a healthy --web-bg run on a run-record write failure - #440

Merged
Jason Robert (jrob5756) merged 3 commits into
mainfrom
fix/435-fix-run-record-launch-gate
Aug 14, 2026
Merged

fix(fleet): don't kill a healthy --web-bg run on a run-record write failure#440
Jason Robert (jrob5756) merged 3 commits into
mainfrom
fix/435-fix-run-record-launch-gate

Conversation

@jrob5756

Copy link
Copy Markdown
Collaborator

Summary

  • The launch health gate (Fleet Manager D2) used to terminate a --web-bg/resume --web-bg child and fail the launch if it couldn't confirm the child's run record within the poll timeout, even when the child was alive and its dashboard was reachable — treating a bookkeeping failure as a workflow failure.
  • Downgrades this to a warning: BackgroundLaunch.run_record_written=False, surfaced via a note pointing at the captured stderr log and a Fleet Manager TUI notification. Only a child that is actually dead, or whose dashboard has gone unreachable, still fails the launch.
  • Introduces conductor.run_id as the single definition of the run_id format. Previously fleet/records.py enforced a broad path-safe pattern while engine/event_log.py independently enforced a narrower hex-only pattern and lowercased its input — a resumed --web-bg run whose checkpoint run_id contained uppercase characters could be silently folded to a different value, causing the parent's launch-gate poll to look for a key the child never wrote and kill the resumed run 15 seconds after a successful start.

Closes#435

Test plan

  • uv run pytest tests/test_cli/test_bg_runner.py tests/test_engine/test_event_log.py tests/test_fleet/

Jason Robertand others added 2 commits August 14, 2026 12:50
…ailure
The launch health gate (Fleet Manager D2) polled for the child's run
record and terminated the child if it wasn't found within the timeout,
even when the child was alive and its dashboard was reachable. This
downgrades that to a warning (BackgroundLaunch.run_record_written=False)
surfaced via a note pointing at the captured stderr log and a Fleet
Manager TUI notification; only an actually-dead child, or one whose
dashboard has gone unreachable, still fails the launch.
Also introduces conductor.run_id as the single definition of the run_id
format, replacing divergent patterns in fleet/records.py and
engine/event_log.py (the latter lowercased its input), which could cause
a resumed --web-bg run's launch-gate poll to look for the wrong key and
kill a successful resume.
Closes#435
…gate
- fleet/records.py: fix _LOG_STEM_TIMESTAMP_RE regression -- the widened
run-id charset can span hyphens, so a plain re.search anchored on the
FIRST timestamp-shaped segment in a log's filename instead of the last
one whenever a workflow name itself contained a YYYYMMDD-HHMMSS-shaped
segment. Anchor with a greedy `.*` prefix + `.match()` (mirroring
fleet/history.py's parser) and correct the comment that asserted the
opposite of the truth. Adds a regression test.
- cli/bg_runner.py: add stage-two coverage for `run_record_written`
through the STARTED / TIMED_OUT / CHILD_EXITED probes (previously only
exercised via the `start_timeout == 0` early return), closing the gap
where the STARTED arm could be hard-coded True with the full suite
green.
- cli/app.py / fleet/tui/screens/new_run.py: add coverage for the resume
--web-bg "could not register itself for discovery" notice and the New
Run screen's warning notification, both previously untested (the
latter was structurally unreachable behind a `Mock()` with an
auto-truthy `.run_record_written`).
- Recommendations applied: re-read the run record once more after the
1s reachability re-probe succeeds before declaring the discovery
record missing; drop the redundant stderr tail from the downgrade
warning; restore the missing Raises: bullet and refresh the stale
"two-stage"/PID-file module docstring in bg_runner.py; tighten
run_id.RUN_ID_PATTERN_SOURCE's upper bound from 200 to 64 chars (a
200-char CONDUCTOR_RUN_ID could blow past a filesystem's per-component
name limit and abort the workflow instead of falling back to a fresh
id); anchor fleet/retention.py's companion-log glob so one run's id
being a hyphen-boundary suffix of another's can't sweep up a foreign
run's captured logs; rename run_id.RUN_ID_RE to the internal
_RUN_ID_RE and drop its redundant \A...\Z anchors (fullmatch already
anchors); fix a pre-existing environment-dependent test flake
(test_filenames_unique_for_simultaneous_starts assumed no ambient
CONDUCTOR_RUN_ID).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756
Jason Robert (jrob5756) marked this pull request as ready for review August 14, 2026 17:27
@jrob5756
Jason Robert (jrob5756) merged commit d8ed6b2 into mainAug 14, 2026
11 checks passed
@jrob5756
Jason Robert (jrob5756) deleted the fix/435-fix-run-record-launch-gate branch August 14, 2026 17:55
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fleet: the --web-bg launch gate can kill a healthy child, and the run_id contract is defined twice

1 participant

@jrob5756