Test: N-clone scenario with hash IDs (no collisions)

Comprehensive test to verify hash IDs eliminate collision problems.

## Test: TestHashIDsNClones

### Purpose
Verify that N clones can work offline and sync without ID collisions using hash IDs.

### Test Scenario
```
Setup:
- 1 bare remote repo
- 5 clones (A, B, C, D, E)

Offline Work:
- Each clone creates 10 issues with different titles
- No coordination, no network access
- Total: 50 unique issues

Sync:
- Clones sync in random order
- Each pull/import other clones' issues

Expected Result:
- All 5 clones converge to 50 issues
- Zero ID collisions
- Zero remapping needed
- Alias conflicts resolved deterministically
```

### Implementation
File: cmd/bd/beads_hashid_test.go (new)

```go
func TestHashIDsFiveClones(t *testing.T) {
    tmpDir := t.TempDir()
    remoteDir := setupBareRepo(t, tmpDir)

    // Setup 5 clones
    clones := make(map[string]string)
    for _, name := range []string{"A", "B", "C", "D", "E"} {
        clones[name] = setupClone(t, tmpDir, remoteDir, name)
    }

    // Each clone creates 10 issues offline
    for name, dir := range clones {
        for i := 0; i < 10; i++ {
            createIssue(t, dir, fmt.Sprintf("%s-issue-%d", name, i))
        }
        // No sync yet!
    }

    // Sync in random order
    syncOrder := []string{"C", "A", "E", "B", "D"}
    for _, name := range syncOrder {
        syncClone(t, clones[name], name)
    }

    // Final convergence round
    for _, name := range []string{"A", "B", "C", "D", "E"} {
        finalPull(t, clones[name], name)
    }

    // Verify all clones have all 50 issues
    for name, dir := range clones {
        issues := getIssues(t, dir)
        if len(issues) != 50 {
            t.Errorf("Clone %s: expected 50 issues, got %d", name, len(issues))
        }

        // Verify all issue IDs are hash-based
        for _, issue := range issues {
            if !strings.HasPrefix(issue.ID, "bd-") || len(issue.ID) != 11 {
                t.Errorf("Invalid hash ID: %s", issue.ID)
            }
        }
    }

    // Verify no collision resolution occurred
    // (This would be in logs if it happened)

    t.Log("✓ All 5 clones converged to 50 issues with zero collisions")
}
```

### Edge Case Tests

#### Test: Hash Collision Detection (Artificial)
```go
func TestHashCollisionDetection(t *testing.T) {
    // Artificially inject collision by mocking hash function
    // Verify system detects and handles it
}
```

#### Test: Alias Conflicts Resolved Deterministically
```go
func TestAliasConflictsNClones(t *testing.T) {
    // Two clones assign same alias to different issues
    // Verify deterministic resolution (content-hash ordering)
    // Verify all clones converge to same alias assignments
}
```

#### Test: Mixed Sequential and Hash IDs (Should Fail)
```go
func TestMixedIDsRejected(t *testing.T) {
    // Try to import JSONL with sequential IDs into hash-ID database
    // Verify error or warning
}
```

### Performance Test

#### Benchmark: Hash ID Generation
```go
func BenchmarkHashIDGeneration(b *testing.B) {
    for i := 0; i < b.N; i++ {
        GenerateHashID("title", "description", time.Now(), "workspace-id")
    }
}

// Expected: < 1μs per generation
```

#### Benchmark: N-Clone Convergence Time
```go
func BenchmarkNCloneConvergence(b *testing.B) {
    for _, n := range []int{3, 5, 10, 20} {
        b.Run(fmt.Sprintf("N=%d", n), func(b *testing.B) {
            // Measure total convergence time
        })
    }
}

// Expected: Linear scaling O(N)
```

### Acceptance Criteria
- TestHashIDsFiveClones passes reliably (10/10 runs)
- Zero ID collisions in any scenario
- All clones converge in single round (not multi-round like old system)
- Alias conflicts resolved deterministically
- Performance benchmarks meet targets (<1μs hash gen)

## Files to Create
- cmd/bd/beads_hashid_test.go

