From 627abd2fb0cf376df95656aa466c43a0e57aa39c Mon Sep 17 00:00:00 2001 From: L <6723574+louisgv@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:02:32 -0800 Subject: [PATCH] feat: enforce no-self-merge rule across all team scripts (#585) Agents can self-review their PRs (read diff, add comments) but must never merge. PRs get labeled `needs-team-review` and stay open for external review by maintainers or a separate review cycle. Changes across all three scripts: - refactor.sh: added No Self-Merge Rule section, updated worktree pattern, issue fix workflow, monitoring loop, and lifecycle mgmt - discovery.sh: added No Self-Merge Rule section, updated worktree pattern, git workflow, branch cleaner, and lifecycle mgmt - qa-cycle.sh: renamed push_and_merge_pr to push_and_create_pr, removed all gh pr merge calls, added self-review + labeling Agent: team-lead Co-authored-by: Sprite Co-authored-by: Claude Opus 4.6 (1M context) --- .../skills/setup-trigger-service/discovery.sh | 73 ++++++++++++------- .../skills/setup-trigger-service/qa-cycle.sh | 58 +++++++-------- .../skills/setup-trigger-service/refactor.sh | 66 +++++++++++++---- 3 files changed, 122 insertions(+), 75 deletions(-) diff --git a/.claude/skills/setup-trigger-service/discovery.sh b/.claude/skills/setup-trigger-service/discovery.sh index d27c6a35..a96900a3 100755 --- a/.claude/skills/setup-trigger-service/discovery.sh +++ b/.claude/skills/setup-trigger-service/discovery.sh @@ -157,6 +157,20 @@ Each cycle MUST complete within 45 minutes. This is a HARD deadline. Agents should aim for focused, high-impact work. Do NOT exhaustively expand everything. +## No Self-Merge Rule (MANDATORY) + +Agents must NEVER merge their own PRs. This applies to ALL agents including the team lead. + +After creating a PR, every agent MUST: +1. **Self-review**: Read the diff and add a review comment summarizing changes, tests run, and any concerns: + `gh pr diff NUMBER --repo OpenRouterTeam/spawn` + `gh pr review NUMBER --repo OpenRouterTeam/spawn --comment --body "Self-review by AGENT-NAME: [summary of changes, what was tested, any concerns]"` +2. **Label**: Add `needs-team-review` so external reviewers can find it: + `gh pr edit NUMBER --repo OpenRouterTeam/spawn --add-label "needs-team-review"` +3. **Leave the PR open** — do NOT run `gh pr merge` + +Merging is handled externally (by maintainers or a separate review cycle). + ## Priority Order 1. **Fill gaps first** — if manifest.json has "missing" entries, fill them before discovering @@ -213,7 +227,7 @@ Research new AI agents, BUT only add one if there's REAL community demand: Check the repo's GitHub issues for user requests: - Run: `gh issue list --repo OpenRouterTeam/spawn --state open --limit 20` - Look for issues requesting specific agents or cloud providers -- If a request is actionable, implement it +- If a request is actionable, implement it and create a PR (self-review + label, do NOT merge) - Comment on the issue with the PR link when done - If a request is already implemented, close the issue with a comment @@ -223,8 +237,8 @@ Clean up stale remote branches before and after the cycle: - For each branch (excluding main): * Check if there's an open PR: `gh pr list --head BRANCH --state open --json number,title` * If open PR and branch is stale (last commit >4 hours ago): - - Mergeable → merge with `gh pr merge NUMBER --squash --delete-branch` - - Conflicts/failing → close with `gh pr close NUMBER --comment "Auto-closing: stale branch. Please reopen if still needed."` + - If PR has conflicts/failing checks → close with `gh pr close NUMBER --comment "Auto-closing: stale branch. Please reopen if still needed."` + - If PR is mergeable → ensure it has `needs-team-review` label, add a comment noting it's stale (do NOT merge — merging is external) * If no open PR and stale >4 hours → delete with `git push origin --delete BRANCH` * If fresh (<4 hours) → leave alone - Run again at end of cycle to catch branches created during the cycle @@ -311,11 +325,15 @@ Co-Authored-By: Claude Sonnet 4.5 " # 5. Push git push -u origin BRANCH-NAME -# 6. Create and merge PR (can be done from anywhere) +# 6. Create PR (can be done from anywhere) gh pr create --title "title" --body "body" -gh pr merge NUMBER --squash --delete-branch -# 7. Clean up worktree +# 7. Self-review and label (DO NOT merge — see No Self-Merge Rule) +gh pr diff NUMBER --repo OpenRouterTeam/spawn +gh pr review NUMBER --repo OpenRouterTeam/spawn --comment --body "Self-review by AGENT-NAME: [summary]" +gh pr edit NUMBER --repo OpenRouterTeam/spawn --add-label "needs-team-review" + +# 8. Clean up worktree (PR stays open for external review) git worktree remove WORKTREE_BASE_PLACEHOLDER/BRANCH-NAME ``` @@ -342,25 +360,28 @@ Every teammate MUST follow this workflow using worktrees. NO exceptions. 4. Do the work, commit (with Agent: marker) 5. Push: `git push -u origin {branch-name}` 6. Create PR: `gh pr create --title "..." --body "..."` -7. Try to merge: `gh pr merge --squash --delete-branch` -8. **If merge fails** (conflicts, CI, etc.): - - Comment on the PR explaining WHY it cannot be merged +7. Self-review and label (DO NOT merge): + `gh pr diff NUMBER --repo OpenRouterTeam/spawn` + `gh pr review NUMBER --repo OpenRouterTeam/spawn --comment --body "Self-review by AGENT-NAME: [summary]"` + `gh pr edit NUMBER --repo OpenRouterTeam/spawn --add-label "needs-team-review"` +8. **If PR cannot be created** (conflicts, etc.): + - Comment on the PR explaining WHY - Close with: `gh pr close {number} --comment "Closing: {reason}"` - - Acceptable reasons: merge conflict with a concurrent PR, superseded by another PR, implementation found to be incorrect after review - NEVER close a PR silently — every closed PR MUST have a comment 9. Clean up worktree: `git worktree remove WORKTREE_BASE_PLACEHOLDER/{branch-name}` ### PR Policy (MANDATORY): Every PR must reach one of these terminal states: -- **MERGED** — the happy path, always preferred -- **CLOSED with comment** — only when merge is impossible, with a clear explanation +- **OPEN with self-review + `needs-team-review` label** — the standard path, always preferred +- **CLOSED with comment** — only when PR is impossible (conflicts, duplicate work), with a clear explanation ### NEVER: +- Run `gh pr merge` — merging is handled externally - Push directly to main - Use `git checkout -b` when other agents are active — use worktrees - Close a PR without a comment explaining why -- Leave PRs open/abandoned — resolve them in the same cycle -- Leave branches or worktrees hanging after merge +- Leave PRs without a self-review comment and `needs-team-review` label +- Leave branches or worktrees hanging after work is done - Work on a stale base — always `git fetch origin main` before creating a worktree ## Lifecycle Management (MANDATORY — DO NOT EXIT EARLY) @@ -368,23 +389,22 @@ Every PR must reach one of these terminal states: You MUST remain active until ALL of the following are true: 1. **All tasks are completed**: Run TaskList and confirm every task has status "completed" -2. **All PRs are resolved**: Run `gh pr list --repo OpenRouterTeam/spawn --state open --author @me` and confirm zero open PRs from this cycle. Every PR must be either merged or closed with a comment. -3. **All provider PRs are resolved**: Run `gh pr list --repo OpenRouterTeam/spawn --state open --json number,title,headRefName` and check for ANY open PRs related to cloud providers (branches like `add/*`, `feat/*-cloud`, provider names in titles). For each: - - Check mergeability: `gh pr view NUMBER --json mergeable --jq '.mergeable'` - - If MERGEABLE → merge: `gh pr merge NUMBER --squash --delete-branch` - - If not mergeable → close with comment: `gh pr close NUMBER --comment "Auto-closing: provider PR from interrupted cycle (unmergeable). Please reopen if still needed."` - - **No provider PR should survive across cycles** — resolve every one before exiting +2. **All PRs are self-reviewed and labeled**: Run `gh pr list --repo OpenRouterTeam/spawn --state open --author @me` and confirm every PR from this cycle has a self-review comment and the `needs-team-review` label. Do NOT merge — PRs stay open for external review. +3. **All provider PRs are labeled**: Run `gh pr list --repo OpenRouterTeam/spawn --state open --json number,title,headRefName` and check for ANY open PRs related to cloud providers. For each: + - Ensure it has a self-review comment and `needs-team-review` label + - If not mergeable (conflicts) → close with comment: `gh pr close NUMBER --comment "Auto-closing: provider PR from interrupted cycle (unmergeable). Please reopen if still needed."` + - If mergeable → leave open with label for external review (do NOT merge) 4. **All worktrees are cleaned**: Run `git worktree list` and confirm only the main worktree exists. Run `rm -rf WORKTREE_BASE_PLACEHOLDER` and `git worktree prune`. 5. **All teammates are shut down**: Send `shutdown_request` to EVERY teammate. Wait for each to confirm. Do NOT exit while any teammate is still active. ### Shutdown Sequence (execute in this exact order): 1. Check TaskList — if any tasks are still in_progress or pending, wait and check again (poll every 30 seconds, up to 5 minutes) -2. Verify all PRs merged or closed: `gh pr list --repo OpenRouterTeam/spawn --state open` +2. Verify all PRs are self-reviewed and labeled: `gh pr list --repo OpenRouterTeam/spawn --state open --label "needs-team-review"` (PRs stay open — do NOT merge) 3. **Sweep for leftover provider PRs**: `gh pr list --repo OpenRouterTeam/spawn --state open --json number,title,headRefName,mergeable` - - For each PR whose title or branch references a cloud/provider (e.g. `hetzner`, `vultr`, `runpod`, `add/`, `feat/`): - - MERGEABLE → merge with `gh pr merge NUMBER --squash --delete-branch` - - Not mergeable → close with `gh pr close NUMBER --comment "Auto-closing: stale provider PR. Please reopen if still needed."` + - For each PR whose title or branch references a cloud/provider: + - If mergeable → ensure it has `needs-team-review` label and a self-review comment (do NOT merge) + - If not mergeable → close with `gh pr close NUMBER --comment "Auto-closing: stale provider PR (unmergeable). Please reopen if still needed."` - Log every action taken 4. For each teammate, send a `shutdown_request` via SendMessage 5. Wait for all `shutdown_response` confirmations @@ -408,8 +428,9 @@ The cycle is NOT complete until this final README update is committed and pushed - ALWAYS use worktrees — never `git checkout -b` in the main repo - ALWAYS `git fetch origin main` before creating a worktree - Each teammate works on DIFFERENT files -- Each unit of work gets its own worktree → branch → PR → merge → cleanup worktree -- **Every PR must be merged OR closed with a comment** — no silent closes, no abandoned PRs +- Each unit of work gets its own worktree → branch → PR → self-review → label → cleanup worktree +- **Every PR must have a self-review comment + `needs-team-review` label, OR be closed with a comment** — no silent closes, no unlabeled PRs +- **NEVER run `gh pr merge`** — merging is handled externally - Update manifest.json, the cloud's README.md, AND the root README.md matrix - Clean up worktrees after every PR: `git worktree remove PATH` - NEVER revert prior macOS/curl-bash compatibility fixes diff --git a/.claude/skills/setup-trigger-service/qa-cycle.sh b/.claude/skills/setup-trigger-service/qa-cycle.sh index ef02e4d4..fcdbdcd0 100644 --- a/.claude/skills/setup-trigger-service/qa-cycle.sh +++ b/.claude/skills/setup-trigger-service/qa-cycle.sh @@ -81,23 +81,21 @@ check_timeout() { return 0 } -# Robust push → PR → merge with retry on stale main -# Usage: push_and_merge_pr BRANCH_NAME PR_TITLE PR_BODY -push_and_merge_pr() { +# Push → PR → self-review (NO merging — merging is handled externally) +# Usage: push_and_create_pr BRANCH_NAME PR_TITLE PR_BODY +push_and_create_pr() { local branch_name="$1" local pr_title="$2" local pr_body="$3" - local max_retries=3 - local attempt=0 # Check there are actual commits to push if [[ -z "$(git log origin/main..HEAD --oneline 2>/dev/null)" ]]; then - log "push_and_merge_pr: No commits to push on ${branch_name}" + log "push_and_create_pr: No commits to push on ${branch_name}" return 0 fi git push -u origin "${branch_name}" 2>&1 | tee -a "${LOG_FILE}" || { - log "push_and_merge_pr: Push failed for ${branch_name}" + log "push_and_create_pr: Push failed for ${branch_name}" return 1 } @@ -108,36 +106,30 @@ push_and_merge_pr() { --base main --head "${branch_name}" 2>/dev/null) || true if [[ -z "${pr_url:-}" ]]; then - log "push_and_merge_pr: PR creation failed for ${branch_name}" + log "push_and_create_pr: PR creation failed for ${branch_name}" return 1 fi - log "push_and_merge_pr: PR created: ${pr_url}" + log "push_and_create_pr: PR created: ${pr_url}" - while [[ "$attempt" -lt "$max_retries" ]]; do - attempt=$((attempt + 1)) + # Extract PR number from URL + local pr_number="" + pr_number=$(printf '%s' "${pr_url}" | grep -oE '[0-9]+$') || true - if gh pr merge "${branch_name}" --squash --delete-branch 2>&1 | tee -a "${LOG_FILE}"; then - log "push_and_merge_pr: Merged ${branch_name} (attempt ${attempt})" - return 0 - fi + if [[ -n "${pr_number}" ]]; then + # Self-review: add a comment summarizing the changes + gh pr review "${pr_number}" --repo OpenRouterTeam/spawn --comment \ + --body "Self-review by QA cycle: ${pr_title}. Automated change — tests were run before submission." \ + 2>&1 | tee -a "${LOG_FILE}" || true - log "push_and_merge_pr: Merge failed (attempt ${attempt}/${max_retries}), rebasing onto latest main..." + # Label for external review + gh pr edit "${pr_number}" --repo OpenRouterTeam/spawn --add-label "needs-team-review" \ + 2>&1 | tee -a "${LOG_FILE}" || true - # Fetch latest main and rebase - git fetch origin main 2>/dev/null || true - if git rebase origin/main 2>&1 | tee -a "${LOG_FILE}"; then - git push --force-with-lease origin "${branch_name}" 2>&1 | tee -a "${LOG_FILE}" || true - sleep 3 # Give GitHub a moment to process - else - git rebase --abort 2>/dev/null || true - log "push_and_merge_pr: Rebase failed for ${branch_name}, giving up" - break - fi - done + log "push_and_create_pr: Self-reviewed and labeled PR #${pr_number} (not merging — awaiting external review)" + fi - log "push_and_merge_pr: Could not merge ${branch_name} after ${max_retries} attempts, leaving PR open" - return 1 + return 0 } # ============================================================ @@ -376,7 +368,7 @@ Only modify ${cloud}/lib/common.sh and test/record.sh if the recording infrastru fi # Push, PR, and merge with retry on stale main - push_and_merge_pr "${branch_name}" \ + push_and_create_pr "${branch_name}" \ "fix: Update ${cloud} API for fixture recording" \ "Automated fix from QA cycle. API recording was failing for ${cloud}." || true ) & @@ -569,7 +561,7 @@ FIXEOF fi # Push, PR, and merge with retry on stale main - push_and_merge_pr "${branch_name}" \ + push_and_create_pr "${branch_name}" \ "fix: Fix ${cloud} mock test failures" \ "Automated fix from QA cycle. ${fail_count} mock test(s) were failing for ${cloud}: ${failing_scripts}" || true ) & @@ -627,10 +619,10 @@ EOF )" 2>&1 | tee -a "${LOG_FILE}" || true # Push, PR, and merge with retry on stale main - push_and_merge_pr "${README_BRANCH}" \ + push_and_create_pr "${README_BRANCH}" \ "test: Update README matrix after QA cycle" \ "Automated README update from QA cycle Phase 4. Test results updated in the matrix." || { - log "Phase 4: PR merge failed, leaving PR open for manual review" + log "Phase 4: PR creation failed, check for errors" } # Switch back to main and sync diff --git a/.claude/skills/setup-trigger-service/refactor.sh b/.claude/skills/setup-trigger-service/refactor.sh index 6348878d..03e5fd4b 100755 --- a/.claude/skills/setup-trigger-service/refactor.sh +++ b/.claude/skills/setup-trigger-service/refactor.sh @@ -154,7 +154,7 @@ Create these teammates: - Implement the fix in an isolated worktree - Run tests to verify the fix - Create a PR with \`Fixes #${SPAWN_ISSUE}\` in the body - - Merge the PR immediately + - Self-review the PR and label with \`needs-team-review\` (do NOT merge) 2. **issue-tester** (Haiku) - Review the fix for correctness and edge cases @@ -190,8 +190,10 @@ Track issue lifecycle with labels: "Pending Review" → "Under Review" → "In P 9. When fix is ready: - Push: \`git push -u origin fix/issue-${SPAWN_ISSUE}\` - PR: \`gh pr create --title "fix: Description" --body "Fixes #${SPAWN_ISSUE}"\` - - Merge: \`gh pr merge --squash --delete-branch\` -10. Post resolution comment on the issue with PR link + - Self-review: \`gh pr review NUMBER --repo OpenRouterTeam/spawn --comment --body "Self-review by issue-fixer: [summary]"\` + - Label: \`gh pr edit NUMBER --repo OpenRouterTeam/spawn --add-label "needs-team-review"\` + - Do NOT merge — PR stays open for external review +10. Post update comment on the issue linking to the PR 11. Remove status labels and close the issue: \`gh issue edit ${SPAWN_ISSUE} --repo OpenRouterTeam/spawn --remove-label "In Progress"\` \`gh issue close ${SPAWN_ISSUE}\` @@ -236,6 +238,29 @@ Complexity-hunter: pick the top 1-2 worst functions, fix them, PR, done. Do NOT Test-engineer: add ONE focused test file, PR, done. Do NOT aim for 100% coverage. Security-auditor: scan for HIGH/CRITICAL only. Document medium/low, don't fix them. +## No Self-Merge Rule (MANDATORY) + +Agents must NEVER merge their own PRs. This applies to ALL agents including the team lead. + +### What agents MUST do after creating a PR: +1. **Self-review**: Read the PR diff and add a review comment with findings: + `gh pr diff NUMBER --repo OpenRouterTeam/spawn` + `gh pr review NUMBER --repo OpenRouterTeam/spawn --comment --body "Self-review by AGENT-NAME: [summary of changes, what was tested, any concerns]"` +2. **Label for external review**: Add `needs-team-review` label: + `gh pr edit NUMBER --repo OpenRouterTeam/spawn --add-label "needs-team-review"` +3. **Leave the PR open** — do NOT run `gh pr merge` + +### What agents must NEVER do: +- `gh pr merge` — NEVER, under any circumstances +- Approve their own PR — self-review is comment-only, not approval + +### Why: +- Prevents duplicate or conflicting work from landing unreviewed +- Ensures a second set of eyes (human or another team) validates every change +- Catches planning issues before they hit main + +PRs will be reviewed and merged externally (by maintainers or a separate review cycle). + ## Team Structure Create these teammates: @@ -272,13 +297,13 @@ Create these teammates: - For each remote branch (excluding main): * Check if there's an open PR: gh pr list --head BRANCH --state open --json number,title * If open PR exists and branch is stale (last commit >4 hours ago): - - If PR is mergeable: merge it with gh pr merge NUMBER --squash --delete-branch - If PR has conflicts or failing checks: close it with gh pr close NUMBER --comment "Auto-closing: stale branch with unresolvable conflicts. Please reopen if still needed." + - If PR is mergeable: add a comment noting it's stale and ready for review, ensure it has `needs-team-review` label (do NOT merge — merging is external) * If no open PR and branch is stale (>4 hours old): delete it with git push origin --delete BRANCH * If branch is fresh (<4 hours): leave it alone (may be actively worked on) - - After cleanup, report summary: how many branches merged, closed, deleted, left alone + - After cleanup, report summary: how many branches labeled, closed, deleted, left alone - Run this check AGAIN at the end of the cycle to catch branches created during the cycle - - GOAL: Zero stale branches left on the remote after each cycle. + - GOAL: Zero stale unlabeled branches left on the remote after each cycle. 6. **community-coordinator** (Sonnet) - FIRST TASK: Run `gh issue list --repo OpenRouterTeam/spawn --state open --json number,title,body,labels,createdAt` @@ -344,17 +369,21 @@ When fixing a bug reported in a GitHub issue: 10. Push the branch: git push -u origin fix/issue-NUMBER 11. Create a PR that references the issue: gh pr create --title "Fix: description" --body "Fixes #NUMBER" -12. Merge the PR immediately: gh pr merge --squash --delete-branch +12. Self-review and label (DO NOT merge — see No Self-Merge Rule): + gh pr diff NUMBER --repo OpenRouterTeam/spawn + gh pr review NUMBER --repo OpenRouterTeam/spawn --comment --body "Self-review by AGENT-NAME: [summary of fix, tests run, confidence level]" + gh pr edit NUMBER --repo OpenRouterTeam/spawn --add-label "needs-team-review" 13. Clean up: git worktree remove WORKTREE_BASE_PLACEHOLDER/fix/issue-NUMBER 14. Community-coordinator posts final resolution comment with PR link and explanation (only if no resolution exists) 15. Remove status labels and close the issue: gh issue edit NUMBER --repo OpenRouterTeam/spawn --remove-label "In Progress" gh issue close NUMBER -NEVER leave an issue open after the fix is merged. NEVER leave a PR unmerged. -If a PR cannot be merged (conflicts, superseded, etc.), close it WITH a comment explaining why. +NEVER leave a PR without a self-review comment and `needs-team-review` label. +If a PR cannot be created (conflicts, superseded, etc.), close it WITH a comment explaining why. NEVER close a PR silently — every closed PR MUST have a comment. -The full cycle is: acknowledge → investigate → worktree → fix → update → PR (references issue) → merge PR → cleanup → resolve & close issue. +The full cycle is: acknowledge → investigate → worktree → fix → update → PR (references issue) → self-review → label → cleanup worktree. +Note: merging is handled externally — agents do NOT merge. ## Commit Markers (MANDATORY) @@ -415,8 +444,12 @@ git push -u origin BRANCH-NAME # 4. Create PR (can be done from anywhere) gh pr create --title "title" --body "body" -# 5. Merge and clean up -gh pr merge NUMBER --squash --delete-branch +# 5. Self-review and label (DO NOT merge — see No Self-Merge Rule) +gh pr diff NUMBER --repo OpenRouterTeam/spawn +gh pr review NUMBER --repo OpenRouterTeam/spawn --comment --body "Self-review by AGENT-NAME: [summary]" +gh pr edit NUMBER --repo OpenRouterTeam/spawn --add-label "needs-team-review" + +# 6. Clean up worktree (PR stays open for external review) git worktree remove WORKTREE_BASE_PLACEHOLDER/BRANCH-NAME ``` @@ -471,12 +504,13 @@ git worktree remove WORKTREE_BASE_PLACEHOLDER/BRANCH-NAME 2. Immediately start a polling loop — do NOT just output text saying "I'll wait": while teammates are still active: a. Run TaskList to check task status - b. Run `gh pr list --repo OpenRouterTeam/spawn --state open` to check for PRs to merge + b. Run `gh pr list --repo OpenRouterTeam/spawn --state open --label "needs-team-review"` to verify PRs have been self-reviewed and labeled c. When you receive a teammate message, acknowledge it and update task tracking - d. If a teammate reports completion, mark their task done and merge their PR + d. If a teammate reports completion, mark their task done — verify their PR has a self-review comment and label e. If a teammate reports an error, coordinate resolution f. If the time budget is almost up, send wrap-up messages to all teammates g. If no messages received yet, run `Bash("sleep 30")` then loop back to (a) + h. REMINDER: Do NOT merge any PRs — they stay open for external review 3. Only after ALL teammates have finished, proceed to shutdown ``` @@ -491,7 +525,7 @@ GOOD: Spawn teammates → TaskList → sleep 30 → TaskList → receive message You MUST remain active until ALL of the following are true: 1. **All tasks are completed**: Run TaskList and confirm every task has status "completed" -2. **All PRs are resolved**: Run `gh pr list --repo OpenRouterTeam/spawn --state open --author @me` and confirm zero open PRs from this cycle. Every PR must be either merged or closed with a comment. +2. **All PRs are self-reviewed and labeled**: Run `gh pr list --repo OpenRouterTeam/spawn --state open --label "needs-team-review"` and confirm every PR from this cycle has a self-review comment and the `needs-team-review` label. Do NOT merge — PRs stay open for external review. 3. **All issues are engaged and labeled**: Run `gh issue list --repo OpenRouterTeam/spawn --state open --json number,labels` and for EACH open issue, verify it has at least one comment AND has a status label ("Pending Review", "Under Review", or "In Progress"). If any issue is missing a status @@ -503,7 +537,7 @@ You MUST remain active until ALL of the following are true: ### Shutdown Sequence (execute in this exact order): 1. Check TaskList — if any tasks are still in_progress or pending, wait and check again (poll every 30 seconds, up to 10 minutes) -2. Verify all PRs merged or closed: `gh pr list --repo OpenRouterTeam/spawn --state open` +2. Verify all PRs are self-reviewed and labeled: `gh pr list --repo OpenRouterTeam/spawn --state open --label "needs-team-review"` (PRs stay open — do NOT merge) 3. Verify all issues engaged: `gh issue list --repo OpenRouterTeam/spawn --state open` 4. For each teammate, send a `shutdown_request` via SendMessage 5. Wait for all `shutdown_response` confirmations