The tenant runner (assembly-economics 2521955) refuses any web-fetcher other than 0.2.0. Instead of defaulting to a moving ~/web-fetcher checkout, the approach now uses an explicit WEB_FETCHER_PATH/ASSEMBLY_WEB_FETCHER_PATH or keeps a shallow clone of tag v0.2.0 under ~/.cache/rein-aharness/ and refuses it if HEAD is not exactly at the tag. Each run passes --cache to a fresh temp directory outside the checkout; its path is reported in the hub detail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 193986@bnt-lap001 Assistant-Session: 585bfbea-320e-47b3-8c0e-bc1513a53307
127 lines
5.9 KiB
Python
127 lines
5.9 KiB
Python
"""Tests for the assembly-checkpoint approach (offline; local bare origin)."""
|
|
|
|
import subprocess
|
|
import textwrap
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from rein_aharness import approaches as ap
|
|
from rein_aharness import assembly_checkpoint as ac
|
|
from rein_aharness.assembly_checkpoint import (AssemblyCheckpointError, ensure_web_fetcher, kind_from_title,
|
|
run_assembly_checkpoint)
|
|
|
|
RUNNER = textwrap.dedent('''
|
|
import json, sys, pathlib
|
|
kind = sys.argv[sys.argv.index("--kind") + 1]
|
|
cache = pathlib.Path(sys.argv[sys.argv.index("--cache") + 1])
|
|
assert cache.is_dir() and not cache.resolve().is_relative_to(pathlib.Path.cwd().resolve())
|
|
mode = pathlib.Path("checkpoints/MODE").read_text().strip()
|
|
if mode == "out":
|
|
print(json.dumps({"status": "out-of-window", "date": "2026-10-12", "kind": kind})); sys.exit(3)
|
|
if mode == "outside":
|
|
pathlib.Path("README.md").write_text("tampered")
|
|
p = pathlib.Path("checkpoints/2026/2026-10-14-" + kind + ".md")
|
|
p.parent.mkdir(parents=True, exist_ok=True); p.write_text("# record")
|
|
print(json.dumps({"status": "ok", "date": "2026-10-14", "kind": kind, "path": str(p), "ok": 5,
|
|
"not_found": 4, "error": 0, "assessment": False, "phase": "setup"}))
|
|
''')
|
|
|
|
|
|
def _git(cwd, *args):
|
|
subprocess.run(["git", "-C", str(cwd), *args], check=True, capture_output=True)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _web_fetcher_path(tmp_path, monkeypatch):
|
|
monkeypatch.setenv("WEB_FETCHER_PATH", str(tmp_path / "wf"))
|
|
monkeypatch.delenv("ASSEMBLY_WEB_FETCHER_PATH", raising=False)
|
|
|
|
|
|
@pytest.fixture
|
|
def repo(tmp_path: Path) -> Path:
|
|
origin = tmp_path / "origin.git"
|
|
_git(tmp_path, "init", "-q", "--bare", "-b", "main", str(origin))
|
|
work = tmp_path / "work"
|
|
_git(tmp_path, "clone", "-q", str(origin), str(work))
|
|
_git(work, "config", "user.email", "t@t"), _git(work, "config", "user.name", "t")
|
|
(work / "checkpoints").mkdir()
|
|
(work / "checkpoints" / "run_checkpoint.py").write_text(RUNNER)
|
|
(work / "checkpoints" / "MODE").write_text("in")
|
|
(work / "README.md").write_text("x")
|
|
_git(work, "add", "-A"), _git(work, "commit", "-qm", "init"), _git(work, "push", "-q", "origin", "HEAD:main")
|
|
return work
|
|
|
|
|
|
def test_kind_from_title():
|
|
assert kind_from_title("Assembly Economics reality checkpoint (full) — steady phase") == "full"
|
|
assert kind_from_title("anything") == "light"
|
|
|
|
|
|
def test_in_window_commits_and_pushes(repo):
|
|
r = run_assembly_checkpoint(repo, kind="light", report_to_hub=False)
|
|
assert r.ok and r.committed and r.pushed and r.path.endswith("2026-10-14-light.md")
|
|
origin_head = subprocess.run(["git", "-C", str(repo), "rev-parse", "origin/main"],
|
|
capture_output=True, text=True).stdout.strip()
|
|
assert origin_head == r.origin_sha
|
|
|
|
|
|
def test_out_of_window_is_noop(repo):
|
|
(repo / "checkpoints" / "MODE").write_text("out")
|
|
_git(repo, "commit", "-qam", "mode out"), _git(repo, "push", "-q", "origin", "HEAD:main")
|
|
r = run_assembly_checkpoint(repo, kind="light", report_to_hub=False)
|
|
assert r.ok and r.out_of_window and not r.committed and not r.pushed
|
|
|
|
|
|
def test_refuses_paths_outside_checkpoints(repo):
|
|
(repo / "checkpoints" / "MODE").write_text("outside")
|
|
_git(repo, "commit", "-qam", "mode outside"), _git(repo, "push", "-q", "origin", "HEAD:main")
|
|
r = run_assembly_checkpoint(repo, kind="light", report_to_hub=False)
|
|
assert r.ok # README change is not staged: only checkpoints/ is added
|
|
changed = subprocess.run(["git", "-C", str(repo), "show", "--name-only", "--format=", "HEAD"],
|
|
capture_output=True, text=True).stdout.split()
|
|
assert all(p.startswith("checkpoints/") for p in changed)
|
|
|
|
|
|
def test_label_selects_assembly_checkpoint():
|
|
from rein_aharness.ops_run_client import OpsRun
|
|
import inspect
|
|
kw = {p: None for p in inspect.signature(OpsRun).parameters}
|
|
for k, p in inspect.signature(OpsRun).parameters.items():
|
|
if p.default is not inspect.Parameter.empty:
|
|
kw[k] = p.default
|
|
kw.update(id="x", title="Assembly Economics reality checkpoint (light) — setup phase", description="d",
|
|
labels=["assembly-checkpoint", "research", "automated"], target_repo="assembly-economics",
|
|
activity_definition_id="assembly-checkpoint-setup-daily")
|
|
assert ap.select_approach(OpsRun(**kw)) == ap.APPROACH_ASSEMBLY_CHECKPOINT
|
|
|
|
|
|
def _tagged_origin(tmp_path: Path, tag: str) -> Path:
|
|
src = tmp_path / "wf-src"
|
|
_git(tmp_path, "init", "-q", "-b", "main", str(src))
|
|
_git(src, "config", "user.email", "t@t"), _git(src, "config", "user.name", "t")
|
|
(src / "README").write_text("wf")
|
|
_git(src, "add", "-A"), _git(src, "commit", "-qm", "init"), _git(src, "tag", tag)
|
|
return src
|
|
|
|
|
|
def test_ensure_web_fetcher_clones_pinned_tag(tmp_path, monkeypatch):
|
|
monkeypatch.delenv("WEB_FETCHER_PATH")
|
|
monkeypatch.setenv("ASSEMBLY_WEB_FETCHER_URL", (_tagged_origin(tmp_path, ac.WEB_FETCHER_TAG)).as_uri())
|
|
dest = ensure_web_fetcher(tmp_path / "cache")
|
|
assert dest == tmp_path / "cache" / f"web-fetcher-{ac.WEB_FETCHER_TAG}" and (dest / "README").exists()
|
|
assert ensure_web_fetcher(tmp_path / "cache") == dest # reused, re-verified
|
|
|
|
|
|
def test_ensure_web_fetcher_refuses_drifted_checkout(tmp_path, monkeypatch):
|
|
monkeypatch.delenv("WEB_FETCHER_PATH")
|
|
monkeypatch.setenv("ASSEMBLY_WEB_FETCHER_URL", (_tagged_origin(tmp_path, ac.WEB_FETCHER_TAG)).as_uri())
|
|
dest = ensure_web_fetcher(tmp_path / "cache")
|
|
_git(dest, "config", "user.email", "t@t"), _git(dest, "config", "user.name", "t")
|
|
_git(dest, "commit", "-q", "--allow-empty", "-m", "drift")
|
|
with pytest.raises(AssemblyCheckpointError, match="not v0.2.0"):
|
|
ensure_web_fetcher(tmp_path / "cache")
|
|
|
|
|
|
def test_explicit_web_fetcher_path_wins(tmp_path):
|
|
assert ensure_web_fetcher(tmp_path / "cache") == tmp_path / "wf"
|