fix: align assigneeID format with hooked issue format (#946)
The polecat manager was using rig/name format while sling sets rig/polecats/name. This caused gt polecat status to show 'done' for working polecats because GetAssignedIssue couldn't find them. Fixes gt-oohy
This commit is contained in:
@@ -327,7 +327,7 @@ func (b *Beads) List(opts ListOptions) ([]*Issue, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListByAssignee returns all issues assigned to a specific assignee.
|
// ListByAssignee returns all issues assigned to a specific assignee.
|
||||||
// The assignee is typically in the format "rig/polecatName" (e.g., "gastown/Toast").
|
// The assignee is typically in the format "rig/polecats/polecatName" (e.g., "gastown/polecats/Toast").
|
||||||
func (b *Beads) ListByAssignee(assignee string) ([]*Issue, error) {
|
func (b *Beads) ListByAssignee(assignee string) ([]*Issue, error) {
|
||||||
return b.List(ListOptions{
|
return b.List(ListOptions{
|
||||||
Status: "all", // Include both open and closed for state derivation
|
Status: "all", // Include both open and closed for state derivation
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ func NewManager(r *rig.Rig, g *git.Git, t *tmux.Tmux) *Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// assigneeID returns the beads assignee identifier for a polecat.
|
// assigneeID returns the beads assignee identifier for a polecat.
|
||||||
// Format: "rig/polecatName" (e.g., "gastown/Toast")
|
// Format: "rig/polecats/polecatName" (e.g., "gastown/polecats/Toast")
|
||||||
func (m *Manager) assigneeID(name string) string {
|
func (m *Manager) assigneeID(name string) string {
|
||||||
return fmt.Sprintf("%s/%s", m.rig.Name, name)
|
return fmt.Sprintf("%s/polecats/%s", m.rig.Name, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// agentBeadID returns the agent bead ID for a polecat.
|
// agentBeadID returns the agent bead ID for a polecat.
|
||||||
@@ -265,8 +265,8 @@ func (m *Manager) buildBranchName(name, issue string) string {
|
|||||||
|
|
||||||
// {year} and {month}
|
// {year} and {month}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
vars["{year}"] = now.Format("06") // YY format
|
vars["{year}"] = now.Format("06") // YY format
|
||||||
vars["{month}"] = now.Format("01") // MM format
|
vars["{month}"] = now.Format("01") // MM format
|
||||||
|
|
||||||
// {name}
|
// {name}
|
||||||
vars["{name}"] = name
|
vars["{name}"] = name
|
||||||
@@ -1108,13 +1108,13 @@ func (m *Manager) CleanupStaleBranches() (int, error) {
|
|||||||
|
|
||||||
// StalenessInfo contains details about a polecat's staleness.
|
// StalenessInfo contains details about a polecat's staleness.
|
||||||
type StalenessInfo struct {
|
type StalenessInfo struct {
|
||||||
Name string
|
Name string
|
||||||
CommitsBehind int // How many commits behind origin/main
|
CommitsBehind int // How many commits behind origin/main
|
||||||
HasActiveSession bool // Whether tmux session is running
|
HasActiveSession bool // Whether tmux session is running
|
||||||
HasUncommittedWork bool // Whether there's uncommitted or unpushed work
|
HasUncommittedWork bool // Whether there's uncommitted or unpushed work
|
||||||
AgentState string // From agent bead (empty if no bead)
|
AgentState string // From agent bead (empty if no bead)
|
||||||
IsStale bool // Overall assessment: safe to clean up
|
IsStale bool // Overall assessment: safe to clean up
|
||||||
Reason string // Why it's considered stale (or not)
|
Reason string // Why it's considered stale (or not)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DetectStalePolecats identifies polecats that are candidates for cleanup.
|
// DetectStalePolecats identifies polecats that are candidates for cleanup.
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ func TestAssigneeID(t *testing.T) {
|
|||||||
m := NewManager(r, git.NewGit(r.Path), nil)
|
m := NewManager(r, git.NewGit(r.Path), nil)
|
||||||
|
|
||||||
id := m.assigneeID("Toast")
|
id := m.assigneeID("Toast")
|
||||||
expected := "test-rig/Toast"
|
expected := "test-rig/polecats/Toast"
|
||||||
if id != expected {
|
if id != expected {
|
||||||
t.Errorf("assigneeID = %q, want %q", id, expected)
|
t.Errorf("assigneeID = %q, want %q", id, expected)
|
||||||
}
|
}
|
||||||
@@ -446,81 +446,83 @@ func TestAddWithOptions_AgentsMDFallback(t *testing.T) {
|
|||||||
t.Errorf("AGENTS.md content = %q, want %q", gotContent, wantContent)
|
t.Errorf("AGENTS.md content = %q, want %q", gotContent, wantContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestReconcilePoolWith tests all permutations of directory and session existence.
|
// TestReconcilePoolWith tests all permutations of directory and session existence.
|
||||||
// This is the core allocation policy logic.
|
// This is the core allocation policy logic.
|
||||||
//
|
//
|
||||||
// Truth table:
|
// Truth table:
|
||||||
// HasDir | HasSession | Result
|
//
|
||||||
// -------|------------|------------------
|
// HasDir | HasSession | Result
|
||||||
// false | false | available (not in-use)
|
// -------|------------|------------------
|
||||||
// true | false | in-use (normal finished polecat)
|
// false | false | available (not in-use)
|
||||||
// false | true | orphan → kill session, available
|
// true | false | in-use (normal finished polecat)
|
||||||
// true | true | in-use (normal working polecat)
|
// false | true | orphan → kill session, available
|
||||||
|
// true | true | in-use (normal working polecat)
|
||||||
func TestReconcilePoolWith(t *testing.T) {
|
func TestReconcilePoolWith(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
namesWithDirs []string
|
namesWithDirs []string
|
||||||
namesWithSessions []string
|
namesWithSessions []string
|
||||||
wantInUse []string // names that should be marked in-use
|
wantInUse []string // names that should be marked in-use
|
||||||
wantOrphans []string // sessions that should be killed
|
wantOrphans []string // sessions that should be killed
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no dirs, no sessions - all available",
|
name: "no dirs, no sessions - all available",
|
||||||
namesWithDirs: []string{},
|
namesWithDirs: []string{},
|
||||||
namesWithSessions: []string{},
|
namesWithSessions: []string{},
|
||||||
wantInUse: []string{},
|
wantInUse: []string{},
|
||||||
wantOrphans: []string{},
|
wantOrphans: []string{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "has dir, no session - in use",
|
name: "has dir, no session - in use",
|
||||||
namesWithDirs: []string{"toast"},
|
namesWithDirs: []string{"toast"},
|
||||||
namesWithSessions: []string{},
|
namesWithSessions: []string{},
|
||||||
wantInUse: []string{"toast"},
|
wantInUse: []string{"toast"},
|
||||||
wantOrphans: []string{},
|
wantOrphans: []string{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no dir, has session - orphan killed",
|
name: "no dir, has session - orphan killed",
|
||||||
namesWithDirs: []string{},
|
namesWithDirs: []string{},
|
||||||
namesWithSessions: []string{"nux"},
|
namesWithSessions: []string{"nux"},
|
||||||
wantInUse: []string{},
|
wantInUse: []string{},
|
||||||
wantOrphans: []string{"nux"},
|
wantOrphans: []string{"nux"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "has dir, has session - in use",
|
name: "has dir, has session - in use",
|
||||||
namesWithDirs: []string{"capable"},
|
namesWithDirs: []string{"capable"},
|
||||||
namesWithSessions: []string{"capable"},
|
namesWithSessions: []string{"capable"},
|
||||||
wantInUse: []string{"capable"},
|
wantInUse: []string{"capable"},
|
||||||
wantOrphans: []string{},
|
wantOrphans: []string{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "mixed: one with dir, one orphan session",
|
name: "mixed: one with dir, one orphan session",
|
||||||
namesWithDirs: []string{"toast"},
|
namesWithDirs: []string{"toast"},
|
||||||
namesWithSessions: []string{"toast", "nux"},
|
namesWithSessions: []string{"toast", "nux"},
|
||||||
wantInUse: []string{"toast"},
|
wantInUse: []string{"toast"},
|
||||||
wantOrphans: []string{"nux"},
|
wantOrphans: []string{"nux"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple dirs, no sessions",
|
name: "multiple dirs, no sessions",
|
||||||
namesWithDirs: []string{"toast", "nux", "capable"},
|
namesWithDirs: []string{"toast", "nux", "capable"},
|
||||||
namesWithSessions: []string{},
|
namesWithSessions: []string{},
|
||||||
wantInUse: []string{"capable", "nux", "toast"},
|
wantInUse: []string{"capable", "nux", "toast"},
|
||||||
wantOrphans: []string{},
|
wantOrphans: []string{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple orphan sessions",
|
name: "multiple orphan sessions",
|
||||||
namesWithDirs: []string{},
|
namesWithDirs: []string{},
|
||||||
namesWithSessions: []string{"slit", "rictus"},
|
namesWithSessions: []string{"slit", "rictus"},
|
||||||
wantInUse: []string{},
|
wantInUse: []string{},
|
||||||
wantOrphans: []string{"rictus", "slit"},
|
wantOrphans: []string{"rictus", "slit"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "complex: dirs, valid sessions, orphan sessions",
|
name: "complex: dirs, valid sessions, orphan sessions",
|
||||||
namesWithDirs: []string{"toast", "capable"},
|
namesWithDirs: []string{"toast", "capable"},
|
||||||
namesWithSessions: []string{"toast", "nux", "slit"},
|
namesWithSessions: []string{"toast", "nux", "slit"},
|
||||||
wantInUse: []string{"capable", "toast"},
|
wantInUse: []string{"capable", "toast"},
|
||||||
wantOrphans: []string{"nux", "slit"},
|
wantOrphans: []string{"nux", "slit"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user