Add safe post-merge moot lease cleanup for already-merged PRs #515

Closed
opened 2026-07-08 03:07:45 -05:00 by jcwalker3 · 7 comments
Owner

Problem

A reviewer/reconciler PR lease (#407) can remain active (or merely look stale) on a PR after that PR has already been merged by another live session. The next LLM session is then left uncertain whether to adopt, force-clean, ignore, or wait for TTL — even though the PR is already merged and the lease is moot.

Observed live: PR #487 merged by a concurrent session (session_id=97274-...) while a separate merger session was mid-preflight to adopt what looked like an orphaned lease. The mandatory final live-state check caught state=closed / merged_at set and stopped the adoption — but nothing gives an explicit, safe resolution for the now-moot lease, and gitea_acquire_reviewer_pr_lease does not itself refuse adoption on an already-merged PR.

Required behavior

  1. Refuse merge-oriented lease adoption on merged/closed PRs. gitea_acquire_reviewer_pr_lease must fail closed (no adoption, no acquisition) when live PR state is merged/closed, with a clear "PR already merged; lease adoption for merge is moot" reason.
  2. Explicit post-merge moot-lease read/cleanup path. Provide a safe way to resolve a lingering lease on an already-merged PR that:
    • only acts when live PR state is merged/closed,
    • never steals or force-cleans an active foreign lease on an open PR,
    • is explicitly scoped as moot/post-merge cleanup,
    • is read-first: reports state before any mutation.
  3. Clear structured report. The tool/report states: PR already merged (merge_commit_sha), issue closure state, lease is moot, cleanup performed or skipped (and why), and that no merge and no adoption occurred.

Acceptance criteria

  • gitea_acquire_reviewer_pr_lease fails closed on a merged/closed PR with a post_merge_moot reason and performs no mutation.
  • A post-merge moot-lease cleanup/read path exists and only operates when live PR state is merged/closed.
  • Cleanup never force-cleans an active foreign lease while the PR is still open.
  • Report clearly distinguishes: merged state, issue closure, lease moot, cleanup performed vs skipped, and asserts no merge/adoption occurred.
  • Tests prove: (a) adoption refused on merged PR, (b) post-merge moot cleanup path is safe and idempotent, (c) open-PR foreign lease is never force-cleaned.
  • No relaxation of #407 reviewer-lease gates or #16 gated-merge gates for open PRs.

Non-goals

  • Changing merge eligibility for open PRs.
  • Stealing or overriding leases on open PRs.
  • Auto-closing issues or deleting branches (out of scope; separate cleanup).

Reference

Materialized during PR #487 / issue #485 merge handling on Scaled-Tech-Consulting/Gitea-Tools. Related: reviewer PR leases #407; gated merge #16; already-landed reconciliation (gitea_reconcile_already_landed_pr).

## Problem A reviewer/reconciler PR lease (#407) can remain `active` (or merely look stale) on a PR **after that PR has already been merged by another live session**. The next LLM session is then left uncertain whether to adopt, force-clean, ignore, or wait for TTL — even though the PR is already merged and the lease is moot. Observed live: PR #487 merged by a concurrent session (`session_id=97274-...`) while a separate merger session was mid-preflight to adopt what looked like an orphaned lease. The mandatory final live-state check caught `state=closed` / `merged_at` set and stopped the adoption — but nothing gives an explicit, safe resolution for the now-moot lease, and `gitea_acquire_reviewer_pr_lease` does not itself refuse adoption on an already-merged PR. ## Required behavior 1. **Refuse merge-oriented lease adoption on merged/closed PRs.** `gitea_acquire_reviewer_pr_lease` must fail closed (no adoption, no acquisition) when live PR state is merged/closed, with a clear "PR already merged; lease adoption for merge is moot" reason. 2. **Explicit post-merge moot-lease read/cleanup path.** Provide a safe way to resolve a lingering lease on an already-merged PR that: - only acts when live PR state is merged/closed, - never steals or force-cleans an *active foreign* lease on an **open** PR, - is explicitly scoped as moot/post-merge cleanup, - is read-first: reports state before any mutation. 3. **Clear structured report.** The tool/report states: PR already merged (merge_commit_sha), issue closure state, lease is moot, cleanup performed or skipped (and why), and that **no merge and no adoption occurred**. ## Acceptance criteria - [ ] `gitea_acquire_reviewer_pr_lease` fails closed on a merged/closed PR with a `post_merge_moot` reason and performs no mutation. - [ ] A post-merge moot-lease cleanup/read path exists and only operates when live PR state is merged/closed. - [ ] Cleanup never force-cleans an active foreign lease while the PR is still open. - [ ] Report clearly distinguishes: merged state, issue closure, lease moot, cleanup performed vs skipped, and asserts no merge/adoption occurred. - [ ] Tests prove: (a) adoption refused on merged PR, (b) post-merge moot cleanup path is safe and idempotent, (c) open-PR foreign lease is never force-cleaned. - [ ] No relaxation of #407 reviewer-lease gates or #16 gated-merge gates for open PRs. ## Non-goals - Changing merge eligibility for open PRs. - Stealing or overriding leases on open PRs. - Auto-closing issues or deleting branches (out of scope; separate cleanup). ## Reference Materialized during PR #487 / issue #485 merge handling on `Scaled-Tech-Consulting/Gitea-Tools`. Related: reviewer PR leases #407; gated merge #16; already-landed reconciliation (`gitea_reconcile_already_landed_pr`).
jcwalker3 added the status:in-progress label 2026-07-08 03:08:07 -05:00
Author
Owner

Issue claim heartbeat

<!-- gitea-issue-claim-heartbeat:v1 --> **Issue claim heartbeat** - kind: claim - issue: #515 - branch: feat/issue-515-post-merge-moot-lease - phase: claimed - profile: prgs-author - pr: none - blocker: none - next_action: create worktree and begin implementation
Author
Owner

Issue claim heartbeat

<!-- gitea-issue-claim-heartbeat:v1 --> **Issue claim heartbeat** - kind: claim - issue: #515 - branch: feat/issue-515-post-merge-moot-lease - phase: claimed - profile: prgs-author - pr: none - blocker: none - next_action: create worktree and begin implementation
Author
Owner

Issue claim heartbeat

<!-- gitea-issue-claim-heartbeat:v1 --> **Issue claim heartbeat** - kind: claim - issue: #515 - branch: feat/issue-515-post-merge-moot-lease - phase: claimed - profile: prgs-author - pr: none - blocker: none - next_action: create worktree and begin implementation
Author
Owner

Issue claim heartbeat

<!-- gitea-issue-claim-heartbeat:v1 --> **Issue claim heartbeat** - kind: progress - issue: #515 - branch: feat/issue-515-post-merge-moot-lease - phase: create_pr - profile: prgs-author - pr: none - blocker: none - next_action: gitea_create_pr
Author
Owner

Issue claim heartbeat

<!-- gitea-issue-claim-heartbeat:v1 --> **Issue claim heartbeat** - kind: progress - issue: #515 - branch: feat/issue-515-post-merge-moot-lease - phase: pr_open - profile: prgs-author - pr: 527 - blocker: none - next_action: reviewer_review
sysadmin removed the status:in-progress label 2026-07-08 04:02:25 -05:00
Author
Owner

Controller Closure Comment

  • PR #527: Merged successfully at commit af938064cd7558872af888c41eef64380ff0a111.
  • Validation: Accepted. All targeted tests passed.
  • Suite Results: The single failure (test_merge_blocked_on_stale_approval_head) was verified as a baseline failure pre-existing on master. All other 1822 tests passed.
  • Reviewer Lease: Verified as moot and safely released.
  • Closure: This issue is now resolved and closed.
### Controller Closure Comment - **PR #527**: Merged successfully at commit `af938064cd7558872af888c41eef64380ff0a111`. - **Validation**: Accepted. All targeted tests passed. - **Suite Results**: The single failure (`test_merge_blocked_on_stale_approval_head`) was verified as a baseline failure pre-existing on master. All other 1822 tests passed. - **Reviewer Lease**: Verified as moot and safely released. - **Closure**: This issue is now resolved and closed.
Author
Owner

Controller Audit Correction Comment

  1. Tool Namespace Clarification: The reconciler tools are hosted on the gitea-reviewer MCP server, which dynamically delegates and enforces role-scoped policies. This allows a prgs-reconciler session to call reconciler-mapped tools on this server.
  2. Baseline Verification: The failing test TestMergePR.test_merge_blocked_on_stale_approval_head has been verified to fail on the pre-merge base commit c54ac0d4de85d3f6b5246327b3200a6a39282933 (before PR #527 was merged). This confirms it is a long-standing baseline failure and not a regression of PR #527.
  3. Root Checkout Update: The root checkout fast-forward (git merge prgs/master --ff-only) was performed to align the baseline with prgs/master and keep the stable control checkout current, as authorized by the controller queue management process.
### Controller Audit Correction Comment 1. **Tool Namespace Clarification**: The reconciler tools are hosted on the `gitea-reviewer` MCP server, which dynamically delegates and enforces role-scoped policies. This allows a `prgs-reconciler` session to call reconciler-mapped tools on this server. 2. **Baseline Verification**: The failing test `TestMergePR.test_merge_blocked_on_stale_approval_head` has been verified to fail on the pre-merge base commit `c54ac0d4de85d3f6b5246327b3200a6a39282933` (before PR #527 was merged). This confirms it is a long-standing baseline failure and not a regression of PR #527. 3. **Root Checkout Update**: The root checkout fast-forward (`git merge prgs/master --ff-only`) was performed to align the baseline with `prgs/master` and keep the stable control checkout current, as authorized by the controller queue management process.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Scaled-Tech-Consulting/Gitea-Tools#515