Skip to content
Merged
40 changes: 24 additions & 16 deletions hermes_cli/update_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -9656,21 +9656,36 @@ def _fleet_probe_expected_runtimes(
cannot prove nothing was running; same contract as
``_restart_phase_failure_is_incomplete``, #78574).
* the pre-update plan inventoried ≥1 runtime.
* the Windows pause/resume token carries paused ``profiles`` or
``unmapped`` entries — ``_pause_windows_gateways_for_update`` /
``_resume_windows_gateways_after_update`` populate NEITHER
``restarted_services`` NOR ``killed_pids``, which is exactly why the
original ``(restarted_services or killed_pids)`` guard never fires on
Windows.

The same condition gates the 2.0s settle sleep: a freshly resumed Windows
gateway needs the settle window to rewrite ``gateway_state.json`` just
like a systemd-restarted one.
``windows_resume_token`` is deliberately EXCLUDED (#93406 residual). The
pause/resume token is bookkeeping for ``_pause_windows_gateways_for_update``
/ ``_resume_windows_gateways_after_update`` — it is not a runtime
inventory, and its entries do not correspond to rows
``collect_fleet_versions()`` is capable of returning:

* ``unmapped`` entries (Scheduled-Task gateways) never publish
``gateway_state.json`` rows at all, and
* a paused profile gateway is resumed as a DETACHED relaunch that may not
republish its identity within the probe window.

Counting the token therefore made ``_fleet_rows_expected`` True on every
Windows update that had paused a gateway, the probe's polling window ran
out with zero rows on a perfectly healthy update, and verification
reported "no rows … verification incomplete" and exited 1 after a long
silent wait. Expected-runtimes must key only on signals that map to rows
the probe can actually see; a genuinely live pre-update Windows gateway
is already covered by ``pre_restart_pids`` and the plan inventory. The
parameter stays in the signature so the call site keeps passing the token
(cheap, explicit, and the docstring is where the exclusion is explained).

The same condition gates the 2.0s settle sleep: a freshly restarted
gateway needs the settle window to rewrite ``gateway_state.json``.

Note this keys ONLY on zero-rows-despite-expected-runtimes. A non-empty
snapshot — including rows in ``unknown`` state — is still judged solely by
``print_fleet_version_matrix``.
"""
del windows_resume_token # excluded on purpose — see docstring (#93406)
if restarted_services or killed_pids:
return True
if pre_restart_pids is None or pre_restart_pids:
Expand All @@ -9680,13 +9695,6 @@ def _fleet_probe_expected_runtimes(
return True
except Exception:
pass
if isinstance(windows_resume_token, dict) and (
windows_resume_token.get("profiles")
or windows_resume_token.get("unmapped")
or windows_resume_token.get("services")
or windows_resume_token.get("expected_services")
):
return True
return False


Expand Down
Loading
Loading