"""Dual-run flags, meter, and hardened task status command.""" from __future__ import annotations import json import subprocess from pathlib import Path import pytest from repo_manager import dual_run from repo_manager.commands.task_status import update_task_status def _git(repo: Path, *args: str) -> None: subprocess.run(["git", *args], cwd=repo, check=True, capture_output=True) def _fixture(tmp_path: Path) -> Path: repo = tmp_path / "pilot" repo.mkdir() _git(repo, "init") _git(repo, "config", "user.email", "t@example.com") _git(repo, "config", "user.name", "T") (repo / "workplans").mkdir() (repo / "workplans" / "P-WP-0001.md").write_text( """--- id: P-WP-0001 type: workplan title: Pilot status: active --- ## T ```task id: P-WP-0001-T01 status: todo state_hub_task_id: "11111111-1111-4111-8111-111111111111" ``` x """, encoding="utf-8", ) _git(repo, "add", ".") _git(repo, "commit", "-m", "seed") return repo def test_flags_and_pilot(monkeypatch: pytest.MonkeyPatch): monkeypatch.delenv("RM_WRITEBACK", raising=False) monkeypatch.delenv("RM_RECONCILE", raising=False) monkeypatch.delenv("RM_PILOT_REPOS", raising=False) assert dual_run.writeback_enabled() is False monkeypatch.setenv("RM_WRITEBACK", "1") monkeypatch.setenv("RM_PILOT_REPOS", "repo-manager,other") assert dual_run.writeback_for_repo("repo-manager") is True assert dual_run.writeback_for_repo("nope") is False monkeypatch.delenv("RM_PILOT_REPOS", raising=False) assert dual_run.writeback_for_repo("any") is True def test_meter(tmp_path: Path, monkeypatch: pytest.MonkeyPatch): meter = tmp_path / "meter.jsonl" monkeypatch.setenv("RM_METER_PATH", str(meter)) dual_run.record_mutation( source="repo-manager", kind="test", repo_slug="x", detail={"a": 1}, ) dual_run.record_mutation(source="state-hub", kind="test", repo_slug="x") summary = dual_run.meter_summary(meter) assert summary["repo-manager"] == 1 assert summary["state-hub"] == 1 assert summary["total"] == 2 def test_update_by_uuid_and_idempotency(tmp_path: Path, monkeypatch: pytest.MonkeyPatch): repo = _fixture(tmp_path) monkeypatch.setenv("RM_METER_PATH", str(tmp_path / "m.jsonl")) monkeypatch.setenv("RM_IDEMPOTENCY_PATH", str(tmp_path / "idemp.json")) r1 = update_task_status( repo, "11111111-1111-4111-8111-111111111111", "progress", idempotency_key="k1", repo_slug="pilot", ) assert r1.status == "applied" assert r1.evidence.get("git_sha") text = (repo / "workplans" / "P-WP-0001.md").read_text(encoding="utf-8") assert "status: progress" in text r2 = update_task_status( repo, "11111111-1111-4111-8111-111111111111", "progress", idempotency_key="k1", repo_slug="pilot", ) assert r2.status == "applied" assert r2.evidence.get("git_sha") == r1.evidence.get("git_sha") # Different payload same key → conflict r3 = update_task_status( repo, "11111111-1111-4111-8111-111111111111", "done", idempotency_key="k1", repo_slug="pilot", ) assert r3.status == "rejected" assert r3.error and r3.error.get("code") == "conflict"