From 2812d6121ba54605bfd71e435527b0c48a6735b7 Mon Sep 17 00:00:00 2001 From: chelsealong Date: Mon, 24 Aug 2026 16:18:13 +0000 Subject: [PATCH] fix(cli): note pre_restart_pids' per-PID data model gap, pin the matching-start_time path Addresses the two follow-up notes from review: document that pre_restart_pids is a bare PID set (not (pid, start_time) pairs), so a recycled PID from one gateway landing in another's stale record could still mislabel it as down; and add a companion test asserting a matching start_time still yields the live/current row. --- hermes_cli/update_receipt.py | 6 ++++++ .../test_fleet_matrix_down_state.py | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/hermes_cli/update_receipt.py b/hermes_cli/update_receipt.py index 9a0f85f602..7f5a1dd967 100644 --- a/hermes_cli/update_receipt.py +++ b/hermes_cli/update_receipt.py @@ -391,6 +391,12 @@ def collect_fleet_versions( # stop, startup failure, stale record from a long-dead # gateway) keeps the historical no-row behavior so the # feature's rollout can't false-positive. + # + # ``_pre_restart`` is a bare set of PIDs, not (pid, start_time) + # pairs, so a recycled PID from gateway A landing in B's stale + # record could still mislabel B as down if A's PID happened to + # be in the pre-restart snapshot — inherent to the snapshot's + # data model, not something this guard can fix on its own. gw_state = record.get("gateway_state") if ( pid in _pre_restart diff --git a/tests/hermes_cli/test_fleet_matrix_down_state.py b/tests/hermes_cli/test_fleet_matrix_down_state.py index 8c403e46bf..0519e30c25 100644 --- a/tests/hermes_cli/test_fleet_matrix_down_state.py +++ b/tests/hermes_cli/test_fleet_matrix_down_state.py @@ -95,6 +95,27 @@ def test_recycled_pid_is_not_reported_stale(monkeypatch, tmp_path): assert fleet[0]["state"] == "down" +def test_matching_start_time_is_still_live(monkeypatch, tmp_path): + """A record whose start_time matches the live process is not recycled.""" + from gateway.status import _get_process_start_time + + pid = os.getpid() + _setup( + monkeypatch, + tmp_path, + { + "pid": pid, + "start_time": _get_process_start_time(pid), + "gateway_state": "running", + "code_sha": "HEADSHA", + "kind": "hermes-gateway", + }, + ) + fleet = ur.collect_fleet_versions(pre_restart_pids=[pid]) + assert len(fleet) == 1 + assert fleet[0]["state"] == "current" + + def test_live_gateway_rows_unchanged(monkeypatch, tmp_path): """The live-pid path is untouched by the down-state addition.""" _setup(