Adds #529 acceptance criteria 1/4/5. - post_merge_validation.py: assess_post_merge_validation defines the four canonical validation distinctions (clean pass / baseline-accepted / blocked / post-merge moot) and fails closed on two mistakes: (a) an active approval on a PR already merged/closed before review submission, and (b) post-merge moot validation claimed without merged-state + merge-commit proof. - issue_workflow_labels.py: durable validation:* process-state labels (clean-pass / baseline-accepted / blocked / post-merge-moot) registered in CANONICAL_LABEL_SPECS so manage_labels creates them. - final_report_validator.py: _rule_reviewer_post_merge_validation wired into the review_pr rule set. - tests/test_post_merge_validation.py: module behavior, label registration, and the wired review rule. Refs #529 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
120 lines
4.3 KiB
Python
120 lines
4.3 KiB
Python
"""Post-merge moot validation wording + label tests (#529, criteria 1/4/5)."""
|
|
|
|
import unittest
|
|
|
|
from post_merge_validation import (
|
|
BASELINE_ACCEPTED_OUTCOME,
|
|
BLOCKED_OUTCOME,
|
|
CLEAN_PASS_OUTCOME,
|
|
LABEL_BASELINE_ACCEPTED,
|
|
LABEL_BLOCKED,
|
|
LABEL_CLEAN_PASS,
|
|
LABEL_POST_MERGE_MOOT,
|
|
POST_MERGE_MOOT_OUTCOME,
|
|
assess_post_merge_validation,
|
|
process_state_label,
|
|
)
|
|
from final_report_validator import assess_final_report_validator
|
|
from issue_workflow_labels import CANONICAL_LABELS, VALIDATION_LABELS
|
|
|
|
_MOOT_PROOF = (
|
|
"Validation status: post-merge moot validation\n"
|
|
"PR state: merged\n"
|
|
"Merge commit sha: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b\n"
|
|
"Validation finding: full suite passed, for the record.\n"
|
|
)
|
|
|
|
|
|
class TestPostMergeValidation(unittest.TestCase):
|
|
def test_not_applicable_when_no_merged_or_moot_signal(self):
|
|
result = assess_post_merge_validation(
|
|
"Review decision: approve. Validation: full suite passed."
|
|
)
|
|
self.assertFalse(result["block"])
|
|
self.assertTrue(result["skipped"])
|
|
|
|
def test_active_approval_on_merged_pr_blocked(self):
|
|
report = (
|
|
"PR is already merged. Review decision: approve. "
|
|
"Validation: full suite passed."
|
|
)
|
|
result = assess_post_merge_validation(report)
|
|
self.assertTrue(result["block"])
|
|
self.assertEqual(result["outcome"], POST_MERGE_MOOT_OUTCOME)
|
|
self.assertEqual(result["process_state_label"], LABEL_POST_MERGE_MOOT)
|
|
|
|
def test_active_approval_on_merged_pr_via_structured_signal_blocked(self):
|
|
report = "Review decision: approve. Validation: full suite passed."
|
|
result = assess_post_merge_validation(report, pr_merged_or_closed=True)
|
|
self.assertTrue(result["block"])
|
|
|
|
def test_moot_wording_without_proof_blocked(self):
|
|
report = "Recording post-merge moot validation for this PR."
|
|
result = assess_post_merge_validation(report)
|
|
self.assertTrue(result["block"])
|
|
self.assertTrue(result["reasons"])
|
|
|
|
def test_moot_wording_with_full_proof_allowed(self):
|
|
result = assess_post_merge_validation(_MOOT_PROOF)
|
|
self.assertFalse(result["block"])
|
|
self.assertEqual(result["outcome"], POST_MERGE_MOOT_OUTCOME)
|
|
|
|
def test_merged_signal_only_guides_without_blocking(self):
|
|
result = assess_post_merge_validation(
|
|
"PR was already merged before review; recording findings."
|
|
)
|
|
self.assertFalse(result["block"])
|
|
self.assertTrue(result["safe_next_action"])
|
|
|
|
def test_process_state_label_mapping(self):
|
|
self.assertEqual(process_state_label(CLEAN_PASS_OUTCOME), LABEL_CLEAN_PASS)
|
|
self.assertEqual(
|
|
process_state_label(BASELINE_ACCEPTED_OUTCOME), LABEL_BASELINE_ACCEPTED
|
|
)
|
|
self.assertEqual(process_state_label(BLOCKED_OUTCOME), LABEL_BLOCKED)
|
|
self.assertEqual(
|
|
process_state_label(POST_MERGE_MOOT_OUTCOME), LABEL_POST_MERGE_MOOT
|
|
)
|
|
self.assertIsNone(process_state_label("nonsense"))
|
|
|
|
|
|
class TestValidationLabelsRegistered(unittest.TestCase):
|
|
def test_validation_labels_are_canonical(self):
|
|
for label in (
|
|
LABEL_CLEAN_PASS,
|
|
LABEL_BASELINE_ACCEPTED,
|
|
LABEL_BLOCKED,
|
|
LABEL_POST_MERGE_MOOT,
|
|
):
|
|
self.assertIn(label, VALIDATION_LABELS)
|
|
self.assertIn(label, CANONICAL_LABELS)
|
|
|
|
|
|
class TestPostMergeValidationWiredIntoReview(unittest.TestCase):
|
|
def test_review_pr_blocks_active_approval_on_merged_pr(self):
|
|
report = (
|
|
"PR is already merged. Review decision: approve. "
|
|
"Validation: full suite passed."
|
|
)
|
|
result = assess_final_report_validator(report, "review_pr")
|
|
self.assertTrue(result["blocked"])
|
|
self.assertTrue(
|
|
any(
|
|
f["rule_id"] == "reviewer.post_merge_validation"
|
|
for f in result["findings"]
|
|
)
|
|
)
|
|
|
|
def test_review_pr_allows_proven_post_merge_moot(self):
|
|
result = assess_final_report_validator(_MOOT_PROOF, "review_pr")
|
|
self.assertFalse(
|
|
any(
|
|
f["rule_id"] == "reviewer.post_merge_validation"
|
|
for f in result["findings"]
|
|
)
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|