* fix: Commit embedded formulas for go install @latest The internal/formula/formulas/ directory was gitignored, causing `go install github.com/steveyegge/gastown/cmd/gt@latest` to fail with: pattern formulas/*.formula.json: no matching files found The go:embed directive requires these files at build time, but go install @latest doesn't run go:generate. By committing the generated formulas, users can install directly without cloning. Maintainers should run `go generate ./...` after modifying .beads/formulas/ to keep the embedded copy in sync. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * ci: Add check for committed embedded formulas Adds a new CI job that: 1. Builds without running go:generate (catches missing formulas) 2. Verifies committed formulas match .beads/formulas/ source Also removes redundant go:generate steps from other jobs since formulas are now committed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: exclude towers-of-hanoi test formulas from embed These are durability stress test fixtures (pre-computed move sequences), not production formulas users need. Excluding them reduces embedded content by ~10K lines. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: gus <steve.yegge@gmail.com>
470 lines
14 KiB
TOML
470 lines
14 KiB
TOML
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: <branch>
|
|
# Issue: <issue-id>
|
|
# Polecat: <polecat-name>
|
|
# MR: <mr-bead-id>
|
|
# 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 <message-id>
|
|
```
|
|
|
|
**HELP / Blocked**:
|
|
Assess and respond. If you can't help, escalate to Mayor.
|
|
Archive after handling:
|
|
```bash
|
|
gt mail archive <message-id>
|
|
```
|
|
|
|
**HANDOFF**:
|
|
Read predecessor context. Check for in-flight merges.
|
|
Archive after absorbing context:
|
|
```bash
|
|
gt mail archive <message-id>
|
|
```
|
|
|
|
**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 <rig>
|
|
```
|
|
|
|
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 <branch>
|
|
```
|
|
|
|
If branch doesn't exist for a queued MR:
|
|
- Close the MR bead: `bd close <mr-id> --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/<polecat-branch>
|
|
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/<polecat-branch>)
|
|
```
|
|
|
|
3. **Create conflict-resolution task**:
|
|
```bash
|
|
bd create --type=task --priority=1 \
|
|
--title="Resolve merge conflicts: <original-issue-title>" \
|
|
--description="## Conflict Resolution Required
|
|
|
|
Original MR: <mr-bead-id>
|
|
Branch: <polecat-branch>
|
|
Original Issue: <issue-id>
|
|
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 <branch>
|
|
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 <rig>/witness -s "MERGED <polecat-name>" -m "Branch: <branch>
|
|
Issue: <issue-id>
|
|
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 "<issue-id>"
|
|
# OR verify the commit SHA is on main:
|
|
git branch --contains <commit-sha> | grep main
|
|
```
|
|
|
|
If work is NOT on main, DO NOT close the MR bead. Investigate first.
|
|
|
|
```bash
|
|
bd close <mr-bead-id> --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 <polecat-name>
|
|
```
|
|
|
|
**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 <merge-ready-message-id>
|
|
```
|
|
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 <polecat-branch>
|
|
```
|
|
|
|
**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 <message-id>
|
|
```
|
|
|
|
**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/<branch>`
|
|
2. If branch gone, verify work is on main: `git log origin/main --oneline | grep "<source_issue>"`
|
|
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."""
|