From 8949dc8328e9b86a0cf1f80bcf3a976c67c4837a Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Wed, 29 Jul 2026 18:19:51 +0200 Subject: [PATCH] fix(native-eval): rebootstrap replacement leases --- scripts/native_eval/fleet.py | 4 +++- tests/test_native_eval_fleet.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/scripts/native_eval/fleet.py b/scripts/native_eval/fleet.py index 433d775..d35abb6 100644 --- a/scripts/native_eval/fleet.py +++ b/scripts/native_eval/fleet.py @@ -563,7 +563,8 @@ def _execute_entry(self, run_label: str) -> bool: if remote_state == "missing": if self._local_artifacts(run.run_label): raise FleetError("local artifacts exist but the remote run state is missing") - if not entry.get("bootstrapped_at_utc"): + current = self._store.get(run.run_label) + if current.get("bootstrapped_lease_id") != lease.lease_id: self._hydrate_lease(lease) self._dispatch(lease, run) elif remote_state == "stale": @@ -894,6 +895,7 @@ def _hydrate_lease(self, lease: Lease) -> None: self._run_label_for_lease(lease.lease_id), status="ready", bootstrapped_at_utc=utc_now(), + bootstrapped_lease_id=lease.lease_id, ) def _probe_remote(self, lease: Lease, run_label: str) -> str: diff --git a/tests/test_native_eval_fleet.py b/tests/test_native_eval_fleet.py index b9855ff..cac6a63 100644 --- a/tests/test_native_eval_fleet.py +++ b/tests/test_native_eval_fleet.py @@ -1273,6 +1273,35 @@ def test_recovery_required_resumes_existing_remote_run(tmp_path: Path) -> None: assert final["status"] == "completed" +def test_recovery_rehydrates_replacement_lease_despite_old_bootstrap_timestamp( + tmp_path: Path, +) -> None: + label = "openclaw-gpt55-full-2-r1-20260727" + run = _planned(_run_spec(label)) + run.update( + { + "status": "recovery_required", + "requested_lease_slug": "replacement", + "bootstrapped_at_utc": "2026-07-27T00:00:00Z", + } + ) + run_index = tmp_path / "manifests" / "run_index.json" + _write_index(run_index, [run]) + config = _config(tmp_path, run_index) + executor = FakeExecutor(config.local_root, expected_counts={label: 2}) + + assert FleetController(config, executor=executor).run() == 0 + + final = json.loads(run_index.read_text(encoding="utf-8"))["runs"][0] + assert final["status"] == "completed" + assert final["bootstrapped_lease_id"] == "cbx_1" + assert any( + command and command[0] == "ssh" and "fleet-hydrate" in " ".join(command) + for command in executor.commands + ) + assert executor.dispatches == [label] + + def test_recovery_infers_success_from_verified_full_archive_and_done_log( tmp_path: Path, ) -> None: