feat: dedicated reconciler capability for closing landed PRs (Closes #309) #379
Labels
Clear labels
allocator
anti-stomp
architecture
bug
chore
codex
concurrency
contamination
control-plane
dashboard
database
design
documentation
enhancement
gitea
glitchtip
important
incident
incident-bridge
integration
jenkins
labels
leases
mcp
mcp-health
mcp-menu
multi-project
mutating
nice-to-have
observability
portability
preflight
protected-branch
queue
read-only
reconnect
recovery
refactor
release
reliability
resumable-review
reviewer
roadmap
safety
security
self-hosted
sentry
stale-runtime
status:blocked
status:in-progress
status:pr-open
status:ready
terminal-lock
testing
tracker
type:bug
type:feature
type:feature
type:guardrail
visibility
workflow
workflow-hardening
workflow-hardening
Controller-owned work allocator
Prevent concurrent LLM session stomping
Architecture / structural design
OpenAI Codex client / workflow session surface
Concurrent session safety
Workflow or session contamination incident
MCP control-plane coordination and allocation authority
MCP operational dashboard/queue view
Internal coordination storage (SQLite/Postgres)
Design / investigation, no implementation
Docs / runbooks
New feature or improvement
Gitea MCP workflow
GlitchTip integration
Operational or process incident requiring durable audit trail
Sentry-to-Gitea incident bridging
Integration testing
Jenkins integration
Label taxonomy management
Lease adopt/release/expire lifecycle
MCP server / tooling
MCP namespace and runtime health
MCP menu surface
Work spanning multiple monitoring projects or Gitea repos
Mutating action; requires gating
Observability, metrics, traces, error reporting
Cross-platform / portability
Shared preflight gates before mutation
Protected branch / stable-branch policy concern
Work queue visibility and allocation
Read-only, no mutation
MCP client reconnect/reload recovery path
Recovery paths for stale/foreign leases
Code refactor / restructure
Release / versioning
Reliability / failure handling
Persist and resume prepared review verdicts across sessions
Reviewer workflow tooling
Roadmap / umbrella issue
Safety rails and fail-closed mutation guards
Security / trust boundary
Self-hosted infrastructure integration
Sentry error monitoring integration
Stale backend daemon / runtime-vs-master parity failures
Issue is blocked
Issue is being worked on
Issue has an open pull request
Issue is ready for work
Terminal review lock (#332) path
Tests / test coverage
Issue tracker hygiene / meta
Bug or defect
Feature or enhancement
Feature or enhancement
Safety gate or guardrail
Workflow state visibility for LLMs/operators
Cross-tool workflow
LLM workflow coordination hardening
LLM workflow coordination hardening
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Scaled-Tech-Consulting/Gitea-Tools#379
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Closes #309.
Already-landed open PRs block the review queue: the already-landed gate correctly stops approval/merge (PR #278 case), but no task path could close the redundant PR, so every review run re-encountered it and stopped. This PR adds the dedicated reconciler close path: exact close capabilities under a new
reconcilerrole, wrong-role routing, and a fail-closed close gate.Changes
task_capability_map.py— new tasksreconcile_close_landed_pr→gitea.pr.closeandreconcile_close_landed_issue→gitea.issue.close, both under a dedicatedreconcilerrole. The role grants no review/approve/request-changes/merge authority, and normal reviewer profiles keep no broad PR-close authority.role_session_router.py— reconciler tasks routewrong_role_stopin author or reviewer sessions with a dedicated recovery message (WRONG_ROLE_RECONCILER_MSG); matching reconciler sessions routeallowed_current_session. Reviewer/author routing untouched.review_proofs.py— newassess_reconciler_close_gate:CLOSE_ALLOWEDonly when every proof passes: PR live-verified open, candidate head SHA pinned (full 40-hex) and matching the live head, target branch freshly fetched with full SHA, head an ancestor of the target, exactgitea.pr.closeproven.NOT_LANDED_CLOSE_BLOCKED— non-landed PRs can never be closed through this path.RECOVERY_HANDOFF_REQUIRED— ancestor proof complete butgitea.pr.closemissing.GATE_NOT_PROVEN— any missing/stale proof (closed PR state, changed head, missing target SHA, unchecked ancestry) fails closed.gitea.issue.closecapability.review/approve/request_changes/merge allowed: Falseand the required final-report field list (identity/profile, close capability proof, PR live state, candidate head SHA, target branch SHA, ancestor proof, linked issue status, PR close result, issue close result, no review/merge confirmation).tests/test_reconciler_close_gate.py— 17 tests: capability map entries, review-permission denial, wrong-role routing, and all gate paths (landed close, non-landed block, stale target, closed PR state, changed head, missing close capability, linked-issue already closed / open with and without capability, review-mutation denial across outcomes).Acceptance criteria mapping (#309)
gitea.pr.closeproduces a recovery handoff.Scope note
Profile provisioning for a concrete
prgs-reconcilerprofile (config/keychain) is #310/#304 territory and intentionally not included; this PR provides the capability map, routing, and gate those issues plug into. #306 duplicates this issue.Validation
python -m pytest tests/in the issue worktree (basec20a936): 1271 passed, 2 failed, 6 skipped, 20 subtests passed.Both failures are pre-existing on the clean base with this change stashed: the #359 artifact-warning test (fix PR #364 open) and
test_final_report_validator.py::TestReviewPrRules::test_clean_reviewer_report_passes, which currently fails on live master without this diff.🤖 Generated with Claude Code
All tests pass successfully after merging master (1405 passed, 1 failed [pre-existing]). Reviewed the implementation of
assess_reconciler_close_gateinreview_proofs.py, task/role session mappings intask_capability_map.pyandrole_session_router.py, and the test suite intests/test_reconciler_close_gate.py. It correctly introduces the dedicated reconciler role tasks to close already-landed open PRs and issues securely without broad reviewer permissions. Verified that the remaining failure is pre-existing on master.