[object Object]

← back to Ticket System

reaper: --block now honors suggest() disposition (done/blocked/open), not hardcoded blocked

4c64af7e2eee289008953e99df6776e205b29bac · 2026-09-14 08:30:41 -0700 · Steve Abrams

Steve's call 2026-09-14: honor the per-ticket suggestion literally. A zombie whose
last action reads complete/verified/shipped closes to done; a gated/awaiting-Steve
one goes blocked; a died-mid-work one returns to open (re-enters the RUN-NOW/dispatch
queue). All three are valid STATUSES; every set stays reversible (tk status <id> doing).
Header doc + console output updated to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ua2TVTdVcyufh968ZCZXdc

Files touched

Diff

commit 4c64af7e2eee289008953e99df6776e205b29bac
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Sep 14 08:30:41 2026 -0700

    reaper: --block now honors suggest() disposition (done/blocked/open), not hardcoded blocked
    
    Steve's call 2026-09-14: honor the per-ticket suggestion literally. A zombie whose
    last action reads complete/verified/shipped closes to done; a gated/awaiting-Steve
    one goes blocked; a died-mid-work one returns to open (re-enters the RUN-NOW/dispatch
    queue). All three are valid STATUSES; every set stays reversible (tk status <id> doing).
    Header doc + console output updated to match.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Ua2TVTdVcyufh968ZCZXdc
---
 reaper.js | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/reaper.js b/reaper.js
index 298ab414..80cf1d87 100644
--- a/reaper.js
+++ b/reaper.js
@@ -3,11 +3,13 @@
 // Root cause (found 2026-07-27): nothing transitions a ticket out of `doing`
 // when its owning Claude session ends, so `doing` silently accumulates zombies.
 // This finds DOING tickets that are (a) idle > THRESHOLD_H and (b) have NO live
-// `claude … Work ticket <id>` process, then SUGGESTS a disposition from the last
-// action text. Report-only by default; --block sets the safe default (→ blocked).
+// worker (matched by a "Work ticket <id>" cmdline OR the ticket's owner label in
+// a live process's TK_AGENT env), then SUGGESTS a disposition from the last action
+// text (done / blocked / open). Report-only by default; --block honors that
+// suggestion literally (done→done, blocked→blocked, open→re-open for dispatch).
 //
 //   node reaper.js                 # report zombies + suggested dispositions
-//   node reaper.js --block         # additionally set each zombie → blocked (reversible)
+//   node reaper.js --block         # set each zombie → its suggested status (reversible)
 //
 const { execSync } = require('child_process');
 const { tickets: loadTickets } = require('./lib.js'); // read the store directly
@@ -73,12 +75,16 @@ for (const z of zombies)
   console.log(`  ${z.id.padEnd(11)} idle ${String(z.idleH).padStart(6)}h  @${(z.assignee||'—').padEnd(22)} → ${z.suggest.padEnd(7)}  «${z.last}»`);
 
 if (BLOCK) {
-  console.log(`\n--block: setting each zombie → blocked (reversible; safe default)…`);
+  console.log(`\n--block: setting each zombie → its suggested disposition (done/blocked/open; reversible)…`);
   const TK = require('path').join(__dirname, 'tk');
+  const icon = { done: '✅', blocked: '⛔', open: '↩︎' };
   for (const z of zombies) {
-    sh(`TK_AGENT=reaper node ${TK} comment ${z.fullId} "reaper: DOING but idle ${z.idleH}h with no live worker → auto-blocked (suggested: ${z.suggest}). Owning session ended without tk done/status." 2>/dev/null`);
-    sh(`TK_AGENT=reaper node ${TK} status ${z.fullId} blocked 2>/dev/null`);
-    console.log(`  ⛔ ${z.id} → blocked`);
+    // Honor suggest() literally: done→done, blocked→blocked, open→open. `open`
+    // returns the ticket to the dispatch queue (Steve's call 2026-09-14). All
+    // three are valid STATUSES and every set is reversible (tk status <id> doing).
+    sh(`TK_AGENT=reaper node ${TK} comment ${z.fullId} "reaper: DOING but idle ${z.idleH}h with no live worker → auto-set ${z.suggest} (owning session ended without tk done/status). Reversible: tk status ${z.fullId} doing." 2>/dev/null`);
+    sh(`TK_AGENT=reaper node ${TK} status ${z.fullId} ${z.suggest} 2>/dev/null`);
+    console.log(`  ${icon[z.suggest] || '•'} ${z.id} → ${z.suggest}`);
   }
 } else {
   console.log(`\n(report-only — re-run with --block to auto-block, or reconcile by hand.)`);

← 321f4cfd Record bounded empty-queue monitoring cycle yf1520  ·  back to Ticket System  ·  auto-data-snapshot: 2026-09-14T09:19:35 (1 data files) — dat 65fa9e87 →