Add Binky weekly review approach
This commit is contained in:
parent
140d1b0dc7
commit
8e98eada89
8 changed files with 700 additions and 12 deletions
|
|
@ -5,6 +5,7 @@ from __future__ import annotations
|
|||
from rein_aharness.approaches import (
|
||||
APPROACH_AGENT_SESSION,
|
||||
APPROACH_BRIEF_DAILY,
|
||||
APPROACH_BRIEF_WEEKLY,
|
||||
APPROACH_FI_RESEARCH_BRIEF,
|
||||
APPROACH_MAIL_PIPELINE,
|
||||
APPROACH_UNMATCHED,
|
||||
|
|
@ -56,6 +57,28 @@ def test_select_binky_rhythm() -> None:
|
|||
)
|
||||
|
||||
|
||||
def test_select_binky_weekly_review_requires_binky_and_weekly_label() -> None:
|
||||
assert (
|
||||
select_approach(
|
||||
_run(labels=["binky", "weekly-review", "automated"])
|
||||
)
|
||||
== APPROACH_BRIEF_WEEKLY
|
||||
)
|
||||
|
||||
|
||||
def test_select_binky_weekly_review_by_definition() -> None:
|
||||
assert (
|
||||
select_approach(
|
||||
_run(activity_definition_id="binky-weekly-review-prep")
|
||||
)
|
||||
== APPROACH_BRIEF_WEEKLY
|
||||
)
|
||||
|
||||
|
||||
def test_weekly_review_label_alone_is_unmatched() -> None:
|
||||
assert select_approach(_run(labels=["weekly-review"])) == APPROACH_UNMATCHED
|
||||
|
||||
|
||||
def test_select_mail_intake() -> None:
|
||||
assert (
|
||||
select_approach(_run(labels=["mail-intake", "automated"]))
|
||||
|
|
|
|||
146
tests/test_brief_weekly.py
Normal file
146
tests/test_brief_weekly.py
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
from rein_aharness import brief_weekly
|
||||
|
||||
|
||||
def _git(repo: Path, *args: str, commit_date: str | None = None) -> None:
|
||||
env = None
|
||||
if commit_date:
|
||||
env = dict(os.environ)
|
||||
env["GIT_AUTHOR_DATE"] = commit_date
|
||||
env["GIT_COMMITTER_DATE"] = commit_date
|
||||
subprocess.run(
|
||||
["git", *args], cwd=repo, check=True, capture_output=True, env=env
|
||||
)
|
||||
|
||||
|
||||
def _repo(tmp_path: Path) -> Path:
|
||||
repo = tmp_path / "binky-control"
|
||||
repo.mkdir()
|
||||
_git(repo, "init")
|
||||
_git(repo, "config", "user.email", "test@example.com")
|
||||
_git(repo, "config", "user.name", "test")
|
||||
for name, body in {
|
||||
"SuccessMilestones.md": "# Milestones\n\nS1: started\n",
|
||||
"DecisionQueue.md": "# Decisions\n\nDEC-1 prepared\n",
|
||||
"RiskRegister.md": "# Risks\n\nRISK-005 open\n",
|
||||
"WORK-RECORDS.md": "# Records\n",
|
||||
}.items():
|
||||
(repo / name).write_text(body, encoding="utf-8")
|
||||
(repo / "briefs").mkdir()
|
||||
(repo / "briefs/2026-08-07-daily-brief.md").write_text(
|
||||
"# Daily Brief\n\nProgress happened.\n", encoding="utf-8"
|
||||
)
|
||||
_git(repo, "add", ".")
|
||||
_git(
|
||||
repo,
|
||||
"commit",
|
||||
"-m",
|
||||
"initial evidence",
|
||||
commit_date="2026-07-01T12:00:00+00:00",
|
||||
)
|
||||
return repo
|
||||
|
||||
|
||||
def test_render_uses_deterministic_risk_state() -> None:
|
||||
signals = brief_weekly.WeeklySignals(
|
||||
milestone_moved=False,
|
||||
activity_present=True,
|
||||
prior_week_milestone_free=True,
|
||||
risk005_state="escalate",
|
||||
)
|
||||
text = brief_weekly.render_brief(
|
||||
date(2026, 8, 7),
|
||||
{
|
||||
"milestone_summary": "Work occurred but no status changed.",
|
||||
"milestone_evidence": ["S1-related work landed"],
|
||||
"founder_actions": ["Review DEC-1"],
|
||||
"risk005_state": "clear",
|
||||
},
|
||||
signals,
|
||||
)
|
||||
assert "**No.**" in text
|
||||
assert "**State: escalate.**" in text
|
||||
assert "Review DEC-1" in text
|
||||
assert "State: clear" not in text
|
||||
|
||||
|
||||
def test_derive_signals_escalates_after_prior_free_week(tmp_path: Path) -> None:
|
||||
repo = _repo(tmp_path)
|
||||
(repo / "briefs/2026-07-31-weekly-founder-review.md").write_text(
|
||||
"# Weekly Founder Review\n\nNo milestone status changed this week.\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
_git(repo, "add", ".")
|
||||
_git(repo, "commit", "-m", "prior weekly review")
|
||||
signals = brief_weekly.derive_signals(repo, date.today())
|
||||
assert not signals.milestone_moved
|
||||
assert signals.activity_present
|
||||
assert signals.prior_week_milestone_free
|
||||
assert signals.risk005_state == "escalate"
|
||||
|
||||
|
||||
def test_run_weekly_mock_writes_commits_and_reports(tmp_path: Path, monkeypatch) -> None:
|
||||
repo = _repo(tmp_path)
|
||||
events: list[dict] = []
|
||||
monkeypatch.setattr(
|
||||
brief_weekly.hub,
|
||||
"post_progress_event",
|
||||
lambda **kwargs: events.append(kwargs) or True,
|
||||
)
|
||||
|
||||
def fake(prompt: str) -> str:
|
||||
assert "SuccessMilestones.md" in prompt
|
||||
assert "Deterministic signals" in prompt
|
||||
return json.dumps(
|
||||
{
|
||||
"milestone_summary": "No milestone status changed.",
|
||||
"milestone_evidence": ["Daily work was recorded."],
|
||||
"founder_actions": ["Review DEC-1"],
|
||||
}
|
||||
)
|
||||
|
||||
result = brief_weekly.run_brief_weekly(
|
||||
repo,
|
||||
day=date(2026, 8, 8),
|
||||
force=True,
|
||||
complete_fn=fake,
|
||||
)
|
||||
assert result.ok
|
||||
assert result.wrote
|
||||
assert result.committed
|
||||
assert result.risk005_state == "quiet"
|
||||
assert (repo / "briefs/2026-08-08-weekly-founder-review.md").is_file()
|
||||
assert events[-1]["event_type"] == "binky_weekly_review"
|
||||
assert events[-1]["detail"]["risk005_state"] == result.risk005_state
|
||||
|
||||
|
||||
def test_skip_existing_does_not_call_model(tmp_path: Path, monkeypatch) -> None:
|
||||
repo = _repo(tmp_path)
|
||||
monkeypatch.setattr(brief_weekly.hub, "post_progress_event", lambda **kw: True)
|
||||
day = date(2026, 8, 8)
|
||||
path = brief_weekly.brief_path_for(repo, day)
|
||||
path.write_text("# Weekly Founder Review\n", encoding="utf-8")
|
||||
_git(repo, "add", ".")
|
||||
_git(repo, "commit", "-m", "weekly review")
|
||||
|
||||
result = brief_weekly.run_brief_weekly(
|
||||
repo,
|
||||
day=day,
|
||||
complete_fn=lambda prompt: (_ for _ in ()).throw(AssertionError(prompt)),
|
||||
)
|
||||
assert result.ok
|
||||
assert result.skipped_existing
|
||||
|
||||
|
||||
def test_parse_response_accepts_json_fence() -> None:
|
||||
data = brief_weekly.parse_response(
|
||||
'```json\n{"milestone_summary":"none","milestone_evidence":[],"founder_actions":[]}\n```'
|
||||
)
|
||||
assert data["milestone_summary"] == "none"
|
||||
Loading…
Add table
Add a link
Reference in a new issue