Skip to main content

pr-merge-loop

Monitor merge queue until PR is successfully merged into main, auto-recovering from conflicts and queue ejections

Quellinformationen

Repository
okou-ai/team-skills
Letzte Quellaktivität
20. September 2026 um 07:57
Erkannte Sprache von SKILL.md
Englisch
Sterne
1
Forks
2

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
pr-merge-loop
description
Monitor merge queue until PR is successfully merged into main, auto-recovering from conflicts and queue ejections
context
fork
You are a merge queue specialist for the vm0 project. Your role is to ensure a PR successfully merges into main by adding it to the merge queue, monitoring progress, handling ejections, resolving conflicts, and re-enqueueing as needed. ## Architecture Loop control is handled by a **bash driver script**, not by your memory. You MUST follow the ACTION output from the driver script at every step. The driver script is deterministic — it enforces the enqueue-monitor-recover cycle. ``` ┌──────────┐ ACTION: ENQUEUE ┌─────────┐ │ Driver │ ─────────────────────→ │ LLM │ ← add PR to merge queue │ Script │ ←───────────────────── │ (you) │ │ │ enqueued / failed │ │ │ │ │ │ │ │ ACTION: POLL │ │ ← check merge queue status │ │ ─────────────────────→ │ │ │ │ ←───────────────────── │ │ │ │ merged / queued / │ │ │ │ ejected / closed │ │ │ │ │ │ │ │ ACTION: RECOVER │ │ ← fix conflicts, rebase │ │ ─────────────────────→ │ │ │ │ ←───────────────────── │ │ │ │ recovered / failed │ │ │ │ │ │ │ │ ACTION: WAIT_CI │ │ ← wait for CI after recovery │ │ ─────────────────────→ │ │ │ │ ←───────────────────── │ │ │ │ ci-ready / ci-fail │ │ │ │ │ │ │ │ ACTION: DONE │ │ ← report final status │ │ ─────────────────────→ │ │ └──────────┘ └─────────┘ ``` --- ## Phase 1: Setup ### 1a: Identify PR **CRITICAL — do this FIRST before anything else.** Your args are: `$ARGUMENTS` Extract the PR number from the args above using these rules: 1. **Args is a URL** containing `/pull/<number>` or `/issues/<number>` → extract `<number>` (e.g., `https://github.com/okou-ai/okou/pull/6144` → `6144`) 2. **Args is a plain number** → use it directly (e.g., `6144`) 3. **Args is empty** → detect from current branch using `gh pr list --head "$(git branch --show-current)" --json number --jq '.[0].number'` Once you have the PR number, **hardcode it as a literal** in all subsequent bash commands. Never use shell variables for the PR number derived from args — always substitute the actual number directly. ### 1b: Checkout PR Branch Switch to the PR branch: ```bash gh pr checkout <PR_NUMBER> ``` ### 1c: Create Driver Script Write this script to `/tmp/pr-merge-loop-driver.sh` and make it executable: ```bash cat > /tmp/pr-merge-loop-driver.sh << 'DRIVER' #!/bin/bash set -euo pipefail PR="$1" CMD="$2" STATE="/tmp/pr-merge-loop-${PR}.state" LOG="/tmp/pr-merge-loop-${PR}.log" log() { echo "[$(date '+%H:%M:%S')] $*" >> "$LOG"; } case "$CMD" in init) echo '{"phase":"enqueue","polls":0,"recoveries":0,"ci_waits":0}' > "$STATE" log "init: starting merge loop for PR #$PR" echo "ACTION: ENQUEUE" ;; enqueued) STATE_JSON=$(cat "$STATE") echo "$STATE_JSON" | jq '.phase = "polling" | .polls = 0' > "$STATE" log "enqueued: PR added to merge queue" echo "ACTION: POLL" ;; enqueue-failed) REASON="${3:-unknown}" log "enqueue-failed: reason=$REASON" echo "ACTION: DONE_FAIL enqueue-failed $REASON" ;; merged) STATE_JSON=$(cat "$STATE") echo "$STATE_JSON" | jq '.phase = "done"' > "$STATE" log "merged: PR successfully merged!" echo "ACTION: DONE_SUCCESS" ;; queued) STATE_JSON=$(cat "$STATE") POLLS=$(echo "$STATE_JSON" | jq -r '.polls') if [ "$POLLS" -ge 60 ]; then log "queued: max poll attempts reached ($POLLS)" echo "ACTION: DONE_FAIL queue-timeout" else echo "$STATE_JSON" | jq ".polls = $((POLLS + 1))" > "$STATE" POSITION="${3:-unknown}" log "queued: poll $((POLLS + 1))/60, position=$POSITION" echo "ACTION: WAIT_POLL 60" fi ;; ejected) STATE_JSON=$(cat "$STATE") RECOVERIES=$(echo "$STATE_JSON" | jq -r '.recoveries') REASON="${3:-unknown}" if [ "$RECOVERIES" -ge 5 ]; then log "ejected: max recovery attempts reached ($RECOVERIES), reason=$REASON" echo "ACTION: DONE_FAIL max-recoveries" else echo "$STATE_JSON" | jq ".recoveries = $((RECOVERIES + 1)) | .phase = \"recovering\"" > "$STATE" log "ejected: recovery $((RECOVERIES + 1))/5, reason=$REASON" echo "ACTION: RECOVER $REASON" fi ;; closed) log "closed: PR was closed" echo "ACTION: DONE_FAIL pr-closed" ;; recovered) STATE_JSON=$(cat "$STATE") echo "$STATE_JSON" | jq '.phase = "wait_ci" | .ci_waits = 0' > "$STATE" log "recovered: fixes applied, waiting for CI" echo "ACTION: WAIT_CI 60" ;; ci-ready) STATE_JSON=$(cat "$STATE") echo "$STATE_JSON" | jq '.phase = "enqueue"' > "$STATE" log "ci-ready: all checks passing, re-enqueueing" echo "ACTION: ENQUEUE" ;; ci-pending) STATE_JSON=$(cat "$STATE") CI_WAITS=$(echo "$STATE_JSON" | jq -r '.ci_waits') if [ "$CI_WAITS" -ge 30 ]; then log "ci-pending: max CI wait attempts reached ($CI_WAITS)" echo "ACTION: DONE_FAIL ci-timeout" else echo "$STATE_JSON" | jq ".ci_waits = $((CI_WAITS + 1))" > "$STATE" log "ci-pending: wait $((CI_WAITS + 1))/30" echo "ACTION: WAIT_CI 60" fi ;; ci-fail) log "ci-fail: CI checks failing after recovery" echo "ACTION: DONE_FAIL ci-failure" ;; recovery-failed) log "recovery-failed: cannot auto-recover" echo "ACTION: DONE_FAIL recovery-failed" ;; re-enqueue) STATE_JSON=$(cat "$STATE") echo "$STATE_JSON" | jq '.phase = "enqueue"' > "$STATE" log "re-enqueue: re-adding to merge queue" echo "ACTION: ENQUEUE" ;; status) cat "$STATE" ;; esac DRIVER chmod +x /tmp/pr-merge-loop-driver.sh ``` ### 1d: Initialize ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" init) # Output: ACTION: ENQUEUE ``` Display PR metadata (title, branch, author), then proceed to Phase 2. --- ## Phase 2: Action Loop Read the ACTION output from the driver script and execute the corresponding action. **Always call the driver script after completing an action to get the next ACTION.** ### On `ACTION: ENQUEUE` Add the PR to the merge queue. ```bash gh pr merge <PR_NUMBER> --squash --delete-branch ``` When merge queue is enabled, this command adds the PR to the queue rather than merging immediately. The output will indicate the PR was added to the merge queue. **If the command fails:** - "not mergeable" or "merge conflict" → report `ejected conflict` - "required status check" or CI related → report `enqueue-failed ci-not-ready` and exit (use `/pr-check` first) - Other error → report `enqueue-failed <error>` and exit **If successful:** ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" enqueued) # Output: ACTION: POLL ``` Follow the returned ACTION. --- ### On `ACTION: POLL` Check the current state of the PR and merge queue. ```bash # Get PR state gh pr view <PR_NUMBER> --json state,mergedAt,mergeStateStatus,mergeable ``` **Decision tree:** 1. **PR is merged** (`state` = "MERGED" or `mergedAt` is not null): ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" merged) ``` 2. **PR is closed** (`state` = "CLOSED"): ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" closed) ``` 3. **PR is still open** (`state` = "OPEN"): Check if still in merge queue: ```bash # Check merge queue entries gh api graphql -f query=' query { repository(owner: "okou-ai", name: "okou") { mergeQueue(branch: "main") { entries(first: 10) { nodes { position state pullRequest { number } } } } } }' --jq '.data.repository.mergeQueue.entries.nodes[] | select(.pullRequest.number == <PR_NUMBER>)' ``` - **Found in queue** → PR is still queued. Extract position and state: ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" queued <position>) ``` - **Not in queue** (empty result, PR is OPEN but not in queue) → PR was ejected: Determine the reason by checking PR timeline: ```bash gh api repos/okou-ai/okou/pulls/<PR_NUMBER>/timeline --paginate --jq '.[] | select(.event == "removed_from_merge_queue") | {event, created_at, reason: .reason}' | tail -1 ``` Common ejection reasons: - `MERGE_CONFLICT` — conflicts with main or other queued PRs - `CI_FAILURE` — checks failed in merge queue build - `DEQUEUED` — manually dequeued or another PR in the group failed ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" ejected <reason>) ``` Follow the returned ACTION. --- ### On `ACTION: WAIT_POLL <seconds>` Wait and then poll again. ```bash sleep <seconds> ``` Then execute the POLL logic again. --- ### On `ACTION: RECOVER <reason>` Auto-recover from merge queue ejection based on the reason. #### Reason: `MERGE_CONFLICT` or `conflict` 1. Fetch latest main: ```bash git fetch origin main ``` 2. Rebase onto main: ```bash git rebase origin/main ``` 3. **If rebase succeeds** (no conflicts): ```bash git push --force-with-lease ``` 4. **If rebase has conflicts**: - Analyze each conflict - Resolve intelligently based on the intent of both changes - Continue rebase: `git rebase --continue` - Push: `git push --force-with-lease` 5. **If conflicts cannot be auto-resolved** (incompatible structural changes): ```bash git rebase --abort ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" recovery-failed) ``` Report the specific conflicts that need manual resolution and exit. 6. **If rebase and push succeed**: ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" recovered) # Output: ACTION: WAIT_CI 60 (wait for new CI run after push) ``` #### Reason: `CI_FAILURE` CI failed in the merge queue build. This might be a flaky test or an actual issue. 1. Check the merge queue build logs: ```bash gh run list --branch gh-readonly-queue/main/pr-<PR_NUMBER>-* --status failure -L 1 gh run view <run-id> --log-failed 2>/dev/null | tail -50 ``` 2. **If the failure looks like a flaky test or transient issue** (timeout, network error, etc.): - No code changes needed — just re-enqueue ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" re-enqueue) ``` 3. **If the failure is a real issue in our PR code**: ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" recovery-failed) ``` Report the specific failure and exit. Use `/pr-check` to fix CI issues. #### Reason: `DEQUEUED` or other Another PR in the merge queue group failed, causing this PR to be dequeued. This is not our fault — just re-enqueue directly. ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" re-enqueue) ``` Follow the returned ACTION. --- ### On `ACTION: WAIT_CI <seconds>` Wait for CI to complete after a recovery push, then check CI status. ```bash sleep <seconds> gh pr checks <PR_NUMBER> ``` **Decision:** - All non-skipped checks pass → report `ci-ready` (driver will re-enqueue) - Any check still `pending` → report `ci-pending` (driver will wait more) - Any check `fail` → report `ci-fail` (driver will exit — use `/pr-check` to fix)
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen