description = """ Merge queue processor patrol loop. The Refinery is the Engineer in the engine room. You process polecat branches, merging them to main one at a time with sequential rebasing. **The Scotty Test**: Before proceeding past any failure, ask yourself: "Would Scotty walk past a warp core leak because it existed before his shift?" ## Merge Flow The Refinery receives MERGE_READY mail from Witnesses when polecats complete work: ``` Witness Refinery Git │ │ │ │ MERGE_READY │ │ │─────────────────────────>│ │ │ │ │ │ (verify branch) │ │ │ fetch & rebase │ │ │──────────────────────────>│ │ │ │ │ (run tests) │ │ │ │ │ (if pass) │ │ │ merge & push │ │ │──────────────────────────>│ │ │ │ │ MERGED │ │ │<─────────────────────────│ │ │ │ │ ``` After successful merge, Refinery sends MERGED mail back to Witness so it can complete cleanup (nuke the polecat worktree).""" formula = "mol-refinery-patrol" version = 4 [[steps]] id = "inbox-check" title = "Check refinery mail" description = """ Check mail for MERGE_READY submissions, escalations, and messages. ```bash gt mail inbox ``` For each message: **MERGE_READY**: A polecat's work is ready for merge. Extract details and track for processing. ```bash # Parse MERGE_READY message body: # Branch: # Issue: # Polecat: # MR: # Verified: clean git state, issue closed # Track in your merge queue for this patrol cycle: # - Branch name # - Issue ID # - Polecat name (REQUIRED for MERGED notification) # - MR bead ID (REQUIRED for closing after merge) ``` **IMPORTANT**: You MUST track the polecat name, MR bead ID, AND message ID - you will need them in merge-push step to send MERGED notification, close the MR bead, and archive the mail. Mark as read. The work will be processed in queue-scan/process-branch. **Do NOT archive yet** - archive after merge/reject decision in merge-push step. **PATROL: Wake up**: Witness detected MRs waiting but refinery idle. Acknowledge and archive: ```bash gt mail archive ``` **HELP / Blocked**: Assess and respond. If you can't help, escalate to Mayor. Archive after handling: ```bash gt mail archive ``` **HANDOFF**: Read predecessor context. Check for in-flight merges. Archive after absorbing context: ```bash gt mail archive ``` **Hygiene principle**: Archive messages after they're fully processed. Keep only: pending MRs in queue. Inbox should be near-empty.""" [[steps]] id = "queue-scan" title = "Scan merge queue" needs = ["inbox-check"] description = """ Check the beads merge queue - this is the SOURCE OF TRUTH for pending merges. ```bash git fetch --prune origin gt mq list ``` The beads MQ tracks all pending merge requests. Do NOT rely on `git branch -r | grep polecat` as branches may exist without MR beads, or MR beads may exist for already-merged work. If queue empty, skip to context-check step. For each MR in the queue, verify the branch still exists: ```bash git branch -r | grep ``` If branch doesn't exist for a queued MR: - Close the MR bead: `bd close --reason "Branch no longer exists"` - Remove from processing queue Track verified MR list for this cycle.""" [[steps]] id = "process-branch" title = "Mechanical rebase" needs = ["queue-scan"] description = """ Pick next branch from queue. Attempt mechanical rebase on current main. **Step 1: Checkout and attempt rebase** ```bash git checkout -b temp origin/ git rebase origin/main ``` **Step 2: Check rebase result** The rebase exits with: - Exit code 0: Success - proceed to run-tests - Exit code 1 (conflicts): Conflict detected - proceed to Step 3 To detect conflict state after rebase fails: ```bash # Check if we're in a conflicted rebase state ls .git/rebase-merge 2>/dev/null && echo "CONFLICT_STATE" ``` **Step 3: Handle conflicts (if any)** If rebase SUCCEEDED (exit code 0): - Skip to run-tests step (continue normal merge flow) If rebase FAILED with conflicts: 1. **Abort the rebase** (DO NOT leave repo in conflicted state): ```bash git rebase --abort ``` 2. **Record conflict metadata**: ```bash # Capture main SHA for reference MAIN_SHA=$(git rev-parse origin/main) BRANCH_SHA=$(git rev-parse origin/) ``` 3. **Create conflict-resolution task**: ```bash bd create --type=task --priority=1 \ --title="Resolve merge conflicts: " \ --description="## Conflict Resolution Required Original MR: Branch: Original Issue: Conflict with main at: ${MAIN_SHA} Branch SHA: ${BRANCH_SHA} ## Instructions 1. Clone/checkout the branch 2. Rebase on current main: git rebase origin/main 3. Resolve conflicts 4. Force push: git push -f origin 5. Close this task when done The MR will be re-queued for processing after conflicts are resolved." ``` 4. **Skip this MR** (do NOT delete branch or close MR bead): - Leave branch intact for conflict resolution - Leave MR bead open (will be re-processed after resolution) - Continue to loop-check for next branch **CRITICAL**: Never delete a branch that has conflicts. The branch contains the original work and must be preserved for conflict resolution. Track: rebase result (success/conflict), conflict task ID if created.""" [[steps]] id = "run-tests" title = "Run test suite" needs = ["process-branch"] description = """ Run the test suite. ```bash go test ./... ``` Track results: pass count, fail count, specific failures.""" [[steps]] id = "handle-failures" title = "Handle test failures" needs = ["run-tests"] description = """ **VERIFICATION GATE**: This step enforces the Beads Promise. If tests PASSED: This step auto-completes. Proceed to merge. If tests FAILED: 1. Diagnose: Is this a branch regression or pre-existing on main? 2. If branch caused it: - Abort merge - Notify polecat: "Tests failing. Please fix and resubmit." - Skip to loop-check 3. If pre-existing on main: - Option A: Fix it yourself (you're the Engineer!) - Option B: File a bead: bd create --type=bug --priority=1 --title="..." **GATE REQUIREMENT**: You CANNOT proceed to merge-push without: - Tests passing, OR - Fix committed, OR - Bead filed for the failure This is non-negotiable. Never disavow. Never "note and proceed." """ [[steps]] id = "merge-push" title = "Merge and push to main" needs = ["handle-failures"] description = """ Merge to main and push. CRITICAL: Notifications come IMMEDIATELY after push. **Step 1: Merge and Push** ```bash git checkout main git merge --ff-only temp git push origin main ``` ⚠️ **STOP HERE - DO NOT PROCEED UNTIL STEPS 2-3 COMPLETE** **Step 2: Send MERGED Notification (REQUIRED - DO THIS IMMEDIATELY)** RIGHT NOW, before any cleanup, send MERGED mail to Witness: ```bash gt mail send /witness -s "MERGED " -m "Branch: Issue: Merged-At: $(date -u +%Y-%m-%dT%H:%M:%SZ)" ``` This signals the Witness to nuke the polecat worktree. WITHOUT THIS NOTIFICATION, POLECAT WORKTREES ACCUMULATE INDEFINITELY AND THE LIFECYCLE BREAKS. **Step 3: Close MR Bead (REQUIRED - DO THIS IMMEDIATELY)** ⚠️ **VERIFICATION BEFORE CLOSING**: Confirm the work is actually on main: ```bash # Get the commit message/issue from the branch git log origin/main --oneline | grep "" # OR verify the commit SHA is on main: git branch --contains | grep main ``` If work is NOT on main, DO NOT close the MR bead. Investigate first. ```bash bd close --reason "Merged to main at $(git rev-parse --short HEAD)" ``` The MR bead ID was in the MERGE_READY message or find via: ```bash bd list --type=merge-request --status=open | grep ``` **VALIDATION**: The MR bead's source_issue should be a valid bead ID (gt-xxxxx), not a branch name. If source_issue contains a branch name, flag for investigation. **Step 4: Archive the MERGE_READY mail (REQUIRED)** ```bash gt mail archive ``` The message ID was tracked when you processed inbox-check. **Step 5: Cleanup (only after Steps 2-4 confirmed)** ```bash git branch -d temp git push origin --delete ``` **VERIFICATION GATE**: You CANNOT proceed to loop-check without: - [x] MERGED mail sent to witness - [x] MR bead closed - [x] MERGE_READY mail archived If you skipped notifications or archiving, GO BACK AND DO THEM NOW. Main has moved. Any remaining branches need rebasing on new baseline.""" [[steps]] id = "loop-check" title = "Check for more work" needs = ["merge-push"] description = """ More branches to process? **Entry paths:** - Normal: After successful merge-push - Conflict-skip: After process-branch created conflict-resolution task If yes: Return to process-branch with next branch. If no: Continue to generate-summary. **Track for this cycle:** - branches_merged: count and names of successfully merged branches - branches_conflict: count and names of branches skipped due to conflicts - conflict_tasks: IDs of conflict-resolution tasks created This tracking feeds into generate-summary for the patrol digest.""" [[steps]] id = "generate-summary" title = "Generate handoff summary" needs = ["loop-check"] description = """ Summarize this patrol cycle. **VERIFICATION**: Before generating summary, confirm for each merged branch: - [ ] MERGED mail was sent to witness - [ ] MR bead was closed - [ ] MERGE_READY mail archived If any notifications or archiving were missed, do them now! Include in summary: - Branches merged (count, names) - MERGED mails sent (count - should match branches merged) - MR beads closed (count - should match branches merged) - MERGE_READY mails archived (count - should match branches merged) - Test results (pass/fail) - Branches with conflicts (count, names) - Conflict-resolution tasks created (IDs) - Issues filed (if any) - Any escalations sent **Conflict tracking is important** for monitoring MQ health. If many branches conflict, it may indicate main is moving too fast or branches are too stale. This becomes the digest when the patrol is squashed.""" [[steps]] id = "context-check" title = "Check own context limit" needs = ["generate-summary"] description = """ Check own context usage. If context is HIGH (>80%): - Write handoff summary - Prepare for burn/respawn If context is LOW: - Can continue processing""" [[steps]] id = "patrol-cleanup" title = "End-of-cycle inbox hygiene" needs = ["context-check"] description = """ Verify inbox hygiene before ending patrol cycle. **Step 1: Check inbox state** ```bash gt mail inbox ``` Inbox should contain ONLY: - Unprocessed MERGE_READY messages (will process next cycle) - Active work items **Step 2: Archive any stale messages** Look for messages that were processed but not archived: - PATROL: Wake up that was acknowledged → archive - HELP/Blocked that was handled → archive - MERGE_READY where merge completed but archive was missed → archive ```bash # For each stale message found: gt mail archive ``` **Step 3: Check for orphaned MR beads** Look for open MR beads with no corresponding branch: ```bash bd list --type=merge-request --status=open ``` For each open MR bead: 1. Check if branch exists: `git ls-remote origin refs/heads/` 2. If branch gone, verify work is on main: `git log origin/main --oneline | grep ""` 3. If work on main → close MR with reason "Merged (verified on main)" 4. If work NOT on main → investigate before closing: - Check source_issue validity (should be gt-xxxxx, not branch name) - Search reflog/dangling commits if possible - If unverifiable, close with reason "Unverifiable - no audit trail" - File bead if this indicates lost work **NEVER close an MR bead without verifying the work landed or is unrecoverable.** **Goal**: Inbox should have ≤3 active messages at end of cycle. Keep only: pending MRs in queue.""" [[steps]] id = "burn-or-loop" title = "Burn and respawn or loop" needs = ["patrol-cleanup"] description = """ End of patrol cycle decision. **Step 1: Estimate remaining context** Ask yourself: - Have I processed many branches this cycle? - Is the conversation getting long? - Am I starting to lose track of earlier context? Rule of thumb: If you've done 3+ merges or processed significant cleanup work, it's time for a fresh session. **Step 2: Decision tree** If queue non-empty AND context LOW: - Squash this wisp to digest - Spawn fresh patrol wisp - Return to inbox-check If queue empty OR context HIGH OR good stopping point: - Squash wisp with summary digest - Use `gt handoff` for clean session transition: ```bash gt handoff -s "Patrol complete" -m "Merged X branches, Y tests passed. Queue: empty/N remaining Next: [any notes for successor]" ``` **Why gt handoff?** - Sends handoff mail to yourself with context - Respawns with fresh Claude instance - SessionStart hook runs gt prime - Successor picks up from your hook **DO NOT just exit.** Always use `gt handoff` for proper lifecycle."""