feat: merge-report lease proof fields and handoff audit (#535)

Surface lease_proof_source / recovery reason from sanctioned session
provenance on gitea_merge_pr results, and block final reports that claim
manual/seeded/injected lease proof without MCP adoption evidence.

Closes #535
This commit is contained in:
2026-07-09 12:56:12 -04:00
parent c738e5b10d
commit 2b4c291f12
5 changed files with 330 additions and 0 deletions
+97
View File
@@ -781,6 +781,103 @@ class TestMergePrRules(unittest.TestCase):
self.assertEqual(result["grade"], "A")
self.assertFalse(result["blocked"])
def test_manual_seeded_lease_claim_blocks_without_mcp_evidence(self):
lines = [
"## Controller Handoff",
"",
"- Task: merge PR #203",
"- Repo: Scaled-Tech-Consulting/Gitea-Tools",
"- Role: merger",
"- Identity: sysadmin / prgs-merger",
"- Issue/PR: #182 / PR #203",
"- Branch/SHA: feat/x @ 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Files changed: review_proofs.py",
"- Validation: pytest in branches/review-203",
"- Mutations: merge completed",
"- File edits by reviewer: none",
"- Worktree/index mutations: none",
"- Git ref mutations: git fetch prgs master",
"- MCP/Gitea mutations: merge completed",
"- Review mutations: none",
"- Merge mutations: merged using manually seeded lease proof",
"- Cleanup mutations: none",
"- External-state mutations: none",
"- Read-only diagnostics: metadata check",
"- Current status: PR merged",
"- Blockers: none",
"- Next: none",
"- Safety: review and merge are separate roles",
"- Selected PR: #203",
"- Pinned reviewed head: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Reviewed head SHA: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Final live head SHA before approval: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Final live head SHA before merge: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Push occurred during validation: no",
"- Active profile: prgs-merger",
"- Role kind: merger",
"- Merge capability source: profile",
"- Explicit operator authorization: MERGE PR 203",
"- Expected head SHA: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Approval at current head: yes",
"- Merge result: PR merged successfully",
"- Cleanup status: complete",
]
report = "\n".join(lines)
result = assess_final_report_validator(report, "merge_pr")
self.assertTrue(result["blocked"])
codes = {f.get("rule_id") for f in result.get("findings") or []}
self.assertIn("shared.manual_lease_proof_handoff", codes)
def test_manual_seeded_claim_allowed_when_adoption_cited(self):
lines = [
"## Controller Handoff",
"",
"- Task: merge PR #203",
"- Repo: Scaled-Tech-Consulting/Gitea-Tools",
"- Role: merger",
"- Identity: sysadmin / prgs-merger",
"- Issue/PR: #182 / PR #203",
"- Branch/SHA: feat/x @ 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Files changed: review_proofs.py",
"- Validation: pytest in branches/review-203",
"- Mutations: merge completed",
"- File edits by reviewer: none",
"- Worktree/index mutations: none",
"- Git ref mutations: git fetch prgs master",
"- MCP/Gitea mutations: gitea_adopt_merger_pr_lease then merge",
"- Review mutations: none",
"- Merge mutations: historical manual seed replaced by sanctioned adoption",
"- Cleanup mutations: none",
"- External-state mutations: none",
"- Read-only diagnostics: metadata check",
"- Current status: PR merged",
"- Blockers: none",
"- Next: none",
"- Safety: review and merge are separate roles",
"- Selected PR: #203",
"- Pinned reviewed head: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Reviewed head SHA: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Final live head SHA before approval: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Final live head SHA before merge: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Push occurred during validation: no",
"- Active profile: prgs-merger",
"- Role kind: merger",
"- Merge capability source: profile",
"- Explicit operator authorization: MERGE PR 203",
"- Expected head SHA: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
"- Approval at current head: yes",
"- lease_proof_source: gitea_adopt_merger_pr_lease",
"- lease_proof_kind: sanctioned_adoption",
"- adoption_comment_id: 8288",
"- Merge result: PR merged successfully",
"- Cleanup status: complete",
]
report = "\n".join(lines)
result = assess_final_report_validator(report, "merge_pr")
self.assertFalse(result["blocked"])
codes = {f.get("rule_id") for f in result.get("findings") or []}
self.assertNotIn("shared.manual_lease_proof_handoff", codes)
def test_missing_merger_fields_blocks(self):
lines = [
"## Controller Handoff",