Skip to content

feat: add a wall-clock time budget per parent mutation session - #888

Merged
devdanzin merged 1 commit into
mainfrom
feat/parent-session-time-budget
Jul 2, 2026
Merged

devdanzin merged 1 commit into
mainfrom
feat/parent-session-time-budget

Conversation

@devdanzin

Copy link
Copy Markdown
Owner

Summary

A --session-fuzz run got stuck ~1 hour in a single breadth session on one large (167-statement), timeout-rich parent (324.py). With --timeout=120, each timed-out child costs up to 120s and a mutation runs up to ~8 of them, so the session ran for over an hour without a find.

Why the existing countermeasures don't help:

  • record_timeout tracks a consecutive streak and only writes a consecutive_timeouts health event at threshold 5 — nothing aborts. And the streak resets on any non-timeout (timeouts are interspersed with fast score 0.00 children), so it rarely even fires.
  • Timeouts never count toward sterility (a timed-out child returns early, before analyze_run/the cold-streak logic), so the parent is never retired and keeps being re-selected.
  • A breadth session only ends on a find or after max_mutations — no time bound.

Fix: a per-parent-session wall-clock budget = max(PARENT_SESSION_TIME_BUDGET_MULTIPLIER (5) × execution_timeout, 300s), checked between mutations (abandon the session) and between repetitions (skip remaining runs, so one timeout-heavy mutation can't overrun the budget). On budget-hit without a find, the parent is retired (is_sterile) so the scheduler stops picking a timeout sink; a parent_time_budget_exceeded health event is emitted. With --timeout=120 the budget is 600s, bounding the pathological case from 60+ min to ~10 min.

Test plan

  • test_abandons_and_retires_parent_over_time_budget — session abandons + retires the parent + fires the health event when the deadline is passed.
  • test_skips_runs_past_session_deadline — the run loop stops starting repetitions past the deadline.
  • Full suite 2174 passed; mypy lafleur clean; ruff clean.

Closes #887

🤖 Generated with Claude Code

A timeout-rich parent could monopolize the fuzzer for hours. With --timeout=120,
a large (167-statement) parent whose children mostly time out ran a single
breadth session for over an hour without a find. The existing timeout
countermeasures only logged: record_timeout tracks a CONSECUTIVE streak and
writes a consecutive_timeouts health event at threshold 5, but nothing aborts,
and the streak resets on any non-timeout (so it rarely fired). Timeouts also
never count toward sterility (a timed-out child returns early, before analyze_run
and the cold-streak logic), so the parent was never retired and kept being
re-selected. A breadth session has no time bound.

Add a per-session wall-clock budget = max(PARENT_SESSION_TIME_BUDGET_MULTIPLIER *
execution_timeout, PARENT_SESSION_TIME_BUDGET_FLOOR_SECONDS), checked between
mutations (abandon the session) and between repetitions (skip remaining runs).
When the budget is hit without a find the parent is retired (is_sterile) so the
scheduler stops picking a timeout sink, and a parent_time_budget_exceeded health
event is emitted.

Closes #887

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@devdanzin
devdanzin merged commit bf3d746 into main Jul 2, 2026
2 checks passed
@devdanzin
devdanzin deleted the feat/parent-session-time-budget branch July 2, 2026 14:52
Sign up for free to 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.

Timeout-rich parent can monopolize the fuzzer for hours: countermeasures only log, no time budget

1 participant