Fix TestFallbackToDirectModeEnablesFlush deadlock causing 10min test timeout

## Problem

TestFallbackToDirectModeEnablesFlush in direct_mode_test.go deadlocks for 9m59s before timing out, causing the entire test suite to take 10+ minutes instead of <10 seconds.

## Root Cause

Database lock contention between test cleanup and flushToJSONL():
- Test cleanup (line 36) tries to close DB via defer
- flushToJSONL() (line 132) is still accessing DB
- Results in deadlock: database/sql.(*DB).Close() waits for mutex while GetJSONLFileHash() holds it

## Stack Trace Evidence

```
goroutine 512 [sync.Mutex.Lock, 9 minutes]:
database/sql.(*DB).Close(0x14000643790)
  .../database/sql/sql.go:927 +0x84
github.com/steveyegge/beads/cmd/bd.TestFallbackToDirectModeEnablesFlush.func1()
  .../direct_mode_test.go:36 +0xf4

While goroutine running flushToJSONL() holds DB connection via GetJSONLFileHash()
```

## Impact

- Test suite: 10+ minutes → should be <10 seconds
- ALL other tests pass in ~4 seconds
- This ONE test accounts for 99.9% of test runtime

## Related

This is the EXACT same issue documented in MAIN_TEST_REFACTOR_NOTES.md for why main_test.go refactoring was deferred - global state manipulation + DB cleanup = deadlock.

## Fix Approaches

1. **Add proper cleanup sequencing** - stop flush goroutines BEFORE closing DB
2. **Use test-specific DB lifecycle** - ensure flush completes before cleanup
3. **Mock the flush mechanism** - avoid real DB for testing this code path
4. **Add explicit timeout handling** - fail fast with clear error instead of hanging

## Files

- cmd/bd/direct_mode_test.go:36-132
- cmd/bd/autoflush.go:353 (validateJSONLIntegrity)
- cmd/bd/autoflush.go:508 (flushToJSONLWithState)

## Acceptance

- Test passes without timeout
- Test suite completes in <10 seconds
- No deadlock between cleanup and flush operations


bd message: Fix inefficient client-side filtering for --unread-only


Integration Testing

Verify cache removal doesn't break any workflows


Create tip system infrastructure for contextual hints

Implement a tip/hint system that shows helpful contextual messages after successful commands. This is different from the existing error-path "Hint:" messages - tips appear on success paths to educate users about features they might not know about.


Investigate why test issues persist in database

Test issues (bd-0do3, bd-cjxp, bd-phr2, etc.) keep appearing in ready/list output, cluttering real work. These appear to be leftover test data from test runs.

Need to investigate:
1. Why are test issues not being cleaned up after tests?
2. Are tests creating issues in the main database instead of test databases?
3. Should we add better test isolation or cleanup hooks?
4. Can we add a label/prefix to distinguish test issues from real issues?

These test issues have characteristics:
- Empty descriptions
- Generic titles like "Test issue 0", "Bug P0", "Issue to reopen with reason"
- Created around 2025-11-07 19:00-19:07
- Some assigned to test users like "alice", "bob", "testuser"

## Root Cause Analysis

**Problem**: Python MCP integration tests created test issues in production `.beads/beads.db` instead of isolated test databases.

**Evidence**:
- 29 test issues created on Nov 7, 2025 at 19:00-19:07
- Patterns: "Bug P0", "Test issue X", assignees "alice"/"bob"/"testuser"
- Git commit 0e8936b shows test issues committed to .beads/beads.jsonl
- Tests were being fixed for workspace isolation around the same time

**Why It Happened**:
1. Before commit 0e8936b, `test_client_lazy_initialization()` didn't set `BEADS_WORKING_DIR`
2. Tests fell back to discovering `.beads/` in the project root directory
3. Auto-sync committed test issues to production database

**Resolution**:
1. ✅ Closed 29 test pollution issues (bd-0do3, bd-cjxp, etc.)
2. ✅ Added `failIfProductionDatabase()` guard in Go test helpers
3. ✅ Added production pollution checks in RPC test setup
4. ✅ Created `conftest.py` with pytest safety checks for Python tests
5. ✅ Added `BEADS_TEST_MODE` env var to mark test execution
6. ✅ Tests now fail fast if they detect production database usage

**Prevention**:
- All test helper functions now verify database paths are in temp directories
- Python tests fail immediately if BEADS_DB points to production
- BEADS_TEST_MODE flag helps identify test vs production execution
- Clear error messages guide developers to use proper test isolation

**Files Modified**:
- cmd/bd/test_helpers_test.go - Added failIfProductionDatabase()
- internal/rpc/rpc_test.go - Added temp directory verification
- integrations/beads-mcp/tests/conftest.py - New file with pytest safeguards


Add comprehensive tests for show.go commands (show, update, edit, close)

Need to add tests for cmd/bd/show.go which contains show, update, edit, and close commands.

**Challenge**: The existing test patterns use rootCmd.SetArgs() and rootCmd.Execute(), but the global `store` variable needs to match what the commands use. Initial attempt created tests that failed with "no issue found" because the test's store instance wasn't the same as the command's store.

**Files to test**:
- show.go (contains showCmd, updateCmd, editCmd, closeCmd)

**Coverage needed**:
- show command (single issue, multiple issues, JSON output, with dependencies, with labels, with compaction)
- update command (status, priority, title, assignee, description, multiple fields, multiple issues)
- edit command (requires $EDITOR, may need mocking)
- close command (single issue, multiple issues, with reason, JSON output)

**Test approach**:
1. Study working test patterns in init_test.go, list_test.go, etc.
2. Ensure BEADS_NO_DAEMON=1 is set
3. Properly initialize database with bd init
4. Use the command's global store, not a separate instance
5. May need to reset global state between tests

