fix(update): ignore successful receipt stop reason

This commit is contained in:
tachyon-r
2026-08-28 20:46:12 -04:00
committed by kshitij
parent 10e8756cf4
commit cd27df3c2e
2 changed files with 81 additions and 7 deletions
+20 -7
View File
@@ -78,14 +78,27 @@ def _current_checkout_sha() -> str | None:
def _receipt_looks_unfinished(receipt: dict) -> bool:
"""True when *receipt* is from an update that did not finish cleanly."""
"""True when *receipt* is from an update that did not finish cleanly.
``stop_reason`` records *how* the command boundary closed the receipt
(``completed at command boundary``, ``sys.exit(0)``, even KeyboardInterrupt
on an otherwise successful run). A truthy stop_reason must not make a
successful receipt look unfinished, or the next ``hermes update`` retriggers
``fleet_restart_pending`` from pre-pull plan SHAs.
"""
exit_code = receipt.get("exit_code")
outcome = receipt.get("outcome")
if exit_code not in (0, None):
return True
if outcome in ("failed", "partial", "running"):
return True
gateway_restart = receipt.get("gateway_restart")
return bool(
receipt.get("stop_reason")
or receipt.get("exit_code") not in (0, None)
or receipt.get("outcome") in ("failed", "partial", "running")
or (isinstance(gateway_restart, dict) and gateway_restart.get("incomplete"))
)
if isinstance(gateway_restart, dict) and gateway_restart.get("incomplete"):
return True
stop_reason = receipt.get("stop_reason")
if stop_reason and outcome != "success" and exit_code != 0:
return True
return False
def _receipt_reports_stale_runtime(expected_sha: str | None = None) -> bool:
@@ -254,6 +254,67 @@ def test_successful_receipt_with_pre_update_plan_shas_does_not_retrigger(
assert update_cmd._pending_fleet_restart_needed() is False
def test_successful_command_boundary_receipt_without_fleet_does_not_retrigger(
monkeypatch,
):
"""A normal command-boundary stop is not an interrupted update."""
disk_sha = "n" * 40
old_sha = "o" * 40
monkeypatch.setattr(update_cmd, "_current_checkout_sha", lambda: disk_sha)
monkeypatch.setattr(update_cmd_fleet, "_current_checkout_sha", lambda: disk_sha)
receipt_dir = get_hermes_home() / "logs" / "update_receipts"
receipt_dir.mkdir(parents=True)
(receipt_dir / "latest.json").write_text(
json.dumps(
{
"exit_code": 0,
"outcome": "success",
"stop_reason": "completed at command boundary",
"plan": {
"expected_sha": old_sha,
"runtimes": [
{
"kind": "gateway",
"profile": "default",
"pid": 1,
"code_sha": old_sha,
}
],
},
"fleet": [],
"gateway_restart": {},
}
),
encoding="utf-8",
)
assert update_cmd._pending_fleet_restart_needed() is False
@pytest.mark.parametrize(
"receipt",
[
{"outcome": "success", "exit_code": 0, "stop_reason": "sys.exit(0)"},
{"outcome": "success", "stop_reason": "KeyboardInterrupt: "},
{"exit_code": 0, "stop_reason": "sys.exit(0)"},
],
)
def test_successful_non_boundary_stop_reasons_are_finished(receipt):
"""Successful sys.exit(0)/KeyboardInterrupt must not look unfinished."""
assert update_cmd._receipt_looks_unfinished(receipt) is False
def test_failed_interrupt_stop_reason_is_unfinished():
assert update_cmd._receipt_looks_unfinished(
{
"outcome": "failed",
"exit_code": 1,
"stop_reason": "KeyboardInterrupt: ",
}
) is True
def test_stale_fleet_matrix_on_latest_receipt_is_pending(monkeypatch):
disk_sha = "n" * 40
monkeypatch.setattr(update_cmd, "_current_checkout_sha", lambda: disk_sha)