"""Tests for MCP-native post-merge cleanup proof (#517).""" import sys import unittest from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from final_report_validator import assess_final_report_validator # noqa: E402 from mcp_native_cleanup_proof import ( # noqa: E402 assess_authorized_reconciler_cleanup_path, assess_mcp_native_cleanup_proof, assess_merger_cleanup_handoff_guidance, assess_raw_branch_delete_report, assess_raw_comment_delete_report, ) def _authorized_cleanup_report(**overrides): fields = { "Merge mutations": "gitea_merge_pr on PR #100", "Cleanup mutations": ( "gitea_reconcile_merged_cleanups deleted remote branch; " "gitea_cleanup_post_merge_moot_lease released lease" ), "Reconciler capability": "prgs-reconciler / gitea.branch.delete resolved", "Next actor": "reconciler session complete", } fields.update(overrides) lines = ["## Controller Handoff", ""] lines.extend(f"- {key}: {value}" for key, value in fields.items()) return "\n".join(lines) class TestRawBranchDeleteBlocked(unittest.TestCase): def test_git_branch_d_blocked(self): report = "Cleanup mutations: git branch -d feat/issue-1-x" result = assess_raw_branch_delete_report(report) self.assertTrue(result["block"]) self.assertIn("git branch -d", result["commands"][0]) def test_git_push_delete_in_ledger_blocked(self): report = "- Git ref mutations: git push origin --delete feat/x" result = assess_raw_branch_delete_report(report) self.assertTrue(result["block"]) def test_narrative_git_push_delete_not_blocked(self): report = "\n".join([ "## Validation", "Workflow §28B forbids raw git push --delete for cleanup.", "- Cleanup mutations: none", "- Git ref mutations: none", "- Worktree mutations: none", ]) result = assess_raw_branch_delete_report(report) self.assertFalse(result["block"]) def test_authorized_mcp_path_passes(self): report = _authorized_cleanup_report() result = assess_raw_branch_delete_report(report) self.assertFalse(result["block"]) class TestRawCommentDeleteBlocked(unittest.TestCase): def test_curl_delete_comment_in_ledger_blocked(self): report = ( "- Cleanup mutations: curl -X DELETE https://gitea.example/api/v1/repos/o/r/" "issues/9/comments/42" ) result = assess_raw_comment_delete_report(report) self.assertTrue(result["block"]) def test_narrative_comment_delete_not_blocked(self): report = "\n".join([ "Files reviewed: post_merge_cleanup_proof.py (raw comment delete patterns)", "Validation note: never use delete_issue_comment for lease cleanup.", "- Cleanup mutations: none", "- Git ref mutations: none", "- Worktree mutations: none", ]) result = assess_raw_comment_delete_report(report) self.assertFalse(result["block"]) def test_delete_issue_comment_helper_in_ledger_blocked(self): report = "- Cleanup mutations: delete_issue_comment purged lease comments" result = assess_raw_comment_delete_report(report) self.assertTrue(result["block"]) def test_moot_lease_append_only_passes(self): report = _authorized_cleanup_report() result = assess_raw_comment_delete_report(report) self.assertFalse(result["block"]) class TestAuthorizedReconcilerPath(unittest.TestCase): def test_cleanup_without_mcp_tool_blocked(self): report = "\n".join([ "## Controller Handoff", "- Cleanup mutations: removed branch manually after merge", "- Reconciler capability: prgs-reconciler", ]) result = assess_authorized_reconciler_cleanup_path(report) self.assertTrue(result["block"]) self.assertTrue(any("authorized MCP" in r for r in result["reasons"])) def test_authorized_cleanup_succeeds(self): result = assess_authorized_reconciler_cleanup_path(_authorized_cleanup_report()) self.assertFalse(result["block"]) def test_git_ref_cleanup_without_mcp_tool_blocked(self): report = "\n".join([ "## Controller Handoff", "- Cleanup mutations: none", "- Git ref mutations: git branch -D feat/issue-517-test", "- Reconciler capability: prgs-reconciler", ]) result = assess_authorized_reconciler_cleanup_path(report) self.assertTrue(result["block"]) self.assertTrue( any("Git ref mutations cleanup must name" in r for r in result["reasons"]) ) def test_worktree_cleanup_without_mcp_tool_blocked(self): report = "\n".join([ "## Controller Handoff", "- Cleanup mutations: none", "- Worktree mutations: git worktree remove branches/review-pr542", "- Reconciler capability: prgs-reconciler", ]) result = assess_authorized_reconciler_cleanup_path(report) self.assertTrue(result["block"]) self.assertTrue( any("Worktree mutations cleanup must name" in r for r in result["reasons"]) ) def test_git_fetch_in_git_ref_mutations_not_cleanup_claim(self): report = "\n".join([ "## Controller Handoff", "- Cleanup mutations: none", "- Git ref mutations: git fetch prgs master", ]) result = assess_authorized_reconciler_cleanup_path(report) self.assertFalse(result["block"]) class TestMergerHandoffGuidance(unittest.TestCase): def test_merger_cleanup_without_handoff_blocked(self): report = "Merger deleted remote branch and removed worktree after merge" result = assess_merger_cleanup_handoff_guidance(report) self.assertTrue(result["block"]) def test_merger_cleanup_with_reconciler_handoff_passes(self): report = ( "Merger deleted remote branch; next actor: reconciler for worktree audit" ) result = assess_merger_cleanup_handoff_guidance(report) self.assertFalse(result["block"]) class TestCompositeVerifier(unittest.TestCase): def test_full_authorized_report_passes(self): result = assess_mcp_native_cleanup_proof(_authorized_cleanup_report()) self.assertFalse(result["block"], result["reasons"]) def test_raw_bypasses_fail_composite(self): report = "\n".join([ "## Controller Handoff", "- Merge mutations: gitea_merge_pr", "- Cleanup mutations: git branch -D feat/x; curl -X DELETE .../comments/1", ]) result = assess_mcp_native_cleanup_proof(report) self.assertTrue(result["block"]) self.assertGreaterEqual(len(result["reasons"]), 2) def test_narrative_cleanup_mentions_pass_when_ledgers_none(self): report = "\n".join([ "## Review summary", "Validated workflow §28B MCP-native cleanup guidance.", "Files reviewed describe raw git branch -d and delete_issue_comment blocks.", "", "## Controller Handoff", "- Cleanup mutations: none", "- Git ref mutations: none", "- Worktree mutations: none", ]) result = assess_mcp_native_cleanup_proof(report) self.assertFalse(result["block"], result["reasons"]) def test_git_ref_cleanup_bypass_blocked_in_composite(self): report = "\n".join([ "## Controller Handoff", "- Cleanup mutations: none", "- Git ref mutations: git branch -D feat/issue-517-test", "- Reconciler capability: prgs-reconciler", ]) result = assess_mcp_native_cleanup_proof(report) self.assertTrue(result["block"]) self.assertTrue( any("Git ref mutations cleanup must name" in r for r in result["reasons"]) ) class TestFinalReportValidatorIntegration(unittest.TestCase): def test_validator_blocks_raw_branch_delete_in_review_report(self): report = "\n".join([ "## Controller Handoff", "- Cleanup mutations: git branch -d feat/issue-517-test", ]) result = assess_final_report_validator(report, "review_pr") rules = {f["rule_id"] for f in result["findings"]} self.assertIn("shared.mcp_native_cleanup_proof", rules) def test_validator_passes_authorized_cleanup_report(self): result = assess_final_report_validator(_authorized_cleanup_report(), "review_pr") blocked = [f for f in result["findings"] if f.get("severity") == "block"] mcp_blocks = [ f for f in blocked if f.get("rule_id") == "shared.mcp_native_cleanup_proof" ] self.assertEqual(mcp_blocks, []) def test_validator_passes_narrative_cleanup_mentions_with_none_ledgers(self): report = "\n".join([ "## Review summary", "Workflow §28B documents raw git push --delete and delete_issue_comment blocks.", "", "## Controller Handoff", "- Cleanup mutations: none", "- Git ref mutations: none", "- Worktree mutations: none", ]) result = assess_final_report_validator(report, "review_pr") mcp_blocks = [ f for f in result["findings"] if f.get("rule_id") == "shared.mcp_native_cleanup_proof" and f.get("severity") == "block" ] self.assertEqual(mcp_blocks, []) def test_validator_blocks_git_ref_cleanup_bypass(self): report = "\n".join([ "## Controller Handoff", "- Cleanup mutations: none", "- Git ref mutations: git branch -D feat/issue-517-test", "- Reconciler capability: prgs-reconciler", ]) result = assess_final_report_validator(report, "reconcile_already_landed") rules = {f["rule_id"] for f in result["findings"] if f.get("severity") == "block"} self.assertIn("shared.mcp_native_cleanup_proof", rules) if __name__ == "__main__": unittest.main()