Merge commit 'b5ee6567aade4fdce4c57d826184bfd01ebb522e' into HEAD

# Conflicts:
#	tests/test_resolve_task_capability.py
This commit is contained in:
2026-07-07 10:18:20 -04:00
20 changed files with 1858 additions and 1 deletions
+68
View File
@@ -479,6 +479,7 @@ import issue_lock_worktree # noqa: E402
import already_landed_reconcile # noqa: E402
import issue_claim_heartbeat # noqa: E402
import merged_cleanup_reconcile # noqa: E402
import review_merge_state_machine # noqa: E402
import native_mcp_preference # noqa: E402
@@ -4274,6 +4275,14 @@ _GUIDE_RULES = {
"inventory, summarize) needs no explicit authorization. Enforced "
"fail closed via subagent_gate.assess_subagent_delegation and "
"validate_subagent_report (#266)."),
"review_merge_state_machine": (
"PR review/merge must follow the enforced state machine: PRECHECK → "
"INVENTORY → SELECT_PR → PIN_HEAD_SHA → CREATE_BRANCHES_WORKTREE → "
"VALIDATE → REVIEW_DECISION → APPROVE_OR_REQUEST_CHANGES → "
"PRE_MERGE_RECHECK → MERGE → POST_MERGE_REPORT. Failed upstream "
"states forbid downstream approve/merge. infra_stop and capability "
"blocks stop immediately. Blocked recovery handoffs must restart the "
"full workflow — never replay approve/merge commands (#290)."),
"native_mcp_preference": (
"Gitea mutations must use native MCP tools first. When MCP is "
"available, block shell scripts, direct API calls, WebFetch, "
@@ -4989,6 +4998,65 @@ def _build_runtime_task_capabilities(
@mcp.tool()
def gitea_assess_review_merge_state_machine(
target_state: str | None = None,
state_completion: dict[str, bool] | None = None,
pre_merge_gates: dict[str, bool] | None = None,
infra_stop: bool = False,
capability_blocked: bool = False,
recovery_handoff_text: str | None = None,
final_report_text: str | None = None,
) -> dict:
"""Read-only: assess enforced PR review/merge workflow state (#290)."""
completion = state_completion or {}
blockers = review_merge_state_machine.assess_workflow_blockers(
infra_stop=infra_stop,
capability_blocked=capability_blocked,
)
result = {
"workflow": review_merge_state_machine.workflow_status(
completion,
infra_stop=infra_stop,
capability_blocked=capability_blocked,
),
"blockers": blockers,
"approve": review_merge_state_machine.can_approve(
completion,
infra_stop=infra_stop,
capability_blocked=capability_blocked,
),
"merge": review_merge_state_machine.can_merge(
completion,
pre_merge_gates=pre_merge_gates,
infra_stop=infra_stop,
capability_blocked=capability_blocked,
),
}
if target_state:
result["advancement"] = review_merge_state_machine.assess_state_advancement(
completion,
target_state=target_state,
infra_stop=infra_stop,
capability_blocked=capability_blocked,
)
if recovery_handoff_text is not None:
result["recovery_handoff"] = (
review_merge_state_machine.assess_blocked_recovery_handoff(
recovery_handoff_text
)
)
if final_report_text is not None:
result["final_report_claims"] = (
review_merge_state_machine.assess_final_report_state_claims(
final_report_text,
state_completion=completion,
approve_completed=bool(completion.get("APPROVE_OR_REQUEST_CHANGES")),
merge_completed=bool(completion.get("MERGE")),
)
)
return result
@mcp.tool()
def gitea_assess_gitea_operation_path(
task: str,