Files
settled-reach/.claude/skills/pr-process/SKILL.md
T
jpmschweitzerandClaude Fable 5 c9d9b56933 docs(rules): tea pr create must omit --repo (T-1102)
An explicit --repo slug makes tea skip local-repo setup, but pr create unconditionally needs the local repo handle and dies with 'local repository required' — the documented 'all flags explicit' rule was the trap. Root-caused shipping PR #175. tea-cli.md + pr-process template fixed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 17:15:38 +02:00

12 KiB

name, description, user-invocable, allowed-tools
name description user-invocable allowed-tools
pr-process Author-side PR lifecycle: commit, lint, push, create PR, AND pick up review comments from /pr-review. Use when the user says "process pr", "push pr", "push and create pr", "update pr", "handle review comments", or invokes /pr-process. Runs from the worktree. The counterpart to /pr-review which runs from main. true Bash, Read, Grep, Glob, AskUserQuestion, Skill

Process PR Skill

Push commits to remote and create or update a PR. Operates exclusively on the current branch — never touches main.

Safety Rules (NON-NEGOTIABLE)

  • NEVER merge a PR into main. No tea pr merge, no git merge into main.
  • NEVER checkout or push to main.
  • NEVER force-push unless the user explicitly requests it.
  • NEVER use --no-verify or skip hooks.
  • Only push to the current working branch.

Workflow

0. Dry-run mode check

If the user invokes /pr-process --dry-run:

  • Print: "Dry-run mode — inspecting state, nothing will be pushed or committed."
  • Run steps 1 through 4a in inspect-only mode:
    • Step 4: run make check-systems-db to check current stamp freshness (no merge)
    • Step 4a: report which watched files changed vs origin/main; show whether make regen-db would be triggered; do NOT run the regen, stage, or commit
  • Print a summary: watched files changed (list), regen needed (yes/no), DB stamp fresh (yes/no)
  • Print "Dry run complete — use /pr-process to apply."
  • Stop. Do not push or create a PR.

1. Validate branch

git branch --show-current

If on main, stop: "You're on main. Switch to a topic branch first."

1a. Orphan process check (MANDATORY)

Stale Godot processes from prior test runs compete with fresh runs for CPU and can silently wedge test-runner invocations. Before any test-invoking step (1b, 1c), check for long-lived Godot processes from prior stuck test runs:

# List any godot/gdUnit4 processes running longer than 5 minutes
ps -eo pid,etimes,cmd | awk '$2 > 300 && /godot.*(GdUnitCmdTool|[Gg]d[Uu]nit)/ {print $1, $2"s", substr($0, index($0,$3))}'

If any are listed: they are almost certainly orphans from a prior test run that hung. Ask the user before killing — they may be intentional. Default: offer to kill <PIDs> and wait a few seconds for the processes to exit before proceeding. Re-run the check until empty.

Do not proceed to 1b/1c with orphan Godot processes alive — they will steal CPU from the fresh runs and may cause the new invocation to hang indefinitely (Sprint 36 lost an hour of test verification to this exact failure mode).

1b. Zero warnings policy (MANDATORY)

Before pushing, verify the branch has zero lint warnings. Any warning must be either fixed or suppressed with a commented justification.

For client/visual branches:

gdlint client/scripts/ client/ui/ 2>&1

If warnings remain, fix them before pushing. For warnings that cannot be fixed (e.g. intentional long lines in data literals), add a # gdlint: ignore comment with a reason.

For server branches:

cargo clippy --manifest-path server/Cargo.toml --all-targets -- -D warnings 2>&1

This must match the pre-push gate's own invocation exactly (--all-targets is easy to drop locally and then miss warnings the gate still catches).

For CI/tooling branches:

ruff check tooling/ 2>&1

The goal is zero warnings in the pre-push output. Advisory warnings that the pre-push hook reports as "(advisory, not blocking)" should still be zero — they are advisory only because we haven't enforced them yet.

1c. Runtime smoke test (MANDATORY)

Before pushing, verify the game actually runs. This is non-negotiable — Sprint 28 proved that code review without runtime testing misses critical bugs (parse errors, depth sorting, scene tree failures).

For client/visual branches:

tooling/godot-cold-parse wipes the cached script-class registry (matching the cold-start ordering CI / fresh clones see — Sprint 36 close caught a class_name base-class registration bug that warm caches masked) and runs a headless parse, filtering known pre-existing noise. Pass --run-menu if the branch has UI changes to also launch the main menu briefly:

tooling/godot-cold-parse --run-menu

If it reports a "Could not find base class X" error, the fix is almost always an autoload-order issue (see CLAUDE.md → GDScript conventions → Autoload parse-order rule) — fix the ordering, don't just rebuild the cache to mask it locally (the same error resurfaces post-merge).

Any lines it reports are new errors introduced by this branch. Fix them before pushing.

For server branches:

cargo test --manifest-path server/Cargo.toml 2>&1

Full suite, not --lib--lib skips the believability/derivation golden harnesses (separate test binaries) and would silently under-test cascade changes. This must match the pre-push gate's own invocation (team-patterns.md) exactly; a weaker local pass here just gives false confidence right before the gate catches it anyway.

If any errors are found, stop and fix them before pushing. Do not push broken code for reviewers to find — that wastes everyone's time.

If the branch includes visual changes (character creation, UI, rendering), the team should have manually launched the game and verified the change works on screen before invoking /pr-process. If they haven't, ask: "Have you run make game and verified this works visually?"

2. Commit uncommitted changes

git status
git diff --stat

Run both commands from the repo root (git rev-parse --show-toplevel). Running from a subdirectory can hide real changes (Sprint 30: a wrong-CWD git diff returned 0 lines, masking uncommitted work).

