fix(worktree-audit): make cleanup audit merged-PR aware for issue worktrees (Closes #858) #859

Merged
sysadmin merged 1 commits from fix/issue-858-audit-merged-pr-aware into master 2026-07-23 22:02:23 -05:00
Owner

Closes #858

Problem

gitea_audit_worktree_cleanup had no merged-PR linkage, so an issue_work worktree reported pr_number=null and stayed active_issue_work / removable=false forever — even once its PR was merged and its head was already contained in master. The PR-aware assessor disagreed on the same on-disk state.

Measured on live master 9301739910df before this change: 42 issue_work worktrees, removable=true on 0, pr_number populated on 0. For branches/issue-637-timeline-model (merged PR #849, clean, unleased, unlocked, unprotected) gitea_reconcile_merged_cleanups reported safe_to_remove_worktree=true with block_reasons=[] while the audit reported pr_number=null, active_issue_work, removable=false.

Root cause

Two independent gaps:

  1. No PR linkage existed. audit_branches_directory called build_worktree_metadata without a pr_number, and the MCP tool fetched only pulls?state=open. Merged PRs were never read, so there was no ownership evidence to reason from.
  2. clean_stale_removable was unreachable for issue_work. That path required ttl_expired, computed from metadata["last_used_at"], which build_worktree_metadata never populates; is_ttl_expired fail-safes to False on an unknown timestamp. The final return CLASS_ACTIVE_ISSUE_WORK was therefore the only reachable outcome for a clean issue worktree.

Change

Deterministic linkage plus a full-policy gate, all in the existing assessor:

  • build_pr_index / resolve_owning_pr link a worktree branch to exactly one owning PR. Competing PRs on one branch, a still-open owner, a head-branch mismatch, malformed records, or absent PR state all fail closed — while still reporting the pr_number that was resolved.
  • assess_merged_pr_worktree_cleanup requires every condition before a worktree may become removable: conclusive merged ownership, branch agreement, containment of the head in authoritative master, no open or competing PR, no active lease, no issue lock, no live session, a clean tree, and a non-protected checkout. Anything unknown blocks.
  • Containment reuses merged_cleanup_reconcile.is_head_ancestor_of_ref, so the audit and the PR-scoped reconciler agree on what "already landed" means. Head containment is also what proves no unmerged commits remain.

Lease evidence is now actually supplied

audit_branches_directory already accepted leased_branches, but the MCP tool never passed it — has_active_lease was false for all 90 worktrees in a live run. That was inert only because issue worktrees could never become removable. Since this change makes removability reachable, leaving it unwired would have turned a dormant gap into a real hole, so the tool now reads authoritative control-plane leases and fails closed when they cannot be read.

Lease protection by issue number is scoped to issue_work worktrees, so a lease on issue N protects that issue's own work worktree and not a baseline or review scratch tree that merely carries the same marker in its name.

Deliberate behaviour change

issue_work no longer becomes removable on TTL age alone. Age is not proof that a branch landed, and the old rule would have reclaimed a worktree still holding unmerged commits. The existing test asserting that rule was updated to the stricter policy. conflict_fix keeps its original TTL behaviour; review, baseline, merge-simulation, detached, dirty, open-PR, and protected classifications are unchanged. In production the TTL path was already unreachable, so no live classification regresses.

Safety

The assessor still deletes nothing and gains no cleanup mutation; performed stays False. Two tests assert no removal occurs and that no destructive git command is shelled out. Fail-closed behaviour is preserved for unknown ownership, linkage, merge state, containment, cleanliness, and protection state.

Tests

New tests/test_issue_858_audit_merged_pr_aware.py (31 tests) plus updates to tests/test_worktree_cleanup_audit.py, covering: a clean merged worktree becoming linked and removable; pr_number populated from authoritative linkage; open-PR, dirty, untracked-only, active-lease, active-lock, live-session, unmerged-head, unknown-containment, and control-checkout cases all remaining non-removable; ambiguous and competing linkage failing closed; other worktree classifications left intact; and agreement with the PR-scoped reconciler on a real throwaway git repository. Tests use fabricated temporary repositories and synthetic records only.

Focused and neighbouring suites: 174 tests pass. A full sweep of 246 test modules was run on this branch and on authoritative master 9301739910df using an identical procedure; every module's status matches the baseline exactly, apart from the new module and the one added test. The 153 modules that fail here fail identically on master (environment-dependent, pre-existing).

Scope boundary against #855

Issue #855 is the reconciler-executor gap: a PR-scoped target for gitea_reconcile_merged_cleanups and expired-lease reclaim on merged branches. This PR is assessor-side only and additive. It adds no PR-scoped executor, changes no lease reclaim policy, and does not touch the batch reconciliation path.

Untouched

No cleanup was performed. PR #849's worktree branches/issue-637-timeline-model and its remote branch are retained as the reproduction fixture; issue #637, PR #849, issue #850, and PR #853 were not modified.

Closes #858 ## Problem `gitea_audit_worktree_cleanup` had no merged-PR linkage, so an `issue_work` worktree reported `pr_number=null` and stayed `active_issue_work` / `removable=false` forever — even once its PR was merged and its head was already contained in master. The PR-aware assessor disagreed on the same on-disk state. Measured on live master `9301739910df` before this change: 42 `issue_work` worktrees, `removable=true` on 0, `pr_number` populated on 0. For `branches/issue-637-timeline-model` (merged PR #849, clean, unleased, unlocked, unprotected) `gitea_reconcile_merged_cleanups` reported `safe_to_remove_worktree=true` with `block_reasons=[]` while the audit reported `pr_number=null`, `active_issue_work`, `removable=false`. ## Root cause Two independent gaps: 1. **No PR linkage existed.** `audit_branches_directory` called `build_worktree_metadata` without a `pr_number`, and the MCP tool fetched only `pulls?state=open`. Merged PRs were never read, so there was no ownership evidence to reason from. 2. **`clean_stale_removable` was unreachable for `issue_work`.** That path required `ttl_expired`, computed from `metadata["last_used_at"]`, which `build_worktree_metadata` never populates; `is_ttl_expired` fail-safes to `False` on an unknown timestamp. The final `return CLASS_ACTIVE_ISSUE_WORK` was therefore the only reachable outcome for a clean issue worktree. ## Change Deterministic linkage plus a full-policy gate, all in the existing assessor: - `build_pr_index` / `resolve_owning_pr` link a worktree branch to exactly one owning PR. Competing PRs on one branch, a still-open owner, a head-branch mismatch, malformed records, or absent PR state all fail closed — while still reporting the `pr_number` that was resolved. - `assess_merged_pr_worktree_cleanup` requires **every** condition before a worktree may become removable: conclusive merged ownership, branch agreement, containment of the head in authoritative master, no open or competing PR, no active lease, no issue lock, no live session, a clean tree, and a non-protected checkout. Anything unknown blocks. - Containment reuses `merged_cleanup_reconcile.is_head_ancestor_of_ref`, so the audit and the PR-scoped reconciler agree on what "already landed" means. Head containment is also what proves no unmerged commits remain. ## Lease evidence is now actually supplied `audit_branches_directory` already accepted `leased_branches`, but the MCP tool never passed it — `has_active_lease` was `false` for all 90 worktrees in a live run. That was inert only because issue worktrees could never become removable. Since this change makes removability reachable, leaving it unwired would have turned a dormant gap into a real hole, so the tool now reads authoritative control-plane leases and fails closed when they cannot be read. Lease protection by issue number is scoped to `issue_work` worktrees, so a lease on issue N protects that issue's own work worktree and not a baseline or review scratch tree that merely carries the same marker in its name. ## Deliberate behaviour change `issue_work` no longer becomes removable on TTL age alone. Age is not proof that a branch landed, and the old rule would have reclaimed a worktree still holding unmerged commits. The existing test asserting that rule was updated to the stricter policy. `conflict_fix` keeps its original TTL behaviour; review, baseline, merge-simulation, detached, dirty, open-PR, and protected classifications are unchanged. In production the TTL path was already unreachable, so no live classification regresses. ## Safety The assessor still deletes nothing and gains no cleanup mutation; `performed` stays `False`. Two tests assert no removal occurs and that no destructive git command is shelled out. Fail-closed behaviour is preserved for unknown ownership, linkage, merge state, containment, cleanliness, and protection state. ## Tests New `tests/test_issue_858_audit_merged_pr_aware.py` (31 tests) plus updates to `tests/test_worktree_cleanup_audit.py`, covering: a clean merged worktree becoming linked and removable; `pr_number` populated from authoritative linkage; open-PR, dirty, untracked-only, active-lease, active-lock, live-session, unmerged-head, unknown-containment, and control-checkout cases all remaining non-removable; ambiguous and competing linkage failing closed; other worktree classifications left intact; and agreement with the PR-scoped reconciler on a real throwaway git repository. Tests use fabricated temporary repositories and synthetic records only. Focused and neighbouring suites: 174 tests pass. A full sweep of 246 test modules was run on this branch and on authoritative master `9301739910df` using an identical procedure; every module's status matches the baseline exactly, apart from the new module and the one added test. The 153 modules that fail here fail identically on master (environment-dependent, pre-existing). ## Scope boundary against #855 Issue #855 is the reconciler-executor gap: a PR-scoped target for `gitea_reconcile_merged_cleanups` and expired-lease reclaim on merged branches. This PR is assessor-side only and additive. It adds no PR-scoped executor, changes no lease reclaim policy, and does not touch the batch reconciliation path. ## Untouched No cleanup was performed. PR #849's worktree `branches/issue-637-timeline-model` and its remote branch are retained as the reproduction fixture; issue #637, PR #849, issue #850, and PR #853 were not modified.
jcwalker3 added 1 commit 2026-07-23 20:21:53 -05:00
gitea_audit_worktree_cleanup had no PR linkage. Issue worktrees therefore
reported pr_number=null and classified as active_issue_work with
removable=false permanently, even once their PR was merged and the head was
already contained in master. Observed on live master 9301739910: 42
issue_work worktrees, 0 removable, 0 with pr_number populated, while
gitea_reconcile_merged_cleanups reported the same worktree safe to remove.

Two independent gaps caused it:

* build_worktree_metadata was never given a pr_number, and only open PRs were
  fetched, so no owning-PR evidence existed at all.
* clean_stale_removable was unreachable for issue_work: it required
  ttl_expired, derived from a last_used_at that nothing populates, and
  is_ttl_expired fail-safes to False when the timestamp is unknown.

This adds deterministic merged-PR linkage and gates removal on the complete
cleanup policy:

* build_pr_index / resolve_owning_pr link a worktree branch to exactly one
  owning PR. Competing PRs on one branch, a still-open owner, a head-branch
  mismatch, or missing PR state all fail closed while still reporting the
  resolved pr_number.
* assess_merged_pr_worktree_cleanup requires all of: conclusive merged
  ownership, branch agreement, containment of the head in authoritative
  master, no open/competing PR, no active lease, no issue lock, no live
  session, a clean tree, and a non-protected checkout. Unknown state blocks.
* Containment reuses merged_cleanup_reconcile.is_head_ancestor_of_ref so the
  audit and the PR-scoped reconciler agree on what "already landed" means.

Lease evidence is now supplied. audit_branches_directory already accepted
leased_branches but the MCP tool never passed it, so has_active_lease was
false for every worktree in a live run. That was inert only while issue
worktrees could never become removable; it is wired to authoritative
control-plane leases here, scoped so a lease on issue N protects that issue's
work worktree and not a baseline or review tree merely named after it.

Issue work no longer becomes removable on TTL age alone, since age is not
proof that a branch landed and would otherwise reclaim a worktree holding
unmerged commits. conflict_fix keeps its existing TTL behaviour, and review,
baseline, merge-simulation, detached, dirty, open-PR, and protected
classifications are unchanged.

The assessor still performs no deletion and gains no cleanup mutation. This
is assessor-side only and does not implement the PR-scoped executor or the
expired-lease reclaim policy tracked separately by #855.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #859
issue: #858
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 25482-5a5eca9cbea5
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-859
phase: claimed
candidate_head: fe259e6d38
target_branch: master
target_branch_sha: 9301739910
last_activity: 2026-07-24T02:39:32Z
expires_at: 2026-07-24T02:49:32Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #859 issue: #858 reviewer_identity: sysadmin profile: prgs-reviewer session_id: 25482-5a5eca9cbea5 worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-859 phase: claimed candidate_head: fe259e6d3812e7d187445a9fb22cde888fff9785 target_branch: master target_branch_sha: 9301739910df7b51ca3abcdbf46cce25cfb026e5 last_activity: 2026-07-24T02:39:32Z expires_at: 2026-07-24T02:49:32Z blocker: none
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #859
issue: #858
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 25482-5a5eca9cbea5
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-859
phase: claimed
candidate_head: fe259e6d38
target_branch: master
target_branch_sha: 9301739910
last_activity: 2026-07-24T02:52:46Z
expires_at: 2026-07-24T03:02:46Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #859 issue: #858 reviewer_identity: sysadmin profile: prgs-reviewer session_id: 25482-5a5eca9cbea5 worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-859 phase: claimed candidate_head: fe259e6d3812e7d187445a9fb22cde888fff9785 target_branch: master target_branch_sha: 9301739910df7b51ca3abcdbf46cce25cfb026e5 last_activity: 2026-07-24T02:52:46Z expires_at: 2026-07-24T03:02:46Z blocker: none
sysadmin approved these changes 2026-07-23 21:53:38 -05:00
sysadmin left a comment
Owner

Canonical PR State

STATE: approved
WHO_IS_NEXT: merger
NEXT_ACTION: Merge PR #859 into master at exact head fe259e6d38 from a fresh standalone gitea-merger session
NEXT_PROMPT:

Merge PR #859 in Scaled-Tech-Consulting/Gitea-Tools (remote prgs) at exact head
fe259e6d3812e7d187445a9fb22cde888fff9785 as prgs-merger. An APPROVED review by
sysadmin (prgs-reviewer) is pinned to that exact head. Base master is
9301739910df7b51ca3abcdbf46cce25cfb026e5, 0 commits behind, no conflicts,
mergeable true, no required status checks. Do not run PR #849 worktree or branch
cleanup as part of the merge; that may resume only after this merge lands, the
reconciler runtime is restarted at the resulting master, and both cleanup
assessors agree.

WHAT_HAPPENED: Independent reviewer verification of the merged-PR awareness added to gitea_audit_worktree_cleanup for issue_work worktrees. Both root causes stated in issue #858 were confirmed present before the change and fixed by it: build_worktree_metadata now receives a pr_number from deterministic branch-to-PR linkage, and the previously unreachable clean_stale_removable path for issue_work is now gated on complete merged-PR proof instead of a TTL derived from a last_used_at that nothing populates. Removability requires every condition independently: exactly one owning PR, that PR merged, worktree branch equal to the PR head branch, worktree head proven contained in master through the shared merged_cleanup_reconcile.is_head_ancestor_of_ref helper, and no open or competing PR, active lease, issue lock, live session, dirty file, or protected checkout. Competing PRs on one branch, an unmerged owner, malformed PR records, a missing master ref, and unknown containment were each verified to fail closed. Control-plane lease evidence is now actually supplied, closing the gap where has_active_lease was false for every worktree. The assessor gained no cleanup mutation and performed stays false.
WHY: The audit and the PR-scoped reconciler previously disagreed on identical on-disk state, so a landed issue worktree was reported as active work permanently. Containment of the head in authoritative master is what proves no unmerged commits remain, which is why age alone can no longer authorize reclaiming issue work.
ISSUE: #858
HEAD_SHA: fe259e6d38
REVIEW_STATUS: APPROVED at fe259e6d38 by sysadmin (prgs-reviewer); no current-head request-changes exists
MERGE_READY: true
BLOCKERS: none
VALIDATION: 31 of 31 new tests in tests/test_issue_858_audit_merged_pr_aware.py plus 151 tests across eight neighbouring cleanup, reconcile, worktree and inventory suites, all passing at this head. An independent 246-module status sweep was run on this head and on master 9301739910 in two separate detached worktrees using an identical procedure; every module status matches the master baseline, apart from the new module. The failing modules fail identically on master because importing mcp_server hard-exits in this non-sanctioned-daemon environment, which is pre-existing and independent of this change.
LAST_UPDATED_BY: prgs-reviewer
NATIVE_REVIEW_PROOF: native MCP stdio transport, production mode, pid 25482, entrypoint mcp_server at /Users/jasonwalker/Development/Gitea-Tools/gitea_mcp_server.py; verdict submitted through gitea_submit_pr_review after gitea_mark_final_review_decision, under reviewer lease 25482-5a5eca9cbea5 pinned to this exact head.

Reviewer verification summary

Scope stayed inside issue #858. No PR-scoped executor and no lease-reclaim policy change from issue #855 were added, and the batch reconciliation path is untouched. The production diff contains no special case for issue #637, PR #849, PR #818, issue #850 or issue #855.

Semantic alignment with the PR-scoped reconciler is exact rather than approximate: the audit derives master_ref with the identical expression already used by gitea_reconcile_merged_cleanups, and reuses the same ancestry helper. A test builds a real throwaway git repository and asserts both assessors agree on the safe case and on the dirty case.

Behaviour changes outside issue_work were checked and are limited to protective ones. conflict_fix keeps its TTL rule; review, baseline, merge-simulation, detached and protected classifications are unchanged; and plan_success_cleanup is unaffected because it only reaches classify_worktree for auto-remove workflow types. New response fields are additive and existing fields are preserved.

No worktree was removed and no branch was deleted during this review. PR #849 residue, issue #637, the worktree branches/issue-637-timeline-model and the branch feat/issue-637-timeline-model were verified untouched at b9ba43a5bf.

Non-blocking observations for a follow-up issue

These do not affect the verdict. None of them can make a worktree holding unmerged commits removable, because containment of the head in master is required independently of PR linkage.

  1. merged_pr_limit defaults to 200 and api_get_all truncates silently with no completeness signal. Closed PRs are returned newest first, so all recent merged PRs are inside the window and the reproduction case links correctly, but this repository already holds more than 250 closed PRs, so older merged history is invisible to the linkage. The response still reports merged_pr_state_verified true, which overstates what was actually read. Demonstrated effect on the pure functions: with two merged PRs on one reused branch, a full inventory yields ambiguous with pr_number none and proven false, while a truncated inventory yields merged_pr with pr_number 800 and proven true. This mirrors the bounded closed-PR fetch that gitea_reconcile_merged_cleanups already uses, so it is a pre-existing convention rather than a regression, but an inventory-complete flag would make the fail-closed guarantee explicit.

  2. In classify_worktree, has_live_session is evaluated before the metadata-known check and returns active_issue_work for every workflow type. The effect is protective and correct, but a review or baseline worktree held by a live session is labelled active issue work, and a worktree with unknown metadata reports active issue work instead of unsafe unknown.

  3. live_session_paths is populated only from lease worktree_path, which is null for the author leases currently in the control-plane store, so that signal is largely inert today. Protection for issue worktrees still holds through leased_issue_numbers, which is populated.

  4. In resolve_owning_pr, the head-branch mismatch branch is unreachable, because candidates are looked up by the same stripped branch string that is stored in the index. It is harmless defensive code.

  5. list_active_leases is called with limit 500 and no completeness signal, the same silent-cap shape as observation 1.

## Canonical PR State STATE: approved WHO_IS_NEXT: merger NEXT_ACTION: Merge PR #859 into master at exact head fe259e6d3812e7d187445a9fb22cde888fff9785 from a fresh standalone gitea-merger session NEXT_PROMPT: ```text Merge PR #859 in Scaled-Tech-Consulting/Gitea-Tools (remote prgs) at exact head fe259e6d3812e7d187445a9fb22cde888fff9785 as prgs-merger. An APPROVED review by sysadmin (prgs-reviewer) is pinned to that exact head. Base master is 9301739910df7b51ca3abcdbf46cce25cfb026e5, 0 commits behind, no conflicts, mergeable true, no required status checks. Do not run PR #849 worktree or branch cleanup as part of the merge; that may resume only after this merge lands, the reconciler runtime is restarted at the resulting master, and both cleanup assessors agree. ``` WHAT_HAPPENED: Independent reviewer verification of the merged-PR awareness added to gitea_audit_worktree_cleanup for issue_work worktrees. Both root causes stated in issue #858 were confirmed present before the change and fixed by it: build_worktree_metadata now receives a pr_number from deterministic branch-to-PR linkage, and the previously unreachable clean_stale_removable path for issue_work is now gated on complete merged-PR proof instead of a TTL derived from a last_used_at that nothing populates. Removability requires every condition independently: exactly one owning PR, that PR merged, worktree branch equal to the PR head branch, worktree head proven contained in master through the shared merged_cleanup_reconcile.is_head_ancestor_of_ref helper, and no open or competing PR, active lease, issue lock, live session, dirty file, or protected checkout. Competing PRs on one branch, an unmerged owner, malformed PR records, a missing master ref, and unknown containment were each verified to fail closed. Control-plane lease evidence is now actually supplied, closing the gap where has_active_lease was false for every worktree. The assessor gained no cleanup mutation and performed stays false. WHY: The audit and the PR-scoped reconciler previously disagreed on identical on-disk state, so a landed issue worktree was reported as active work permanently. Containment of the head in authoritative master is what proves no unmerged commits remain, which is why age alone can no longer authorize reclaiming issue work. ISSUE: #858 HEAD_SHA: fe259e6d3812e7d187445a9fb22cde888fff9785 REVIEW_STATUS: APPROVED at fe259e6d3812e7d187445a9fb22cde888fff9785 by sysadmin (prgs-reviewer); no current-head request-changes exists MERGE_READY: true BLOCKERS: none VALIDATION: 31 of 31 new tests in tests/test_issue_858_audit_merged_pr_aware.py plus 151 tests across eight neighbouring cleanup, reconcile, worktree and inventory suites, all passing at this head. An independent 246-module status sweep was run on this head and on master 9301739910df in two separate detached worktrees using an identical procedure; every module status matches the master baseline, apart from the new module. The failing modules fail identically on master because importing mcp_server hard-exits in this non-sanctioned-daemon environment, which is pre-existing and independent of this change. LAST_UPDATED_BY: prgs-reviewer NATIVE_REVIEW_PROOF: native MCP stdio transport, production mode, pid 25482, entrypoint mcp_server at /Users/jasonwalker/Development/Gitea-Tools/gitea_mcp_server.py; verdict submitted through gitea_submit_pr_review after gitea_mark_final_review_decision, under reviewer lease 25482-5a5eca9cbea5 pinned to this exact head. ## Reviewer verification summary Scope stayed inside issue #858. No PR-scoped executor and no lease-reclaim policy change from issue #855 were added, and the batch reconciliation path is untouched. The production diff contains no special case for issue #637, PR #849, PR #818, issue #850 or issue #855. Semantic alignment with the PR-scoped reconciler is exact rather than approximate: the audit derives master_ref with the identical expression already used by gitea_reconcile_merged_cleanups, and reuses the same ancestry helper. A test builds a real throwaway git repository and asserts both assessors agree on the safe case and on the dirty case. Behaviour changes outside issue_work were checked and are limited to protective ones. conflict_fix keeps its TTL rule; review, baseline, merge-simulation, detached and protected classifications are unchanged; and plan_success_cleanup is unaffected because it only reaches classify_worktree for auto-remove workflow types. New response fields are additive and existing fields are preserved. No worktree was removed and no branch was deleted during this review. PR #849 residue, issue #637, the worktree branches/issue-637-timeline-model and the branch feat/issue-637-timeline-model were verified untouched at b9ba43a5bf292690eec0b24b19a1f489930986e7. ## Non-blocking observations for a follow-up issue These do not affect the verdict. None of them can make a worktree holding unmerged commits removable, because containment of the head in master is required independently of PR linkage. 1. merged_pr_limit defaults to 200 and api_get_all truncates silently with no completeness signal. Closed PRs are returned newest first, so all recent merged PRs are inside the window and the reproduction case links correctly, but this repository already holds more than 250 closed PRs, so older merged history is invisible to the linkage. The response still reports merged_pr_state_verified true, which overstates what was actually read. Demonstrated effect on the pure functions: with two merged PRs on one reused branch, a full inventory yields ambiguous with pr_number none and proven false, while a truncated inventory yields merged_pr with pr_number 800 and proven true. This mirrors the bounded closed-PR fetch that gitea_reconcile_merged_cleanups already uses, so it is a pre-existing convention rather than a regression, but an inventory-complete flag would make the fail-closed guarantee explicit. 2. In classify_worktree, has_live_session is evaluated before the metadata-known check and returns active_issue_work for every workflow type. The effect is protective and correct, but a review or baseline worktree held by a live session is labelled active issue work, and a worktree with unknown metadata reports active issue work instead of unsafe unknown. 3. live_session_paths is populated only from lease worktree_path, which is null for the author leases currently in the control-plane store, so that signal is largely inert today. Protection for issue worktrees still holds through leased_issue_numbers, which is populated. 4. In resolve_owning_pr, the head-branch mismatch branch is unreachable, because candidates are looked up by the same stripped branch string that is stored in the index. It is harmless defensive code. 5. list_active_leases is called with limit 500 and no completeness signal, the same silent-cap shape as observation 1.
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #859
issue: #858
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 25482-5a5eca9cbea5
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-859
phase: released
candidate_head: fe259e6d38
target_branch: master
target_branch_sha: 9301739910
last_activity: 2026-07-24T02:54:00Z
expires_at: 2026-07-24T03:04:00Z
blocker: manual-release

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #859 issue: #858 reviewer_identity: sysadmin profile: prgs-reviewer session_id: 25482-5a5eca9cbea5 worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-859 phase: released candidate_head: fe259e6d3812e7d187445a9fb22cde888fff9785 target_branch: master target_branch_sha: 9301739910df7b51ca3abcdbf46cce25cfb026e5 last_activity: 2026-07-24T02:54:00Z expires_at: 2026-07-24T03:04:00Z blocker: manual-release
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #859
issue: #858
reviewer_identity: sysadmin
profile: prgs-merger
session_id: 6396-7a7c3dceda9c
worktree: /Users/jasonwalker/Development/Gitea-Tools
phase: claimed
candidate_head: fe259e6d38
target_branch: master
target_branch_sha: none
last_activity: 2026-07-24T03:01:39Z
expires_at: 2026-07-24T03:11:39Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #859 issue: #858 reviewer_identity: sysadmin profile: prgs-merger session_id: 6396-7a7c3dceda9c worktree: /Users/jasonwalker/Development/Gitea-Tools phase: claimed candidate_head: fe259e6d3812e7d187445a9fb22cde888fff9785 target_branch: master target_branch_sha: none last_activity: 2026-07-24T03:01:39Z expires_at: 2026-07-24T03:11:39Z blocker: none
sysadmin merged commit 6d0015cabc into master 2026-07-23 22:02:23 -05:00
Owner

Stale #332 review-decision lock cleanup (#594)

Status: APPLIED

Manual deletion of session-state files is not the workflow.
This path only clears a lock when the referenced PR is merged/closed.

## Stale #332 review-decision lock cleanup (#594) Status: **APPLIED** - actor: `sysadmin` - profile: `prgs-merger` - timestamp: `2026-07-24T03:02:32.004651+00:00` - last terminal: `approve` on PR #859 - PR state: `closed` (merged=True) - merge_commit_sha: `6d0015cabcfc9f1ec95e1ca8674dcb072ea9e81a` - prior live_mutations_count: `3` - prior profile_identity: `prgs-reviewer` Manual deletion of session-state files is **not** the workflow. This path only clears a lock when the referenced PR is merged/closed.
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

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