feat(author-workflow): enforce exact issue lock before branch/commit/push/PR (Issue #204)
Recreation of the #204 work from closed PR #205 (invalid provenance), rebuilt cleanly on master under the prgs author identity with no PR #203 content: - Add gitea_lock_issue MCP tool: locks exactly one issue to its branch name, fails closed on branch/issue-number mismatch and on issues already tied to an open PR (by head branch or Closes/Fixes reference). - gitea_create_pr now requires the issue lock: head must match the locked branch, title/body must contain Closes/Fixes #<locked issue> exactly, and ambiguous references (equivalent / related / same as) are rejected. - scripts/worktree-start refuses to create an issue-linked worktree unless the lock file exists and matches the requested branch. - assess_controller_handoff rejects handoffs whose selected issue / opened PR fields carry multiple numbers or fuzzy equivalence wording. - Tests: TestIssueLocking (lock + create_pr gates), handoff exact-reference tests, worktree-start lock coverage. Closes #204 Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
@@ -838,6 +838,40 @@ class TestControllerHandoff(unittest.TestCase):
|
||||
self.assertEqual(result["verdict"], "incomplete")
|
||||
self.assertIn("No review/merge confirmation", result["missing_fields"])
|
||||
|
||||
def test_author_role_rejects_equivalent_or_multiple_issues(self):
|
||||
# 1. equivalent reference blocked
|
||||
incomplete_eq = self.BASE_HANDOFF + "\n" + "\n".join([
|
||||
"- Selected issue: Issue #194 / #196 equivalent",
|
||||
"- Claim/comment status: comment-claimed",
|
||||
"- PR number opened: #999",
|
||||
"- No review/merge: confirmed",
|
||||
])
|
||||
res = assess_controller_handoff(incomplete_eq, role="author")
|
||||
self.assertEqual(res["verdict"], "incomplete")
|
||||
self.assertIn("Selected issue", res["missing_fields"])
|
||||
|
||||
# 2. multiple issues blocked
|
||||
incomplete_multi = self.BASE_HANDOFF + "\n" + "\n".join([
|
||||
"- Selected issue: #194, #196",
|
||||
"- Claim/comment status: comment-claimed",
|
||||
"- PR number opened: #999",
|
||||
"- No review/merge: confirmed",
|
||||
])
|
||||
res = assess_controller_handoff(incomplete_multi, role="author")
|
||||
self.assertEqual(res["verdict"], "incomplete")
|
||||
self.assertIn("Selected issue", res["missing_fields"])
|
||||
|
||||
def test_author_role_rejects_fuzzy_pr_number(self):
|
||||
incomplete_pr = self.BASE_HANDOFF + "\n" + "\n".join([
|
||||
"- Selected issue: #196",
|
||||
"- Claim/comment status: comment-claimed",
|
||||
"- PR number opened: PR #203 / #204 equivalent",
|
||||
"- No review/merge: confirmed",
|
||||
])
|
||||
res = assess_controller_handoff(incomplete_pr, role="author")
|
||||
self.assertEqual(res["verdict"], "incomplete")
|
||||
self.assertIn("PR number opened", res["missing_fields"])
|
||||
|
||||
def test_inventory_role_requires_inventory_fields(self):
|
||||
complete = self.BASE_HANDOFF + "\n" + "\n".join([
|
||||
"- Repositories checked: Gitea-Tools, mcp-control-plane",
|
||||
|
||||
Reference in New Issue
Block a user