Skip to content

Delete a Merged Feature Branch Through a pr_review.py cleanup Subcommand - #2970

Merged
ptr727 merged 3 commits into
developfrom
feature/pr-review-cleanup-2967
Oct 14, 2026
Merged

ptr727 merged 3 commits into
developfrom
feature/pr-review-cleanup-2967

Conversation

@ptr727

@ptr727 ptr727 commented Oct 14, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a cleanup subcommand to scripts/pr_review.py that runs the merged-feature-branch verify-then-delete in code, so the delete runs under the host-safety installer's existing Bash(python3 scripts/pr_review.py:*) allow rule instead of as a hand-typed delete the write guard or the auto-mode classifier refuses. drive-pr step 4 and merge-and-release step 8 now call it, and the hand form stays as the fallback for a host without that rule, with its commands reported paste-ready where the seat cannot run them.

python3 scripts/pr_review.py cleanup <number> --repo OWNER/NAME:

  • Reads the head branch from the pull request. It takes no branch name.
  • Refuses (exit 1) unless the pull request is merged, its base is develop, its headRepository.nameWithOwner equals --repo, and the head branch is not develop, main, or the default branch read live.
  • Checks the same origin owner comment and reply check (exit 64). Then it binds the owner to registry/repos.json and admits only a registered repository or a fork, using handoff.py's require_write_scope, which it imports rather than copies.
  • Refuses (exit 1) a branch that any ruleset (rules/branches/{branch}) or classic protection (branches/{branch}, .protected) covers. A read that fails or comes back in the wrong shape exits 2, and it never counts as "no rules".
  • Reads the ref by exact qualified name through GraphQL. A branch that is already gone exits 0. A tip that differs from headRefOid exits 1 and names both commits. Otherwise it sends deleteRef with the node id that same read returned.
  • Confirms the delete by reading the ref back. If the delete reported a failure but the ref is gone, it reports done. If the ref is still there, or the read-back does not answer, it exits 2. The delete's output is printed rather than suppressed.
  • Has no --dry-run, because no other subcommand of this script has one.

deleteRef is the script's fifth mutation document, and the whole-source write test now pins five.

The delete carries no expected tip, so this is verify-then-delete, the same gate the hand form uses, rather than a compare-and-swap.

Tests

tests/test_pr_review.py has new CleanupCase cases. They mock GraphQL and REST and use constructed names only. They cover:

  • each refusal
  • an already-gone branch
  • a moved tip
  • a read-back that still shows the ref
  • a read-back that does not answer
  • a delete that reports a failure, decided by the read-back either way
  • unread rule, protection, pull request, and tip reads
  • a branch name that would change a REST path
  • out-of-scope and registry refusals, an admitted fork, and an unreadable registry

cleanup is also added to the cross-owner write table, which now also asserts that neither of the new transports is reached. The new subcommand was not run against any live branch.

Local Review

A strict local pass ran for three rounds, and the receipt was recorded at this head.

Filed rather than fixed:

Declined with evidence:

  • The concern that a private repository on a plan without rulesets would always exit 2. A read of a private fleet repository's rules/branches endpoint returned a JSON list.

Left open after the edit budget was spent, class introduced:

  • No test asserts that the failed REST read's stderr and rc reach the output (cleanup_rest). Only the diagnostic text is uncovered. The exit 2 itself is covered.

Closes #2967

🤖 Generated with Claude Code

ptr727 and others added 3 commits October 13, 2026 19:38
Add `cleanup <number> --repo OWNER/NAME`, which reads the head branch from
the merged pull request, refuses unless it merged into develop from a head
in that repository, is not a permanent branch, and is covered by no ruleset
or branch protection, then deletes the ref only where its tip is the pull
request's headRefOid and confirms the delete by reading the ref back. The
owner and repository are bound to the registry through handoff.py's own
write-scope check. Point drive-pr and merge-and-release at it, keeping the
hand form and the paste-ready report as the fallback for a host without the
managed allow rule.

Closes #2967

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
State the tip check as verify-then-delete rather than a compare-and-swap,
name the registry's fork admission and which exit a registry refusal takes,
read the rule and protection endpoints through reread_json so a transient
failure is retried, cover the fork path and both new transports in the
tests, and restore the subcommand list's column.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Split reread_json so cleanup can print the last read's stderr where nothing
parsed, state that 64 also covers an origin that cannot be read, and rewrap
the lines the previous commit left long.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 14, 2026 02:50
@coderabbitai

coderabbitai Bot commented Oct 14, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Repository: ptr727/ProjectTemplate/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1638669e-317b-4d16-b14a-a30da83531d1
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ptr727

ptr727 commented Oct 14, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head b815a2e7118e2de5c21c31c8e71ef2de80132eaf, the content this pull request carries at that commit against develop, and it recorded 1 finding.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved cleanup safety issues remain in scripts/pr_review.py, including path encoding, pagination handling, and nested response validation.

2 open findings
What changed in this PR

Adds a verified cleanup subcommand for deleting merged feature branches, with documentation, workflow, and test updates.

