fix(kernel/goals): close goal-run self-cleanup race + termination test coverage (follow-up #5840)#5848
Merged
Merged
Conversation
…ning; cover termination paths Follow-up to #5840. Self-cleanup race: the spawned loop's trailing runs.remove(goal_id) ran unconditionally on natural completion. If a concurrent start() had already replaced the run, that remove deleted the NEW run's handle, orphaning a live loop (unstoppable and invisible until it self-terminated at the iteration cap). Tag each run with a monotonic generation and self-clean via remove_if so a task only drops its own entry. Remove the dead pub is_running (no callers; routes use state()). Add run_loop termination tests for the paths #5840 shipped without coverage: operator stop flag, kernel shutdown signal, GOAL_BLOCKED, and the consecutive-rate-limit circuit breaker (start_paused to skip tick sleeps).
houko
added a commit
that referenced
this pull request
May 29, 2026
#5853) rustfmt flags several blocks merged via #5835, #5839, #5848, and #5849 (method chains and multi-line statements rustfmt collapses/reflows). main was therefore red on the Quality "Check formatting" step, which fails the Quality job on every open PR. Pure `cargo fmt` output — no logic change. Co-authored-by: Evan <[email protected]>
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 free
to 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.
Follow-up to #5840 (autonomous goal runner), addressing the three items from review.
1. Goal-run self-cleanup race (correctness)
The spawned loop's trailing
runs.remove(&goal_id)ran unconditionally whenrun_loopcompleted naturally. If a concurrentstart()for the same goal had already replaced the run (aborting the old task and inserting a new handle), the old task — finishing naturally at nearly the same instant — would remove the new run's handle, orphaning a live loop: unstoppable viastop(), invisible tostate(), and only self-terminating at the iteration cap.Fix: each run is tagged with a monotonic
generation(AtomicU64on the runner), and the task self-cleans viaruns.remove_if(&goal_id, |_, h| h.generation == generation)so it only ever drops its own entry. Abort was already safe (an aborted future never reaches the cleanup); this closes the natural-completion case.2. Remove dead
is_runningpub fn is_runninghad no callers (routes usestate()); removed.3. Termination test coverage
#5840 shipped tests only for
GOAL_DONEandmax_iterations. Addedrun_looptests for the paths that matter most for an unattended loop:GOAL_BLOCKED(ends asStopped, goal not marked completed)start_pausedskips the inter-tick sleeps, asserts it trips before the iteration cap)Verification
cargo clippy -p librefang-kernel --lib -- -D warnings— clean (dev container)cargo test -p librefang-kernel --lib goal_runner::tests— 7 passed (4 new + 3 existing)