feat: add prgs-reconciler profile and gated already-landed PR close (Closes #310)

Introduce a dedicated reconciler role with gitea_reconcile_already_landed_pr,
which closes open PRs only after live fetch and ancestor proof against a fresh
target branch. Document the gitea-reconciler namespace and extend task routing.
This commit is contained in:
2026-07-07 09:20:50 -04:00
parent 0fe8f57dda
commit 9cf1b41b77
12 changed files with 750 additions and 2 deletions
+43
View File
@@ -72,6 +72,14 @@ AUTHOR_TASKS = frozenset({
"comment_pr",
"address_pr_change_requests",
"delete_branch",
"work_issue",
"work-issue",
})
RECONCILER_TASKS = frozenset({
"reconcile_already_landed_pr",
"reconcile_already_landed",
"reconcile-landed-pr",
})
TASK_REQUIRED_ROLE = {
@@ -90,12 +98,21 @@ TASK_REQUIRED_ROLE = {
"blind_pr_queue_review": "reviewer",
"request_changes_pr": "reviewer",
"approve_pr": "reviewer",
"work_issue": "author",
"work-issue": "author",
"reconcile_already_landed_pr": "reconciler",
"reconcile_already_landed": "reconciler",
"reconcile-landed-pr": "reconciler",
}
WRONG_ROLE_REVIEWER_MSG = (
"Wrong role/session for reviewer task. Launch reviewer MCP namespace."
)
WRONG_ROLE_RECONCILER_MSG = (
"Wrong role/session for reconciler task. Launch reconciler MCP namespace."
)
_session_last_route: dict | None = None
@@ -191,6 +208,32 @@ def route_task_session(
_record_route(result)
return result
if required_role == "reconciler":
message = WRONG_ROLE_RECONCILER_MSG
if active_role_kind == "reconciler":
message = (
"Reconciler task requires gitea.pr.close on a dedicated "
"reconciler profile."
)
result = {
"task_type": task_type,
"required_role": required_role,
"active_role": active_role_kind,
"active_profile": active_profile,
"route_result": ROUTE_WRONG_ROLE,
"downstream_allowed": False,
"reasons": [
message,
"Reconciler tasks cannot run in author or reviewer sessions.",
"Static-profile mode does not permit in-place role switching.",
],
"message": WRONG_ROLE_RECONCILER_MSG,
"runtime_switching_supported": runtime_switching_supported,
"profile_switch_blocked": not runtime_switching_supported,
}
_record_route(result)
return result
if required_role == "author":
route = ROUTE_TO_AUTHOR
message = (