generated from coulomb/repo-seed
Add lifecycle renormalization consistency repair
This commit is contained in:
@@ -28,10 +28,13 @@ from consistency_check import (
|
||||
_BACKGROUND_CHECKS,
|
||||
_detect_behind_remote,
|
||||
_git_pull,
|
||||
_patch_frontmatter_field,
|
||||
_patch_task_status_in_file,
|
||||
_report_needs_action,
|
||||
archive_closed_workplans,
|
||||
canonical_workplan_filename,
|
||||
check_repo,
|
||||
fix_repo,
|
||||
get_tasks_from_workplan,
|
||||
iter_workplan_files,
|
||||
normalise_workstream_status,
|
||||
@@ -726,6 +729,133 @@ class TestPatchTaskStatusInFile:
|
||||
assert result is False
|
||||
|
||||
|
||||
class TestPatchFrontmatterField:
|
||||
def test_patches_existing_scalar_field(self, tmp_path):
|
||||
f = tmp_path / "workplan.md"
|
||||
f.write_text("---\nid: WP-001\nstatus: proposed\n---\nBody\n", encoding="utf-8")
|
||||
|
||||
assert _patch_frontmatter_field(f, "status", "active") is True
|
||||
|
||||
patched = f.read_text(encoding="utf-8")
|
||||
assert "status: active" in patched
|
||||
assert "id: WP-001" in patched
|
||||
|
||||
def test_is_idempotent_when_field_already_matches(self, tmp_path):
|
||||
f = tmp_path / "workplan.md"
|
||||
f.write_text("---\nid: WP-001\nstatus: active\n---\nBody\n", encoding="utf-8")
|
||||
|
||||
assert _patch_frontmatter_field(f, "status", "active") is False
|
||||
assert f.read_text(encoding="utf-8").count("status: active") == 1
|
||||
|
||||
|
||||
class TestLifecycleRenormalization:
|
||||
def _make_repo(self, tmp_path, status: str = "proposed") -> Path:
|
||||
repo = tmp_path / "repo"
|
||||
workplans = repo / "workplans"
|
||||
workplans.mkdir(parents=True)
|
||||
(workplans / "STATE-WP-0001-demo.md").write_text(
|
||||
"---\n"
|
||||
"id: STATE-WP-0001\n"
|
||||
"type: workplan\n"
|
||||
"title: Demo\n"
|
||||
"domain: custodian\n"
|
||||
"repo: state-hub\n"
|
||||
f"status: {status}\n"
|
||||
"owner: codex\n"
|
||||
"state_hub_workstream_id: \"ws-1\"\n"
|
||||
"---\n\n"
|
||||
"## Implement Demo\n\n"
|
||||
"```task\n"
|
||||
"id: STATE-WP-0001-T01\n"
|
||||
"status: in_progress\n"
|
||||
"priority: high\n"
|
||||
"state_hub_task_id: \"task-1\"\n"
|
||||
"```\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
return repo
|
||||
|
||||
def _api_get_for_repo(self, repo: Path):
|
||||
ws = {
|
||||
"id": "ws-1",
|
||||
"repo_id": "repo-1",
|
||||
"topic_id": "topic-1",
|
||||
"slug": "state-wp-0001",
|
||||
"title": "Demo",
|
||||
"status": "proposed",
|
||||
"planning_priority": None,
|
||||
"planning_order": None,
|
||||
}
|
||||
task = {
|
||||
"id": "task-1",
|
||||
"title": "Implement Demo",
|
||||
"status": "in_progress",
|
||||
"description": None,
|
||||
}
|
||||
|
||||
def fake_get(_api_base, path, params=None):
|
||||
if path == "/repos/state-hub":
|
||||
import socket
|
||||
|
||||
return {
|
||||
"id": "repo-1",
|
||||
"slug": "state-hub",
|
||||
"local_path": str(repo),
|
||||
"host_paths": {socket.gethostname(): str(repo)},
|
||||
}
|
||||
if path == "/workstreams/ws-1":
|
||||
return ws
|
||||
if path == "/tasks/task-1":
|
||||
return task
|
||||
if path == "/tasks" and params == {"workstream_id": "ws-1"}:
|
||||
return [task]
|
||||
if path == "/workstreams/ws-1/dependencies":
|
||||
return []
|
||||
if path == "/workstreams" and params == {"repo_id": "repo-1"}:
|
||||
return [ws]
|
||||
if path == "/workstreams" and params and params.get("topic_id") == "topic-1":
|
||||
return []
|
||||
return []
|
||||
|
||||
return fake_get
|
||||
|
||||
def test_active_task_in_planning_workplan_reports_c23_not_c04(self, tmp_path, monkeypatch):
|
||||
repo = self._make_repo(tmp_path)
|
||||
monkeypatch.setattr("consistency_check._api_get", self._api_get_for_repo(repo))
|
||||
|
||||
report = check_repo("http://unused", "state-hub")
|
||||
|
||||
check_ids = [issue.check_id for issue in report.issues]
|
||||
assert "C-23" in check_ids
|
||||
assert "C-04" not in check_ids
|
||||
issue = next(issue for issue in report.issues if issue.check_id == "C-23")
|
||||
assert issue.fixable is True
|
||||
assert issue.file_value == "proposed"
|
||||
|
||||
def test_fix_repo_repairs_planning_workplan_with_active_task(self, tmp_path, monkeypatch):
|
||||
repo = self._make_repo(tmp_path)
|
||||
wp = repo / "workplans" / "STATE-WP-0001-demo.md"
|
||||
patches = []
|
||||
|
||||
def fake_patch(_api_base, path, body):
|
||||
patches.append((path, body))
|
||||
return {"ok": True}
|
||||
|
||||
monkeypatch.setattr("consistency_check._api_get", self._api_get_for_repo(repo))
|
||||
monkeypatch.setattr("consistency_check._api_patch", fake_patch)
|
||||
monkeypatch.setattr("consistency_check._detect_behind_remote", lambda _repo_path: False)
|
||||
monkeypatch.setattr("consistency_check._detect_ahead_of_remote", lambda _repo_path: 0)
|
||||
monkeypatch.setattr("consistency_check._git_commit_writeback", lambda *args, **kwargs: True)
|
||||
monkeypatch.setattr("consistency_check._write_custodian_brief", lambda *args, **kwargs: False)
|
||||
monkeypatch.setattr("consistency_check._git_push", lambda _repo_path: (True, "pushed"))
|
||||
|
||||
report = fix_repo("http://unused", "state-hub")
|
||||
|
||||
assert ("/workstreams/ws-1", {"status": "active"}) in patches
|
||||
assert "status: active" in wp.read_text(encoding="utf-8")
|
||||
assert any("C-23 fixed" in fix for fix in report.fixes_applied)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _git_pull (T02 remote fix helper)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user