fix(done): use ResolveHookDir for dispatcher lookup (sc-g7bl3)
When a polecat runs gt done after work is complete, it should notify the dispatcher (the agent that slung the work). This notification was failing silently when the polecat's worktree was deleted before gt done finished. The issue was that getDispatcherFromBead() used ResolveBeadsDir(cwd) which relies on the polecat's .beads/redirect file. If the worktree is deleted (e.g., by Witness cleanup), the redirect file is gone and bead lookup fails. Fix: Use ResolveHookDir(townRoot, issueID, cwd) instead. ResolveHookDir uses prefix-based routing via routes.jsonl which works regardless of worktree state. This ensures dispatcher notifications are sent reliably even when the worktree is cleaned up before gt done completes. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -456,7 +456,7 @@ notifyWitness:
|
|||||||
|
|
||||||
// Notify dispatcher if work was dispatched by another agent
|
// Notify dispatcher if work was dispatched by another agent
|
||||||
if issueID != "" {
|
if issueID != "" {
|
||||||
if dispatcher := getDispatcherFromBead(cwd, issueID); dispatcher != "" && dispatcher != sender {
|
if dispatcher := getDispatcherFromBead(townRoot, cwd, issueID); dispatcher != "" && dispatcher != sender {
|
||||||
dispatcherNotification := &mail.Message{
|
dispatcherNotification := &mail.Message{
|
||||||
To: dispatcher,
|
To: dispatcher,
|
||||||
From: sender,
|
From: sender,
|
||||||
@@ -645,7 +645,7 @@ func updateAgentStateOnDone(cwd, townRoot, exitType, _ string) { // issueID unus
|
|||||||
if _, err := bd.Run("agent", "state", agentBeadID, "awaiting-gate"); err != nil {
|
if _, err := bd.Run("agent", "state", agentBeadID, "awaiting-gate"); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Warning: couldn't set agent %s to awaiting-gate: %v\n", agentBeadID, err)
|
fmt.Fprintf(os.Stderr, "Warning: couldn't set agent %s to awaiting-gate: %v\n", agentBeadID, err)
|
||||||
}
|
}
|
||||||
// ExitCompleted and ExitDeferred don't set state - observable from tmux
|
// ExitCompleted and ExitDeferred don't set state - observable from tmux
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZFC #10: Self-report cleanup status
|
// ZFC #10: Self-report cleanup status
|
||||||
@@ -678,12 +678,19 @@ func getIssueFromAgentHook(bd *beads.Beads, agentBeadID string) string {
|
|||||||
|
|
||||||
// getDispatcherFromBead retrieves the dispatcher agent ID from the bead's attachment fields.
|
// getDispatcherFromBead retrieves the dispatcher agent ID from the bead's attachment fields.
|
||||||
// Returns empty string if no dispatcher is recorded.
|
// Returns empty string if no dispatcher is recorded.
|
||||||
func getDispatcherFromBead(cwd, issueID string) string {
|
//
|
||||||
|
// BUG FIX (sc-g7bl3): Use townRoot and ResolveHookDir for bead lookup instead of
|
||||||
|
// ResolveBeadsDir(cwd). When the polecat's worktree is deleted before gt done finishes,
|
||||||
|
// ResolveBeadsDir(cwd) fails because the redirect file is gone. ResolveHookDir uses
|
||||||
|
// prefix-based routing via routes.jsonl which works regardless of worktree state.
|
||||||
|
func getDispatcherFromBead(townRoot, cwd, issueID string) string {
|
||||||
if issueID == "" {
|
if issueID == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
bd := beads.New(beads.ResolveBeadsDir(cwd))
|
// Use ResolveHookDir for resilient bead lookup - works even if worktree is deleted
|
||||||
|
beadsDir := beads.ResolveHookDir(townRoot, issueID, cwd)
|
||||||
|
bd := beads.New(beadsDir)
|
||||||
issue, err := bd.Show(issueID)
|
issue, err := bd.Show(issueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
Reference in New Issue
Block a user