From eb6fb3c73b165b4f6d7a66ef6f8f9123ead208e9 Mon Sep 17 00:00:00 2001 From: mayor Date: Mon, 5 Jan 2026 20:24:47 +0100 Subject: [PATCH] fix(refinery): use rig's default_branch instead of hardcoded 'main' - Add DefaultBranch field to RoleData struct - Update refinery.md.tmpl to use {{ .DefaultBranch }} template variable - Populate DefaultBranch from rig config in prime.go and rig/manager.go - Default to 'main' if not configured - Add test verifying DefaultBranch rendering in refinery template Fixes issue where refinery agents merged to master instead of the configured default branch (e.g., 'develop' or 'develop-cstar'). --- internal/cmd/install.go | 1 + internal/cmd/prime.go | 11 +++++ internal/rig/manager.go | 10 +++++ internal/templates/roles/refinery.md.tmpl | 12 +++--- internal/templates/templates.go | 1 + internal/templates/templates_test.go | 50 +++++++++++++++++++++++ 6 files changed, 79 insertions(+), 6 deletions(-) diff --git a/internal/cmd/install.go b/internal/cmd/install.go index 61c25c7d..2aeca357 100644 --- a/internal/cmd/install.go +++ b/internal/cmd/install.go @@ -271,6 +271,7 @@ func createMayorCLAUDEmd(hqRoot, townRoot string) error { TownRoot: townRoot, TownName: townName, WorkDir: hqRoot, + DefaultBranch: "main", // Mayor doesn't merge, but field required MayorSession: session.MayorSessionName(), DeaconSession: session.DeaconSessionName(), } diff --git a/internal/cmd/prime.go b/internal/cmd/prime.go index e25cab32..650e4901 100644 --- a/internal/cmd/prime.go +++ b/internal/cmd/prime.go @@ -19,6 +19,7 @@ import ( "github.com/steveyegge/gastown/internal/constants" "github.com/steveyegge/gastown/internal/events" "github.com/steveyegge/gastown/internal/lock" + "github.com/steveyegge/gastown/internal/rig" "github.com/steveyegge/gastown/internal/session" "github.com/steveyegge/gastown/internal/style" "github.com/steveyegge/gastown/internal/templates" @@ -308,12 +309,22 @@ func outputPrimeContext(ctx RoleContext) error { // Get town name for session names townName, _ := workspace.GetTownName(ctx.TownRoot) + // Get default branch from rig config (default to "main" if not set) + defaultBranch := "main" + if ctx.Rig != "" && ctx.TownRoot != "" { + rigPath := filepath.Join(ctx.TownRoot, ctx.Rig) + if rigCfg, err := rig.LoadRigConfig(rigPath); err == nil && rigCfg.DefaultBranch != "" { + defaultBranch = rigCfg.DefaultBranch + } + } + data := templates.RoleData{ Role: roleName, RigName: ctx.Rig, TownRoot: ctx.TownRoot, TownName: townName, WorkDir: ctx.WorkDir, + DefaultBranch: defaultBranch, Polecat: ctx.Polecat, MayorSession: session.MayorSessionName(), DeaconSession: session.DeaconSessionName(), diff --git a/internal/rig/manager.go b/internal/rig/manager.go index 5c7a0ab1..41388081 100644 --- a/internal/rig/manager.go +++ b/internal/rig/manager.go @@ -791,12 +791,22 @@ func (m *Manager) createRoleCLAUDEmd(workspacePath string, role string, rigName // Get town name for session names townName, _ := workspace.GetTownName(m.townRoot) + // Get default branch from rig config (default to "main" if not set) + defaultBranch := "main" + if rigName != "" { + rigPath := filepath.Join(m.townRoot, rigName) + if rigCfg, err := LoadRigConfig(rigPath); err == nil && rigCfg.DefaultBranch != "" { + defaultBranch = rigCfg.DefaultBranch + } + } + data := templates.RoleData{ Role: role, RigName: rigName, TownRoot: m.townRoot, TownName: townName, WorkDir: workspacePath, + DefaultBranch: defaultBranch, Polecat: workerName, // Used for crew member name as well MayorSession: fmt.Sprintf("gt-%s-mayor", townName), DeaconSession: fmt.Sprintf("gt-%s-deacon", townName), diff --git a/internal/templates/roles/refinery.md.tmpl b/internal/templates/roles/refinery.md.tmpl index 5179d88b..8661f80d 100644 --- a/internal/templates/roles/refinery.md.tmpl +++ b/internal/templates/roles/refinery.md.tmpl @@ -109,7 +109,7 @@ not by Go code. This follows the Zero Friction Control (ZFC) principle. **Example: Handling a Conflict** ```bash git checkout -b temp origin/polecat/rictus-12345 -git rebase origin/main +git rebase origin/{{ .DefaultBranch }} # If conflict: git status # See what conflicted # DECISION: Can I resolve it? Is it trivial? @@ -226,7 +226,7 @@ If queue empty, skip to context-check step. **process-branch**: Pick next branch, rebase on main ```bash git checkout -b temp origin/polecat/ -git rebase origin/main +git rebase origin/{{ .DefaultBranch }} ``` If conflicts unresolvable: notify polecat, skip to loop-check. @@ -251,9 +251,9 @@ GATE: Cannot proceed to merge without fix OR bead filed **merge-push**: Merge to main and push immediately ```bash -git checkout main +git checkout {{ .DefaultBranch }} git merge --ff-only temp -git push origin main +git push origin {{ .DefaultBranch }} git branch -d temp git push origin --delete polecat/ ``` @@ -340,8 +340,8 @@ gt mail send {{ .RigName }}/ -s "Rebase needed" \ ### Git Operations - `git fetch origin` - Fetch all remote branches -- `git rebase origin/main` - Rebase on current main -- `git push origin main` - Push merged changes +- `git rebase origin/{{ .DefaultBranch }}` - Rebase on current main +- `git push origin {{ .DefaultBranch }}` - Push merged changes **IMPORTANT**: The merge queue source of truth is `gt mq list {{ .RigName }}`, NOT git branches. Do NOT use `git branch -r | grep polecat` or `git ls-remote | grep polecat` to check for work. diff --git a/internal/templates/templates.go b/internal/templates/templates.go index ea4c8f56..7809d04b 100644 --- a/internal/templates/templates.go +++ b/internal/templates/templates.go @@ -29,6 +29,7 @@ type RoleData struct { TownRoot string // e.g., "/Users/steve/ai" TownName string // e.g., "ai" - the town identifier for session names WorkDir string // current working directory + DefaultBranch string // default branch for merges (e.g., "main", "develop") Polecat string // polecat name (for polecat role) Polecats []string // list of polecats (for witness role) BeadsDir string // BEADS_DIR path diff --git a/internal/templates/templates_test.go b/internal/templates/templates_test.go index b0c301cb..519cc4eb 100644 --- a/internal/templates/templates_test.go +++ b/internal/templates/templates_test.go @@ -26,6 +26,7 @@ func TestRenderRole_Mayor(t *testing.T) { TownRoot: "/test/town", TownName: "town", WorkDir: "/test/town", + DefaultBranch: "main", MayorSession: "gt-town-mayor", DeaconSession: "gt-town-deacon", } @@ -59,6 +60,7 @@ func TestRenderRole_Polecat(t *testing.T) { TownRoot: "/test/town", TownName: "town", WorkDir: "/test/town/myrig/polecats/TestCat", + DefaultBranch: "main", Polecat: "TestCat", MayorSession: "gt-town-mayor", DeaconSession: "gt-town-deacon", @@ -92,6 +94,7 @@ func TestRenderRole_Deacon(t *testing.T) { TownRoot: "/test/town", TownName: "town", WorkDir: "/test/town", + DefaultBranch: "main", MayorSession: "gt-town-mayor", DeaconSession: "gt-town-deacon", } @@ -119,6 +122,53 @@ func TestRenderRole_Deacon(t *testing.T) { } } +func TestRenderRole_Refinery_DefaultBranch(t *testing.T) { + tmpl, err := New() + if err != nil { + t.Fatalf("New() error = %v", err) + } + + // Test with custom default branch (e.g., "develop") + data := RoleData{ + Role: "refinery", + RigName: "myrig", + TownRoot: "/test/town", + TownName: "town", + WorkDir: "/test/town/myrig/refinery/rig", + DefaultBranch: "develop", + MayorSession: "gt-town-mayor", + DeaconSession: "gt-town-deacon", + } + + output, err := tmpl.RenderRole("refinery", data) + if err != nil { + t.Fatalf("RenderRole() error = %v", err) + } + + // Check that the custom default branch is used in git commands + if !strings.Contains(output, "origin/develop") { + t.Error("output missing 'origin/develop' - DefaultBranch not being used for rebase") + } + if !strings.Contains(output, "git checkout develop") { + t.Error("output missing 'git checkout develop' - DefaultBranch not being used for checkout") + } + if !strings.Contains(output, "git push origin develop") { + t.Error("output missing 'git push origin develop' - DefaultBranch not being used for push") + } + + // Verify it does NOT contain hardcoded "main" in git commands + // (main may appear in other contexts like "main branch" descriptions, so we check specific patterns) + if strings.Contains(output, "git rebase origin/main") { + t.Error("output still contains hardcoded 'git rebase origin/main' - should use DefaultBranch") + } + if strings.Contains(output, "git checkout main") { + t.Error("output still contains hardcoded 'git checkout main' - should use DefaultBranch") + } + if strings.Contains(output, "git push origin main") { + t.Error("output still contains hardcoded 'git push origin main' - should use DefaultBranch") + } +} + func TestRenderMessage_Spawn(t *testing.T) { tmpl, err := New() if err != nil {