refactor(swarm): remove idle polecat reuse logic (self-cleaning model)

The swarm dispatch command now always spawns fresh polecats instead of
searching for idle ones to reuse. With the self-cleaning model, polecats
self-nuke when done - there are no idle polecats to reuse.

Closes: gt-h4yc3

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
mayor
2026-01-10 22:45:56 -08:00
committed by Steve Yegge
parent 5607bc4f01
commit 1bed63f087

View File

@@ -131,11 +131,12 @@ Transitions the swarm from 'created' to 'active' state.`,
var swarmDispatchCmd = &cobra.Command{ var swarmDispatchCmd = &cobra.Command{
Use: "dispatch <epic-id>", Use: "dispatch <epic-id>",
Short: "Assign next ready task to an idle worker", Short: "Assign next ready task to a fresh polecat",
Long: `Dispatch the next ready task from an epic to an available worker. Long: `Dispatch the next ready task from an epic to a new polecat.
Finds the first unassigned task in the epic's ready front and slings it Finds the first unassigned task in the epic's ready front and spawns a
to an idle polecat in the rig. fresh polecat to work on it. Self-cleaning model: polecats are always
fresh - there are no idle polecats to reuse.
Examples: Examples:
gt swarm dispatch gt-abc # Dispatch next task from epic gt-abc gt swarm dispatch gt-abc # Dispatch next task from epic gt-abc
@@ -458,49 +459,15 @@ func runSwarmDispatch(cmd *cobra.Command, args []string) error {
return nil return nil
} }
// Find idle polecats (no hooked work) // Self-cleaning model: Always spawn fresh polecats for work.
polecatGit := git.NewGit(foundRig.Path) // There are no "idle" polecats - polecats self-nuke when done.
polecatMgr := polecat.NewManager(foundRig, polecatGit) // Just sling to the rig and let gt sling spawn a fresh polecat.
polecats, err := polecatMgr.List()
if err != nil {
return fmt.Errorf("listing polecats: %w", err)
}
// Check which polecats have no hooked work
var idlePolecats []string
for _, p := range polecats {
// Check if polecat has hooked work by querying beads
hookCheckCmd := exec.Command("bd", "list", "--status=hooked", "--assignee", fmt.Sprintf("%s/polecats/%s", foundRig.Name, p.Name), "--json")
hookCheckCmd.Dir = foundRig.BeadsPath()
var hookOut bytes.Buffer
hookCheckCmd.Stdout = &hookOut
if err := hookCheckCmd.Run(); err == nil {
var hooked []interface{}
if err := json.Unmarshal(hookOut.Bytes(), &hooked); err == nil && len(hooked) == 0 {
idlePolecats = append(idlePolecats, p.Name)
}
}
}
if len(idlePolecats) == 0 {
fmt.Println("No idle polecats available")
fmt.Printf("\nUnassigned ready tasks:\n")
for _, task := range unassigned {
fmt.Printf(" ○ %s: %s\n", task.ID, task.Title)
}
fmt.Printf("\nCreate a new polecat or wait for one to become idle.\n")
return nil
}
// Dispatch first unassigned task to first idle polecat
task := unassigned[0] task := unassigned[0]
worker := idlePolecats[0]
target := fmt.Sprintf("%s/%s", foundRig.Name, worker)
fmt.Printf("Dispatching %s to %s...\n", task.ID, target) fmt.Printf("Dispatching %s to fresh polecat in %s...\n", task.ID, foundRig.Name)
// Use gt sling to assign the task // Use gt sling to spawn a fresh polecat and assign the task
slingCmd := exec.Command("gt", "sling", task.ID, target) slingCmd := exec.Command("gt", "sling", task.ID, foundRig.Name)
slingCmd.Dir = townRoot slingCmd.Dir = townRoot
slingCmd.Stdout = os.Stdout slingCmd.Stdout = os.Stdout
slingCmd.Stderr = os.Stderr slingCmd.Stderr = os.Stderr
@@ -509,15 +476,12 @@ func runSwarmDispatch(cmd *cobra.Command, args []string) error {
return fmt.Errorf("slinging task: %w", err) return fmt.Errorf("slinging task: %w", err)
} }
fmt.Printf("%s Dispatched %s: %s → %s\n", style.Bold.Render("✓"), task.ID, task.Title, target) fmt.Printf("%s Dispatched %s: %s → fresh polecat\n", style.Bold.Render("✓"), task.ID, task.Title)
// Show remaining tasks and workers // Show remaining tasks
if len(unassigned) > 1 { if len(unassigned) > 1 {
fmt.Printf("\n%d more ready tasks available\n", len(unassigned)-1) fmt.Printf("\n%d more ready tasks available\n", len(unassigned)-1)
} }
if len(idlePolecats) > 1 {
fmt.Printf("%d more idle polecats available\n", len(idlePolecats)-1)
}
return nil return nil
} }