rein-aharness/tests/test_brief_daily.py
tegwick f6930ad115 Rename package, CLI, and deploy artifacts to rein-aharness (HARNESS-WP-0002-T02)
agent_harness -> rein_aharness (package + all imports), CLI command
agent-harness -> rein-aharness, Docker image tag, k8s namespace/labels/
names, Makefile targets, deploy script env var/paths. In-repo identity
strings (hub event source, metrics harness field, default assignee,
argparse prog name, commit author identity) updated to match.

Historical documents left untouched on purpose: docs/adr/ADR-001-agent-harness-architecture.md,
docs/architecture.md (dated v0.1 snapshot), workplans/HARNESS-WP-0001
(completed under the old name), and the SSH host alias
"forgejo-agent-harness" (external ~/.ssh/config entry, not owned here).

Verified: 47/47 tests pass, CLI runs correctly from a fresh venv,
`make image` builds and the resulting container runs correctly.

deploy/README.md gained an explicit rename cutover checklist for what
this session cannot safely do unattended -- moving the host-side
secrets dir and checkout on railiance01, and not deleting the old k8s
namespace until the new one is confirmed working. The actual live
cutover (running that checklist against the real Railiance deployment)
is not attempted here -- real production surgery on binky-control's
live automation, needs the operator present.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 14:22:18 +02:00

125 lines
3.8 KiB
Python

from __future__ import annotations
import json
import subprocess
from datetime import date
from pathlib import Path
from rein_aharness import brief_daily
def _git_repo(tmp_path: Path) -> Path:
repo = tmp_path / "binky-control"
repo.mkdir()
subprocess.run(["git", "init"], cwd=repo, check=True, capture_output=True)
subprocess.run(
["git", "config", "user.email", "test@example.com"],
cwd=repo,
check=True,
capture_output=True,
)
subprocess.run(
["git", "config", "user.name", "test"],
cwd=repo,
check=True,
capture_output=True,
)
(repo / "DecisionQueue.md").write_text(
"# DecisionQueue\n\n## Open\n\n### DEC-2026-999\nstatus: prepared\n",
encoding="utf-8",
)
(repo / "OfficeHourQueue.md").write_text("# OH\n", encoding="utf-8")
(repo / "AutopilotWorkQueue.md").write_text("# AWQ\n", encoding="utf-8")
(repo / "RiskRegister.md").write_text("# Risks\n", encoding="utf-8")
(repo / "briefs").mkdir()
subprocess.run(["git", "add", "."], cwd=repo, check=True, capture_output=True)
subprocess.run(
["git", "commit", "-m", "init"],
cwd=repo,
check=True,
capture_output=True,
)
return repo
def test_render_brief_format() -> None:
md = brief_daily.render_brief(
date(2026, 7, 22),
{
"decide_now": ["DEC-1 approve cutover"],
"progress": ["WP-0005 finished"],
"risks": [],
"best_next_hour": "Approve DEC-1",
},
)
assert md.startswith("# Daily Brief — 2026-07-22\n")
assert "## Decide now" in md
assert "## Progress" in md
assert "## Risks" in md
assert "## Best next hour" in md
assert "No RiskRegister changes" in md
assert "Approve DEC-1" in md
def test_parse_brief_response_fences() -> None:
data = brief_daily.parse_brief_response(
'```json\n{"decide_now":[],"progress":["x"],"risks":[],'
'"best_next_hour":"none"}\n```'
)
assert data["progress"] == ["x"]
def test_run_brief_daily_mock(tmp_path: Path, monkeypatch) -> None:
repo = _git_repo(tmp_path)
monkeypatch.setattr(brief_daily.hub, "post_progress_event", lambda **kw: True)
day = date(2026, 7, 22)
def fake(prompt: str) -> str:
assert "DecisionQueue" in prompt
return json.dumps(
{
"decide_now": ["DEC-2026-999 go"],
"progress": ["scaffold landed"],
"risks": [],
"best_next_hour": "no founder action needed today",
}
)
result = brief_daily.run_brief_daily(
repo, day=day, complete_fn=fake, force=True
)
assert result.ok
assert result.wrote
assert result.committed
path = repo / "briefs" / "2026-07-22-daily-brief.md"
assert path.is_file()
text = path.read_text(encoding="utf-8")
assert "DEC-2026-999" in text
assert "scaffold landed" in text
def test_skip_existing_brief(tmp_path: Path, monkeypatch) -> None:
repo = _git_repo(tmp_path)
monkeypatch.setattr(brief_daily.hub, "post_progress_event", lambda **kw: True)
day = date(2026, 7, 22)
path = brief_daily.brief_path_for(repo, day)
path.write_text("# Daily Brief — 2026-07-22\n\nalready\n", encoding="utf-8")
subprocess.run(["git", "add", "."], cwd=repo, check=True, capture_output=True)
subprocess.run(
["git", "commit", "-m", "brief"],
cwd=repo,
check=True,
capture_output=True,
)
called = {"n": 0}
def boom(prompt: str) -> str:
called["n"] += 1
raise AssertionError("should not call LLM")
result = brief_daily.run_brief_daily(
repo, day=day, complete_fn=boom, force=False
)
assert result.ok
assert result.skipped_existing
assert called["n"] == 0