## Comparison to Old System
This test replaces:
- TestTwoCloneCollision (bd-71107098) - no longer needed
- TestThreeCloneCollision (bd-cbed9619) - no longer needed
- TestFiveCloneCollision (bd-a40f374f) - no longer needed

Old system required complex collision resolution and multi-round convergence.
New system: single-round convergence with zero collisions.


Consider central serialization package for JSON handling

Multiple parts of the codebase handle JSON serialization of issues with slightly different approaches. Consider creating a centralized serialization package to ensure consistency.

Current serialization locations:
- `cmd/bd/export.go` - JSONL export (issues to file)
- `cmd/bd/import.go` - JSONL import (file to issues)
- `internal/rpc/protocol.go` - RPC JSON marshaling
- `internal/storage/memory/memory.go` - In-memory marshaling

Potential benefits:
- Single source of truth for JSON format
- Consistent field naming
- Easier to add new fields
- Centralized validation

Note: This is marked **optional** because:
- Current serialization mostly works
- May not provide enough benefit to justify refactor
- Risk of breaking compatibility

Decision point: Evaluate if benefits outweigh refactoring cost

Impact: TBD based on investigation - may defer to future work


Centralize BD_DEBUG logging into debug package

The codebase has 43 scattered instances of `if os.Getenv("BD_DEBUG") != ""` debug checks across 6 files. Centralize into a debug logging package.

Current locations:
- `cmd/bd/main.go` - 15 checks
- `cmd/bd/autoflush.go` - 6 checks
- `cmd/bd/nodb.go` - 4 checks
- `internal/rpc/server.go` - 2 checks
- `internal/rpc/client.go` - 5 checks
- `cmd/bd/daemon_autostart.go` - 11 checks

Target structure:
```
internal/debug/
└── debug.go
```

Benefits:
- Centralized debug logging
- Easier to add structured logging later
- Testable (can mock debug output)
- Consistent debug message format

Impact: Removes 43 scattered checks, improves code clarity


Run final validation and cleanup checks

Final validation pass to ensure all cleanup objectives met and no regressions introduced.

Validation checklist:
1. Dead code verification: `go run golang.org/x/tools/cmd/deadcode@latest -test ./...`
2. Test coverage: `go test -cover ./...`
3. Build verification: `go build ./cmd/bd/`
4. Linting: `golangci-lint run`
5. Integration tests
6. Metrics verification
7. Git clean check

Final metrics to report:
- LOC removed: ~____
- Files deleted: ____
- Files created: ____
- Test coverage: ____%
- Build time: ____ (before/after)
- Test run time: ____ (before/after)

Impact: Confirms all cleanup objectives achieved successfully

## Validation Results

**Dead Code:** ✅ Found and removed 1 unreachable function (`DroppedEventsCount`)
**Tests:** ✅ All pass
**Coverage:**
- Main: 39.6%
- cmd/bd: 20.2%
- Created follow-up issues (bd-85487065 through bd-bc2c6191) to improve coverage

**Build:** ✅ Clean
**Linting:** 73 issues (up from 34 baseline)
- Increase due to unused functions from refactoring
- Need cleanup in separate issue

**Integration Tests:** ✅ All pass
**Metrics:** 56,464 LOC across 193 Go files
**Git:** 2 files modified (deadcode fix + auto-synced JSONL)

## Follow-up Issues Created
- bd-85487065: Add tests for internal/autoimport (0% coverage)
- bd-0dcea000: Add tests for internal/importer (0% coverage)
- bd-4d7fca8a: Add tests for internal/utils (0% coverage)
- bd-6221bdcd: Improve cmd/bd coverage (20.2% -> target higher)
- bd-bc2c6191: Improve internal/daemon coverage (22.5% -> target higher)


Add tests for internal/importer package

Currently 0.0% coverage. Need tests for JSONL import logic including collision detection and resolution.


Implement git worktree management

Create git worktree lifecycle management for separate beads branch.

Tasks:
- Create internal/git/worktree.go
- Implement CreateBeadsWorktree(branch, path)
- Implement RemoveBeadsWorktree(path)
- Implement CheckWorktreeHealth(path)
- Configure sparse checkout (only .beads/)
- Implement SyncJSONLToWorktree()
- Handle worktree errors gracefully
- Auto-cleanup on config change

Estimated effort: 3-4 days


Multi-clone collision resolution testing and documentation

Epic to track improvements to multi-clone collision resolution based on ultrathinking analysis of-3d844c58 and [deleted:bd-71107098].

Current state:
- 2-clone collision resolution is SOUND and working correctly
- Hash-based deterministic collision resolution works
- Test fails due to timestamp comparison, not actual logic issues

Work needed:
1. Fix TestTwoCloneCollision to compare content not timestamps
2. Add TestThreeCloneCollision for regression protection
3. Document 3-clone ID non-determinism as known behavior


Stress test: event storm handling

Simulate 100+ rapid JSONL writes. Verify debouncer batches to single import. Verify no data loss. Test daemon stability.


Update docs for import bug fix

Update AGENTS.md, README.md, TROUBLESHOOTING.md with import.orphan_handling config documentation. Document resurrection behavior, tombstones, config modes. Add troubleshooting section for import failures with deleted parents.


Doctor: exclude merge artifacts from 'multiple JSONL' warning

## Problem
`bd doctor` warns about 'Multiple JSONL files found' when merge artifact files exist:
```
JSONL Files: Multiple JSONL files found: beads.base.jsonl, beads.left.jsonl, issues.jsonl ⚠
```

This is confusing because these aren't real issue JSONL files - they're temporary snapshots for deletion tracking.

## Fix
Exclude known merge artifact patterns from the multiple-JSONL warning:

```go
// In doctor JSONL check
skipPatterns := map[string]bool{
    "beads.base.jsonl": true,
    "beads.left.jsonl": true,
    "beads.right.jsonl": true,
}
```

## Files
- cmd/bd/doctor/ (JSONL check logic)


Wire config to import pipeline

Connect import.orphan_handling config to importer.go and sqlite validation functions. Pass mode flag through call chain. Implement all four modes (strict/resurrect/skip/allow) with proper error messages and logging.


Auth tokens expire too quickly

## Summary

[Brief description of the bug]

## Steps to Reproduce

1. Step 1
2. Step 2
3. Step 3

## Expected Behavior

[What should happen]

## Actual Behavior

[What actually happens]

## Environment

- OS: [e.g., macOS 15.7.1]
- Version: [e.g., bd 0.20.1]
- Additional context: [any relevant details]

## Additional Context

[Screenshots, logs, or other relevant information]


Code Review: PR #551 - Persist close_reason to issues table

Code review of PR #551 which fixes close_reason persistence bug.

## Summary
The PR correctly fixes a bug where close_reason was only stored in the events table, not in the issues.close_reason column. This caused `bd show --json` to return empty close_reason.

## What Was Fixed
- ✅ CloseIssue now updates both close_reason and closed_at
- ✅ ReOpenIssue clears both close_reason and closed_at
- ✅ Comprehensive tests added for both storage and CLI layers
- ✅ Clear documentation in queries.go about dual storage strategy

## Quality Assessment
✅ Tests cover both storage layer and CLI JSON output
✅ Handles reopen case (clearing close_reason)
✅ Good comments explaining dual-storage design
✅ No known issues

## Potential Followups
See linked issues for suggestions.


Create npm package structure for bd-wasm

Set up npm package for distribution:
- Create package.json with bd-wasm name
- Bundle bd.wasm + wasm_exec.js
- Create CLI wrapper (bin/bd) that invokes WASM
- Add installation scripts if needed
- Configure package for Claude Code Web sandbox compatibility


Update documentation for beads-merge integration

Document the integrated merge functionality.

**Updates needed**:
- AGENTS.md: Replace "use external beads-merge" with "bd merge"
- README.md: Add git merge driver section
- TROUBLESHOOTING.md: Update merge conflict resolution
- ADVANCED.md: Document 3-way merge algorithm
- Create CREDITS.md or ATTRIBUTION.md for @neongreen

**Highlight**: Deletion sync fix (bd-hv01)


Refactor: extract common helpers in sync-branch hook checks

Code review of #532 fix identified duplication between checkSyncBranchHookCompatibility and checkSyncBranchHookQuick.

