Add final-report mutation ledger verifier (#331)
Introduce assess_mutation_ledger_report so reviewer final reports cannot claim no file edits when the action log records performed mutations. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
"""Tests for final-report mutation ledger verifier (#331)."""
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
from review_proofs import assess_mutation_ledger_report # noqa: E402
|
||||
|
||||
|
||||
class TestMutationLedgerReport(unittest.TestCase):
|
||||
def test_none_claim_with_performed_edit_blocks(self):
|
||||
report = (
|
||||
"Review decision: request_changes.\n"
|
||||
"File edits by reviewer: none\n"
|
||||
)
|
||||
action_log = [
|
||||
{"action": "Edited", "path": "walkthrough.md", "tracked": False},
|
||||
]
|
||||
result = assess_mutation_ledger_report(report, action_log=action_log)
|
||||
self.assertFalse(result["proven"])
|
||||
self.assertTrue(result["file_edits_claimed_none"])
|
||||
|
||||
def test_reported_edit_passes(self):
|
||||
report = (
|
||||
"File edits by reviewer: Edited walkthrough.md (untracked)\n"
|
||||
"Mutation ledger: Edited walkthrough.md untracked in review worktree\n"
|
||||
)
|
||||
action_log = [
|
||||
{
|
||||
"action": "Edited",
|
||||
"path": "walkthrough.md",
|
||||
"tracked": False,
|
||||
"in_repo": True,
|
||||
},
|
||||
]
|
||||
result = assess_mutation_ledger_report(
|
||||
report,
|
||||
action_log=action_log,
|
||||
walkthrough_explicitly_requested=True,
|
||||
)
|
||||
self.assertTrue(result["proven"])
|
||||
|
||||
def test_unreported_mutation_blocks(self):
|
||||
report = "File edits by reviewer: none\n"
|
||||
action_log = [{"action": "Wrote", "path": "/tmp/review-notes.txt"}]
|
||||
result = assess_mutation_ledger_report(report, action_log=action_log)
|
||||
self.assertFalse(result["proven"])
|
||||
self.assertIn("/tmp/review-notes.txt", result["unreported_paths"])
|
||||
|
||||
def test_outside_repo_requires_label(self):
|
||||
report = (
|
||||
"File edits by reviewer: Wrote /tmp/review-notes.txt\n"
|
||||
)
|
||||
action_log = [
|
||||
{
|
||||
"action": "Wrote",
|
||||
"path": "/tmp/review-notes.txt",
|
||||
"outside_repo": True,
|
||||
},
|
||||
]
|
||||
result = assess_mutation_ledger_report(report, action_log=action_log)
|
||||
self.assertFalse(result["proven"])
|
||||
self.assertIn("outside repo", " ".join(result["reasons"]).lower())
|
||||
|
||||
def test_gated_rejection_excluded_from_performed(self):
|
||||
report = "File edits by reviewer: none\nRejected gated calls: submit_pr_review blocked\n"
|
||||
action_log = [
|
||||
{
|
||||
"action": "Edited",
|
||||
"path": "walkthrough.md",
|
||||
"performed": False,
|
||||
"gated_rejected": True,
|
||||
},
|
||||
]
|
||||
result = assess_mutation_ledger_report(report, action_log=action_log)
|
||||
self.assertTrue(result["proven"])
|
||||
self.assertEqual(result["performed_mutations"], [])
|
||||
|
||||
def test_post_status_artifact_requires_final_git_status(self):
|
||||
report = (
|
||||
"File edits by reviewer: Created scratch/notes.md (untracked)\n"
|
||||
)
|
||||
action_log = [
|
||||
{
|
||||
"action": "Created",
|
||||
"path": "scratch/notes.md",
|
||||
"tracked": False,
|
||||
"after_git_status": True,
|
||||
},
|
||||
]
|
||||
result = assess_mutation_ledger_report(
|
||||
report,
|
||||
action_log=action_log,
|
||||
final_git_status_reported=False,
|
||||
)
|
||||
self.assertFalse(result["proven"])
|
||||
self.assertIn("final git status", " ".join(result["reasons"]).lower())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user