Changes:

  • Adds verification, protection checks, deletion, and read-back confirmation.
  • Updates cleanup instructions and generated skill copies.
  • Expands tests and mutation-safety coverage.
File Summary
tests/​test_pr_review.py Adds cleanup behavior and safety tests.
scripts/​README.md Documents the cleanup command.
scripts/​pr_review.py Implements branch verification and deletion.
.github/​skills/​merge-and-release/​SKILL.md Updates release cleanup instructions.
.github/​skills/​drive-pr/​SKILL.md Updates PR workflow cleanup instructions.
.claude-plugin/​fleet-skills/​skills/​merge-and-release/​SKILL.md Updates generated release skill.
.claude-plugin/​fleet-skills/​skills/​drive-pr/​SKILL.md Updates generated drive skill.
.claude-plugin/​fleet-skills/​.source-digests/​merge-and-release Updates source digest.
.claude-plugin/​fleet-skills/​.source-digests/​drive-pr Updates source digest.
.agents/​skills/​merge-and-release/​SKILL.md Updates canonical release skill.
.agents/​skills/​drive-pr/​SKILL.md Updates canonical drive skill.

🧠 Review effort: Lite


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/pr_review.py
Comment thread scripts/pr_review.py
@codecov

codecov Bot commented Oct 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.69231% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.53%. Comparing base (d2ed08c) to head (b815a2e).

Files with missing lines Patch % Lines
scripts/pr_review.py 97.69% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2970      +/-   ##
===========================================
+ Coverage    60.02%   60.53%   +0.50%     
===========================================
  Files           17       17              
  Lines         8784     8904     +120     
===========================================
+ Hits          5273     5390     +117     
- Misses        3511     3514       +3     
Flag Coverage Δ
python-3.13 60.53% <97.69%> (+0.50%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ptr727

ptr727 commented Oct 14, 2026

Copy link
Copy Markdown
Owner Author

Local review finding left open in the description (no test asserts that a failed cleanup_rest read prints its stderr and rc): deferred to #2971. The exit 2 it produces is already covered by test_an_unread_rule_set_stops_at_2_rather_than_reading_as_none.

@ptr727

ptr727 commented Oct 14, 2026

Copy link
Copy Markdown
Owner Author

Copilot's headline also names "nested response validation" beside its two counted findings, with no finding or thread of its own. Read against the head: cleanup_ref refuses a ref missing its id or target.oid (exit 2) before either is used, _cleanup exits 2 where pullRequest, defaultBranchRef.name, headRefName, or headRefOid is missing, branch_rules exits 2 on a rules answer that is not a list of objects or a protection answer without a boolean protected, and headRepository: null refuses (exit 1, test_a_head_repository_gone_is_refused). No nested field is read unvalidated, so no change.

@ptr727
ptr727 merged commit 4537d02 into develop Oct 14, 2026
14 checks passed
ptr727 added a commit that referenced this pull request Oct 14, 2026
…de-Override and Shell-Rewrite Denies to Main (#2980)

- #2970 adds a `cleanup` subcommand to `scripts/pr_review.py` that runs
the merged-feature-branch verify-then-delete in code. It reads the head
branch from the merged pull request, refuses a base other than
`develop`, a head from another repository, a protected or default
branch, and a repository outside the registry, reads the ref by its
qualified name, deletes only when its tip matches `headRefOid`, and
confirms the delete by reading the ref back. `drive-pr` step 4 and
`merge-and-release` step 8 now call it, with the hand form kept as the
fallback
- #2974 makes `gh-write-guard` deny an `include.path`/`includeIf`
override on a commit or push, on a command that runs other git commands
(`rebase`, `submodule`, `bisect`, `filter-branch`, `difftool`,
`mergetool`), and on any command git does not build in. It reads an
`eval` argument holding an include key as the command it runs, and keeps
a local branch name such as `release/1.0` whole when checking it against
the rule set. A differential against the previous guard found zero allow
flips, and the known new over-denials are listed in that pull request
- #2979 makes `gh-write-guard` read quote-split words and an uppercase
`GIT` through the existing push and include checks, and fail closed on a
run-time word (an expansion, a substitution, a backtick, a brace
expansion) where the subcommand goes, among a push's or a commit's
global options or arguments, on a redirection before the subcommand, and
on an unquoted comment among a push's words. The managed permission
rule's description now names `pr_review.py cleanup`. A differential
against the previous guard found zero allow flips, and the known new
over-denials and the gaps left open (#2976, #2977, #2978) are listed in
that pull request

After this merges, the host-safety installer payload changes, so the
maintainer runs the installer after promotion.

Closes #2967
Closes #2958
Closes #2960
Closes #2962
Closes #2959
Closes #2961
Closes #2968

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added a guarded cleanup option for merged pull request branches. It
verifies that the branch is eligible and unchanged before deletion, then
confirms the result.
* **Security**
* Strengthened protections against potentially unsafe Git commit and
push commands, including attempts to bypass configured safeguards.
* **Documentation**
* Updated guidance for branch cleanup, safety checks, and the outcomes
reported when cleanup cannot proceed.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@ptr727
ptr727 deleted the feature/pr-review-cleanup-2967 branch October 14, 2026 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants