📋 Work Assignment: bd pin: pinned field overwritten by subsequent bd commands

Issue: bd-phtv
Title: bd pin: pinned field overwritten by subsequent bd commands
Priority: P1
Type: bug

Description:
## Summary

The `bd pin` command correctly sets `pinned=1` in SQLite, but any subsequent `bd` command (including read-only commands like `bd show`) resets `pinned` to 0.

## Reproduction Steps

```bash
bd --no-daemon pin <issue-id> --for=max
sqlite3 .beads/beads.db "SELECT id, pinned FROM issues WHERE id=\"<issue-id>\""
# Shows pinned=1 ✓

bd --no-daemon show <issue-id> --json
sqlite3 .beads/beads.db "SELECT id, pinned FROM issues WHERE id=\"<issue-id>\""
# Shows pinned=0 ✗ WRONG
```

## Root Cause Investigation

### Prime Suspects

1. **JSONL import overwrites DB** - The `pinned` field has `omitempty` so false values arent in JSONL. When JSONL is imported, it overwrites the DB pinned=1 with default pinned=0.

2. **Files to check:**
   - `internal/importer/importer.go` - ImportIssue() may unconditionally set all fields
   - `internal/storage/sqlite/issues.go` - UpsertIssue() may not preserve pinned
   - `cmd/bd/main.go` - ensureStoreActive() may trigger import

### Debug Steps

```bash
# Add debug logging to track what is writing pinned=0
grep -rn "pinned" internal/storage/sqlite/*.go
grep -rn "Pinned" internal/importer/*.go
```

## Likely Fix

In `internal/importer/importer.go` or `internal/storage/sqlite/issues.go`:

```go
// When upserting from JSONL, preserve pinned field if already set
func (s *SQLiteStorage) UpsertIssue(ctx context.Context, issue *types.Issue) error {
    // Check if issue exists and is pinned
    existing, _ := s.GetIssue(ctx, issue.ID)
    if existing != nil && existing.Pinned && !issue.Pinned {
        // Preserve existing pinned status
        issue.Pinned = existing.Pinned
    }
    // ... rest of upsert
}
```

OR the import should skip fields that are omitempty and not present in JSONL:

```go
// In importer, only update fields that are explicitly set in JSONL
// Pinned with omitempty means absent = dont change, not absent = false
```

## Testing

```bash
# After fix:
bd --no-daemon pin <issue-id> --for=max
bd --no-daemon show <issue-id> --json  # Should not reset pinned
bd list --pinned  # Should show the pinned issue
bd hook --agent max  # Should show pinned work
```

## Files to Modify

1. **internal/importer/importer.go** - Preserve pinned on import
2. **internal/storage/sqlite/issues.go** - UpsertIssue preserve pinned
3. **Add test** in internal/importer/importer_test.go

## Success Criteria
- `bd pin` survives subsequent bd commands
- `bd list --pinned` shows pinned issues
- `bd hook --agent X` shows pinned work
- Existing tests still pass

## Workflow
1. Run `gt prime` to load polecat context
2. Work on your task, commit changes regularly
3. Run `bd close <issue-id>` when done
4. Run `bd sync` to push beads changes
5. Push code: `git push origin HEAD`
6. Run `gt done` to signal completion

## Handoff Protocol
Before signaling done, ensure:
- Git status is clean (no uncommitted changes)
- Issue is closed with `bd close`
- Beads are synced with `bd sync`
- Code is pushed to origin

The `gt done` command verifies these and signals the Witness.


Digest: mol-deacon-patrol

Patrol 6: Routine, 26 sessions healthy


Digest: mol-deacon-patrol

Patrol cycle 30: Routine


Digest: mol-deacon-patrol

Patrol 24: town idle, all healthy


📋 Work Assignment: TIDY UP: Your previous work (gt-odvf: bd mol CLI docs) wa...

Issue: gt-vg6u
Title: TIDY UP: Your previous work (gt-odvf: bd mol CLI docs) wa...
Priority: P2
Type: task

Description:
TIDY UP: Your previous work (gt-odvf: bd mol CLI docs) was already merged to main. Check your git status is clean, sync beads, and if nothing to do, just run 'gt done'.

## Workflow
1. Run `gt prime` to load polecat context
2. Run `bd sync --from-main` to get fresh beads
3. Work on your task, commit changes regularly
4. Run `bd close <issue-id>` when done
5. Run `bd sync` to push beads changes
6. Push code: `git push origin HEAD`
7. Run `gt done` to signal completion

## Handoff Protocol
Before signaling done, ensure:
- Git status is clean (no uncommitted changes)
- Issue is closed with `bd close`
- Beads are synced with `bd sync`
- Code is pushed to origin

The `gt done` command verifies these and signals the Witness.


Digest: mol-deacon-patrol

Patrol cycle 4: Processed 1 handoff msg, 2 convoys still open (PRs 140/149), wyvern refinery restarted, orphan gt-boot session cleaned, all agents healthy.


Digest: mol-deacon-patrol

Patrol cycle 8: detailed check, all healthy


Digest: mol-deacon-patrol

Patrol 119: All healthy.


Test3

Test after fix


Digest: mol-deacon-patrol

Patrol complete: no callbacks, no pending polecats, no gates, all health OK, no plugins, no orphans, 22/26 doctor checks passed


Digest: mol-deacon-patrol

P13: clear


Digest: mol-deacon-patrol

Patrol #2: all agents healthy, no incidents


🤝 HANDOFF: Patrol System Operational

## Session Summary

### Accomplished
- Patrol system is working end-to-end
- Daemon detects naked Deacon, seeds builtins, instantiates mol-deacon-patrol
- Deacon handoff bead (hq-8r8) has 7 patrol steps attached
- Builtin molecules seeded to town beads (hq-70c = Deacon Patrol)
- Created mol-deacon-patrol proto in gastown beads (gt-iep9) for new format
- Filed gt-yd98: Molecule format bridge (convert markdown → child issues)
- Refinery restarted, picking up handoff
- Cleaned stale polecats

### Current State
- Daemon: Running (PID 92818)
- Deacon: Patrol attached (hq-8r8 → hq-70c)
- Refinery: Running, has handoff
- Witnesses: Running
- Polecats: None active (cleaned stale)

### Next Steps (Christmas Launch)
1. gt-3x0z.7: Summary generation protocol - ready to spawn
2. gt-3x0z.8: mol-polecat-work squash step - blocked on .7
3. gt-rana.4: Basic patrol runner in Deacon - blocked on .8
4. Test Deacon executing its patrol steps (not just having them attached)

### Key Insight
Two molecule formats exist:
- Old: Embedded markdown in Description (daemon uses this)
- New: Child issues in DAG (bd mol spawn uses this)

gt-yd98 filed to build bridge between them.

### Commands
- bd show gt-ngpz - Christmas plan epic
- bd ready - see what's ready to spawn
- gt spawn --issue <id> --rig gastown --create - spawn polecat


POLECAT_DONE testcat

Exit: COMPLETED
Issue: bd-d28c
MR: bd-yx22
Branch: polecat/testcat


Digest: mol-deacon-patrol

Patrol 78


Tracking anti-pattern: Daemon maintains recentDeaths shadow state

crew/jack/internal/daemon/daemon.go (lines 47-56, 770-816) maintains a parallel tracking list of session deaths:
```go
type Daemon struct {
    deathsMu     sync.Mutex
    recentDeaths []sessionDeath  // Shadow state
}
```

Per 'Discover, Don't Track': Reality is truth. State is derived. The daemon should query tmux directly on each heartbeat to discover dead sessions rather than maintaining a historical record of deaths with locking and cleanup logic.

This creates stale state and complex reconciliation that could get out of sync with reality.

Already fixed - recentDeaths shadow state was previously removed from daemon.go


Digest: mol-deacon-patrol

Patrol cycle 8: inbox clear, all 6 agents healthy, fixed 1 orphan


POLECAT_STARTED beads/max

Issue: bd-m8ro
Session: gt-beads-max


Digest: mol-deacon-patrol

Patrol cycle 17: All agents healthy, 4 convoys open, no incidents


Digest: mol-deacon-patrol

Patrol #20: routine, handoff threshold reached


Digest: mol-deacon-patrol

Patrol 100: quiet


ZFC violation: beads.go uses strings.Contains for sync conflict detection

Go code in mayor/rig/internal/beads/beads.go (lines 443-450) uses strings.Contains() to detect beads repository errors and sync conflicts from stderr.

```go
if strings.Contains(stderr, "not a beads repository") ||
    strings.Contains(stderr, "No .beads directory") ...
if strings.Contains(stderr, "sync conflict") || strings.Contains(stderr, "CONFLICT")
```

Same ZFC violation: Go should transport errors to agents, not parse them to make decisions.

Fixed ZFC violations: done.go now uses --cleanup-status flag instead of computing from git, beads.go removed strings.Contains error parsing for ErrNotARepo/ErrSyncConflict


Digest: mol-deacon-patrol

Patrol 15: 17 sessions running


Digest: mol-deacon-patrol

Patrol cycle 20: final check before handoff, all healthy


Digest: mol-deacon-patrol

Patrol cycle 113: All healthy


Digest: mol-deacon-patrol

Patrol 20: Routine


Digest: mol-deacon-patrol

Patrol #23: Quick cycle. All healthy.


POLECAT_STARTED beads/capable

Issue: bd-t4u1
Session: gt-beads-capable


MR Ready: Logger (bd-u2sc.4)

Logger completed. slog for daemon logging. Branch: polecat/Logger ready for merge.


Digest: mol-deacon-patrol

Patrol 73


Digest: mol-deacon-patrol

Patrol 19: nominal


Start work

Work on gt-h1n5: Witness patrol banners and wisp-based execution. Read the issue with 'bd show gt-h1n5', implement the fix, test, commit, push, close the issue, then run 'gt done'.


Digest: mol-deacon-patrol

Patrol 1: all rigs healthy (beads/gastown/wyvern), no callbacks, no orphans, doctor fixed 1 orphan session


Digest: mol-deacon-patrol

Patrol 2: all healthy, no changes


Digest: mol-deacon-patrol

Patrol cycle 9: All agents healthy, no orphans, routine


Digest: mol-deacon-patrol

Patrol 2: All agents healthy, no issues


Digest: mol-deacon-patrol

Patrol 16: 18 running


Digest: mol-deacon-patrol

Patrol 1: All agents healthy, cleaned stale wisps


Digest: mol-deacon-patrol

Patrol C53: all healthy, no callbacks


Digest: mol-deacon-patrol

Patrol cycle 4: all clear


Digest: mol-deacon-patrol

Patrol C23: All healthy


Digest: mol-deacon-patrol

Patrol 59: Stable


POLECAT_STARTED india

Issue: bd-indn
Session: gt-beads-india


Digest: mol-deacon-patrol

Patrol cycle 33: Routine


Build failure: undefined GateCreate API

Your branch polecat/delta failed to build after rebase on main.

Error: internal/rpc/additional_coverage_test.go references undefined types:
- client.GateCreate undefined
- GateCreateArgs undefined
- GateCreateResult undefined
- client.GateList undefined
- GateListArgs undefined

Please rebase on current main and fix the test to use the actual API, then resubmit.


Digest: mol-deacon-patrol

Patrol 20: Town idle, preparing handoff


Digest: mol-deacon-patrol

Patrol #7: All healthy.


Digest: mol-deacon-patrol

Patrol complete: restarted Mayor, burned 1 orphan wisp, all steps clean


Digest: mol-deacon-patrol

Patrol complete: cleaned 3 handoffs, all agents healthy, no orphans or gates


Digest: mol-deacon-patrol

Patrol 18: all clear


Digest: mol-deacon-patrol

Patrol cycle 1: all healthy, gastown 5 polecats 12 pending, beads 8 pending


Digest: mol-deacon-patrol

Patrol cycle 6: Healthy.


Boot marker file uses TTL instead of querying tmux directly

crew/jack/internal/boot/boot.go (lines 81-95) uses a marker file with TTL to check if boot is running:
```go
func (b *Boot) IsRunning() bool {
    info, err := os.Stat(b.markerPath())
    age := time.Since(info.ModTime())
    if age > DefaultMarkerTTL {
        _ = os.Remove(b.markerPath())
        return false
    }
    return true
}
```

If Boot crashes without cleaning up the marker, stale marker causes false 'already running' errors. Should query tmux.HasSession() directly - observable reality vs stale cache.

Fixed IsRunning() to query tmux directly instead of marker file TTL


Overnight Hanoi Demo: Prove Nondeterministic Idempotence at Scale

Master epic for the million-step Hanoi demonstration.

## Goal
Run a 20-disk Towers of Hanoi (1,048,575 steps) overnight to prove:
1. Molecules are self-documenting (agents can resume mid-stream)
2. Nondeterministic Idempotence works at scale
3. Gas Town can execute arbitrarily long workflows
4. Convoy tracking provides visibility into mega-molecules

## Success Criteria
- Cook and pour 20-disk Hanoi formula
- Agent executes autonomously overnight
- Deacon restarts if agent gets stuck
- Progress visible via convoy dashboard
- Completion signaled when done

## Components
- Beads: bd mol progress, display guards (bd-5nu1)
- Gastown: formula update, convoy integration (gt-brd1b)

## The Insight
Molecules need an 'instructions' layer - the formula description field
already exists and survives cooking/pouring. We just need to use it
intentionally as agent-actionable priming.

## Status Update

**7-disk demo SUCCEEDED** (127 moves, 21 seconds, ~162ms/close)

The molecule system works. Wisps can be created, dependencies execute correctly, and large sequential workflows complete.

**10-disk demo BLOCKED** by wisp creation timeout. Creating 1025 issues serially takes too long (30+ seconds, killed).

**Next steps for overnight demo:**
1. Optimize bd mol wisp for batch issue creation
2. Or: Pre-cook the formula offline and import

Demoted to P3 - proof of concept achieved. Full scale-up is nice-to-have.


SPAWN: valkyrie starting on gt-um6q

Polecat spawn notification.

Polecat: valkyrie
Issue: gt-um6q
Session: gt-gastown-valkyrie
Spawned by: beads/crew/dave

The Deacon will trigger this polecat when Claude is ready (WaitForClaudeReady).
The polecat's SessionStart hook runs gt prime, and work assignment is in its inbox.
Monitor for stuck/idle state after a few minutes.


POLECAT_DONE alpha

Exit: COMPLETED
Issue: bd-6sm6
MR: mr-1766557985-04756998
Branch: polecat/alpha


POLECAT_STARTED gastown/furiosa

Issue: gt-t9u7
Session: gt-gastown-furiosa


POLECAT_STARTED beads/slit

Issue: bd-7z4
Session: gt-beads-slit


Digest: mol-deacon-patrol

Patrol 4: All agents healthy, no inbox, no orphans


Digest: mol-deacon-patrol

Cycle 19: stable


Digest: mol-deacon-patrol

Patrol cycle 2: all clear, witnesses/refineries running


POLECAT_DONE immortan

Exit: COMPLETED
Issue: gt-tnca.1
MR: gt-ubd4
Branch: polecat/immortan


POLECAT_STARTED cheedo

Issue: bd-dxtc
Session: gt-beads-cheedo


Digest: mol-deacon-patrol

Patrol cycle 6 complete: all clear. Patrol count 6.


Digest: mol-deacon-patrol

Patrol 13: OK


Digest: mol-deacon-patrol

Patrol cycle 9: All quiet, 3 rigs healthy


Digest: mol-deacon-patrol

Patrol C68: routine, all healthy


Digest: mol-deacon-patrol

Patrol 19: Quiet. All healthy.


Digest: mol-deacon-patrol

Patrol 10: thorough check passed, all healthy


Digest: mol-deacon-patrol

Patrol cycle 2: all healthy, no incidents


Digest: mol-deacon-patrol

Patrol 20: Final before handoff


Digest: mol-deacon-patrol

Patrol cycle 1: Inbox clear (handoff from prev), 4 convoys open, all witnesses/refineries healthy, no orphans. Polecats furiosa/nux/slit/rictus/dementus started. Context low - continuing.


🤝 HANDOFF: mol-ready-work review and infrastructure beads

## Session Summary

Reviewed mol-ready-work (cherry-picked from polecat/immortan), filed follow-up beads.

## Completed This Session

1. **Unified startup protocols** - All roles now use 'gt mol status' + RUN IT pattern
   - Commit: 37c2382

2. **Cherry-picked mol-ready-work** from stranded polecat branch
   - Commit: b3fa1f7
   - Now available: `gt mol catalog` shows it

3. **Critical review of mol-ready-work** - identified missing infrastructure

4. **Filed beads for follow-ups**:
   - gt-ynp6: gt context --usage (tmux line count hack)
   - gt-58it: bd sync --from-main flag
   - gt-nmtp: refactor builtin_molecules.go (1620 lines)
   - gt-az41: mol-ready-work safe vs aggressive variants
   - gt-drp5: mol-ready-work graceful GitHub/label handling

## Context for Successor

Key insight from overseer: Use tmux scrollback line count as context proxy:
- `tmux capture-pane -p | wc -l`
- ~1800 lines = warning for Opus 4.5
- ~2000+ = critical, need handoff

## Ready Work
Run `bd ready` to see available issues. The mol-ready-work beads are under gt-tnca epic.

## Git State
- main is clean and pushed
- beads synced


Digest: mol-deacon-patrol

Patrol 7: Quiet. Handing off.


Digest: mol-deacon-patrol

Patrol 8 complete: all healthy


📋 Work Assignment: Add bd doctor --fix flag to automatically repair issues

Issue: bd-ykd9
Title: Add bd doctor --fix flag to automatically repair issues
Priority: P2
Type: feature

Description:
Add bd doctor --fix flag to automatically repair detected issues.

## Current State
- Doctor checks return issues with "Fix" field containing fix instructions
- No automatic fix execution
- User must manually follow fix instructions

## Implementation

### 1. Add --fix flag to doctor.go
```go
// In cmd/bd/doctor.go init()
doctorCmd.Flags().Bool("fix", false, "Automatically fix detected issues")
doctorCmd.Flags().Bool("yes", false, "Skip confirmation prompts (use with --fix)")
```

### 2. Create fix registry (cmd/bd/doctor/fix/registry.go)
```go
package fix

// Fixer can automatically repair an issue
type Fixer interface {
    // CanFix returns true if this fixer handles the given check name
    CanFix(checkName string) bool
    // Fix attempts to repair the issue, returns error if failed
    Fix(ctx context.Context, issue *CheckResult) error
    // Description returns human-readable description of what will be fixed
    Description() string
}

var registry []Fixer

func Register(f Fixer) {
    registry = append(registry, f)
}

func GetFixer(checkName string) Fixer {
    for _, f := range registry {
        if f.CanFix(checkName) {
            return f
        }
    }
    return nil
}
```

### 3. Implement fixers (one per file)

**cmd/bd/doctor/fix/hooks.go**
```go
type HooksFixer struct{}

func (f *HooksFixer) CanFix(name string) bool {
    return name == "git-hooks" || name == "hooks-outdated"
}

func (f *HooksFixer) Fix(ctx context.Context, issue *CheckResult) error {
    return hooks.Install(".", true) // force reinstall
}

func (f *HooksFixer) Description() string {
    return "Reinstall git hooks"
}

func init() {
    Register(&HooksFixer{})
}
```

**cmd/bd/doctor/fix/sync_branch.go**
```go
type SyncBranchFixer struct{}

func (f *SyncBranchFixer) CanFix(name string) bool {
    return name == "sync-branch-missing" || name == "sync-branch-diverged"
}

func (f *SyncBranchFixer) Fix(ctx context.Context, issue *CheckResult) error {
    // Reset to remote or create branch
    return syncbranch.ResetToRemote(ctx, repoRoot, branch, jsonlPath)
}
```

**cmd/bd/doctor/fix/merge_driver.go**
```go
type MergeDriverFixer struct{}

func (f *MergeDriverFixer) CanFix(name string) bool {
    return name == "merge-driver-missing" || name == "merge-driver-outdated"
}

func (f *MergeDriverFixer) Fix(ctx context.Context, issue *CheckResult) error {
    return setupMergeDriver()
}
```

### 4. Update doctor run logic

```go
func runDoctor(cmd *cobra.Command, args []string) {
    issues := runAllChecks()

    if \!fixFlag {
        // Existing behavior - just display issues
        displayIssues(issues)
        return
    }

    // Collect fixable issues
    var fixable []FixableIssue
    for _, issue := range issues {
        if fixer := fix.GetFixer(issue.CheckName); fixer \!= nil {
            fixable = append(fixable, FixableIssue{issue, fixer})
        }
    }

    if len(fixable) == 0 {
        fmt.Println("No automatically fixable issues found")
        return
    }

    // Show what will be fixed
    fmt.Printf("Found %d fixable issues:\n", len(fixable))
    for i, f := range fixable {
        fmt.Printf("  %d. [%s] %s\n", i+1, f.Issue.CheckName, f.Fixer.Description())
    }

    // Confirm unless --yes
    if \!yesFlag {
        fmt.Print("\nProceed with fixes? [Y/n] ")
        // ... read confirmation
    }

    // Apply fixes
    for _, f := range fixable {
        fmt.Printf("Fixing %s... ", f.Issue.CheckName)
        if err := f.Fixer.Fix(ctx, f.Issue); err \!= nil {
            fmt.Printf("FAILED: %v\n", err)
        } else {
            fmt.Println("OK")
        }
    }
}
```

## Fixable Checks (Initial Set)

| Check | Fixer | Action |
|-------|-------|--------|
| git-hooks | HooksFixer | Reinstall hooks |
| hooks-outdated | HooksFixer | Update hooks |
| merge-driver-missing | MergeDriverFixer | Configure merge driver |
| sync-branch-diverged | SyncBranchFixer | Reset to remote |
| daemon-version-mismatch | DaemonFixer | Restart daemon |

## Testing
```bash
# Test with broken hooks
rm .git/hooks/pre-commit
bd doctor --fix --yes

# Verify fix applied
bd doctor  # Should pass now
```

## Success Criteria
- --fix flag triggers automatic repair
- User prompted for confirmation (unless --yes)
- Clear output showing what was fixed
- Graceful handling of fix failures
- At least 5 common issues auto-fixable

## Workflow
1. Run `gt prime` to load polecat context
2. Work on your task, commit changes regularly
3. Run `bd close <issue-id>` when done
4. Run `bd sync` to push beads changes
5. Push code: `git push origin HEAD`
6. Run `gt done` to signal completion

## Handoff Protocol
Before signaling done, ensure:
- Git status is clean (no uncommitted changes)
- Issue is closed with `bd close`
- Beads are synced with `bd sync`
- Code is pushed to origin

The `gt done` command verifies these and signals the Witness.


Digest: mol-deacon-patrol

Patrol cycle 3: All agents healthy, routine check


Digest: mol-deacon-patrol

Patrol #4: routine, all healthy


Digest: mol-deacon-patrol

Patrol 8: all nominal


Digest: mol-deacon-patrol

Patrol 1 complete: all agents healthy (gastown/wyvern), no callbacks, no pending gates, no orphans


Digest: mol-deacon-patrol

Patrol 1: All healthy (beads/gastown witness+refinery running). Deleted handoff mail. No convoys, gates, orphans, or abandoned work.


Digest: mol-deacon-patrol

Patrol cycle 6: All quiet


Digest: mol-deacon-patrol

Patrol cycle 14: healthy


Digest: mol-deacon-patrol

Patrol 9: Routine.


POLECAT_STARTED beads/mike

Issue: bd-0fvq
Session: gt-beads-mike


Digest: mol-deacon-patrol

Patrol #26: All healthy. Emma active 2h15m.


Digest: mol-deacon-patrol

Patrol 18: No callbacks, all healthy


Digest: mol-deacon-patrol

Patrol 20: final check - all healthy, MQ beads:8 gastown:13


Digest: mol-deacon-patrol

Patrol 10: Halfway point, all systems nominal


Digest: mol-deacon-patrol

Patrol 14: Town idle


Digest: mol-deacon-patrol

Patrol 3: All healthy.


Digest: mol-deacon-patrol

Patrol cycle 20: All healthy (3W/3R), gastown monitoring 2 polecats, routine handoff


Handoff mail not delivered to mayor inbox

Town log shows predecessor handed off at 12:59:33 with message about gt-7psb8, but gt mail inbox shows 0 messages. The handoff context was lost.

Reproduction:
1. Mayor runs gt handoff with -s 'context'
2. New mayor session starts
3. gt mail inbox shows empty

Expected: Handoff mail in inbox


POLECAT_STARTED golf

Issue: bd-de6
Session: gt-beads-golf


🤝 HANDOFF: GH#692 epic - continue with remaining tasks

## Context

Completed bd-u2sc.2 (sort.Slice → slices.SortFunc migration). Pushed to main.

## Work Completed

- **bd-u2sc.2** [CLOSED] - Migrated 19 instances of sort.Slice to slices.SortFunc
  - 16 files in cmd/bd/ updated
  - All tests pass
  - Commit: e67712dc

## Remaining Epic Work (bd-u2sc)

Check `bd show bd-u2sc` for full epic. Recommended order:

1. **bd-u2sc.1** [P2] - Replace map[string]interface{} with typed JSON response structs
   - ~20 instances in compact.go, cleanup.go, daemons.go, daemon_lifecycle.go
   - Good next step - improves type safety

2. **bd-u2sc.3** [P3] - Split large cmd/bd files into logical modules
   - sync.go (2201 lines), init.go (1742), show.go (1380)
   - Larger refactor

3. **bd-u2sc.4** [P3] - Introduce slog for structured daemon logging

4. **bd-bqcc** [P2] - Consolidate maintenance commands into `bd doctor --fix`

## Commands

```bash
bd show bd-u2sc           # View epic
bd update bd-u2sc.1 --status in_progress  # Claim next task
```


Digest: mol-deacon-patrol

Patrol 11: All healthy, no inbox


Digest: mol-deacon-patrol

Patrol cycle 5: All healthy, queues unchanged (beads 8, gastown 12, wyvern 0)


Digest: mol-deacon-patrol

Patrol 1: All agents healthy. 2 convoys in progress (PR #970 review, nudge docs). No incidents.


Digest: mol-deacon-patrol

Patrol 7: All healthy, refinery queue 13


ZFC violation: Branch pattern matching in doctor checks

Multiple files use branch name pattern matching to infer state:

1. **doctor/branch_check.go** (lines 31-87): Checks if persistent roles are on main branch
2. **doctor/rig_check.go** (line 745): `strings.HasPrefix(branch, "polecat/")`
3. **cmd/mq_integration.go** (lines 35, 88-98): Branch prefix matching for logic

Example:
```go
if strings.HasPrefix(branch, "polecat/") {
    // ... logic based on branch pattern
}
```

This is Go inferring state from branch name signals rather than reading agent-declared state from beads.

Replaced hardcoded 'polecat/' strings with constants.BranchPolecatPrefix for consistency. Full ZFC fix (declaring identity in beads) would require larger architectural changes.


Digest: mol-deacon-patrol

Patrol 169: All healthy, gastown/furiosa polecat working


📋 Work Assignment: gt done: Notify Witness with exit outcome

Issue: gt-jzot
Title: gt done: Notify Witness with exit outcome
Priority: P1
Type: task

Description:
When polecat runs gt done, it should send mail to Witness:

```
gt mail send <rig>/witness -s 'POLECAT_DONE <name>' -m 'Exit: COMPLETED
Issue: <issue-id>
MR: <mr-id>
Branch: <branch>'
```

Exit types:
- COMPLETED: Work done, MR submitted
- ESCALATED: Hit blocker, needs human
- DEFERRED: Work paused, issue still open

This enables Witness patrol to:
1. See completion in inbox-check step
2. Verify git state is clean
3. Kill session and prune worktree
4. Close the polecat lease in its patrol wisp

Paired with gt-r6td (spawn notification) - together they bracket polecat lifecycle.

## Workflow
1. Run `gt prime` to load polecat context
2. Work on your task, commit changes regularly
3. Run `bd close <issue-id>` when done
4. Run `bd sync` to push beads changes
5. Push code: `git push origin HEAD`
6. Run `gt done` to signal completion

## Handoff Protocol
Before signaling done, ensure:
- Git status is clean (no uncommitted changes)
- Issue is closed with `bd close`
- Beads are synced with `bd sync`
- Code is pushed to origin

The `gt done` command verifies these and signals the Witness.


Digest: mol-deacon-patrol

Patrol 4: routine, all clear


Digest: mol-deacon-patrol

Patrol 20: All healthy - handoff cycle