From 54ad8c7fd2eb76893dd470a5e22579321e676893 Mon Sep 17 00:00:00 2001 From: ethernet Date: Wed, 23 Sep 2026 22:05:57 -0400 Subject: [PATCH] fix(update): every published checkout identity moves the bootstrap receipt ece7c172f8 refreshed .hermes-bootstrap-complete only from complete_source_checkout, but two other paths publish a new checkout identity through write_source_stamp without it: the PM updater's finish (update_finish.py, the path an old updater's handoff takes) and boot-time blessed-checkout adoption (post_update.py). The Windows E2E leg installer-script -> hermes-update (v2026.6.19 -> HEAD) takes the handoff, so it still failed "pinnedCommit 2bd1977d8fad != installed HEAD ece7c172f8d8". The refresh now lives inside write_source_stamp, so every caller moves the receipt with the identity it publishes. The tests pin that seam (red on ece7c172f8 with the CI message, green here). --- hermes_cli/source_completion.py | 6 ++---- hermes_cli/source_stamp.py | 3 +++ tests/hermes_cli/test_source_completion_stamp.py | 14 +++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/hermes_cli/source_completion.py b/hermes_cli/source_completion.py index 8dbbb0b962..518f892154 100644 --- a/hermes_cli/source_completion.py +++ b/hermes_cli/source_completion.py @@ -60,11 +60,9 @@ def complete_source_checkout( completion_message=completion_message, ) if complete: - from hermes_cli.source_stamp import refresh_bootstrap_receipt, write_source_stamp + from hermes_cli.source_stamp import write_source_stamp - stamp = write_source_stamp(root) - if stamp is not None: - refresh_bootstrap_receipt(root, stamp) + write_source_stamp(root) return complete diff --git a/hermes_cli/source_stamp.py b/hermes_cli/source_stamp.py index c34b6d33db..a62a12f327 100644 --- a/hermes_cli/source_stamp.py +++ b/hermes_cli/source_stamp.py @@ -60,6 +60,9 @@ def write_source_stamp(root: Path) -> dict | None: with suppress(OSError): os.unlink(tmp_name) _reset_version_info_cache() + # Every path that publishes a new checkout identity (completion handoff, the PM + # updater's finish, boot-time adoption) moves the installers' receipt with it. + refresh_bootstrap_receipt(root, stamp) return stamp diff --git a/tests/hermes_cli/test_source_completion_stamp.py b/tests/hermes_cli/test_source_completion_stamp.py index 6556ffdd56..28aa05afe3 100644 --- a/tests/hermes_cli/test_source_completion_stamp.py +++ b/tests/hermes_cli/test_source_completion_stamp.py @@ -7,6 +7,7 @@ import subprocess import sys from hermes_cli.source_completion import complete_source_checkout +from hermes_cli.source_stamp import write_source_stamp def _repo(tmp_path: Path) -> Path: @@ -61,7 +62,9 @@ def _verify_bootstrap_receipt(root: Path) -> subprocess.CompletedProcess: "--repo", str(root)], capture_output=True, text=True, encoding="utf-8") -def test_update_completion_moves_an_installer_receipt_to_the_updated_head(tmp_path, monkeypatch): +def test_publishing_checkout_identity_moves_an_installer_receipt_to_head(tmp_path): + # write_source_stamp is the one seam: the completion handoff, the PM updater's finish and + # boot-time adoption all publish identity through it, and the receipt must follow every one. root = _repo(tmp_path) release = subprocess.run(["git", "rev-parse", "HEAD"], cwd=root, capture_output=True, text=True, check=True).stdout.strip() branch = subprocess.run(["git", "branch", "--show-current"], cwd=root, capture_output=True, text=True, check=True).stdout.strip() @@ -72,17 +75,14 @@ def test_update_completion_moves_an_installer_receipt_to_the_updated_head(tmp_pa subprocess.run(["git", "commit", "-q", "--allow-empty", "-m", "update"], cwd=root, check=True, capture_output=True, env={**os.environ, "GIT_AUTHOR_NAME": "t", "GIT_AUTHOR_EMAIL": "t@example.invalid", "GIT_COMMITTER_NAME": "t", "GIT_COMMITTER_EMAIL": "t@example.invalid"}) - _completion_dependencies(monkeypatch, lambda **_kwargs: True) - - assert complete_source_checkout(root, desktop=False, assume_yes=True) + assert write_source_stamp(root) is not None result = _verify_bootstrap_receipt(root) assert result.returncode == 0, result.stdout + result.stderr -def test_completion_never_invents_an_installer_receipt(tmp_path, monkeypatch): +def test_publishing_checkout_identity_never_invents_an_installer_receipt(tmp_path): # The receipt's presence is what marks a script install; a manual clone stays one. root = _repo(tmp_path) - _completion_dependencies(monkeypatch, lambda **_kwargs: True) - assert complete_source_checkout(root, desktop=False, assume_yes=True) + assert write_source_stamp(root) is not None assert not (root / ".hermes-bootstrap-complete").exists()