**Success criteria**:
- All test functions pass
- Coverage for show.go increases significantly
- Tests follow existing patterns in cmd/bd/*_test.go


Multi-repo contributor workflow support

Implement separate repository support for OSS contributors to prevent PR pollution while maintaining git ledger and multi-clone sync. Based on contributor-workflow-analysis.md Solution #4.


Fix silent error handling in RPC response writing

Marshal and write errors silently ignored in writeResponse, can send partial JSON and hang clients.

Location: internal/rpc/server_lifecycle_conn.go:228-232

Problem:
- json.Marshal error ignored - cyclic reference sends corrupt JSON
- Write error ignored - connection closed, no indication to caller
- WriteByte error ignored - client hangs waiting for newline
- Flush error ignored - partial data buffered

Current code:
func (s *Server) writeResponse(writer *bufio.Writer, resp Response) {
    data, _ := json.Marshal(resp)  // Ignored!
    _, _ = writer.Write(data)      // Ignored!
    _ = writer.WriteByte('\n')     // Ignored!
    _ = writer.Flush()             // Ignored!
}

Solution: Return errors, handle in caller, close connection on error

Impact: Client hangs waiting for response; corrupt JSON sent

Effort: 1 hour


Issue 1 to reopen


Add integration tests for CompactedResult in MCP server

The CompactedResult model is used for list operations when results exceed COMPACTION_THRESHOLD (20 items), but there are no integration tests verifying the actual MCP server behavior with large result sets.

## What's Missing
- Integration test that mocks a large result set (>20 issues) and verifies CompactedResult is returned
- Verification that preview_count matches PREVIEW_COUNT (5)
- Verification that total_count reflects actual result size
- Test that compaction threshold is configurable (currently hardcoded COMPACTION_THRESHOLD=20)

## Why This Matters
The compaction logic is critical for preventing context overflow with large lists. Without integration tests, we can't verify it works correctly with the actual MCP protocol.

## Suggested Implementation
Create test_mcp_compaction.py with:
1. test_list_with_large_result_set_returns_compacted_result()
2. test_ready_work_respects_compaction_threshold()
3. test_compacted_result_structure_is_valid()


Improve test coverage for cmd/bd/doctor/fix (23.9% → 50%)

The doctor/fix package has only 23.9% test coverage. The doctor fix functionality is important for troubleshooting.

Current coverage: 23.9%
Target coverage: 50%


Fix MCP tools failing to load in Claude Code (GH#346)

Fix FastMCP schema generation bug by refactoring `Issue` model to avoid recursion.

    - Refactored `Issue` in `models.py` to use `LinkedIssue` for dependencies/dependents.
    - Restored missing `Mail*` models to `models.py`.
    - Fixed `tests/test_mail.py` mock assertion.

    Fixes GH#346.


bd validate - Comprehensive health check

Run all validation checks in one command.

Checks:
- Duplicates
- Orphaned dependencies
- Test pollution
- Git conflicts

Supports --fix-all for auto-repair.

Depends on bd-cbed9619.1, bd-0dcea000, bd-31aab707, bd-9826b69a.

Files: cmd/bd/validate.go (new)


Publish @beads/bd package to npm registry

Publish the npm package to the public npm registry:

## Prerequisites
- npm account created
- Organization @beads created (or use different namespace)
- npm login completed locally
- Package tested locally (bd-f282 completed)

## Publishing steps
1. Verify package.json version matches current bd version
2. Run npm pack and inspect tarball contents
3. Test installation from tarball one more time
4. Run npm publish --access public
5. Verify package appears on https://www.npmjs.com/package/@beads/bd
6. Test installation from registry: npm install -g @beads/bd

## Post-publish
- Add npm badge to README.md
- Update CHANGELOG.md with npm package release
- Announce in release notes

## Note
- May need to choose different name if @beads namespace unavailable
- Alternative: beads-cli, bd-cli, or unscoped beads-issue-tracker


Add error handling test for cmd.Help() in search command

Test coverage gap identified by automated analysis (vc-217).

**Original Issue:** [deleted:bd-da96-baseline-lint]

In cmd/bd/search.go:39, the return value of cmd.Help() is not checked, flagged by errcheck linter.

Add test to verify:
- Error handling when cmd.Help() fails (e.g., output redirection fails)
- Proper error propagation to caller
- Command still exits gracefully on help error

This ensures the search command handles help errors properly and doesn't silently ignore failures.

_This issue was automatically created by AI test coverage analysis._


Plugin should provide hooks instead of requiring global install


Issue to reopen with reason


Auto-repair stale merge driver configs with invalid placeholders

Old bd versions (<0.24.0) installed merge driver with invalid placeholders %L %R instead of %A %B. Add detection to bd doctor --fix: check if git config merge.beads.driver contains %L or %R, auto-repair to 'bd merge %A %O %A %B'. One-time migration for users who initialized with old versions.


Add sync.branch configuration

Add configuration layer to support sync.branch setting via config file, environment variable, or CLI flag.

Tasks:
- Add sync.branch field to config schema
- Add BEADS_SYNC_BRANCH environment variable
- Add --branch flag to bd init
- Add bd config get/set sync.branch commands
- Validation (branch name format, conflicts)
- Config migration for existing users

Estimated effort: 1-2 days


Test parent issue


Issue 2 to reopen


Document which files to commit after bd init --branch

GH #312 reported confusion about which files should be committed after running 'bd init --branch beads-metadata'. Updated PROTECTED_BRANCHES.md to clearly document:

1. Files that should be committed to protected branch (main):
   - .beads/.gitignore
   - .gitattributes

2. Files that are automatically gitignored
3. Files that live in the sync branch (beads-metadata)

Changes:
- Added step-by-step instructions in Quick Start section
- Added 'What lives in each branch' section to How It Works
- Clarified the directory structure diagram

Fixes: https://github.com/steveyegge/beads/issues/312


bd-hv01: Multi-repo mode not tested with deletion tracking

Problem: Test suite has no coverage for multi-repo mode. ExportToMultiRepo creates multiple JSONL files but snapshot files are hardcoded to single JSONL location.

Impact: Deletion tracking likely silently broken for multi-repo users, could cause data loss.

Fix: Add test and update snapshot logic to handle multiple JSONL files.

Files: cmd/bd/deletion_tracking_test.go, cmd/bd/deletion_tracking.go, cmd/bd/daemon_sync.go:24-34


Priority 0 in merge may incorrectly win over set priorities

In mergePriority(), priority 0 (which may mean 'unset' due to Go's zero value) beats any explicitly set priority like P1, P2, etc. Should probably treat 0 as 'no priority set' and not let it win conflicts.


bd message: Add HTTP client timeout to prevent hangs

HTTP client in `sendAgentMailRequest` uses default http.Post with no timeout.

**Location:** cmd/bd/message.go:181

**Problem:**
- Can hang indefinitely if server is unresponsive
- No way to cancel stuck requests
- Poor UX in flaky networks

**Fix:**
```go
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Post(url, "application/json", bytes.NewReader(reqBody))
```

**Impact:** Production reliability and security issue


Improve test coverage for internal/daemon (27.3% → 60%)

The daemon package has only 27.3% test coverage. The daemon is critical for background operations and reliability.

Key areas needing tests:
- Daemon autostart logic
- Socket handling
- PID file management
- Health checks

Current coverage: 27.3%
Target coverage: 60%


Deletion propagation via deletions manifest

## Problem

When `bd cleanup -f` or `bd delete` removes issues in one clone, those deletions don't propagate to other clones. The import logic only creates/updates, never deletes. This causes "resurrection" where deleted issues reappear.

## Root Cause

Import sees DB issues not in JSONL and assumes they're "local unpushed work" rather than "intentionally deleted upstream."

## Solution: Deletions Manifest

Add `.beads/deletions.jsonl` - an append-only log of deleted issue IDs with metadata.

### Format
```jsonl
{"id":"bd-xxx","ts":"2025-11-25T10:00:00Z","by":"stevey"}
{"id":"bd-yyy","ts":"2025-11-25T10:05:00Z","by":"claude","reason":"duplicate of bd-zzz"}
```

### Fields
- `id`: Issue ID (required)
- `ts`: ISO 8601 UTC timestamp (required)
- `by`: Actor who deleted (required)
- `reason`: Optional context ("cleanup", "duplicate of X", etc.)

### Import Logic
```
For each DB issue not in JSONL:
  1. Check deletions manifest → if found, delete from DB
  2. Fallback: check git history → if found, delete + backfill manifest
  3. Neither → keep (local unpushed work)
```

### Conflict Resolution
Simultaneous deletions from multiple clones are handled naturally:
- Append-only design means both clones append their deletion records
- On merge, file contains duplicate entries (same ID, different timestamps)
- `LoadDeletions` deduplicates by ID (keeps any/first entry)
- Result: deletion propagates correctly, duplicates are harmless

### Pruning Policy
- Default retention: 7 days (configurable via `deletions.retention_days`)
- Auto-compact during `bd sync` is **opt-in** (disabled by default)
- Hard cap: `deletions.max_entries` (default 50000)
- Git fallback handles pruned entries (self-healing)

### Self-Healing
When git fallback catches a resurrection (pruned entry), it backfills the manifest. One-time git scan cost, then fast again.

### Size Estimates
- ~80 bytes/entry
- 7-day retention with 100 deletions/day = ~56KB
- Git compressed: ~10KB

## Benefits
- ✅ Deletions propagate across clones
- ✅ O(1) lookup (no git scan in normal case)
- ✅ Works in shallow clones
- ✅ Survives history rewrite
- ✅ Audit trail (who deleted what when)
- ✅ Self-healing via git fallback
- ✅ Bounded size via time-based pruning

## References
- Investigation session: 2025-11-25
- Related: bd-2q6d (stale database warnings)


Add migration registry and simplify New()

Create migrations.go with Migration type and registry. Change New() to: openDB -> initSchema -> RunMigrations(db). This removes 8+ separate migrate functions from New().


Add template support for issue creation

Support creating issues from predefined templates to streamline common workflows like epics, bug reports, or feature proposals.

Example usage:
  bd create --from-template epic "Phase 3 Features"
  bd create --from-template bug "Login failure"
  bd template list
  bd template create epic

Templates should include:
- Pre-filled description structure
- Suggested priority and type
- Common labels
- Design/acceptance criteria sections

Implementation notes:
- Store templates in .beads/templates/ directory
- Support YAML or JSON format
- Ship with built-in templates (epic, bug, feature)
- Allow custom project-specific templates


Channel isolation test - beads

Resetting stale in_progress status from old executor run (13 days old)


Add command injection prevention tests for git rm in merge command

Test coverage gap identified by automated analysis (vc-217).

**Original Issue:** [deleted:bd-da96-baseline-lint]

In cmd/bd/merge.go:121, exec.Command is called with variable fullPath, flagged by gosec G204 for potential command injection.

Add tests covering:
- File paths with shell metacharacters (;, |, &, $, etc.)
- Paths with spaces and special characters
- Paths attempting command injection (e.g., 'file; rm -rf /')
- Validation that fullPath is properly sanitized
- Only valid git-tracked files can be removed

This is a critical security path preventing arbitrary command execution.

_This issue was automatically created by AI test coverage analysis._


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]


Clean up merge conflict artifacts in .beads directory

After resolving merge conflicts in .beads/beads.jsonl, leftover artifacts remain as untracked files:
- .beads/beads.base.jsonl
- .beads/beads.left.jsonl

These appear to be temporary files created during merge conflict resolution.

Options to fix:
1. Add these patterns to .beads/.gitignore automatically
2. Clean up these files after successful merge resolution
3. Document that users should delete them manually
4. Add a check in 'bd sync' or 'bd doctor' to detect and remove stale merge artifacts

Preferred solution: Add *.base.jsonl and *.left.jsonl patterns to .beads/.gitignore during 'bd init', and optionally clean them up automatically after successful import.


Auto-detect scenarios and prompt users

Detect when user is in fork/contributor scenario and prompt with helpful suggestions. Check: git remote relationships, existing .beads config, repo ownership. Suggest appropriate wizard.


Test lowercase p0