@@ -284,13 +284,14 @@ Examples:
284284
285285var convoyStrandedCmd = & cobra.Command {
286286 Use : "stranded" ,
287- Short : "Find stranded convoys (ready work or empty) needing attention" ,
287+ Short : "Find stranded convoys (ready work, stuck, or empty) needing attention" ,
288288 Long : `Find convoys that have ready issues but no workers processing them,
289- or empty convoys (0 tracked issues) that need cleanup.
289+ stuck convoys (tracked issues but none ready), or empty convoys that need cleanup.
290290
291291A convoy is "stranded" when:
292292- Convoy is open AND either:
293293 - Has tracked issues that are ready but unassigned, OR
294+ - Has tracked issues but none are ready (stuck — waiting on dependencies/workers), OR
294295 - Has 0 tracked issues (empty — needs auto-close via convoy check)
295296
296297Use this to detect convoys that need feeding or cleanup. The Deacon patrol
@@ -1161,10 +1162,11 @@ func removePolecatWorktree(wt convoyWorktreeInfo) error {
11611162
11621163// strandedConvoyInfo holds info about a stranded convoy.
11631164type strandedConvoyInfo struct {
1164- ID string `json:"id"`
1165- Title string `json:"title"`
1166- ReadyCount int `json:"ready_count"`
1167- ReadyIssues []string `json:"ready_issues"`
1165+ ID string `json:"id"`
1166+ Title string `json:"title"`
1167+ TrackedCount int `json:"tracked_count"`
1168+ ReadyCount int `json:"ready_count"`
1169+ ReadyIssues []string `json:"ready_issues"`
11681170}
11691171
11701172// readyIssueInfo holds info about a ready (stranded) issue.
@@ -1199,22 +1201,26 @@ func runConvoyStranded(cmd *cobra.Command, args []string) error {
11991201 fmt .Printf ("%s Found %d stranded convoy(s):\n \n " , style .Warning .Render ("⚠" ), len (stranded ))
12001202 for _ , s := range stranded {
12011203 fmt .Printf (" 🚚 %s: %s\n " , s .ID , s .Title )
1202- if s .ReadyCount == 0 {
1204+ if s .ReadyCount == 0 && s . TrackedCount == 0 {
12031205 fmt .Printf (" Empty convoy (0 tracked issues) — needs cleanup\n " )
1206+ } else if s .ReadyCount == 0 && s .TrackedCount > 0 {
1207+ fmt .Printf (" Stuck convoy (%d tracked issues, 0 ready)\n " , s .TrackedCount )
12041208 } else {
1205- fmt .Printf (" Ready issues: %d\n " , s .ReadyCount )
1209+ fmt .Printf (" Ready issues: %d (of %d tracked) \n " , s .ReadyCount , s . TrackedCount )
12061210 for _ , issueID := range s .ReadyIssues {
12071211 fmt .Printf (" • %s\n " , issueID )
12081212 }
12091213 }
12101214 fmt .Println ()
12111215 }
12121216
1213- // Separate feed advice ( convoys with ready work) from cleanup advice (empty convoys) .
1214- var feedable , empty []strandedConvoyInfo
1217+ // Separate feed advice, stuck convoys, and cleanup advice.
1218+ var feedable , stuck , empty []strandedConvoyInfo
12151219 for _ , s := range stranded {
12161220 if s .ReadyCount > 0 {
12171221 feedable = append (feedable , s )
1222+ } else if s .TrackedCount > 0 {
1223+ stuck = append (stuck , s )
12181224 } else {
12191225 empty = append (empty , s )
12201226 }
@@ -1226,10 +1232,19 @@ func runConvoyStranded(cmd *cobra.Command, args []string) error {
12261232 fmt .Printf (" gt sling mol-convoy-feed deacon/dogs --var convoy=%s\n " , s .ID )
12271233 }
12281234 }
1229- if len (empty ) > 0 {
1235+ if len (stuck ) > 0 {
12301236 if len (feedable ) > 0 {
12311237 fmt .Println ()
12321238 }
1239+ fmt .Println ("Stuck convoys (tracked issues exist but none are ready):" )
1240+ for _ , s := range stuck {
1241+ fmt .Printf (" 🚚 %s (%d tracked)\n " , s .ID , s .TrackedCount )
1242+ }
1243+ }
1244+ if len (empty ) > 0 {
1245+ if len (feedable ) > 0 || len (stuck ) > 0 {
1246+ fmt .Println ()
1247+ }
12331248 fmt .Println ("To close empty convoys, run:" )
12341249 for _ , s := range empty {
12351250 fmt .Printf (" gt convoy check %s\n " , s .ID )
@@ -1276,10 +1291,11 @@ func findStrandedConvoys(townBeads string) ([]strandedConvoyInfo, error) {
12761291 // attention (auto-close via convoy check or manual cleanup).
12771292 if len (tracked ) == 0 {
12781293 stranded = append (stranded , strandedConvoyInfo {
1279- ID : convoy .ID ,
1280- Title : convoy .Title ,
1281- ReadyCount : 0 ,
1282- ReadyIssues : []string {},
1294+ ID : convoy .ID ,
1295+ Title : convoy .Title ,
1296+ TrackedCount : 0 ,
1297+ ReadyCount : 0 ,
1298+ ReadyIssues : []string {},
12831299 })
12841300 continue
12851301 }
@@ -1312,10 +1328,22 @@ func findStrandedConvoys(townBeads string) ([]strandedConvoyInfo, error) {
13121328
13131329 if len (readyIssues ) > 0 {
13141330 stranded = append (stranded , strandedConvoyInfo {
1315- ID : convoy .ID ,
1316- Title : convoy .Title ,
1317- ReadyCount : len (readyIssues ),
1318- ReadyIssues : readyIssues ,
1331+ ID : convoy .ID ,
1332+ Title : convoy .Title ,
1333+ TrackedCount : len (tracked ),
1334+ ReadyCount : len (readyIssues ),
1335+ ReadyIssues : readyIssues ,
1336+ })
1337+ } else {
1338+ // Stuck convoy: has tracked issues but none are ready.
1339+ // Include in stranded list so callers (e.g., FeedStranded)
1340+ // can distinguish stuck from truly empty.
1341+ stranded = append (stranded , strandedConvoyInfo {
1342+ ID : convoy .ID ,
1343+ Title : convoy .Title ,
1344+ TrackedCount : len (tracked ),
1345+ ReadyCount : 0 ,
1346+ ReadyIssues : []string {},
13191347 })
13201348 }
13211349 }
0 commit comments