Merge remote-tracking branch 'prgs/master' into feat/issue-507-controller-thread-ledger
# Conflicts: # gitea_mcp_server.py
This commit is contained in:
@@ -35,6 +35,9 @@ def _review_handoff(**overrides):
|
||||
"- External-state mutations: none",
|
||||
"- Read-only diagnostics: issue and PR metadata inspected",
|
||||
"- Current status: PR open",
|
||||
"- Next actor: author",
|
||||
"- Next action: address review feedback",
|
||||
"- Next prompt: Fix PR #203 per reviewer request_changes and push updated head",
|
||||
"- Blockers: none",
|
||||
"- Next: await author",
|
||||
"- Safety: no self-review; no self-merge",
|
||||
@@ -92,6 +95,9 @@ def _reconcile_handoff(drop=(), **overrides):
|
||||
"- Read-only diagnostics: gitea_view_pr, gitea_view_issue",
|
||||
"- Reconciliation mutations: PR comment posted",
|
||||
"- Current status: reconciliation complete",
|
||||
"- Next actor: reconciler",
|
||||
"- Next action: close PR #99 after capability proof",
|
||||
"- Next prompt: Reconcile already-landed PR #99 with prgs-reconciler profile",
|
||||
"- Blocker: missing gitea.pr.close capability",
|
||||
"- Safe next action: hand off to a profile with gitea.pr.close",
|
||||
"- No review/merge confirmation: confirmed",
|
||||
@@ -520,6 +526,81 @@ class TestCanonicalReconcileSchema(unittest.TestCase):
|
||||
)
|
||||
|
||||
|
||||
class TestReconcilerCloseProof(unittest.TestCase):
|
||||
"""Issue #306: a reconciler PR close must carry its proof fields."""
|
||||
|
||||
def _closed_report(self, **kwargs):
|
||||
# A report that claims PR #99 was closed via the reconciler path.
|
||||
report = (
|
||||
_reconcile_handoff(**kwargs)
|
||||
.replace(
|
||||
"- Capabilities proven: gitea.read, gitea.pr.comment",
|
||||
"- Capabilities proven: gitea.read, gitea.pr.comment, gitea.pr.close",
|
||||
)
|
||||
.replace("- Missing capabilities: gitea.pr.close", "- Missing capabilities: none")
|
||||
.replace("- PRs closed: none", "- PRs closed: #99")
|
||||
.replace(
|
||||
"- Blocker: missing gitea.pr.close capability", "- Blocker: none"
|
||||
)
|
||||
)
|
||||
return report
|
||||
|
||||
def test_full_proof_close_passes(self):
|
||||
result = assess_final_report_validator(
|
||||
self._closed_report(), "reconcile_already_landed"
|
||||
)
|
||||
self.assertEqual(result["grade"], "A")
|
||||
self.assertFalse(
|
||||
any(f["rule_id"] == "reconcile.close_proof_fields" for f in result["findings"])
|
||||
)
|
||||
|
||||
def test_close_without_capability_proof_blocks(self):
|
||||
# Claims PRs closed: #99 but never proves gitea.pr.close capability.
|
||||
report = _reconcile_handoff().replace("- PRs closed: none", "- PRs closed: #99")
|
||||
result = assess_final_report_validator(report, "reconcile_already_landed")
|
||||
self.assertTrue(result["blocked"])
|
||||
self.assertTrue(
|
||||
any(f["rule_id"] == "reconcile.close_proof_fields" for f in result["findings"])
|
||||
)
|
||||
|
||||
def test_close_without_ancestor_proof_blocks(self):
|
||||
report = self._closed_report(drop=("Ancestor proof",))
|
||||
result = assess_final_report_validator(report, "reconcile_already_landed")
|
||||
self.assertTrue(result["blocked"])
|
||||
self.assertTrue(
|
||||
any(f["rule_id"] == "reconcile.close_proof_fields" for f in result["findings"])
|
||||
)
|
||||
|
||||
def test_close_without_linked_issue_result_blocks(self):
|
||||
report = self._closed_report(drop=("Linked issue live status", "Issues closed"))
|
||||
result = assess_final_report_validator(report, "reconcile_already_landed")
|
||||
self.assertTrue(result["blocked"])
|
||||
self.assertTrue(
|
||||
any(f["rule_id"] == "reconcile.close_proof_fields" for f in result["findings"])
|
||||
)
|
||||
|
||||
def test_close_lock_requires_proof_even_if_text_says_none(self):
|
||||
# Session lock proves a PR was closed; the report omits close proof.
|
||||
result = assess_final_report_validator(
|
||||
_reconcile_handoff(),
|
||||
"reconcile_already_landed",
|
||||
reconciler_close_lock={"pr_closed": True},
|
||||
)
|
||||
self.assertTrue(result["blocked"])
|
||||
self.assertTrue(
|
||||
any(f["rule_id"] == "reconcile.close_proof_fields" for f in result["findings"])
|
||||
)
|
||||
|
||||
def test_comment_only_reconcile_needs_no_close_proof(self):
|
||||
result = assess_final_report_validator(
|
||||
_reconcile_handoff(), "reconcile_already_landed"
|
||||
)
|
||||
self.assertEqual(result["grade"], "A")
|
||||
self.assertFalse(
|
||||
any(f["rule_id"] == "reconcile.close_proof_fields" for f in result["findings"])
|
||||
)
|
||||
|
||||
|
||||
class TestEntryPoint(unittest.TestCase):
|
||||
def test_unknown_task_kind_blocks(self):
|
||||
result = assess_final_report_validator("report", "unknown_mode")
|
||||
|
||||
Reference in New Issue
Block a user