#!/usr/bin/env python3 """Issue #8 — an update must keep the installer's fresh version.txt and asset_hashes.txt instead of restoring the pre-update copies. Since Issue #72 the update is the multi-agent-mux-update skill (in place, no remove.sh) and no .mam_deploy/update.sh is installed. Restoring them left version.txt naming the previous commit and made remove.sh compare against stale hashes, so every updated-but-pristine file was backed up as "locally modified". install_state is the one file whose old keys are merged back (gitignore_created from the original install). """ from __future__ import annotations import os import shutil import subprocess import tempfile from pathlib import Path import pytest REPO_ROOT = Path(__file__).resolve().parent.parent @pytest.fixture def installed_workspace(): temp = tempfile.mkdtemp(prefix="mam_issue8_") ws = Path(temp) / "workspace" ws.mkdir() env = os.environ.copy() env["MAM_REPO_URL"] = str(REPO_ROOT) env["MAM_SKIP_VENV"] = "1" env["MAM_INSTALLER_URL"] = "file://" + str(REPO_ROOT / "deploy" / "install.sh") res = subprocess.run(["bash", str(REPO_ROOT / "deploy" / "install.sh"), str(ws)], env=env, capture_output=True, text=True, timeout=600) assert res.returncode == 0, res.stderr try: yield ws, env finally: shutil.rmtree(temp, ignore_errors=True) def test_update_keeps_fresh_version_and_hashes_and_merges_install_state(installed_workspace): ws, env = installed_workspace mam = ws / ".mam" fresh_version = (mam / "version.txt").read_text() assert "commit=" in fresh_version # Simulate the previous install: stale stamps and an install_state key the # re-install will not write again. (mam / "version.txt").write_text("source=old\ncommit=stale0000\nfetched_at=then\nmethod=git\n") (mam / "asset_hashes.txt").write_text("stale-hash-db\n") with open(mam / "install_state", "a") as fh: fh.write("custom_marker=kept\n") assert not (ws / ".mam_deploy" / "update.sh").exists() upd_env = {k: v for k, v in env.items() if not k.startswith("HERDR_") and k not in ("WORKSPACE_ROOT", "AGENT_SESSIONS_YAML", "MAM_JOBS_DIR")} upd_env["MAM_NO_SUBSCRIBER_DAEMON"] = "1" # The update lists the live herdr agents; never ask a real server here. fake = ws.parent / "fake-herdr-bin" fake.mkdir() (fake / "herdr").write_text('#!/bin/sh\necho \'{"sessions": []}\'\n') (fake / "herdr").chmod(0o755) upd_env["PATH"] = "%s:%s" % (fake, upd_env["PATH"]) res = subprocess.run(["bash", str(ws / ".agents/skills/multi-agent-mux-update/scripts/update.sh"), "--yes"], cwd=str(ws), env=upd_env, capture_output=True, text=True, timeout=600, stdin=subprocess.DEVNULL) assert res.returncode == 0, res.stderr + res.stdout version = (mam / "version.txt").read_text() assert "stale0000" not in version, version assert "commit=" in version and version.strip() != "" hashes = (mam / "asset_hashes.txt").read_text() assert "stale-hash-db" not in hashes and hashes.strip(), "asset_hashes.txt must be the installer's fresh ledger" state = (mam / "install_state").read_text() assert "custom_marker=kept" in state, state assert state.count("gitignore_created=1") == 1, "merged keys must not be duplicated:\n" + state assert not (ws / ".mam_deploy" / "update.sh").exists()