From ccca876c942e2a0d39d72bb8de289d4593fa58a7 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Mon, 5 Oct 2026 05:59:54 -0700 Subject: [PATCH] fix(update): the pause record's owner identity uses the reader's creation-time probe identity() took its creation time from process_identity._process_create_time (psutil only), while identity_is_live judges with update_lock.incarnation_live, whose producer update_lock.process_create_time falls back to the stdlib probe. Without psutil every record was written with ct=None, which the reader can only call unprovable (live), so a killed updater's pause was never orphaned on such a host. identity() now calls update_lock.process_create_time, the same producer the marker uses. Review 5411136378 (#132338) fix 2. --- hermes_cli/update_pause_record.py | 14 +++++++------- tests/hermes_cli/test_update_pause_record.py | 10 ++++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/hermes_cli/update_pause_record.py b/hermes_cli/update_pause_record.py index a225adbba3..eb9a54516b 100644 --- a/hermes_cli/update_pause_record.py +++ b/hermes_cli/update_pause_record.py @@ -70,15 +70,15 @@ def record_path() -> Path: return get_default_hermes_root() / f"{RECORD_STEM}.{_install_key()}.json" -def _create_time(pid: int) -> float | None: - from hermes_cli.process_identity import _process_create_time - return _process_create_time(pid) - - def identity(pid: int | None = None) -> dict: - """``{"pid", "ct"}`` with ``ct`` spelled like the update marker's line 3 (``ct:``).""" + """``{"pid", "ct"}`` with ``ct`` spelled like the update marker's line 3 (``ct:``). + + The creation time comes from the probe :func:`identity_is_live` judges with + (``update_lock.process_create_time``: psutil, else stdlib), so a host without psutil still + writes a provable identity instead of ``ct=None``.""" + from hermes_cli import update_lock pid = os.getpid() if pid is None else int(pid) - created = _create_time(pid) + created = update_lock.process_create_time(pid) return {"pid": pid, "ct": None if created is None else f"ct:{created:.3f}"} diff --git a/tests/hermes_cli/test_update_pause_record.py b/tests/hermes_cli/test_update_pause_record.py index 4d2606bcd4..fc3333bafe 100644 --- a/tests/hermes_cli/test_update_pause_record.py +++ b/tests/hermes_cli/test_update_pause_record.py @@ -650,3 +650,13 @@ def test_a_malformed_retired_list_is_set_aside_only_when_nothing_refers_to_it(tm with pytest.raises(pause_record.RetiredUnknown): pause_record.orphans() assert retired.read_text(encoding="utf-8-sig") == "{trunc" + + +def test_a_host_without_psutil_records_an_identity_the_liveness_rule_can_prove(monkeypatch): + """Review 5411136378 fix 2: the record's creation time comes from the same probe the reader + judges with, so a psutil-less host never writes ``ct=None`` (unprovable, so never orphaned).""" + from hermes_cli import update_lock + monkeypatch.setitem(sys.modules, "psutil", None) # `import psutil` raises ImportError + ident = pause_record.identity() + assert ident["ct"] is not None, "no creation time without psutil" + assert update_lock.incarnation_live(ident["pid"], ident["ct"]) is True