from __future__ import annotations import json import subprocess from datetime import date from pathlib import Path from rein_aharness import fi_research_brief def _git(cwd: Path, *args: str) -> None: subprocess.run(["git", "-C", str(cwd), *args], check=True, capture_output=True) def _repo(tmp_path: Path) -> Path: repo = tmp_path / "freedom-intelligence" repo.mkdir() subprocess.run(["git", "init", "-q", "-b", "main"], cwd=repo, check=True) (repo / "README.md").write_text("baseline\n", encoding="utf-8") subprocess.run(["git", "add", "."], cwd=repo, check=True) subprocess.run( [ "git", "-c", "user.email=test@example.invalid", "-c", "user.name=test", "commit", "-qm", "baseline", ], cwd=repo, check=True, ) return repo def _with_origin(tmp_path: Path, repo: Path) -> Path: remote = tmp_path / "origin.git" subprocess.run(["git", "init", "--bare", "-q", "-b", "main", str(remote)], check=True) _git(repo, "remote", "add", "origin", str(remote)) _git(repo, "push", "-u", "origin", "HEAD:main") return remote def _complete(_prompt: str) -> str: return json.dumps( { "headline_deltas": ["No material delta after allowlist review."], "axis_a": [], "axis_b": [], "axis_c": [], "axis_d": [], "collection_candidates": [], "lab_implications": ["Recheck tomorrow."], } ) def test_fi_brief_pushes_to_origin_and_records_sha(tmp_path: Path) -> None: repo = _repo(tmp_path) _with_origin(tmp_path, repo) result = fi_research_brief.run_fi_research_brief( repo, day=date(2026, 9, 13), report_to_hub=False, complete_fn=_complete, ) assert result.ok is True assert result.committed is True assert result.pushed is True assert result.origin_sha remote_head = subprocess.run( ["git", "-C", str(tmp_path / "origin.git"), "rev-parse", "HEAD"], check=True, capture_output=True, text=True, ).stdout.strip() assert remote_head == result.origin_sha brief = repo / "briefs" / "2026" / "09" / "2026-09-13.md" assert brief.is_file() def test_fi_brief_push_failure_is_not_a_completed_day( tmp_path: Path, monkeypatch ) -> None: repo = _repo(tmp_path) posted: list[dict] = [] def fake_post(**kwargs): posted.append(kwargs) monkeypatch.setattr(fi_research_brief.hub, "post_progress_event", fake_post) result = fi_research_brief.run_fi_research_brief( repo, day=date(2026, 9, 13), report_to_hub=True, complete_fn=_complete, ) assert result.ok is False assert result.committed is True assert result.pushed is False assert "origin publish failed" in result.reason assert posted assert posted[-1]["event_type"] == "executor_run" assert posted[-1]["detail"]["pushed"] is False def _advance_origin(tmp_path: Path, name: str, rel: str) -> None: """Commit to origin from a second clone so the executor's push is non-fast-forward.""" other = tmp_path / name subprocess.run(["git", "clone", "-q", str(tmp_path / "origin.git"), str(other)], check=True) (other / rel).parent.mkdir(parents=True, exist_ok=True) (other / rel).write_text("moved\n", encoding="utf-8") _git(other, "add", rel) _git(other, "-c", "user.email=o@example.invalid", "-c", "user.name=o", "commit", "-qm", "move origin") _git(other, "push", "-q", "origin", "HEAD:main") def test_fi_brief_rebases_once_when_origin_moved(tmp_path: Path) -> None: repo = _repo(tmp_path) _with_origin(tmp_path, repo) _advance_origin(tmp_path, "other", "WORK-RECORDS.md") result = fi_research_brief.run_fi_research_brief( repo, day=date(2026, 9, 22), report_to_hub=False, complete_fn=_complete ) assert result.ok is True assert result.pushed is True remote_head = subprocess.run( ["git", "-C", str(tmp_path / "origin.git"), "rev-parse", "HEAD"], check=True, capture_output=True, text=True, ).stdout.strip() assert remote_head == result.origin_sha parents = subprocess.run( ["git", "-C", str(repo), "rev-list", "--parents", "-1", "HEAD"], check=True, capture_output=True, text=True, ).stdout.split() assert len(parents) == 2 # linear history: rebased, not merged def test_fi_brief_refuses_rebase_of_non_brief_commits(tmp_path: Path) -> None: repo = _repo(tmp_path) _with_origin(tmp_path, repo) (repo / "notes.md").write_text("local only\n", encoding="utf-8") _git(repo, "add", "notes.md") _git(repo, "-c", "user.email=t@example.invalid", "-c", "user.name=t", "commit", "-qm", "stray") _advance_origin(tmp_path, "other", "WORK-RECORDS.md") result = fi_research_brief.run_fi_research_brief( repo, day=date(2026, 9, 22), report_to_hub=False, complete_fn=_complete ) assert result.ok is False assert result.pushed is False assert "outside briefs/" in result.reason def test_fi_brief_rebase_conflict_fails_closed(tmp_path: Path) -> None: repo = _repo(tmp_path) _with_origin(tmp_path, repo) _advance_origin(tmp_path, "other", "briefs/2026/09/2026-09-22.md") result = fi_research_brief.run_fi_research_brief( repo, day=date(2026, 9, 22), report_to_hub=False, complete_fn=_complete ) assert result.ok is False assert result.pushed is False status = subprocess.run( ["git", "-C", str(repo), "status", "--porcelain=v2", "--branch"], check=True, capture_output=True, text=True, ).stdout assert "rebase" not in status.lower() assert not (repo / ".git" / "rebase-merge").exists()