Files
gastown/docs/design/convoy-lifecycle.md
mayor 791b388a93 chore: add design docs and ready command
- Add convoy-lifecycle.md design doc
- Add formula-resolution.md design doc
- Add mol-mall-design.md design doc
- Add ready.go command implementation
- Move dog-pool-architecture.md to docs/design/
- Update .gitignore for beads sync files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 03:24:42 -08:00

4.9 KiB

Convoy Lifecycle Design

Making convoys actively converge on completion.

Problem Statement

Convoys are passive trackers. They group work but don't drive it. The completion loop has a structural gap:

Create → Assign → Execute → Issues close → ??? → Convoy closes

The ??? is "Deacon patrol runs gt convoy check" - a poll-based single point of failure. When Deacon is down, convoys don't close. Work completes but the loop never lands.

Current State

What Works

  • Convoy creation and issue tracking
  • gt convoy status shows progress
  • gt convoy stranded finds unassigned work
  • gt convoy check auto-closes completed convoys

What Breaks

  1. Poll-based completion: Only Deacon runs gt convoy check
  2. No event-driven trigger: Issue close doesn't propagate to convoy
  3. No manual close: Can't force-close abandoned convoys
  4. Single observer: No redundant completion detection
  5. Weak notification: Convoy owner not always clear

Design: Active Convoy Convergence

Principle: Event-Driven, Redundantly Observed

Convoy completion should be:

  1. Event-driven: Triggered by issue close, not polling
  2. Redundantly observed: Multiple agents can detect and close
  3. Manually overridable: Humans can force-close

Event-Driven Completion

When an issue closes, check if it's tracked by a convoy:

Issue closes
    ↓
Is issue tracked by convoy? ──(no)──► done
    │
   (yes)
    ↓
Run gt convoy check <convoy-id>
    ↓
All tracked issues closed? ──(no)──► done
    │
   (yes)
    ↓
Close convoy, send notifications

Implementation options:

  1. Daemon hook on bd update --status=closed
  2. Refinery step after successful merge
  3. Witness step after verifying polecat completion

Option 1 is most reliable - catches all closes regardless of source.

Redundant Observers

Per PRIMING.md: "Redundant Monitoring Is Resilience."

Three places should check convoy completion:

Observer When Scope
Daemon On any issue close All convoys
Witness After verifying polecat work Rig's convoy work
Deacon Periodic patrol All convoys (backup)

Any observer noticing completion triggers close. Idempotent - closing an already-closed convoy is a no-op.

Manual Close Command

Desire path: gt convoy close is expected but missing.

# Close a completed convoy
gt convoy close hq-cv-abc

# Force-close an abandoned convoy
gt convoy close hq-cv-xyz --reason="work done differently"

# Close with explicit notification
gt convoy close hq-cv-abc --notify mayor/

Use cases:

  • Abandoned convoys no longer relevant
  • Work completed outside tracked path
  • Force-closing stuck convoys

Convoy Owner/Requester

Track who requested the convoy for targeted notifications:

gt convoy create "Feature X" gt-abc --owner mayor/ --notify overseer
Field Purpose
owner Who requested (gets completion notification)
notify Additional subscribers

If owner not specified, defaults to creator (from created_by).

Convoy States

OPEN ──(all issues close)──► CLOSED
  │                             │
  │                             ▼
  │                    (add issues)
  │                             │
  └─────────────────────────────┘
         (auto-reopens)

Adding issues to closed convoy reopens automatically.

New state for abandonment:

OPEN ──► CLOSED (completed)
  │
  └────► ABANDONED (force-closed without completion)

Timeout/SLA (Future)

Optional due_at field for convoy deadline:

gt convoy create "Sprint work" gt-abc --due="2026-01-15"

Overdue convoys surface in gt convoy stranded --overdue.

Commands

New: gt convoy close

gt convoy close <convoy-id> [--reason=<reason>] [--notify=<agent>]
  • Closes convoy regardless of tracked issue status
  • Sets close_reason field
  • Sends notification to owner and subscribers
  • Idempotent - closing closed convoy is no-op

Enhanced: gt convoy check

# Check all convoys (current behavior)
gt convoy check

# Check specific convoy (new)
gt convoy check <convoy-id>

# Dry-run mode
gt convoy check --dry-run

New: gt convoy reopen

gt convoy reopen <convoy-id>

Explicit reopen for clarity (currently implicit via add).

Implementation Priority

  1. P0: gt convoy close - Desire path, escape hatch
  2. P0: Event-driven check - Daemon hook on issue close
  3. P1: Redundant observers - Witness/Refinery integration
  4. P2: Owner field - Targeted notifications
  5. P3: Timeout/SLA - Deadline tracking