name: send-pr description: Prepare, validate, and send or update a pull request with full due diligence
Prepare and send (or update) a pull request. Follow every step below in order. If any step fails trivially (lint warning, minor test fix, formatting), fix it and continue. If a failure is non-trivial (widespread test breakage, unclear intent), STOP and report the failure.
Step 0 — Determine GitHub username and base branch, verify commit authorship
Retrieve the GitHub username from git config:
GH_USER=$(git config github.user || gh api user -q .login)
Store this as $GH_USER — it is used for branch naming in later steps.
Determine the base branch for this PR. If a PR already exists, use its base branch. Otherwise, check if the branch was created from another feature branch (e.g. git log --oneline --graph or tracking info). Default to $BASE if unclear. Store this as $BASE — all subsequent steps that reference the upstream use $BASE instead of hardcoding $BASE.
Verify that the author and committer for every commit on this branch match the configured git identity:
EXPECTED_NAME=$(git config user.name)
EXPECTED_EMAIL=$(git config user.email)
git log $BASE..HEAD --format='%an%n%ae%n%cn%n%ce' | sort -u
Every name returned should equal $EXPECTED_NAME and every email should equal $EXPECTED_EMAIL. If any commit has a different author or committer, rewrite those commits using git rebase -x with git commit --amend --reset-author to align them with the configured identity. Do NOT use interactive rebase (-i).
Step 1 — Check for existing PR and ensure feature branch
First, check if there is an open PR for the current branch (gh pr view). Note the result — you will need it in Step 11. If a PR exists, use its base branch as $BASE.
Then ensure the branch name:
- If the current branch starts with
$GH_USER/, continue. - If on
main/master, create a new branch named$GH_USER/<short-description>based on the recent commit messages, switch to it, and continue. - If on another branch not prefixed with
$GH_USER/AND there is no open PR for it, rename it withgit branch -m $GH_USER/<current-name>. - If on another branch not prefixed with
$GH_USER/AND there IS an open PR, do not rename. Continue with the current name.
Step 2 — Commit unstaged changes
First, revert any simtest contamination: if Cargo.lock is dirty, check whether it contains simtest tokio patches (real_tokio, local path references to tokio). If so, run git checkout Cargo.lock to discard those changes. Only commit Cargo.lock changes that reflect real dependency additions from this branch.
Stage and commit all unstaged/untracked files EXCEPT:
- Markdown files that are design docs or debugging notes (not CLAUDE.md, not README.md checked into the project)
- Log files
- Tokio crate patches generated by simtest (typically in a local
patches/dir or Cargo.toml[patch]entries pointing at local tokio paths)
All changes should go into a single commit with a concise single-line message. Do NOT include Co-Authored-By lines. Do NOT create separate commits for Cargo.lock, formatting, or other mechanical changes — everything goes into one commit that will be amended in Step 9.
If there is nothing to commit, move on.
Step 3 — Rebase on upstream
Rebase the current branch onto $BASE. Fetch first.
Resolve merge conflicts automatically — read both sides, understand intent, and pick the correct resolution. Most conflicts in this codebase are mechanical (import ordering, adjacent additions, config entries). Only stop if a conflict involves genuinely contradictory logic where the correct resolution is ambiguous.
Step 4 — Self-review
Run git diff $BASE...HEAD and review the full diff for obvious issues:
Obvious bugs & security issues - pause and alert the user
- panic, assert, unwrap, expect reachable using boundary-condition transaction inputs
- unchecked arithmetic operations with reachable overflow/underflow
- incorrect arithmetic, off-by-one errors, negation
- behavioral changes in transaction processing not gated by protocol-config causing validator equivocation
- backwards-incompatible type system changes
- any change to a bcs-encoded struct
- bcs-encoded enum variants not in last position
Obvious code quality issues:
- Leftover debug logging (
dbg!,println!, temporaryinfo!/warn!calls, any llm signature) todo!(),unimplemented!(), orFIXMEmarkers- Accidental reverts of upstream changes
- Dead code introduced by this branch
- Commented-out code that should be removed
Fix anything found. Stage changes but do not commit yet — they will be amended in Step 9. If something looks intentional but questionable, note it to the user but continue.
Step 5 — Run relevant tests
Determine which packages were changed on this branch (compare against $BASE).
- For unit tests:
SUI_SKIP_SIMTESTS=1 cargo nextest run --no-capture -p <package> - For anything in
sui-e2e-tests:cargo simtest --no-capture -p sui-e2e-tests <test_filter> - Consult crate-specific CLAUDE.md files for test guidance.
Fix trivial test failures (assertion message changes, snapshot updates, etc.) and re-run. Stage changes but do not commit yet — they will be amended in Step 9.
After simtest runs, ALWAYS revert Cargo.lock with git checkout Cargo.lock — simtest patches tokio locally which contaminates the lockfile with real_tokio entries that must never be committed.
If tests fail non-trivially, stop and report.
Step 6 — Clippy
Run cargo xclippy -D warnings. Fix all warnings and errors. Stage changes but do not commit yet — they will be amended in Step 9.
Repeat until clean. If a clippy issue is non-trivial to fix, stop and report.
Step 7 — Format
Run cargo fmt --all. If it produces changes, stage them but do not commit yet — they will be amended in Step 9.
Step 8 — Protocol config snapshots
If any commit on this branch touches crates/sui-protocol-config/src/lib.rs, run:
./scripts/update_all_snapshots.sh
Stage any snapshot changes but do not commit yet — they will be amended in Step 9.
Step 9 — Amend all staged changes
All changes from Steps 4–8 should now be staged but uncommitted. Before amending, run git checkout Cargo.lock one final time to ensure no simtest contamination is staged. Then amend everything into the most recent commit on the branch using git commit --amend --no-edit. The goal is a clean history: no separate commits for formatting, clippy fixes, or lockfile updates.
Step 10 — Scrub commit authorship
Check ALL commits on this branch (vs $BASE) for Co-Authored-By lines mentioning claude or anthropic (case-insensitive), as well as Generated by Claude or similar AI attribution footers. If found, use git rebase -x with git commit --amend to strip those lines. Do NOT use interactive rebase (-i).
Step 11 — Push
Push to the remote feature branch with git push -u origin HEAD. NEVER push to main or master.
If the remote branch exists and has diverged (due to rebase), force-push with git push --force-with-lease. This is expected after rebasing.
Step 12 — Open or update PR
Check if a PR already exists for this branch (gh pr view).
- If a PR is open: done. Print the PR URL.
- If no PR exists: open one in draft mode with
gh pr create --draft. Write a concise title and body summarizing the branch's changes. Print the PR URL.
Be concise in the PR description. Focus on the intent and reasons for the PR, and the functional changes that result, rather than simply listing the names of files or code structures that were modified.