refactor: retire robustness supervision and simplify benchmark watchdogs - #1547
Conversation
Snapshot the reviewed in-progress implementation before integrating upstream changes. Validation and dependency updates remain pending. Co-Authored-By: Claude <noreply@anthropic.com>
Preserve ENABLEMENT and Atom updates, upstream removals and schema migrations while retaining the benchmark-only watchdog and explicit recovery boundaries. Co-Authored-By: Claude <noreply@anthropic.com>
Keep launcher validation scoped to shipped assets and describe the remaining orchestration and critic roles accurately. Co-Authored-By: Claude <noreply@anthropic.com>
Describe empty turns and retained close-out verdict fields without implying that the retired agent still runs. Co-Authored-By: Claude <noreply@anthropic.com>
Keep one session bound across server boot, reuse, fallback and anchor measurements. Stop budget exhaustion without retrying it as a server failure. Co-Authored-By: Claude <noreply@anthropic.com>
Wait for cooperative physical cleanup before closing the database. Keep exactly-once completion with the execution after caller cancellation, and preserve ownership when cleanup is unconfirmed. Co-Authored-By: Claude <noreply@anthropic.com>
Replace timing guesses with execution completion and assert that unconfirmed GPU cleanup preserves leases and database access. Co-Authored-By: Claude <noreply@anthropic.com>
Preserve harness-aware detachment, persisted run environment and authoritative PID checks while keeping the retired monitor and explicit resume boundary. Co-Authored-By: Claude <noreply@anthropic.com>
| # Exercise both sides of the synchronous-to-async shutdown regression. | ||
| closing = dispatcher.close_db_after_executions() | ||
| if inspect.isawaitable(closing): | ||
| await closing |
| # Historical reports retain these terminal reasons after the producer is retired. | ||
| DIED_STOP_REASON = "supervisor_coordinator_died" | ||
| WEDGED_STOP_REASON = "supervisor_tick_stalled" | ||
| SUPERVISOR_RESTART_REASON = "supervisor_restart_requested" |
| on_complete.assert_awaited_once() | ||
| else: | ||
| with pytest.raises(ExecutionCleanupUnconfirmed): | ||
| await execution |
| task, gpu_lease=gpu, gpu_specialist_lease=RayLease(), on_complete=on_complete | ||
| ) | ||
| if confirmed: | ||
| await execution |
| assert (await dispatcher.tasks.get(task.task_id)).state == "running" | ||
| assert await dispatcher.locks.lane_holders() | ||
| finish.set() | ||
| await action |
…dence Keep unsettled rounds exclusive after their nominal lease time and test report alerts only when explicitly recorded. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Preserve bounds, evaluation directory, measurement admission and policy recording coverage without relying on retired timeout arguments. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Exercise real dispatch and completion paths with controlled workers, preserving bounded waits and verifying eventual cleanup instead of immediate handle removal. Co-Authored-By: Claude <noreply@anthropic.com>
Inspect the removed integrate timeout parameter without an invalid call and preserve explicit side effects in deadline and Ray lease tests. Co-Authored-By: Claude <noreply@anthropic.com>
| "* **RULE F3** — repeated `error_class='subprocess_nonzero'` on `baseline`" | ||
| " → stop retrying baseline; send observation 'blocked: …' and let Robustness" | ||
| " intervene. Explore variants may be re-proposed; read the failure log first.", | ||
| " → stop retrying baseline; send observation 'blocked: …'." | ||
| " Explore variants may be re-proposed; read the failure log first.", |
Co-Authored-By: Claude <noreply@anthropic.com>
ReviewChecked paths: The direction matches what was agreed: force unbuffered child output, count both the child's own pipes and the round's server logs as liveness, one silence window plus one hard cap, and drop age-only reclamation in favour of PID-proof reclamation. Blocking1. Warm-reuse rounds arm a 600 s silence gate that has no way to observe the reused server, so healthy work is killed with
In the same change the evidence available to that gate was narrowed:
Any resolved log that already existed at spawn and sits outside the round's own directory — i.e. the previous round's The trigger is the default configuration, not a constructed one: the conc-sweep and baseline-warmup paths both pass This is the defect the PR body already documents and reproduces ("A continuously growing warmup log outside the watched round, or buffered client-only output, triggered the silence sentinel Direction, matching the body's own conclusion: bind the activity source to the execution that actually owns the round — for a reuse round that is the server log the reused server is still writing, not only the new output directory — and do not arm the silence gate on a round whose activity source is not observable. No other blocking issues found. |
Review, part 2 — execution ownership / lease lifecycleFollow-up after reading the rest of the diff. The changes to 2. After a host reboot, or on a DB written before this change, leases and
So a lease row whose Either treat a non-matching 3.
finally:
...
released = release_resources is None or await release_resources()
if not released:
raise ExecutionCleanupUnconfirmed(...)
if lease is not None:
await self.locks.release(lease)An exception raised in When that happens the task's terminal row is already written, but 4.
Retaining ownership for a pending cleanup is the intent; retaining it for the whole session because something failed once is not the same thing. 5. Cancelled in-flight actions get no completion bookkeeping, and the branch that used to handle them is now unreachable.
This is not only a shutdown path: Findings 3, 4 and 5 compound: each one leaves state that only findings 2's reclamation could have cleared, and that reclamation no longer fires while the process is alive. |
Keep warm-reuse metadata separate from silence evidence so buffered Magpie clients are not reaped without a current ready marker. Preserve hard deadlines, session cancellation and existing telemetry. Co-Authored-By: Claude <noreply@anthropic.com>
|
Addressed the warm-reuse silence blocker in d330461 with a three-line production change, rather than introducing cross-layer log tracking. server_already_ready still supplies existing telemetry, but no longer arms silence. The existing incremental scanner must observe a ready marker in the current round before the 600-second gate applies. Old nested logs remain excluded, and hard deadlines, session deadlines and cancellation remain unchanged. The narrowed behavior was explicitly accepted: reuse with no current ready evidence is protected by hard/session/cancel bounds, not by the silence gate. This avoids the original Magpie buffered-output false-kill without modifying Magpie, adding a heartbeat, or scanning unrelated historical logs. It is not a claim that all internally healthy but externally silent workloads can be distinguished from hangs. Tests: 7 expected failures before the change became 17/17 passes; the related local selection passed 228 tests with POSIX cases left for Linux. Latest-head full CPU CI passed: all 12 Python 3.10/3.11 shards and both coverage gates succeeded. https://github.com/AMD-AGI/Hyperloom/actions/runs/35206770698 The implementation, regression tests and CHANGELOG are the only three changed files in this follow-up. 🤖 Generated with Claude Code |
Re-review against merge-base a4c1beaWhat this PR doesRetires the Robustness agent/RCA, the external Monitor and Hyperloom Supervisor, and the runtime Finding 1 is fixed
Findings 2-5 are unchanged and still blocking
2. Leases and running rows are unreclaimable after a reboot, or on a DB written before this change.
Reproduced against a PID that is certainly absent:
3.
The trigger is ordinary: 4.
Two consequences:
Retaining ownership for a pending cleanup is the intent; retaining it for the whole session because something failed once is not. 5. Cancelled in-flight actions get no completion bookkeeping, and the branch that handled them is unreachable.
This is not only a shutdown path: Findings 3, 4 and 5 compound: each leaves state that only finding 2's reclamation could clear, and that reclamation cannot fire while the process is alive. Also checked, no issue foundRemoval is clean: no non-test references remain to No blocking issues beyond the four above. |
Co-Authored-By: Claude <noreply@anthropic.com>
Keep exited-root cleanup unconfirmed and preserve the same specialist actor when stop does not acknowledge teardown. Cover detached descendants with isolated Linux CPU regressions. Co-Authored-By: Claude <noreply@anthropic.com>
Persist diagnostic outcomes when cleanup remains unconfirmed, unregister only completed execution callbacks, and reuse terminal inline results without duplicate effects. Cover cleanup evidence, cancellation and late worker acknowledgment. Co-Authored-By: Claude <noreply@anthropic.com>
Listen to the existing cancel scope while waiting for builds and retain outcomes and pending state until physical cleanup is confirmed. Co-Authored-By: Claude <noreply@anthropic.com>
Wire existing cancellation scopes through pending, running and done-grace paths. Confirm local tree teardown and allow one same-lease follow-up acknowledgment without a background retry mechanism or speculative resource release. Co-Authored-By: Claude <noreply@anthropic.com>
Inspect persisted ownership read-only before resume writes, report bounded diagnostics for unobservable holders, and consume the latest explicit cleanup outcome when reconciling open rounds. Co-Authored-By: Claude <noreply@anthropic.com>
Use one earliest sweep/session deadline across boot, retries and reuse. Preserve stop attribution and admit unknown-duration work only while budget remains, rather than charging the hard cap at admission. Co-Authored-By: Claude <noreply@anthropic.com>
…r state Keep stale locks when process identity cannot be observed, exclude known zombies, and restore the existing safe sweep at actual baseline startup. Co-Authored-By: Claude <noreply@anthropic.com>
Remove the retired per-variant timeout argument and CLI option, preserving the intentional unbounded overall manual sweep and production per-process caps. Co-Authored-By: Claude <noreply@anthropic.com>
Document sweep budgets, cooperative cancellation, durable diagnostic outcomes, explicit resume refusal, bounded same-lease confirmation and safe AITER cleanup. Align recorder field descriptions with measured admission costs. Co-Authored-By: Claude <noreply@anthropic.com>
|
|
||
| import pytest | ||
|
|
||
| import hyperloom.orchestrator.actions.executors._grid_runner # noqa: F401 |
| asyncio.get_running_loop().call_soon(finish.set) | ||
| await _close(dispatcher) | ||
| with pytest.raises(RuntimeError, match="completion failed"): | ||
| await caller |
Replace the stale hard-cap admission assumption with deterministic grid-refusal wiring and verify full terminal outcome evidence for retired recover tasks. Preserve existing resource and timeline assertions. Co-Authored-By: Claude <noreply@anthropic.com>
Preserve the late-acknowledgment and idempotency checks while ensuring all three close calls execute independently of Python assertion optimization. Co-Authored-By: Claude <noreply@anthropic.com>
Review follow-up and requirement reconciliationThe review fixes are now on this branch in scoped commits (each at most five files), with the two integration-contract regressions corrected in 7d8a1a2. That SHA passed all 12 Ubuntu Python 3.10/3.11 test shards and both strict coverage thresholds: https://github.com/AMD-AGI/Hyperloom/actions/runs/35308832684 . The final 2713b1e changes only three close calls inside one test so they execute outside assertions; its final CI has now PASSED: https://github.com/AMD-AGI/Hyperloom/actions/runs/35310187287 . All 12 final-head test shards, both strict coverage thresholds, and CodeQL succeeded; no checks remain pending or failed. Human review is still required and the PR remains unmerged. Findings 2–5
Additional verified fixes
Explicit limitsLocal specialist natural-exit handling does not claim to discover all detached orphans; unknown Ray/foreign-session cleanup still requires operator verification. Historical SBD readers, explicit recovery entrypoints, and KernelForge internal supervision remain intentionally supported. CPU/AST/mock evidence is not real GPU/Ray E2E evidence. Each automatically triggered GPU E2E for these pushes was explicitly approved for precise cancellation and confirmed cancelled before job steps ran. The implementation is frozen to this scope. This response does not request merging or changing the PR state. 🤖 Generated with Claude Code |
Re-review of the follow-up commits, against merge-base 2cc382aWhat changed since the last reviewUpstream main was merged (merge-base moved from Findings 3, 4 and 5 are resolved
Finding 1's fix survived the merge: Tests run locally, 364 passed: One blocking issue remainsA session DB written before this PR can never be resumed once this lands, and no supported interface can clear it.
Reproduced with a pre-upgrade shaped DB (one There is no way past it:
The diagnostic tells the operator to verify cleanup in the original execution environment. For The CHANGELOG does state "Legacy or foreign execution ownership ... No ownership is cleared", so this is disclosed rather than hidden. The problem is that the disclosed remedy cannot be carried out on this path, which leaves existing sessions unrecoverable. Either direction resolves it:
No other blocking issues found. |
Allow an operator to attest that an unattributed task and its workers have stopped, record diagnostic audit evidence, and atomically release only its execution/GPU ledger entries under the session lock. Preserve round ownership, refuse nonempty scopes and later work, and leave normal resume admission unchanged. Co-Authored-By: Claude <noreply@anthropic.com>
Resolution of the remaining legacy-resume blockerThe compatibility gap in the latest review was confirmed: a retained task with empty ownership scope could not pass resume, and manual verification alone had no supported way to update that ledger. Clean legacy databases were not affected. We did not adopt automatic PID fallback: an empty scope also occurs when scope discovery fails, and does not establish the original host, boot or PID namespace. Commit 0fd82c6 adds the explicitly approved, narrow operator acknowledgment path in exactly five files: inference_optimizer recover-session --session-dir PATH \
--confirm-stopped TASK_ID \
--confirmation-reason "Verified the entire task process tree and all remote workers/Ray actors have stopped"The operator must independently establish physical cleanup first. The command does not stop processes or actors. It acquires the real POSIX session lock and updates only the specified task in one SQLite transaction: record operator/time/reason/resource audit evidence, cancel unfinished work, and release its unattributed execution/GPU ledger rows. It preserves existing terminal state, old outcomes, other tasks, round records/fences and round leases. The ordinary reconciler consumes the new cleanup evidence; normal resume admission remains read-only and strict. Nonempty or mixed owner scopes remain rejected. Repeating a completed confirmation is a no-op, but later resources/execution evidence cannot be cleared using the old acknowledgment. There is no wildcard/clear-all, TTL fallback, automatic resume, report upload, or result promotion. Existing recover-session --force retains report-only semantics. This is an explicit exception to the previously selected no-manual-clear boundary, not an implicit weakening of automatic reclamation. Validation: new CLI regressions failed before implementation (9 failed/1 control passed), core regressions also failed first; final local resume/reconcile/session-lock selection passed 185 tests with 12 POSIX-dependent skips. Independent review, Ruff, formatting and Bandit passed. Latest-head Linux validation PASSED on 0fd82c6: https://github.com/AMD-AGI/Hyperloom/actions/runs/35332798196 . All 12 Python 3.10/3.11 test shards, both strict coverage thresholds, and CodeQL succeeded; no checks remain pending or failed. This includes the real POSIX lock/public-CLI path and the existing report recovery tests. Real GPU validation is not claimed; human review of this final fix remains required. The exact automatically triggered GPU E2E was cancelled with explicit approval before any job steps ran. No actual user session ledger or cluster resource was modified while implementing this fix. Temporary working documents stayed outside the repository and were not committed. 🤖 Generated with Claude Code |
Re-review of 0fd82c6The previous blocker is resolved
The guard rails read correctly too: both options are required together, they cannot be combined with One new blocking issueThe atom demo is the only place left telling the agent to poll, after this PR removed that instruction everywhere else.
That line is not new — it is present at merge-base
The result is a contradiction inside one numbered list: step 9 now says crashes are not automatically resumed and need explicit operator approval, while step 8 directly above still instructs a 300-second monitoring loop. An agent following the atom demo will poll or relaunch in the way the rest of this PR forbids. Deleting line 384, as the other four demos do, is the whole fix. No other issues found in the new commit. |
Align both progress reporting and launch requirements with request-driven persisted-state checks. Keep recurring checks opt-in through platform scheduling and preserve explicit resume approval. Co-Authored-By: Claude <noreply@anthropic.com>
|
Addressed the ATOM demo polling instruction in 2e45aad. Only examples/hyperloom-qwen3-14b-fp8-12h-atom/SKILL.md changed (+5/-2). The cited launch requirement now requests persisted-state inspection only on requested status checks. The same file also contained a second instruction at the top of its progress section requiring a summary at every 300-second check; that paragraph now uses the exact request-driven wording already present in the other demos, including platform scheduling only when recurring checks are requested and no background watchdog, blocking polling connection, or automatic resume. Verified before/after: both obsolete fixed-polling instructions were present before the change and are absent now; the replacement paragraph matches the existing non-ATOM demo, list numbering is unchanged, and all other file contents are unchanged. git diff --check passed. This is a one-file instruction correction, not a runtime or temporary-document change. The prior runtime head 0fd82c6 passed full Linux CPU validation. New-head validation PASSED on 2e45aad: https://github.com/AMD-AGI/Hyperloom/actions/runs/35344287663 . All 12 Python 3.10/3.11 test shards, both strict coverage thresholds and CodeQL succeeded, with no failed or pending checks. The exact automatic GPU E2E for this SHA was approved for cancellation; no manual GPU run was started. The PR remains unmerged. 🤖 Generated with Claude Code |
Scope
Hyperloom-only retirement of redundant robustness supervision and simplification of benchmark lifetime management. No Magpie or pod-tools source changes, dependency pin changes, new monitoring service, TTL fallback, or force-cleanup mechanism are included.
Changes
Review findings and retained limits
Legacy ownership recovery follow-up
Commit 0fd82c6 addresses the remaining review blocker in exactly five files. After independently verifying that the entire task process tree, remote workers and Ray actor have stopped, an operator can run
inference_optimizer recover-session --session-dir PATH --confirm-stopped TASK_ID --confirmation-reason TEXT.This explicit, single-task operation requires the real POSIX session lock, accepts only unattributed/empty-scope residual ownership, records an audited cancelled diagnostic outcome, and atomically releases only that task execution/GPU ledger rows. It preserves round/fence/round-lease rows and other tasks, rejects nonempty or mixed scopes and later work, and is idempotent without authorizing future occupancy. It never stops a worker, uploads a report, starts resume, or accepts prior success results. Existing report-only --force behavior is unchanged. Normal resume admission remains read-only and fail-closed.
Local combined resume/reconcile/lock regression: 185 passed, 12 POSIX skips. Earlier targeted CLI regression was 9 failed/1 passed before implementation; core regressions also failed before implementation. Ruff, formatting, Python 3.10 grammar and Bandit passed. Five existing report-recovery tests require Linux because Windows lacks fcntl; no shim or source skip was added to bypass them. No real user session ownership was modified.
ATOM demo instruction follow-up
Commit 2e45aad changes only examples/hyperloom-qwen3-14b-fp8-12h-atom/SKILL.md (+5/-2), removing both remaining mandatory 300-second polling instructions. Status checks now follow the same request-driven persisted-state policy as the other demos; periodic checks require an explicit request and platform scheduling. No runtime code or temporary documents changed.
Validation — current head 2e45aad
Prior verified runtime head 0fd82c6
Prior verified head 2713b1e
Verification checklist
🤖 Generated with Claude Code