Suggested refactoring:
1. Extract getPrePushHookPath(path string) helper for git dir + hook path resolution
2. Extract extractHookVersion(hookContent string) helper for version parsing
3. Consider whether Warning for custom hooks is appropriate (vs OK with info message)
4. Document the intentional behavior difference between full check (Warning for custom) and quick check (OK for custom)


Add performance benchmarks for multi-repo hydration

The contributor-workflow-analysis.md asserts sub-second queries (line 702) and describes smart caching via file mtime tracking (Decision #4, lines 584-618), but doesn't provide concrete performance benchmarks.

VC's requirement (from VC feedback section):
- Executor polls GetReadyWork() every 5-10 seconds
- Queries must be sub-second (ideally <100ms)
- Smart caching must avoid re-parsing JSONLs on every query

Suggested performance targets to validate:
- File stat overhead: <1ms per repo
- Hydration (when needed): <500ms for typical JSONL (<25k)
- Query (from cache): <10ms
- Total GetReadyWork(): <100ms (VC's requirement)

Also test at scale:
- N=1 repo (baseline)
- N=3 repos (typical)
- N=10 repos (edge case)

These benchmarks are critical for library consumers like VC that run automated polling loops.


AI-supervised database migrations for safer schema evolution

## Problem

Database migrations can lose user data through edge cases that are hard to anticipate (e.g., GH #201 where bd migrate failed to set issue_prefix, or bd-d355a07d false positive data loss warnings). Since beads is designed to be run by AI agents, we should leverage AI to make migrations safer.

## Current State

Migrations run blindly with:
- No pre-flight validation
- No data integrity verification
- No rollback on failure
- Limited post-migration testing

Recent issues:
- GH #201: Migration didn't set issue_prefix config, breaking commands
- bd-d355a07d: False positive "data loss" warnings on collision resolution
- Users reported migration data loss (fixed but broader problem remains)

## Proposal: AI-Supervised Migration Framework

Use AI to supervise migrations through structured verification:

### 1. Pre-Migration Analysis
- AI reads migration code and current schema
- Identifies potential data loss scenarios
- Generates validation queries to verify assumptions
- Creates snapshot queries for before/after comparison

### 2. Migration Execution
- Take database backup/snapshot
- Run validation queries (pre-state)
- Execute migration in transaction
- Run validation queries (post-state)

### 3. Post-Migration Verification
- AI compares pre/post snapshots
- Verifies data integrity invariants
- Checks for unexpected data loss
- Validates config completeness (like issue_prefix)

### 4. Rollback on Anomalies
- If AI detects data loss, rollback transaction
- Present human-readable error report
- Suggest fix before retrying

## Example Flow

```
$ bd migrate

→ Analyzing migration plan...
→ AI identified 3 potential data loss scenarios
→ Generating validation queries...
→ Creating pre-migration snapshot...
→ Running migration in transaction...
→ Verifying post-migration state...
✓ All 247 issues accounted for
✓ Config table complete (issue_prefix: "mcp")
✓ Dependencies intact (342 relationships verified)
→ Migration successful!
```

If something goes wrong:
```
$ bd migrate

→ Analyzing migration plan...
→ AI identified issue: Missing issue_prefix config after migration
→ Recommendation: Add prefix detection step
→ Aborting migration - database unchanged
```

## Implementation Ideas

### A. Migration Validator Tool
Create `bd migrate --validate` that:
- Simulates migration on copy of database
- Uses AI to verify data integrity
- Reports potential issues before real migration

### B. Migration Test Generator
AI generates test cases for migrations:
- Edge cases (empty DB, large DB, missing config)
- Data integrity checks
- Regression tests

### C. Migration Invariants
Define invariants that AI checks:
- Issue count should not decrease (unless collision resolution)
- All required config keys present
- Foreign key relationships intact
- No orphaned dependencies

### D. Self-Healing Migrations
AI detects incomplete migrations and suggests fixes:
- Missing config values (like GH #201)
- Orphaned data
- Index inconsistencies

## Benefits

1. **Catch edge cases**: AI explores scenarios humans miss
2. **Self-documenting**: AI explains what migration does
3. **Agent-friendly**: Agents can run migrations confidently
4. **Fewer rollbacks**: Detect issues before committing
5. **Better testing**: AI generates comprehensive test suites

## Open Questions

1. Which AI model? (Fast: Haiku, Thorough: Sonnet/GPT-4)
2. How to balance safety vs migration speed?
3. Should AI validation be required or optional?
4. How to handle offline scenarios (no API access)?
5. What invariants should always be checked?

## Related Work

- bd-b245: Migration registry (makes migrations introspectable)
- GH #201: issue_prefix migration bug (motivating example)
- bd-d355a07d: False positive data loss warnings

## Progress

### ✅ Phase 1: Migration Invariants (COMPLETED)

**Implemented:**
- Created internal/storage/sqlite/migration_invariants.go with 3 invariants
- Updated RunMigrations() to verify invariants after migrations
- All tests pass ✓

### ✅ Phase 2: Inspection Tools (COMPLETED & PUSHED)

**Commit:** 1abe4e7 - "Add migration inspection tools for AI agents (bd-627d Phase 2)"

**Implemented:**
1. ✅ bd migrate --inspect --json - Shows migration plan
2. ✅ bd info --schema --json - Returns schema details
3. ✅ Migration warnings system
4. ✅ Documentation updated in AGENTS.md
5. ✅ All tests pass

### ✅ Phase 3: MCP Tools (COMPLETED & PUSHED)

**Commit:** 2493693 - "Add MCP tools for migration inspection (bd-627d Phase 3)"

**Implemented:**
1. ✅ inspect_migration(workspace_root) tool in beads-mcp
2. ✅ get_schema_info(workspace_root) tool in beads-mcp
3. ✅ Abstract methods in BdClientBase
4. ✅ CLI client implementations
5. ✅ All tests pass

**All phases complete!** Migration inspection fully integrated into MCP server.


Test RPC mutation event


Need comprehensive daemon health check command (bd daemon doctor?)


Add fsnotify dependency to go.mod


Test update


Add concurrent import race condition tests

Currently no tests verify behavior when multiple clones import simultaneously with external_ref matching.

Scenarios to test:
1. Two clones import same external_ref update at same time
2. Clone A imports while Clone B updates same issue
3. Verify transaction isolation prevents corruption
4. Document expected behavior (last-write-wins vs timestamp-based)

Related: bd-1022
Files: internal/importer/external_ref_test.go


Phase 3: Enhance daemon robustness for GH #353

Improve daemon health checks and metadata refresh to prevent staleness issues.

**Tasks:**
1. Enhance daemon health checks to detect unreachable daemons
2. Add daemon metadata refresh (check disk every 5s)
3. Comprehensive testing in sandbox environments

**Implementation:**
- cmd/bd/main.go: Better health check error handling (lines 300-367)
- cmd/bd/daemon_event_loop.go: Periodic metadata refresh
- cmd/bd/daemon_unix.go: Permission-aware process checks

**References:**
- docs/GH353_INVESTIGATION.md (Solutions 4 & 5, lines 161-209)
- Depends on: Phase 2 (bd-u3t)

**Acceptance Criteria:**
- Daemon detects when it's unreachable and auto-switches to direct mode
- Daemon picks up external import operations without restart
- All edge cases handled gracefully


Implement content-hash based collision resolution for deterministic convergence

The current collision resolution uses creation timestamps to decide which issue to keep vs. remap. This is non-deterministic when two clones create issues at nearly the same time.

Root cause of bd-71107098:
- Clone A creates test-1="Issue from clone A" at T0
- Clone B creates test-1="Issue from clone B" at T0+30ms
- Clone B syncs first, remaps Clone A's to test-2
- Clone A syncs second, sees collision, remaps Clone B's to test-2
- Result: titles are swapped between clones

Solution:
- Use content-based hashing (title + description + priority + type)
- Deterministic winner: always keep issue with lower hash
- Same collision on different clones produces same result (idempotent)

Implementation:
- Modify ScoreCollisions in internal/storage/sqlite/collision.go
- Replace timestamp-based scoring with content hash comparison
- Ensure hash function is stable across platforms


Investigate TestRoutingIntegration failure

TestRoutingIntegration/maintainer_with_SSH_remote failed during pre-commit check with "expected role maintainer, got contributor".
This occurred while running `go test -short ./...` on darwin/arm64.
The failure appears unrelated to storage/sqlite changes.
Need to investigate if this is a flaky test or environmental issue.


Implement auto-merge functionality in duplicates command

The duplicates.go file has a TODO at line 95 to implement the performMerge function for automatic duplicate merging. Currently it just prints a warning message. This would automate the merge process instead of just suggesting commands.


bd sync --import-only doesn't update DB mtime causing bd doctor false warning


Implement alias conflict resolution

Handle alias conflicts when multiple clones assign same alias to different issues.

## Scenario
```
Clone A: Creates bd-a1b2c3d4, assigns alias #42
Clone B: Creates bd-e5f6a7b8, assigns alias #42
After sync: Conflict! Which issue gets #42?
```

## Resolution Strategy: Content-Hash Ordering
Deterministic, same result on all clones:
```go
func ResolveAliasConflicts(conflicts []AliasConflict) []AliasRemapping {
    for _, conflict := range conflicts {
        // Sort by hash ID (lexicographic)
        sort.Strings(conflict.IssueIDs)

        // Winner: lowest hash ID (arbitrary but deterministic)
        winner := conflict.IssueIDs[0]

        // Losers: reassign to next available aliases
        for _, loser := range conflict.IssueIDs[1:] {
            newAlias := getNextAlias()
            remappings = append(remappings, AliasRemapping{
                IssueID:  loser,
                OldAlias: conflict.Alias,
                NewAlias: newAlias,
            })
        }
    }
    return remappings
}
```

## Detection During Import
File: internal/importer/importer.go
```go
func handleAliasConflicts(imported []Issue, existing []Issue) error {
    // Build alias map from imported issues
    aliasMap := make(map[int][]string)  // alias → issue IDs

    for _, issue := range imported {
        aliasMap[issue.Alias] = append(aliasMap[issue.Alias], issue.ID)
    }

    // Check against existing aliases
    for alias, importedIDs := range aliasMap {
        existingID := storage.GetIssueIDByAlias(alias)
        if existingID != "" {
            // Conflict! Resolve it
            allIDs := append(importedIDs, existingID)
            conflicts = append(conflicts, AliasConflict{
                Alias:    alias,
                IssueIDs: allIDs,
            })
        }
    }

    // Resolve and apply
    remappings := ResolveAliasConflicts(conflicts)
    applyAliasRemappings(remappings)
}
```

## Alternative Strategies (For Future Consideration)

### Priority-Based
```go
// Higher priority keeps alias
if issueA.Priority < issueB.Priority {
    winner = issueA
}
```

### Timestamp-Based (Last-Write-Wins)
```go
// Newer issue keeps alias
if issueA.UpdatedAt.After(issueB.UpdatedAt) {
    winner = issueA
}
```

### Manual Resolution
```bash
bd resolve-aliases --manual
# Interactive prompt for each conflict
```

## User Notification
```bash
$ bd sync
✓ Synced 5 issues
⚠ Alias conflicts resolved:
  - Issue bd-e5f6a7b8: alias changed from #42 to #100
  - Issue bd-9a8b7c6d: alias changed from #15 to #101
```

## Files to Create/Modify
- internal/storage/sqlite/alias_conflicts.go (new)
- internal/importer/importer.go (detect conflicts)
- cmd/bd/sync.go (show conflict notifications)

## Testing
- Test two clones assign same alias to different issues
- Test conflict resolution is deterministic (same on all clones)
- Test loser gets new alias
- Test winner keeps original alias
- Test multiple conflicts resolved in one import


Add WebSocket support

## Feature Request

[Describe the desired feature]

## Motivation

[Why is this feature needed? What problem does it solve?]

## Use Cases

1. **Use Case 1**: [description]
2. **Use Case 2**: [description]

## Proposed Solution

[High-level approach to implementing this feature]

## Alternatives Considered

- **Alternative 1**: [description and why not chosen]
- **Alternative 2**: [description and why not chosen]


Remove misleading placeholder 'bd merge' command from duplicates output

**Problem:**
The `bd duplicates` command suggests running a command that doesn't exist:
```
bd merge <source-ids> --into <target-id>
```

This is confusing because:
1. `bd merge` is actually a git 3-way JSONL merge driver (takes 4 file paths)
2. The suggested syntax for merging duplicate issues is not implemented
3. Line 75 in duplicates.go even has: `// TODO: performMerge implementation pending`

**Current behavior:**
- Users see suggested command that doesn't work
- No indication that feature is unimplemented
- Related to issue #349 item #2

**Proposed fix:**
Replace line 77 in cmd/bd/duplicates.go with either:

Option A (conservative):
```go
cmd := fmt.Sprintf("# TODO: Merge %s into %s (merge command not yet implemented)",
    strings.Join(sources, " "), target.ID)
```

Option B (actionable):
```go
cmd := fmt.Sprintf("# Duplicate found: %s\n# Manual merge: Close duplicates with 'bd close %s' and link to %s as 'related'",
    strings.Join(sources, " "), strings.Join(sources, " "), target.ID)
```

**Files to modify:**
- cmd/bd/duplicates.go (line ~77)


Improve test coverage for internal/beads (48.1% → 70%)

The beads package is a core package with 48.1% coverage. As the primary package for issue management, it should have at least 70% coverage.

Current coverage: 48.1%
Target coverage: 70%


Fix G104 errors unhandled in internal/storage/sqlite/queries.go:1181

Linting issue: G104: Errors unhandled (gosec) at internal/storage/sqlite/queries.go:1181:4. Error: rows.Close()


(deleted)


Improve test coverage for internal/export (37.1% → 60%)

The export package has only 37.1% test coverage. Export functionality needs good coverage to ensure data integrity.

Current coverage: 37.1%
Target coverage: 60%


Measure notification latency vs git sync

Benchmark end-to-end latency for status updates to propagate between agents using both methods.

Acceptance Criteria:
- Measure git sync latency (commit → push → pull → import)
- Measure Agent Mail latency (send_message → fetch_inbox)
- Document latency distribution (p50, p95, p99)
- Verify <100ms claim for Agent Mail
- Compare against 1-5s baseline for git

Success Metric: Agent Mail latency < 100ms, git sync latency > 1000ms

Latency benchmark completed. Results documented in latency_results.md:
- Git sync: 2000-5000ms (full cycle with network)
- Agent Mail: <100ms (HTTP API round-trip)
- Confirms 20-50x latency reduction claim


bd doctor --fix needs non-interactive mode (-y/--yes flag)

When running `bd doctor --fix` in non-interactive mode (scripts, CI, Claude Code), it prompts 'Continue? (Y/n):' and fails with EOF.

**Expected**: A `-y` or `--yes` flag to auto-confirm fixes.

**Workaround**: Currently have to run `bd init` instead, but that's not discoverable from the doctor output.


Change default JSONL filename from beads.jsonl back to issues.jsonl throughout codebase


Test graceful degradation when server unavailable

Verify that agents continue working normally when Agent Mail server is stopped or unreachable.

Acceptance Criteria:
- Agent detects server unavailable on startup
- Logs "falling back to Beads-only mode"
- All bd commands work normally
- Agent can claim issues (no reservations, like today)
- Git sync operates as normal
- No errors or crashes

Success Metric: Zero functional difference when Agent Mail unavailable


Improve clean vs cleanup command naming/documentation

Clarify the difference between bd clean and bd cleanup to reduce user confusion.

**Current state:**
- bd clean: Remove temporary artifacts (.beads/bd.sock, logs, etc.)
- bd cleanup: Delete old closed issues from database

**Options:**
1. Rename for clarity:
   - bd clean → bd clean-temp
   - bd cleanup → bd cleanup-issues

2. Keep names but improve help text and documentation

3. Add prominent warnings in help output

**Preferred approach:** Option 2 (improve documentation)
- Update short/long descriptions in commands
- Add examples to help text
- Update README.md
- Add cross-references in help output

**Files to modify:**
- cmd/bd/clean.go
- cmd/bd/cleanup.go
- README.md or ADVANCED.md


Don't search parent directories for .beads databases

bd currently walks up the directory tree looking for .beads directories, which can find unrelated databases (e.g., ~/.beads). This causes confusing warnings and potential data pollution.

Should either:
1. Stop at git root (don't search above it)
2. Only use explicit BEADS_DB env var or local .beads
3. At minimum, don't search in home directory