fix(workflow): retire status:pr-open on every terminal PR transition (Closes #780) #782

Merged
sysadmin merged 1 commits from fix/issue-780-terminal-pr-open-label-cleanup into master 2026-07-21 15:14:21 -05:00
Owner

Closes #780

Problem

status:pr-open was applied by gitea_create_pr and never removed again. Every
terminal path finished without touching it, so a repository-wide audit found 40
closed issues still advertising a pull request that had long since merged or
closed.

Fix

terminal_pr_label_cleanup.py is the single authoritative rule. Every
sanctioned terminal path now routes through it, so the paths cannot drift:

Terminal reason Path
merged gitea_merge_pr
closed_without_merge gitea_edit_pr closing the PR
superseded gitea_reconcile_superseded_by_merged_pr
already_landed gitea_reconcile_already_landed_pr
controller_closure gitea_close_issue
retry_recovery new gitea_cleanup_terminal_pr_labels

The rule removes only status:pr-open, preserves every other label verbatim,
allows an empty resulting set when it was the issue's only label, is a no-op
when the label is absent (so retries are harmless), and confirms the outcome by
read-after-write instead of assumption.

Controller closure runs the cleanup before the state change and fails
closed if it cannot be completed and verified — closing first would bake in the
stale label with no later step to catch it. Post-merge cleanup never blocks the
merge, which already happened; failures are reported with a safe_next_action.

Also

  • gitea_assess_terminal_label_hygiene: read-only terminal validation that
    reports any residual status:pr-open, exempting issues that have a genuinely
    open PR.
  • _put_issue_label_names now accepts Gitea's empty response body when the
    requested set is empty, so clearing the last label works.
  • test_audit's close_issue fixture keys on the request instead of call order,
    since closing now also reads labels for the cleanup and its read-back.

Docs

docs/label-taxonomy.md terminal-transition section, a runbook pointer, and the
terminal-label requirements in the review-merge and reconcile-landed
final-report schemas.

Tests

New tests/test_terminal_pr_label_cleanup.py (35 tests) covers merge,
close-without-merge, supersession, already-landed reconciliation, controller
closure, retry/idempotency, preservation of every other label, the only-label
empty set, read-after-write verification, failure reporting, and a regression
that reproduces the observed leak across all five terminal paths at once.

  • Branch ed0e8c8: 4045 passed, 11 failed, 6 skipped.
  • Clean master df31674 baseline: 4010 passed, 11 failed, 6 skipped.
  • Identical 11 failures in both runs (test_commit_payloads x6,
    test_issue_702_review_findings_f1_f6 x2, test_mcp_server preflight,
    test_post_merge_moot_lease, test_reconciler_supersession_close) —
    pre-existing on master, not introduced here.

LLM Handoff Metadata

  • Author identity: jcwalker3 / prgs-author
  • Head SHA: ed0e8c82de
  • Worktree: branches/fix-issue-780-terminal-pr-open-label-cleanup
  • Next role: reviewer (prgs-reviewer). The author did not review or merge this
    PR and holds no merge authority.
Closes #780 ## Problem `status:pr-open` was applied by `gitea_create_pr` and never removed again. Every terminal path finished without touching it, so a repository-wide audit found 40 closed issues still advertising a pull request that had long since merged or closed. ## Fix `terminal_pr_label_cleanup.py` is the single authoritative rule. Every sanctioned terminal path now routes through it, so the paths cannot drift: | Terminal reason | Path | |---|---| | `merged` | `gitea_merge_pr` | | `closed_without_merge` | `gitea_edit_pr` closing the PR | | `superseded` | `gitea_reconcile_superseded_by_merged_pr` | | `already_landed` | `gitea_reconcile_already_landed_pr` | | `controller_closure` | `gitea_close_issue` | | `retry_recovery` | new `gitea_cleanup_terminal_pr_labels` | The rule removes only `status:pr-open`, preserves every other label verbatim, allows an empty resulting set when it was the issue's only label, is a no-op when the label is absent (so retries are harmless), and confirms the outcome by read-after-write instead of assumption. Controller closure runs the cleanup **before** the state change and fails closed if it cannot be completed and verified — closing first would bake in the stale label with no later step to catch it. Post-merge cleanup never blocks the merge, which already happened; failures are reported with a `safe_next_action`. ## Also - `gitea_assess_terminal_label_hygiene`: read-only terminal validation that reports any residual `status:pr-open`, exempting issues that have a genuinely open PR. - `_put_issue_label_names` now accepts Gitea's empty response body when the requested set is empty, so clearing the last label works. - `test_audit`'s close_issue fixture keys on the request instead of call order, since closing now also reads labels for the cleanup and its read-back. ## Docs `docs/label-taxonomy.md` terminal-transition section, a runbook pointer, and the terminal-label requirements in the review-merge and reconcile-landed final-report schemas. ## Tests New `tests/test_terminal_pr_label_cleanup.py` (35 tests) covers merge, close-without-merge, supersession, already-landed reconciliation, controller closure, retry/idempotency, preservation of every other label, the only-label empty set, read-after-write verification, failure reporting, and a regression that reproduces the observed leak across all five terminal paths at once. - Branch `ed0e8c8`: 4045 passed, 11 failed, 6 skipped. - Clean master `df31674` baseline: 4010 passed, 11 failed, 6 skipped. - Identical 11 failures in both runs (`test_commit_payloads` x6, `test_issue_702_review_findings_f1_f6` x2, `test_mcp_server` preflight, `test_post_merge_moot_lease`, `test_reconciler_supersession_close`) — pre-existing on master, not introduced here. ## LLM Handoff Metadata - Author identity: jcwalker3 / prgs-author - Head SHA: ed0e8c82deafa44079a23b5ddd73092b4d554ddf - Worktree: branches/fix-issue-780-terminal-pr-open-label-cleanup - Next role: reviewer (prgs-reviewer). The author did not review or merge this PR and holds no merge authority.
jcwalker3 added 1 commit 2026-07-21 14:43:00 -05:00
status:pr-open was applied by gitea_create_pr and never removed again. Every
terminal path finished without touching it, so a repository audit found 40
closed issues still advertising an open PR.

Add terminal_pr_label_cleanup.py as the single authoritative rule and route
every sanctioned terminal path through it, so the paths cannot drift:

- merge (gitea_merge_pr)
- close without merge (gitea_edit_pr)
- supersession/abandonment (gitea_reconcile_superseded_by_merged_pr)
- already-landed reconciliation (gitea_reconcile_already_landed_pr)
- controller closure (gitea_close_issue)
- retry/recovery (new gitea_cleanup_terminal_pr_labels)

The rule removes only status:pr-open, preserves every other label, allows an
empty resulting set, is a no-op when the label is absent (so retries are
safe), and confirms the outcome by read-after-write rather than assumption.

Controller closure runs the cleanup before the state change and fails closed
if it cannot be completed and verified; closing first would bake in the stale
label with no later step to catch it. Post-merge cleanup never blocks the
merge, which already happened, and reports failures with a safe next action.

Also:
- gitea_assess_terminal_label_hygiene: read-only terminal validation that
  reports residual status:pr-open, exempting issues with a genuinely open PR.
- _put_issue_label_names now accepts Gitea's empty response body when the
  requested set is empty, so clearing the last label works.
- test_audit's close_issue fixture keys on the request instead of call order,
  since closing now also reads labels for the cleanup and its read-back.

Docs: label-taxonomy terminal-transition section, runbook pointer, and the
review-merge / reconcile-landed final-report terminal-label requirements.

Suite: 4045 passed, 11 failed, 6 skipped. The same 11 failures reproduce on
clean master df31674 (4010 passed, 11 failed) and are pre-existing.

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

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #782
issue: #780
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 40811-838360dac52c
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-fix-issue-780-terminal-pr-open-label-cleanup
phase: claimed
candidate_head: ed0e8c82de
target_branch: master
target_branch_sha: df3167488c
last_activity: 2026-07-21T20:01:09Z
expires_at: 2026-07-21T20:11:09Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #782 issue: #780 reviewer_identity: sysadmin profile: prgs-reviewer session_id: 40811-838360dac52c worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-fix-issue-780-terminal-pr-open-label-cleanup phase: claimed candidate_head: ed0e8c82deafa44079a23b5ddd73092b4d554ddf target_branch: master target_branch_sha: df3167488c5451f802549b40463ad59cbaad6109 last_activity: 2026-07-21T20:01:09Z expires_at: 2026-07-21T20:11:09Z blocker: none
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #782
issue: #780
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 40811-838360dac52c
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-fix-issue-780-terminal-pr-open-label-cleanup
phase: validated
candidate_head: ed0e8c82de
target_branch: master
target_branch_sha: df3167488c
last_activity: 2026-07-21T20:02:04Z
expires_at: 2026-07-21T20:12:04Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #782 issue: #780 reviewer_identity: sysadmin profile: prgs-reviewer session_id: 40811-838360dac52c worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-fix-issue-780-terminal-pr-open-label-cleanup phase: validated candidate_head: ed0e8c82deafa44079a23b5ddd73092b4d554ddf target_branch: master target_branch_sha: df3167488c5451f802549b40463ad59cbaad6109 last_activity: 2026-07-21T20:02:04Z expires_at: 2026-07-21T20:12:04Z blocker: none
sysadmin approved these changes 2026-07-21 15:04:18 -05:00
sysadmin left a comment
Owner

Canonical PR State

STATE: approved
WHO_IS_NEXT: merger
NEXT_ACTION: Merge PR #782 at exact head ed0e8c82de after fresh live recheck and lease adoption; do not re-review unless head moves.
NEXT_PROMPT:

Task: merge PR #782 for issue #780 in Scaled-Tech-Consulting/Gitea-Tools.
Expected approved head: ed0e8c82deafa44079a23b5ddd73092b4d554ddf
Author: jcwalker3
Required profile: prgs-merger
Use only the native Gitea merger MCP namespace.
Load the canonical review-merge workflow first.
Verify identity, adopt or acquire merger lease, confirm approval_at_current_head, recheck live head, then merge with confirmation MERGE PR 782.
Do not approve or request changes from the merger role. Report pr_open_label_cleanup from the merge result.

WHAT_HAPPENED: Independent reviewer sysadmin/prgs-reviewer inspected all 9 changed files and traced every #780 terminal path (merge, close-without-merge, supersession/abandonment, already-landed, controller closure, retry/recovery). One authoritative idempotent cleanup rule; only status:pr-open removed; empty label set supported; controller fails closed before state change; merge-path cleanup failure does not block merge and emits safe_next_action. New assess/recovery tools have correct permissions, preflight, audit, and read-after-write. _put_issue_label_names empty-body fix is scoped and safe.
WHY: Acceptance criteria for #780 are met; tests pass; no blocking findings; reviewer independent of author jcwalker3.
ISSUE: #780
HEAD_SHA: ed0e8c82de
REVIEW_STATUS: approved / approval_at_current_head
MERGE_READY: true
BLOCKERS: none
VALIDATION: focused tests/test_terminal_pr_label_cleanup.py 35 passed; broader related suite 162 passed with 1 pre-existing baseline failure test_reconciler_supersession_close; documented full-suite baseline master 4010p/11f/6s vs branch 4045p/11f/6s with identical 11 failures accepted
NATIVE_REVIEW_PROOF: transport=native_mcp; entrypoint=mcp_server; token_fingerprint=ff677c50d33000dc
LAST_UPDATED_BY: sysadmin / prgs-reviewer

Review findings

Files reviewed: terminal_pr_label_cleanup.py; gitea_mcp_server.py (clear_pr_open_label, merge, edit_pr close, already-landed, supersession, close_issue, recovery/assess tools, empty PUT body); task_capability_map.py; tests/test_terminal_pr_label_cleanup.py; tests/test_audit.py; docs/label-taxonomy.md; docs/llm-workflow-runbooks.md; schemas review-merge and reconcile-landed.

Lease session: 40811-838360dac52c
Worktree: branches/review-fix-issue-780-terminal-pr-open-label-cleanup (clean; HEAD matches pinned head)
Namespace: gitea-reviewer only; healthy; master parity in parity at df3167488c

Review Metadata

  • LLM-Agent-SHA: llm-ed0e8c82deaf
  • LLM-Role: reviewer
  • Authenticated-Gitea-User: sysadmin
  • MCP-Profile: prgs-reviewer
  • Eligibility: passed
## Canonical PR State STATE: approved WHO_IS_NEXT: merger NEXT_ACTION: Merge PR #782 at exact head ed0e8c82deafa44079a23b5ddd73092b4d554ddf after fresh live recheck and lease adoption; do not re-review unless head moves. NEXT_PROMPT: ```text Task: merge PR #782 for issue #780 in Scaled-Tech-Consulting/Gitea-Tools. Expected approved head: ed0e8c82deafa44079a23b5ddd73092b4d554ddf Author: jcwalker3 Required profile: prgs-merger Use only the native Gitea merger MCP namespace. Load the canonical review-merge workflow first. Verify identity, adopt or acquire merger lease, confirm approval_at_current_head, recheck live head, then merge with confirmation MERGE PR 782. Do not approve or request changes from the merger role. Report pr_open_label_cleanup from the merge result. ``` WHAT_HAPPENED: Independent reviewer sysadmin/prgs-reviewer inspected all 9 changed files and traced every #780 terminal path (merge, close-without-merge, supersession/abandonment, already-landed, controller closure, retry/recovery). One authoritative idempotent cleanup rule; only status:pr-open removed; empty label set supported; controller fails closed before state change; merge-path cleanup failure does not block merge and emits safe_next_action. New assess/recovery tools have correct permissions, preflight, audit, and read-after-write. _put_issue_label_names empty-body fix is scoped and safe. WHY: Acceptance criteria for #780 are met; tests pass; no blocking findings; reviewer independent of author jcwalker3. ISSUE: #780 HEAD_SHA: ed0e8c82deafa44079a23b5ddd73092b4d554ddf REVIEW_STATUS: approved / approval_at_current_head MERGE_READY: true BLOCKERS: none VALIDATION: focused tests/test_terminal_pr_label_cleanup.py 35 passed; broader related suite 162 passed with 1 pre-existing baseline failure test_reconciler_supersession_close; documented full-suite baseline master 4010p/11f/6s vs branch 4045p/11f/6s with identical 11 failures accepted NATIVE_REVIEW_PROOF: transport=native_mcp; entrypoint=mcp_server; token_fingerprint=ff677c50d33000dc LAST_UPDATED_BY: sysadmin / prgs-reviewer ## Review findings Files reviewed: terminal_pr_label_cleanup.py; gitea_mcp_server.py (clear_pr_open_label, merge, edit_pr close, already-landed, supersession, close_issue, recovery/assess tools, empty PUT body); task_capability_map.py; tests/test_terminal_pr_label_cleanup.py; tests/test_audit.py; docs/label-taxonomy.md; docs/llm-workflow-runbooks.md; schemas review-merge and reconcile-landed. Lease session: 40811-838360dac52c Worktree: branches/review-fix-issue-780-terminal-pr-open-label-cleanup (clean; HEAD matches pinned head) Namespace: gitea-reviewer only; healthy; master parity in parity at df3167488c54 ### Review Metadata - LLM-Agent-SHA: llm-ed0e8c82deaf - LLM-Role: reviewer - Authenticated-Gitea-User: sysadmin - MCP-Profile: prgs-reviewer - Eligibility: passed
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #782
issue: #780
reviewer_identity: sysadmin
profile: prgs-merger
session_id: 48296-08f4a3cd6b63
worktree: branches/merge-pr-782
phase: claimed
candidate_head: ed0e8c82de
target_branch: master
target_branch_sha: df3167488c
last_activity: 2026-07-21T20:13:43Z
expires_at: 2026-07-21T20:23:43Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #782 issue: #780 reviewer_identity: sysadmin profile: prgs-merger session_id: 48296-08f4a3cd6b63 worktree: branches/merge-pr-782 phase: claimed candidate_head: ed0e8c82deafa44079a23b5ddd73092b4d554ddf target_branch: master target_branch_sha: df3167488c5451f802549b40463ad59cbaad6109 last_activity: 2026-07-21T20:13:43Z expires_at: 2026-07-21T20:23:43Z blocker: none
sysadmin merged commit 8e149e6cfa into master 2026-07-21 15:14:21 -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-21T20:14:22.649482+00:00` - last terminal: `approve` on PR #782 - PR state: `closed` (merged=True) - merge_commit_sha: `8e149e6cfa3557e4642a3ac72c971460adbc3037` - prior live_mutations_count: `1` - 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#782