fix(done): restrict gt done to polecats only
Add BD_ACTOR check at start of runDone() to prevent non-polecat roles (crew, deacon, witness, etc.) from calling gt done. Only polecats are ephemeral workers that self-destruct after completing work. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Steve Yegge
parent
f82477d6a6
commit
9a91a1b94f
@@ -82,6 +82,14 @@ func init() {
|
||||
}
|
||||
|
||||
func runDone(cmd *cobra.Command, args []string) error {
|
||||
// Guard: Only polecats should call gt done
|
||||
// Crew, deacons, witnesses etc. don't use gt done - they persist across tasks.
|
||||
// Polecats are ephemeral workers that self-destruct after completing work.
|
||||
actor := os.Getenv("BD_ACTOR")
|
||||
if actor != "" && !isPolecatActor(actor) {
|
||||
return fmt.Errorf("gt done is for polecats only (you are %s)\nPolecats are ephemeral workers that self-destruct after completing work.\nOther roles persist across tasks and don't use gt done.", actor)
|
||||
}
|
||||
|
||||
// Handle --phase-complete flag (overrides --status)
|
||||
var exitType string
|
||||
if donePhaseComplete {
|
||||
@@ -708,6 +716,14 @@ func selfNukePolecat(roleInfo RoleInfo, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// isPolecatActor checks if a BD_ACTOR value represents a polecat.
|
||||
// Polecat actors have format: rigname/polecats/polecatname
|
||||
// Non-polecat actors have formats like: gastown/crew/name, rigname/witness, etc.
|
||||
func isPolecatActor(actor string) bool {
|
||||
parts := strings.Split(actor, "/")
|
||||
return len(parts) >= 2 && parts[1] == "polecats"
|
||||
}
|
||||
|
||||
// selfKillSession terminates the polecat's own tmux session after logging the event.
|
||||
// This completes the self-cleaning model: "done means gone" - both worktree and session.
|
||||
//
|
||||
|
||||
@@ -341,3 +341,39 @@ func TestGetIssueFromAgentHook(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestIsPolecatActor verifies that isPolecatActor correctly identifies
|
||||
// polecat actors vs other roles based on the BD_ACTOR format.
|
||||
func TestIsPolecatActor(t *testing.T) {
|
||||
tests := []struct {
|
||||
actor string
|
||||
want bool
|
||||
}{
|
||||
// Polecats: rigname/polecats/polecatname
|
||||
{"testrig/polecats/furiosa", true},
|
||||
{"testrig/polecats/nux", true},
|
||||
{"myrig/polecats/witness", true}, // even if named "witness", still a polecat
|
||||
|
||||
// Non-polecats
|
||||
{"gastown/crew/george", false},
|
||||
{"gastown/crew/max", false},
|
||||
{"testrig/witness", false},
|
||||
{"testrig/deacon", false},
|
||||
{"testrig/mayor", false},
|
||||
{"gastown/refinery", false},
|
||||
|
||||
// Edge cases
|
||||
{"", false},
|
||||
{"single", false},
|
||||
{"polecats/name", false}, // needs rig prefix
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.actor, func(t *testing.T) {
|
||||
got := isPolecatActor(tt.actor)
|
||||
if got != tt.want {
|
||||
t.Errorf("isPolecatActor(%q) = %v, want %v", tt.actor, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user