Harden gitea_acquire_merger_pr_lease with required candidate_head, live-head
match, and fail-closed POST handling. Add capability-map aliases for reviewer
and merger lease acquire/adopt. Make unknown tasks return structured
unknown_task (no ValueError escape). Expand tests for roles, head scoping,
aliases, and unknown_task.
Closes#718. Addresses #723 resolver unknown_task and lease task mapping.
This implements the native merger lease acquisition tool to allow a merger session to acquire its own lease when a reviewer lease does not exist or has expired, unblocking #679 adoption.
EXCEPTIONAL OPERATOR-AUTHORIZED BREAK-GLASS RECOVERY - incident #722.
Commit 970e68b ("fix: adopt_merger_pr_lease requires merger role") was an
unreviewed direct push that flipped 11 task_capability_map.py entries to
role="merger" instead of the intended 1. Merger profiles forbid the review
permissions, so no configured profile could resolve review_pr / approve_pr /
request_changes_pr (matching_configured_profile was empty repository-wide)
and no fix PR could be formally reviewed. The operator resolved the catch-22
with a one-time break-glass authorization recorded on issue #722
(comment 11918); this commit is the authorized minimum and nothing more.
Changes:
- task_capability_map.py restored to blob 02826af (the preserved intended
correction, local commit c071f8a1): the 10 regressive entries return to
role="reviewer"; adopt_merger_pr_lease keeps role="merger"; merge_pr is
untouched.
- tests/test_task_capability_role_invariants.py added (#723 AC1/AC2):
profile-coverage invariant for formal review tasks, map/router agreement,
merger-only adopt_merger_pr_lease and merge_pr, merger profiles cannot
hold review permissions.
Validation: focused role-mapping tests 72 passed (+22 subtests); full suite
2900 passed, 6 skipped, 1 known warning, 195 subtests.
Recovery step 1 for incident #722; code-defect follow-ups tracked in #723.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EnHNSVQvJ8nCk7KZ9kL4Ym
Prevent merger-local empty decision locks from standing in for reviewer
terminal cleanup, refuse silent re-init overwrite of unresolved terminal
evidence, record post-merge recovery-required state when audit fails, and
add a truthful irrecoverable-provenance path that never claims applied=true.
Closes#709
Bind mutation/credential paths to a process-local native MCP runtime so env
spoofing, direct imports, and offline helpers cannot reconstruct session gates
after native transport failure. Quarantine contaminated formal reviews under
controller authority and honor quarantine in review feedback, merge eligibility,
merge mutation, and canonical handoff validation. Add regression coverage for
the second (PR #694 / review 427) incident class.
Prevent foreign open-PR terminals on the durable review-decision lock from
blocking fresh formal reviews. Scope correction authorization to the named
prior review's PR/head, add read-only diagnosis with exact next_action and
durable handoff payloads, require thread-visible correction audits, and
cover the PR #688 → #692 recovery sequence in regression tests.
Add fail-closed assessment and MCP tool for expired/superseded-head
comment-backed reviewer leases that lack a control-plane lease_id.
- assess_obsolete_reviewer_comment_lease_cleanup eligibility matrix
- diagnose classifications: foreign_active_current_head,
foreign_expired_current_head, foreign_completed_superseded_head,
foreign_expired_superseded_head, orphaned_owner_missing,
ambiguous_conflicting_evidence
- gitea_cleanup_obsolete_reviewer_comment_lease with confirmation
CLEANUP OBSOLETE REVIEWER LEASE <n> and controller_recovery_authorized
- preserve audit history via append-only phase=released marker
- never repoint, transfer validation, use PID ownership, or steal
active current-head foreign leases
- regression for PR #688 lease comment 10749 after recorded expiry
Address REQUEST_CHANGES on PR #680:
Blocker A — role vs capability agreement
- authorization_compatible allows reviewer/merger when they hold the task's
required permission (e.g. gitea.issue.comment on comment_issue/mark_issue/
set_issue_labels/lock_issue) without broad role-bypass.
- Unauthorized escalation without the permission remains fail closed.
- Regression coverage for allowed and denied reviewer/merger cases.
Blocker B — MUTATION_TASKS matches runtime wiring
- Remove unenforced entries; document dedicated-gate exclusions
(mark_final_review_decision, save/resume_review_draft, etc.).
- Wire non-closing gitea_edit_pr as edit_pr; acquire lease uses
acquire_reviewer_pr_lease task through verify_preflight_purity.
- Inventory↔wiring consistency tests replace set-membership-only coverage.
Blocker C — entrypoint side-effect ordering
- Behavioral tests for merge_pr, submit_pr_review, and comment_issue prove
the assessor block aborts before Gitea API mutation and local durable writes.
Validation: 43 focused anti-stomp + related suites green; full suite
2639 passed / 6 skipped.
Closes#604
Add phase-1 observability bridge that turns provider observations into
normal Gitea issues and control-plane incident_links rows. Dry-run is
default; apply creates/links through sanctioned Gitea issue paths only.
Raw incidents remain non-assignable; the #600 allocator sees bridge work
only as ordinary Gitea issues. Builds on #613 substrate and #600 allocator.
Closes#612
Add gitea_allocate_next_work and allocator_service routing policy on top of
the #613 ControlPlaneDB substrate. Workers get atomic assign+lease results
(or wait/no_safe_work/terminal-path outcomes) without self-selecting work
via file locks or comment-only leases. #612 remains downstream.
Closes#600
Durable review-decision locks (#559) can outlive the PR they protect.
When the last terminal mutation references a PR that is already
merged/closed, expose gitea_cleanup_stale_review_decision_lock so a
reviewer can clear the lock with identity/profile gates and a durable
audit trail — without weakening #332 for open PRs or deleting
session-state files by hand.
Also auto-clear same-profile locks after a successful merge of the
approved PR, and document allowed vs forbidden cleanup.
Closes#594
Replace manual in-process _SESSION_LEASE seeding with an auditable
gitea_adopt_merger_pr_lease tool that posts durable adoption proof and
records sanctioned session provenance. Mutation gates now reject bare
record_session_lease calls without provenance from acquire/adopt/heartbeat.
Closes#536
Add audit vs cleanup phase tracking so reconciliation audits stay read-only
unless cleanup is explicitly authorized with delete capability proof, safety
proof, and before/after snapshots. Block gitea_delete_branch and merged-cleanup
execution during audit phase, validate final reports for false no-mutations
claims, and document the boundary in the reconcile-landed-pr workflow.
Merge prgs/master into feat/issue-139-role-aware-work-issue-routing and
keep both work-issue task routing entries and reconcile-landed-pr entries
in task_capability_map.py.
Adds canonical pr-queue-cleanup workflow, report verifier, reviewer-only task
routing, and runbook guidance so operators can drain open PRs one canonical
review at a time with fail-closed boundaries on batching and unauthorized merges.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
- Map work_issue/work-issue to author role and gitea.pr.create in resolver
- Route work-issue sessions through role_session_router before mutations
- Expose work_issue in runtime context task capabilities
- Add work-issue workflow source verifier and canonical routing docs
- Tests for resolver, router, and final-report verifier
Closes#139
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Expose read-only assess/scan tools and capability planning so already-landed
open PRs can be reconciled without review or merge. Register the
gitea-reconcile-landed-pr skill and workflow-source verification.
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.