CRITICAL: Do not trust "already done" claims without checking git state. If agents report that work was "already implemented in a prior commit," verify by checking git status and git diff --stat first. Grepping source files only proves the code exists on disk — it does NOT prove the code is committed. Uncommitted working-tree changes look identical to committed code when you read files. Only git status distinguishes "already shipped" from "just written by a teammate."

If there are uncommitted changes (staged or unstaged), run the commit skill first. Use the /git-commit skill to group changes into logical commits with proper conventional commit messages. Wait for commit to complete before proceeding.

If the working tree is clean (no uncommitted changes), skip to step 3.

3. Check for unpushed commits

git fetch --all
git log --oneline origin/<branch>..<branch>

If no unpushed commits, skip to step 6 (PR check).

4. Check for conflicts with main

git merge-tree --write-tree origin/main HEAD 2>&1

If conflicts reported, merge main into current branch:

git merge origin/main --no-edit

If merge conflicts, stop and report — let the user resolve. If clean, continue.

4a. Regen systems.db if generator sources or data changed (T-858)

Check whether any file in the source-file watch list was modified on this branch versus origin/main. This list covers generator code AND the data files that feed them.

The stamped generator sources come from the shared registry tooling/generator_sources.py (T-1067) — the same module the stamp writer and tooling/check-systems-db-stamp use, so the lists can no longer drift (PR #136 review T7). tooling/pr-watchlist-diff wraps the comparison — its header comment documents the non-stamped watch items it also checks (the surviving one-time planet-gen importers, the schema DDL whose SHA is stamped separately, and the wiki data directories that feed the generators):

tooling/pr-watchlist-diff origin/main HEAD

If output is empty: skip this step entirely.

If any files appear in the output: the DB must be regenerated on top of the current main. Perform the following:

  1. Integrate main. Step 4 merged main into the branch. If you find yourself on a branch that was NOT yet merged with main in step 4, do it now:

    git fetch origin
    git merge origin/main --no-edit
    

    If there are merge conflicts in source files, stop and report which files conflict. Ask the user to resolve manually — do not attempt to auto-resolve generator source conflicts.

  2. Regenerate the DB:

    make regen-db
    

    make regen-db runs all three generators and stamps the meta table. It tolerates coverage gate failures (exit 2 = data quality warning, not an error). If it exits with any other non-zero code, stop and report the stderr output — do not push.

  3. Stage the updated DB:

    git add server/data/systems.db
    
  4. Commit only if the DB actually changed:

    git diff --cached --stat -- server/data/systems.db
    
    • If the diff shows changes: commit with /git-commit, message: chore(db): regen systems.db against rebased sources
    • If no diff (regen produced identical output — sources were self-consistent): unstage the file (git restore --staged server/data/systems.db) and skip the commit. The source changes alone are the PR content.

In dry-run mode (from step 0): report which watch-list files changed and whether regen would be triggered. Do NOT run the regen or modify any files.

This step prevents the pre-push hook from rejecting a push where the branch modifies a generator source or data file but did not regenerate the DB.

5. Push

git push origin <branch>

If push fails, stop and report. Never force-push without explicit request.

6. Check for existing PR

tea pr list --login schweitz --repo jpmschweitzer/settled-reach --state open --output simple

Match current branch name in PR list.

  • PR exists: Report "Pushed N commits to <branch>. PR #X updated." Done.
  • No PR: Continue to step 7.

7. Create a new PR

git log --oneline main..<branch>
git diff --stat main...<branch>

Draft title (<type>(<scope>): <summary>, max 70 chars) and description.

# NB: omit --repo — an explicit slug makes tea skip local-repo setup and
# pr create dies with "local repository required". Run from the MAIN checkout;
# tea infers the repo from origin. (.claude/rules/tea-cli.md)
tea pr create \
  --login schweitz \
  --title "<title>" \
  --description "## Summary ..." \
  --base main \
  --head <branch>

Report PR URL when done.

8. Update ticket status to review

Scan all commit messages in the PR for ticket references. Commits use either the T-NNN convention or the legacy #NNN (which is numerically identical — #440 == T-440):

git log --oneline main..<branch>

Extract ticket ids from T-NNN / #NNN patterns (map a bare #NNN to T-NNN). For each ticket currently in_progress, update it to review:

pql ticket status T-<id> review

Report which tickets were moved to review. Skip tickets that are already done, review, cancelled, or backlog (only transition in_progressreview).

9. Pick up review comments

Check if the PR already has review comments (from a prior /pr-review run):

tea pr --login schweitz --repo jpmschweitzer/settled-reach --comments -o simple <PR_NUMBER>

If comments exist and contain a review verdict (look for "CHANGES REQUESTED" or "REQUEST_CHANGES" or a structured review table):

  1. Parse each file-specific issue from the review comment
  2. Present each issue to the user (or working agents)
  3. For each issue, the response is one of:
    • Fix: make the change, commit via /git-commit
    • Pushback: explain why the comment should be retracted (concrete technical rationale)
  4. After addressing all comments, re-run lint + smoke checks (steps 1b, 1c)
  5. Push updated commits (step 5)
  6. Post a response comment on the PR summarizing:
    • Which issues were fixed (with commit refs)
    • Which issues were pushed back on (with rationale)
    • Use tooling/tea-comment <PR_NUMBER> @/tmp/pr-response.md

If no review comments exist, or the review is APPROVED, skip this step.

10. Next steps

Suggest: "PR processed. Run /pr-review from main to review, or /whats-next for the next batch."

Arguments

If the user passes arguments (e.g., /pr-process "my title"), use them as the PR title instead of generating one.