diff --git a/.beads/beads.jsonl b/.beads/beads.jsonl index 3af9f42f..8a236368 100644 --- a/.beads/beads.jsonl +++ b/.beads/beads.jsonl @@ -9,11 +9,11 @@ {"id":"bd-08e556f2","content_hash":"cd9e7cc106b733dc4893e92a75feae3331b422238f261a7c738c21a18e29719f","title":"Remove Cache Configuration Docs","description":"Remove documentation of deprecated cache env vars","acceptance_criteria":"- Documentation doesn't reference removed env vars\n- CHANGELOG documents breaking change\n- No mentions of storage cache except in CHANGELOG\n\nFiles to update:\n- ADVANCED.md (remove cache configuration section)\n- commands/daemons.md (remove cache env vars)\n- integrations/beads-mcp/SETUP_DAEMON.md (remove cache tuning)\n- CHANGELOG.md (add removal entry)\n\nDeprecated env vars:\n- BEADS_DAEMON_MAX_CACHE_SIZE\n- BEADS_DAEMON_CACHE_TTL\n- BEADS_DAEMON_MEMORY_THRESHOLD_MB","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-28T10:50:15.125488-07:00","updated_at":"2025-10-30T17:12:58.216329-07:00","closed_at":"2025-10-28T10:48:20.606979-07:00"} {"id":"bd-08fd","content_hash":"a76be9b5de417bce89d29b20a5a675d6ac65339c5fd538683a5d76fe3c75a50c","title":"Test child issue","description":"","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-02T11:50:40.640901-08:00","updated_at":"2025-11-02T11:50:47.309652-08:00","closed_at":"2025-11-02T11:50:47.309652-08:00"} {"id":"bd-09b5f2f5","content_hash":"2cf0ab565f49aaa39cc7128cef964f99b37f14a948fbad3c617f9397df1e2541","title":"Daemon fails to auto-import after git pull updates JSONL","description":"After git pull updates .beads/issues.jsonl, daemon doesn't automatically re-import changes, causing stale data to be shown until next sync cycle (up to 5 minutes).\n\nReproduction:\n1. Repo A: Close issues, export, commit, push\n2. Repo B: git pull (successfully updates .beads/issues.jsonl)\n3. bd show \u003cissue\u003e shows OLD status from daemon's SQLite db\n4. JSONL on disk has correct new status\n\nRoot cause: Daemon sync cycle runs on timer (5min). When user manually runs git pull, daemon doesn't detect JSONL was updated externally and continues serving stale data from SQLite.\n\nImpact:\n- High for AI agents using beads in git workflows\n- Breaks fundamental git-as-source-of-truth model\n- Confusing UX: git log shows commit, bd shows old state\n- Data consistency issues between JSONL and daemon\n\nSee WYVERN_SYNC_ISSUE.md for full analysis.","design":"Three possible solutions:\n\nOption 1: Auto-detect and re-import (recommended)\n- Before serving any bd command, check if .beads/issues.jsonl mtime \u003e last import time\n- If newer, auto-import before processing request\n- Fast check, minimal overhead\n\nOption 2: File watcher in daemon\n- Daemon watches .beads/issues.jsonl for mtime changes\n- Auto-imports when file changes\n- More complex, requires file watching infrastructure\n\nOption 3: Explicit sync command\n- User runs `bd sync` after git pull\n- Manual, error-prone, defeats automation\n\nRecommended: Option 1 (auto-detect) + Option 3 (explicit sync) as fallback.","acceptance_criteria":"1. After git pull updates .beads/issues.jsonl, next bd command sees fresh data\n2. No manual import or daemon restart required\n3. Performance impact \u003c 10ms per command (mtime check is fast)\n4. Works in both daemon and non-daemon modes\n5. Test: Two repo clones, update in one, pull in other, verify immediate sync","notes":"**Fixed in v0.21.2!**\n\nThe daemon auto-import is fully implemented:\n- internal/autoimport package handles staleness detection\n- internal/importer package provides shared import logic (used by both CLI and daemon)\n- daemon's checkAndAutoImportIfStale() calls autoimport.AutoImportIfNewer()\n- importFunc uses importer.ImportIssues() with auto-rename enabled\n- All tests passing\n\nThe critical data corruption bug is FIXED:\n✅ After git pull, daemon detects JSONL is newer (mtime check)\n✅ Daemon auto-imports before serving requests\n✅ No stale data served\n✅ No data loss in multi-agent workflows\n\nVerification needed: Run two-repo test to confirm end-to-end behavior.","status":"closed","priority":0,"issue_type":"epic","created_at":"2025-10-25T23:13:12.270766-07:00","updated_at":"2025-11-01T16:52:50.931197-07:00","closed_at":"2025-11-01T16:52:50.931197-07:00"} -{"id":"bd-0a90","content_hash":"d04ded2e8194db5c42c27641f68e52b553ff500e9101861e87e7956ec012dc74","title":"bd show --json doesn't include dependency type field","description":"Fix GitHub issue #202. The JSON output from bd show and bd list commands should include the dependency type field (and optionally created_at, created_by) to match internal storage format and enable better tooling integration.","notes":"PR #203 updated with cleaner implementation: https://github.com/steveyegge/beads/pull/203\n\n## Final Implementation\n\nCleanest possible approach - no internal helper methods needed:\n\n**Design:**\n- `GetDependenciesWithMetadata()` / `GetDependentsWithMetadata()` - canonical implementations with full SQL query\n- `GetDependencies()` / `GetDependents()` - thin wrappers that strip metadata for backward compat\n- `scanIssuesWithDependencyType()` - shared helper for scanning rows with dependency type\n\n**Benefits:**\n- Single source of truth - the `...WithMetadata()` methods ARE the implementation\n- Eliminated ~139 lines of duplicated SQL and scanning code\n- All tests passing (14 dependency-related tests)\n- Backward compatible\n- dependency_type field appears correctly in JSON output\n\n**Note on scan helpers:**\nThe duplication between `scanIssues()` and `scanIssuesWithDependencyType()` is necessary because they handle different SQL result shapes (16 vs 17 columns). This is justified as they serve fundamentally different purposes based on query structure.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-11-02T09:42:08.712725096Z","updated_at":"2025-11-02T15:30:16.582318-08:00","closed_at":"2025-11-02T15:30:16.582318-08:00","external_ref":"https://github.com/steveyegge/beads/issues/202"} -{"id":"bd-0d9c","content_hash":"a61ba371d6c50f21a92e4debeaaa00a4c3eb77ef96fbcdfa89f80e9b13ffff7a","title":"YABB: Spurious issue updates during normal operations","description":"Issue bd-627d was updated during config refactoring session without any actual changes to it. Only timestamps and content_hash changed.\n\nObserved: Running various bd commands (list, create, etc.) caused bd-627d updated_at to change from 14:14 to 14:31.\n\nExpected: Issues should only be updated when explicitly modified.\n\nThis causes:\n- Dirty JSONL after every session\n- False conflicts in git\n- Confusing git history\n\nLikely culprit: Daemon auto-import/export cycle or database migration touching all issues.","notes":"Investigated thoroughly - unable to reproduce. The import logic has IssueDataChanged() checks before calling UpdateIssue (importer/importer.go:458). All tests pass. May have been fixed by recent refactorings. Closing as cannot reproduce - please reopen with specific repro steps if it occurs again.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-11-02T14:36:31.023552-08:00","updated_at":"2025-11-02T16:24:35.356064-08:00","closed_at":"2025-11-02T16:24:35.356072-08:00"} +{"id":"bd-0a90","content_hash":"8f19f9a9e01ccf3a4dd42673a84610f2550db9a9e744806105dc3b9e070f4e46","title":"bd show --json doesn't include dependency type field","description":"Fix GitHub issue #202. The JSON output from bd show and bd list commands should include the dependency type field (and optionally created_at, created_by) to match internal storage format and enable better tooling integration.","notes":"PR #203 updated with cleaner implementation: https://github.com/steveyegge/beads/pull/203\n\n## Final Implementation\n\nCleanest possible approach - no internal helper methods needed:\n\n**Design:**\n- `GetDependenciesWithMetadata()` / `GetDependentsWithMetadata()` - canonical implementations with full SQL query\n- `GetDependencies()` / `GetDependents()` - thin wrappers that strip metadata for backward compat\n- `scanIssuesWithDependencyType()` - shared helper for scanning rows with dependency type\n\n**Benefits:**\n- Single source of truth - the `...WithMetadata()` methods ARE the implementation\n- Eliminated ~139 lines of duplicated SQL and scanning code\n- All tests passing (14 dependency-related tests)\n- Backward compatible\n- dependency_type field appears correctly in JSON output\n\n**Note on scan helpers:**\nThe duplication between `scanIssues()` and `scanIssuesWithDependencyType()` is necessary because they handle different SQL result shapes (16 vs 17 columns). This is justified as they serve fundamentally different purposes based on query structure.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-11-02T09:42:08.712725096Z","updated_at":"2025-11-02T16:40:27.353068-08:00","closed_at":"2025-11-02T16:40:27.353076-08:00","external_ref":"https://github.com/steveyegge/beads/issues/202"} +{"id":"bd-0d9c","content_hash":"a61ba371d6c50f21a92e4debeaaa00a4c3eb77ef96fbcdfa89f80e9b13ffff7a","title":"YABB: Spurious issue updates during normal operations","description":"Issue bd-627d was updated during config refactoring session without any actual changes to it. Only timestamps and content_hash changed.\n\nObserved: Running various bd commands (list, create, etc.) caused bd-627d updated_at to change from 14:14 to 14:31.\n\nExpected: Issues should only be updated when explicitly modified.\n\nThis causes:\n- Dirty JSONL after every session\n- False conflicts in git\n- Confusing git history\n\nLikely culprit: Daemon auto-import/export cycle or database migration touching all issues.","notes":"Investigated thoroughly - unable to reproduce. The import logic has IssueDataChanged() checks before calling UpdateIssue (importer/importer.go:458). All tests pass. May have been fixed by recent refactorings. Closing as cannot reproduce - please reopen with specific repro steps if it occurs again.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-11-02T14:36:31.023552-08:00","updated_at":"2025-11-02T16:40:27.35377-08:00","closed_at":"2025-11-02T16:40:27.353774-08:00"} {"id":"bd-0dcea000","content_hash":"a6fc218b07d270e3498957525c39a869f7c850d687339b6d758a246be20c9591","title":"Add tests for internal/importer package","description":"Currently 0.0% coverage. Need tests for JSONL import logic including collision detection and resolution.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-29T14:06:21.071024-07:00","updated_at":"2025-10-30T17:12:58.183211-07:00","dependencies":[{"issue_id":"bd-0dcea000","depends_on_id":"bd-cbed9619.5","type":"blocks","created_at":"2025-10-29T19:52:05.531279-07:00","created_by":"import-remap"},{"issue_id":"bd-0dcea000","depends_on_id":"bd-cbed9619.4","type":"blocks","created_at":"2025-10-29T19:52:05.53166-07:00","created_by":"import-remap"}]} {"id":"bd-0e1f2b1b","content_hash":"c0b1677fe3f4aa3f395ae4d79bff5362632d5db26477bf571c09f9177b8741ef","title":"Event-driven daemon architecture","description":"Replace 5-second polling sync loop with event-driven architecture that reacts instantly to changes. Eliminates stale data issues while reducing CPU ~60%. Key components: FileWatcher (fsnotify), Debouncer (500ms), RPC mutation events, optional git hooks. Target latency: \u003c500ms (vs 5000ms). See event_driven_daemon.md for full design.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-28T16:20:02.430479-07:00","updated_at":"2025-10-30T17:12:58.221424-07:00","closed_at":"2025-10-28T16:30:26.631191-07:00"} -{"id":"bd-0e74","content_hash":"b0f407df62d992c094ba763db11c4fd5be6386b34f3b7cf94665f2e37dbc0999","title":"Comprehensive testing for separate branch workflow","description":"Comprehensive testing for separate branch workflow including unit tests, integration tests, and performance testing.\n\nTasks:\n- Unit tests for worktree management\n- Unit tests for config parsing\n- Integration tests: create/update/close → beads branch\n- Integration test: merge beads → main\n- Integration test: protected branch scenario\n- Integration test: network failure recovery\n- Integration test: config change handling\n- Manual testing guide\n- Performance testing (worktree overhead)\n\nTest scenarios: fresh setup, issue operations, merge workflow, protected branch, error handling, migration, multiple workspaces, sparse checkout\n\nEstimated effort: 4-5 days","acceptance_criteria":"- All unit tests pass\n- All integration tests pass\n- Manual testing guide works\n- No data loss in any scenario\n- Performance acceptable (\u003c 100ms overhead per commit)","status":"in_progress","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.580741-08:00","updated_at":"2025-11-02T15:31:05.29542-08:00","dependencies":[{"issue_id":"bd-0e74","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:51.348226-08:00","created_by":"stevey"}]} +{"id":"bd-0e74","content_hash":"8a8661c26a526f67df2a64f2da6a18e7db3be52fc8c2971dd7fd90bdb1b7dd91","title":"Comprehensive testing for separate branch workflow","description":"Comprehensive testing for separate branch workflow including unit tests, integration tests, and performance testing.\n\nTasks:\n- Unit tests for worktree management\n- Unit tests for config parsing\n- Integration tests: create/update/close → beads branch\n- Integration test: merge beads → main\n- Integration test: protected branch scenario\n- Integration test: network failure recovery\n- Integration test: config change handling\n- Manual testing guide\n- Performance testing (worktree overhead)\n\nTest scenarios: fresh setup, issue operations, merge workflow, protected branch, error handling, migration, multiple workspaces, sparse checkout\n\nEstimated effort: 4-5 days","acceptance_criteria":"- All unit tests pass\n- All integration tests pass\n- Manual testing guide works\n- No data loss in any scenario\n- Performance acceptable (\u003c 100ms overhead per commit)","status":"open","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.580741-08:00","updated_at":"2025-11-02T16:44:55.864576-08:00","dependencies":[{"issue_id":"bd-0e74","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:51.348226-08:00","created_by":"stevey"}]} {"id":"bd-1022","content_hash":"0b712a337844711597d2dd950d27d4c032a3b746a27f44326d62db740f5944e9","title":"Use external_ref as primary matching key for import updates","description":"Enable re-syncing from external systems (Jira, GitHub, Linear) by using external_ref as the primary matching key during imports. Currently imports treat any content change as a collision, making it impossible to sync updates from external systems without creating duplicates.\n\nSee GH #142 for detailed proposal and implementation plan.\n\nKey changes needed:\n1. Add findByExternalRef() query function\n2. Update DetectCollisions() to match by external_ref first\n3. Update import_shared.go to update existing issues when external_ref matches\n4. Add index on external_ref for performance\n5. Preserve local issues (no external_ref) from being overwritten\n\nThis enables hybrid workflows: import external backlog, break down with local tasks, re-sync anytime.","notes":"## Code Review Complete ✅\n\n**Overall Assessment**: EXCELLENT - Production ready\n\n### Implementation Quality\n- ✓ Clean architecture with proper interface extension\n- ✓ Dual backend support (SQLite + Memory)\n- ✓ Smart matching priority: external_ref → ID → content hash\n- ✓ O(1) lookups with database index\n- ✓ Timestamp-based conflict resolution\n- ✓ Comprehensive test coverage (11 test cases)\n\n### Follow-up Issues Filed\nHigh Priority (P2):\n- bd-897a: Add UNIQUE constraint on external_ref column\n- bd-7315: Add validation for duplicate external_ref in batch imports\n\nMedium Priority (P3):\n- bd-f9a1: Add index usage verification test\n- bd-3f6a: Add concurrent import race condition tests\n\nLow Priority (P4):\n- bd-e166: Improve timestamp comparison readability\n- bd-9e23: Optimize Memory backend with index\n- bd-537e: Add external_ref change tracking\n- bd-df11: Add import metrics\n- bd-9f4a: Document external_ref in content hash\n\n### Key Features\n✅ External systems (Jira, GitHub, Linear) can re-sync without duplicates\n✅ Hybrid workflows: import external backlog, add local tasks, re-sync anytime\n✅ Local issues protected from being overwritten\n✅ Timestamp checking ensures only newer updates applied\n✅ Performance optimized with database index\n\n**Confidence Level**: 95% - Ship it! 🚀","status":"closed","priority":0,"issue_type":"feature","created_at":"2025-11-02T14:55:56.355813-08:00","updated_at":"2025-11-02T15:52:05.786625-08:00","closed_at":"2025-11-02T15:52:05.78663-08:00"} {"id":"bd-1048","content_hash":"5afd0f21d2d75242065b3a96c9246cc3bc9ad05a2f76698d382c854ca29d99d2","title":"Daemon crashes silently on RPC query after startup","description":"The daemon starts successfully but crashes with EOF error when queried via RPC. No panic or error is logged. Happens consistently after 'bd show' or other RPC commands. Last log entry is 'Using event-driven mode'. Workaround: use --no-daemon flag.","status":"open","priority":0,"issue_type":"bug","created_at":"2025-11-02T17:05:03.658333-08:00","updated_at":"2025-11-02T17:05:03.658333-08:00"} {"id":"bd-11e0","content_hash":"591db3f5674cf7f79b1f50d6b8d83fe60e495f02a21e181c9c63d8da88308d58","title":"Database import silently fails when daemon version != CLI version","description":"","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-31T21:08:09.096749-07:00","updated_at":"2025-11-01T19:29:35.267817-07:00","closed_at":"2025-11-01T19:29:35.267817-07:00"} @@ -43,12 +43,12 @@ {"id":"bd-2b34.6","content_hash":"35f5cd1a2cd942610511e4161b7bc1c55e32a6786cf2ae3e36fd094dac026d27","title":"Add tests for daemon lifecycle module","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-31T22:28:42.359587-07:00","updated_at":"2025-11-01T21:22:39.009259-07:00","closed_at":"2025-11-01T21:22:39.009259-07:00"} {"id":"bd-2b34.7","content_hash":"62bfa4e0024d5b68061e3ca64645449e5abfc5849d611f6797cd378e5ea0af93","title":"Add tests for daemon config module","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-31T22:28:42.373684-07:00","updated_at":"2025-11-01T21:21:42.431252-07:00","closed_at":"2025-11-01T21:21:42.431252-07:00"} {"id":"bd-2b34.8","content_hash":"449c5ba132b35ebfbd8ed8dc31f7d96c03311c0dc5eda61d88af3a071e365338","title":"Extract daemon lifecycle functions to daemon_lifecycle.go","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-31T22:28:42.382892-07:00","updated_at":"2025-11-01T21:02:58.350055-07:00","closed_at":"2025-11-01T21:02:58.350055-07:00"} -{"id":"bd-2e80","content_hash":"bb7de865be3d63a2c6c167cf1100a458bfcc4d04d85639bcbcf22f310477e408","title":"Document shared memory test isolation pattern in test_helpers.go","description":"Tests were failing because :memory: creates a shared database across all tests. The fix is to use \"file::memory:?mode=memory\u0026cache=private\" for test isolation.\n\nShould document this pattern in test_helpers.go and potentially update newTestStore to use private memory by default.","status":"closed","priority":3,"issue_type":"chore","created_at":"2025-11-01T22:40:58.993496-07:00","updated_at":"2025-11-02T16:24:35.356654-08:00","closed_at":"2025-11-02T16:24:35.356657-08:00"} +{"id":"bd-2e80","content_hash":"bb7de865be3d63a2c6c167cf1100a458bfcc4d04d85639bcbcf22f310477e408","title":"Document shared memory test isolation pattern in test_helpers.go","description":"Tests were failing because :memory: creates a shared database across all tests. The fix is to use \"file::memory:?mode=memory\u0026cache=private\" for test isolation.\n\nShould document this pattern in test_helpers.go and potentially update newTestStore to use private memory by default.","status":"closed","priority":3,"issue_type":"chore","created_at":"2025-11-01T22:40:58.993496-07:00","updated_at":"2025-11-02T16:40:27.354652-08:00","closed_at":"2025-11-02T16:40:27.354654-08:00"} {"id":"bd-2f388ca7","content_hash":"27498c808874010ee62da58e12434a6ae7c73f4659b2233aaf8dcd59566a907d","title":"Fix TestTwoCloneCollision timeout","description":"","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-28T14:11:25.219607-07:00","updated_at":"2025-10-30T17:12:58.217635-07:00","closed_at":"2025-10-28T16:12:26.286611-07:00"} {"id":"bd-317ddbbf","content_hash":"81a74ccf29037e5a780b12540a4059bab98b9a790a5a043a68118fc00a083cda","title":"Add BEADS_DAEMON_MODE flag handling","description":"Add environment variable BEADS_DAEMON_MODE (values: poll, events). Default to 'poll' for Phase 1. Wire into daemon startup to select runEventLoop vs runEventDrivenLoop.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-28T16:20:02.433638-07:00","updated_at":"2025-10-30T17:12:58.224373-07:00","closed_at":"2025-10-28T12:31:47.819136-07:00"} {"id":"bd-31aab707","content_hash":"8f64a8dbcc5ed63bc73b7d91fca624527033265dc1c89a7775eb2f45b378f382","title":"Unit tests for FileWatcher","description":"Test watcher detects JSONL changes. Test git ref changes trigger import. Test debounce integration. Test watcher recovery from file removal/rename.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T11:30:59.842317-07:00","updated_at":"2025-10-31T12:00:43.189591-07:00","closed_at":"2025-10-31T12:00:43.189591-07:00"} {"id":"bd-325da116","content_hash":"d7c5637527778c5c835f5e4b6e15fbd51a3476d6749ab3155b8aeac08a8ef339","title":"Fix N-way collision convergence","description":"Epic to fix the N-way collision convergence problem documented in n-way-collision-convergence.md.\n\n## Problem Summary\nThe current collision resolution implementation works correctly for 2-way collisions but does not converge for 3-way (and by extension N-way) collisions. TestThreeCloneCollision demonstrates this with reproducible failures.\n\n## Root Causes Identified\n1. Pairwise resolution doesn't scale - each clone makes local decisions without global context\n2. DetectCollisions modifies state during detection (line 83-86 in collision.go)\n3. No remapping history - can't track transitive remap chains (test-1 → test-2 → test-3)\n4. Import-time resolution is too late - happens after git merge\n\n## Solution Architecture\nReplace pairwise resolution with deterministic global N-way resolution using:\n- Content-addressable identity (content hashing)\n- Global collision resolution (sort all versions by hash)\n- Read-only detection phase (separate from modification)\n- Idempotent imports (content-first matching)\n\n## Success Criteria\n- TestThreeCloneCollision passes without skipping\n- All clones converge to identical content after final pull\n- No data loss (all issues present in all clones)\n- Works for N workers (test with 5+ clones)\n- Idempotent imports (importing same JSONL multiple times is safe)\n\n## Implementation Phases\nSee child issues for detailed breakdown of each phase.","status":"closed","priority":0,"issue_type":"epic","created_at":"2025-10-29T23:05:13.889079-07:00","updated_at":"2025-10-31T11:59:41.031668-07:00","closed_at":"2025-10-31T11:59:41.031668-07:00"} -{"id":"bd-3396","content_hash":"66907b79181fce3d1b04dad20c240f37f3347be91f68e7d3fce8dabed1a9d81b","title":"Add merge helper commands (bd sync --merge)","description":"Add commands to merge beads branch back to main.\n\nTasks:\n- Implement bd sync --merge command\n- Implement bd sync --status command\n- Implement bd sync --auto-merge (optional, for automation)\n- Detect merge conflicts and provide guidance\n- Show commit diff between branches\n- Verify main branch is clean before merge\n- Push merged changes to remote\n\nEstimated effort: 2-3 days","acceptance_criteria":"- bd sync --merge successfully merges beads branch\n- Conflicts detected with helpful error message\n- bd sync --status shows clear diff\n- Works with protected main (user must have push access)\n- Git history is clean (no unnecessary merge commits)","status":"in_progress","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.580873-08:00","updated_at":"2025-11-02T15:31:05.295735-08:00","dependencies":[{"issue_id":"bd-3396","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.376916-08:00","created_by":"stevey"}]} +{"id":"bd-3396","content_hash":"43addfac9a43239dd75e1292a6502a79479cb09e67ff5d6823cc3df1b73390bf","title":"Add merge helper commands (bd sync --merge)","description":"Add commands to merge beads branch back to main.\n\nTasks:\n- Implement bd sync --merge command\n- Implement bd sync --status command\n- Implement bd sync --auto-merge (optional, for automation)\n- Detect merge conflicts and provide guidance\n- Show commit diff between branches\n- Verify main branch is clean before merge\n- Push merged changes to remote\n\nEstimated effort: 2-3 days","acceptance_criteria":"- bd sync --merge successfully merges beads branch\n- Conflicts detected with helpful error message\n- bd sync --status shows clear diff\n- Works with protected main (user must have push access)\n- Git history is clean (no unnecessary merge commits)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.580873-08:00","updated_at":"2025-11-02T16:55:25.142702-08:00","closed_at":"2025-11-02T16:55:25.142704-08:00","dependencies":[{"issue_id":"bd-3396","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.376916-08:00","created_by":"stevey"}]} {"id":"bd-36320a04","content_hash":"883eb385fa9eded3826008fa6db3b842cabb2ce0e93a23293449f65024303fb7","title":"Add mutation channel to internal/rpc/server.go","description":"Add mutationChan chan MutationEvent to Server struct. Emit events on CreateIssue, UpdateIssue, DeleteIssue, AddComment. Non-blocking send with default case for full channel.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T19:42:29.860173-07:00","updated_at":"2025-10-31T18:31:27.928693-07:00","closed_at":"2025-10-31T18:31:27.928693-07:00"} {"id":"bd-36870264","content_hash":"fa3b422a3382fba9fe673a10145f6e787ca5c2f3c4966d84148dae89d1fa0e2e","title":"Enforce daemon singleton per workspace with file locking","description":"Agent in ~/src/wyvern discovered 4 simultaneous daemon processes running, causing infinite directory recursion (.beads/.beads/.beads/...). Each daemon used relative paths and created nested .beads/ directories.\n\nRoot cause: No singleton enforcement. Multiple `bd daemon` processes can start in same workspace.\n\nExpected: One daemon per workspace (each workspace = separate .beads/ dir with bd.sock)\nActual: Multiple daemons can run simultaneously in same workspace\n\nNote: Separate git clones = separate workspaces = separate daemons (correct). Git worktrees share .beads/ and have known limitations (documented, use --no-daemon).","design":"Use flock (file locking) on daemon socket or database file to enforce singleton:\n\n1. On daemon start, attempt exclusive lock on .beads/bd.sock or .beads/daemon.lock\n2. If lock held by another process, refuse to start (exit with clear error)\n3. Hold lock for lifetime of daemon process\n4. Release lock on daemon shutdown\n\nAlternative: Use PID file with stale detection (check if PID is still running)\n\nImplementation location: Daemon startup code in cmd/bd/ or internal/daemon/","acceptance_criteria":"1. Starting second daemon process in same workspace fails with clear error\n2. Test: Start daemon, attempt second start, verify failure\n3. Killing daemon releases lock, allowing new daemon to start\n4. No infinite .beads/ directory recursion possible\n5. Works correctly with auto-start mechanism","notes":"## Fix Summary\n\nSuccessfully prevented the nested .beads/.beads/ recursion bug by implementing two safeguards:\n\n1. **Path Canonicalization in FindDatabasePath()** (beads.go):\n - Added filepath.Abs() + filepath.EvalSymlinks() to normalize all database paths\n - Prevents relative path edge cases that create nested directories\n - Ensures all daemons see the same canonical path\n\n2. **Nested Directory Detection** (daemon_lifecycle.go):\n - Added explicit check for \".beads/.beads\" pattern in setupDaemonLock()\n - Fails fast with clear error message if nested structure detected\n - Provides user hints about proper usage\n\n## Root Cause\n\nThe daemon lock (added Oct 22, 2025) correctly prevents simultaneous daemons in the SAME workspace. However, when BEADS_DB used a relative path (e.g., \".beads/beads.db\") from inside the .beads directory, FindDatabasePath() would resolve it to a nested path creating a separate workspace:\n- First daemon: /workspace/.beads/beads.db\n- Second daemon from .beads/: /workspace/.beads/.beads/beads.db ← Different lock file!\n\n## Testing\n\nAll acceptance criteria passed:\n✅ 1. Second daemon start fails with \"daemon already running\" error\n✅ 2. Killing daemon releases lock, new daemon can start \n✅ 3. No infinite .beads/ recursion possible (tested nested BEADS_DB path)\n✅ 4. Works with auto-start mechanism\n\nThe fix addresses the edge case while maintaining the existing lock mechanism's correctness.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-25T23:13:12.269549-07:00","updated_at":"2025-11-01T19:46:06.230339-07:00","closed_at":"2025-11-01T19:46:06.230339-07:00"} {"id":"bd-373c","content_hash":"2ee54c4542489d8d254d17a6fc2e2d581e99badd7a166b36799cdca4be94bcc6","title":"Daemon crashes silently when multiple .db files exist in .beads/","description":"When daemon detects multiple .db files (after filtering out .backup and vc.db files), it writes error details to .beads/daemon-error file before exiting.\n\nThe error file is checked when:\n1. Daemon discovery fails to connect (internal/daemon/discovery.go)\n2. Auto-start fails to yield a running daemon (cmd/bd/main.go)\n3. Daemon list shows 'daemon not responding' error\n\nThis makes the error immediately visible to users without requiring them to check daemon logs.\n\nFile created: cmd/bd/daemon.go (writes daemon-error on multiple .db detection)\nFiles modified: \n- internal/daemon/discovery.go (reads daemon-error and surfaces in DaemonInfo.Error)\n- cmd/bd/main.go (displays daemon-error when auto-start fails)\n\nTesting: Create multiple .db files in .beads/, start daemon, verify error file created and shown in bd daemons list","notes":"Root cause: Daemon exits with os.Exit(1) when multiple .db files detected (daemon.go:1381), but error only goes to daemon log file. User sees 'daemon not responding' without knowing why.\n\nCurrent detection:\n- daemon.go filters out .backup and vc.db files\n- bd doctor detects multiple databases\n- Error message tells user to run 'bd init' or manually remove\n\nProblem: Error is not user-visible unless they check daemon logs.\n\nProposed fix options:\n1. Surface the error in 'bd info' and 'bd daemons list' output\n2. Add a hint in error messages to run 'bd doctor' when daemon fails\n3. Make daemon write error to a .beads/daemon-error file that gets checked\n4. Improve 'bd doctor' to run automatically when daemon is unhealthy","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-31T21:08:03.389259-07:00","updated_at":"2025-11-01T11:13:48.029427-07:00","closed_at":"2025-11-01T11:13:48.029427-07:00","dependencies":[{"issue_id":"bd-373c","depends_on_id":"bd-2752a7a2","type":"discovered-from","created_at":"2025-10-31T21:08:03.390022-07:00","created_by":"stevey"}]} @@ -59,8 +59,8 @@ {"id":"bd-3e307cd4","content_hash":"2d95ea3b6835139e1fd266bbdcd0f683b5b4d26a1041516c4883beeb37b11ede","title":"File change test issue","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-29T19:11:28.425601-07:00","updated_at":"2025-10-31T12:00:43.176605-07:00","closed_at":"2025-10-31T12:00:43.176605-07:00"} {"id":"bd-3e3b","content_hash":"db612c737d8f330bb1ff1bbda043835d1318bb806970677ed768a69e15287653","title":"Add circular dependency detection to bd doctor","description":"Added cycle detection as Check #10 in bd doctor command. Uses same recursive CTE query as DetectCycles() to find circular dependencies. Reports error status with count and fix suggestion if cycles found.","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-11-01T20:18:23.416056-07:00","updated_at":"2025-11-01T20:18:26.76113-07:00","closed_at":"2025-11-01T20:18:26.76113-07:00"} {"id":"bd-3e9ddc31","content_hash":"4e03660281dbe2c069617fc8d723d546d6e5eb386142c0359b862747867a1b90","title":"Replace getStorageForRequest with Direct Access","description":"Replace all getStorageForRequest(req) calls with s.storage","acceptance_criteria":"- No references to getStorageForRequest() in codebase (except in deleted file)\n- All handlers use s.storage directly\n- Code compiles without errors\n\nFiles to update:\n- internal/rpc/server_issues_epics.go (~8 calls)\n- internal/rpc/server_labels_deps_comments.go (~4 calls)\n- internal/rpc/server_compact.go (~2 calls)\n- internal/rpc/server_export_import_auto.go (~2 calls)\n- internal/rpc/server_routing_validation_diagnostics.go (~1 call)\n\nPattern: store, err := s.getStorageForRequest(req) → store := s.storage","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T23:20:10.393759-07:00","updated_at":"2025-10-30T17:12:58.21613-07:00","closed_at":"2025-10-28T14:08:38.06721-07:00"} -{"id":"bd-3ee2c7e9","content_hash":"a1a26c30e2d2d791d3dd5b3fe3a917304cb001b1d024e4627e46fd93c98bcf86","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-26T16:53:40.970042-07:00","updated_at":"2025-11-02T17:03:29.63837-08:00","closed_at":"2025-11-02T17:03:29.63837-08:00"} -{"id":"bd-3f6a","content_hash":"7fef5b08bbb32c4f4ab7d906539a765b01f1a74d0bb71102c954a5bdec4b442e","title":"Add concurrent import race condition tests","description":"Currently no tests verify behavior when multiple clones import simultaneously with external_ref matching.\n\nScenarios to test:\n1. Two clones import same external_ref update at same time\n2. Clone A imports while Clone B updates same issue\n3. Verify transaction isolation prevents corruption\n4. Document expected behavior (last-write-wins vs timestamp-based)\n\nRelated: bd-1022\nFiles: internal/importer/external_ref_test.go","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-02T15:32:11.286956-08:00","updated_at":"2025-11-02T16:46:49.278728-08:00","closed_at":"2025-11-02T16:46:49.278738-08:00"} +{"id":"bd-3ee2c7e9","content_hash":"80a0101dd9082c194cd4f138dc116c0fc14d178d8afacb6b5b61ee863ee2eea7","title":"Add \"bd daemons\" command for multi-daemon management","description":"Add a new \"bd daemons\" command with subcommands to manage daemon processes across all beads repositories/worktrees. Should show all running daemons with metadata (version, workspace, uptime, last sync), allow stopping/restarting individual daemons, auto-clean stale processes, view logs, and show exclusive lock status.","design":"Subcommands:\n- list: Show all running daemons with metadata (workspace, PID, version, socket path, uptime, last activity, exclusive lock status)\n- stop \u003cpath|pid\u003e: Gracefully stop a specific daemon\n- restart \u003cpath|pid\u003e: Stop and restart daemon\n- killall: Emergency stop all daemons\n- health: Verify each daemon responds to ping\n- logs \u003cpath\u003e: View daemon logs\n\nFeatures:\n- Auto-clean stale sockets/dead processes\n- Discovery: Scan for .beads/bd.sock files + running processes\n- Communication: Use existing socket protocol, add GET /status endpoint for metadata","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-26T16:53:40.970042-07:00","updated_at":"2025-11-02T17:08:52.041882-08:00","closed_at":"2025-11-02T17:08:52.041887-08:00"} +{"id":"bd-3f6a","content_hash":"7fef5b08bbb32c4f4ab7d906539a765b01f1a74d0bb71102c954a5bdec4b442e","title":"Add concurrent import race condition tests","description":"Currently no tests verify behavior when multiple clones import simultaneously with external_ref matching.\n\nScenarios to test:\n1. Two clones import same external_ref update at same time\n2. Clone A imports while Clone B updates same issue\n3. Verify transaction isolation prevents corruption\n4. Document expected behavior (last-write-wins vs timestamp-based)\n\nRelated: bd-1022\nFiles: internal/importer/external_ref_test.go","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-02T15:32:11.286956-08:00","updated_at":"2025-11-02T17:08:52.042337-08:00","closed_at":"2025-11-02T17:08:52.04234-08:00"} {"id":"bd-3f80d9e0","content_hash":"10716746db7f5efcb9380e184d3ae8abfefd5b84d500340899e13e3b81d4e02a","title":"Improve internal/daemon test coverage (currently 22.5%)","description":"Daemon functionality needs better coverage:\n- Auto-start behavior\n- Lock file management\n- Discovery mechanisms\n- Connection handling\n- Error recovery","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-29T14:06:30.832728-07:00","updated_at":"2025-10-30T17:12:58.186077-07:00"} {"id":"bd-40a0","content_hash":"44ac6f2956fce0d7f1fa4d6f4e09b93b14bdd914c1199ed68dedf9c85fbdf4cf","title":"bd doctor should check for multiple DBs, multiple JSONLs, daemon health","description":"","design":"\nCurrently bd doctor only checks:\n- .beads/ directory exists\n- Database version vs CLI version \n- ID format (hash vs sequential)\n- CLI version vs latest GitHub release\n\nIt should ALSO check for operational issues that cause silent failures:\n\n1. **Multiple database files** (*.db excluding backups and vc.db)\n - Warn if multiple *.db files found (ambiguous which to use)\n - Suggest running 'bd migrate' or manually removing old DBs\n\n2. **Multiple JSONL files** \n - Check for both issues.jsonl and beads.jsonl\n - Warn about ambiguity, suggest standardizing on one\n\n3. **Daemon health** (integrate bd daemons health)\n - Check if daemon running for this workspace\n - Detect version mismatches between daemon and CLI\n - Detect zombie daemons (running but unresponsive)\n - Detect stale daemon.pid files\n\n4. **Database-JSONL sync issues**\n - Check if JSONL is newer than last import\n - Warn if they're out of sync\n\n5. **Permissions issues**\n - Check if .beads/ directory is writable\n - Check if database file is readable/writable\n\nImplementation approach:\n- Add new check functions to doctor.go\n- Reuse logic from bd daemons health\n- Keep checks fast (\u003c 1 second total)\n- Output actionable fixes for each issue\n","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-10-31T21:16:47.042913-07:00","updated_at":"2025-10-31T21:21:27.093525-07:00","closed_at":"2025-10-31T21:21:27.093525-07:00"} {"id":"bd-46381404","content_hash":"1963d7e754c6eaafba9cbefc6d9f38cc4d872386d9d100ecbba7d7f24cbbcea3","title":"Test database naming","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.309676-07:00","updated_at":"2025-10-31T12:00:43.185201-07:00","closed_at":"2025-10-31T12:00:43.185201-07:00"} @@ -77,24 +77,25 @@ {"id":"bd-5599","content_hash":"c48839a6f7f5ca4083ced2f0f47cd250046146032555a14864ac3469a42bb76b","title":"Fix TestListCommand duplicate dependency constraint violation","description":"","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-31T21:27:05.557548-07:00","updated_at":"2025-10-31T21:27:11.429018-07:00","closed_at":"2025-10-31T21:27:11.429018-07:00"} {"id":"bd-581b80b3","content_hash":"04c4d952852ae2673e551d9776698c52b0189754ac5f9ca295bed464a5b86a43","title":"bd find-duplicates - AI-powered duplicate detection","description":"Find semantically duplicate issues.\n\nApproaches:\n1. Mechanical: Exact title/description matching\n2. Embeddings: Cosine similarity (cheap, scalable)\n3. AI: LLM-based semantic comparison (expensive, accurate)\n\nUses embeddings by default for \u003e100 issues.\n\nFiles: cmd/bd/find_duplicates.go (new)","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-29T20:49:49.126801-07:00","updated_at":"2025-10-30T17:12:58.218673-07:00"} {"id":"bd-589c7c1e","content_hash":"efbc1fe1379d414d2af33f5aff9787e4f8a3234922199bdc9abce25dba99aef0","title":"Fix revive style issues (78 issues)","description":"Style violations: unused parameters (many cmd/args in cobra commands), missing exported comments, stuttering names (SQLiteStorage), indent-error-flow issues.","design":"Rename unused params to _, add godoc comments to exported types, fix stuttering names, simplify control flow.","notes":"Fixed 19 revive issues:\n- 14 unused-parameter (renamed to _)\n- 2 redefines-builtin-id (max→maxCount, min→minInt)\n- 3 indent-error-flow (gofmt fixed 2, skipped 1 complex nested one)\n\nRemaining issues are acceptable: 11 unused-params in deeper code, 2 empty-blocks with comments, 1 complex indent case, 1 superfluous-else in test.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-27T23:20:10.391821-07:00","updated_at":"2025-10-30T17:12:58.215077-07:00","closed_at":"2025-10-27T23:02:41.30653-07:00"} -{"id":"bd-5a90","content_hash":"819c14b3bb55fcd113b4e848e4bfcb0c3475756658575dba8d34922ca8e14077","title":"Test parent issue","description":"","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-02T11:50:35.85367-08:00","updated_at":"2025-11-02T15:33:55.654259-08:00","closed_at":"2025-11-02T15:33:55.654259-08:00"} +{"id":"bd-5a90","content_hash":"025d43c12e9cc08c6d1db0b4a97f7a086a1a9f24f07769d48a7e2666d04ea217","title":"Test parent issue","description":"","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-02T11:50:35.85367-08:00","updated_at":"2025-11-02T16:40:27.355372-08:00","closed_at":"2025-11-02T16:40:27.355375-08:00"} {"id":"bd-5aad5a9c","content_hash":"03aa8900fd0e6f4bd911364bb69d4446f239c6a5e9688f0fc4928f3de1259242","title":"Add TestNWayCollision for 5+ clones","description":"## Overview\nAdd comprehensive tests for N-way (5+) collision resolution to verify the solution scales beyond 3 clones.\n\n## Purpose\nWhile TestThreeCloneCollision validates the basic N-way case, we need to verify:\n1. Solution scales to arbitrary N\n2. Performance is acceptable with more clones\n3. Convergence time is bounded\n4. No edge cases in larger collision groups\n\n## Implementation Tasks\n\n### 1. Create TestFiveCloneCollision\nFile: beads_twoclone_test.go (or new beads_nway_test.go)\n\n```go\nfunc TestFiveCloneCollision(t *testing.T) {\n // Test with 5 clones creating same ID with different content\n // Verify all 5 clones converge after sync rounds\n \n t.Run(\"SequentialSync\", func(t *testing.T) {\n testNCloneCollision(t, 5, \"A\", \"B\", \"C\", \"D\", \"E\")\n })\n \n t.Run(\"ReverseSync\", func(t *testing.T) {\n testNCloneCollision(t, 5, \"E\", \"D\", \"C\", \"B\", \"A\")\n })\n \n t.Run(\"RandomSync\", func(t *testing.T) {\n testNCloneCollision(t, 5, \"C\", \"A\", \"E\", \"B\", \"D\")\n })\n}\n```\n\n### 2. Implement generalized testNCloneCollision\nGeneralize the 3-clone test to handle arbitrary N:\n\n```go\nfunc testNCloneCollision(t *testing.T, numClones int, syncOrder ...string) {\n t.Helper()\n \n if len(syncOrder) != numClones {\n t.Fatalf(\"syncOrder length (%d) must match numClones (%d)\", \n len(syncOrder), numClones)\n }\n \n tmpDir := t.TempDir()\n \n // Setup remote and N clones\n remoteDir := setupBareRepo(t, tmpDir)\n cloneDirs := make(map[string]string)\n \n for i := 0; i \u003c numClones; i++ {\n name := string(rune('A' + i))\n cloneDirs[name] = setupClone(t, tmpDir, remoteDir, name)\n }\n \n // Each clone creates issue with same ID but different content\n for name, dir := range cloneDirs {\n createIssue(t, dir, fmt.Sprintf(\"Issue from clone %s\", name))\n }\n \n // Sync in specified order\n for _, name := range syncOrder {\n syncClone(t, cloneDirs[name], name)\n }\n \n // Final pull for convergence\n for name, dir := range cloneDirs {\n finalPull(t, dir, name)\n }\n \n // Verify all clones have all N issues\n expectedTitles := make(map[string]bool)\n for i := 0; i \u003c numClones; i++ {\n name := string(rune('A' + i))\n expectedTitles[fmt.Sprintf(\"Issue from clone %s\", name)] = true\n }\n \n for name, dir := range cloneDirs {\n titles := getTitles(t, dir)\n if !compareTitleSets(titles, expectedTitles) {\n t.Errorf(\"Clone %s missing issues: expected %v, got %v\", \n name, expectedTitles, titles)\n }\n }\n \n t.Log(\"✓ All\", numClones, \"clones converged successfully\")\n}\n```\n\n### 3. Add performance benchmarks\nTest convergence time and memory usage:\n\n```go\nfunc BenchmarkNWayCollision(b *testing.B) {\n for _, n := range []int{3, 5, 10, 20} {\n b.Run(fmt.Sprintf(\"N=%d\", n), func(b *testing.B) {\n for i := 0; i \u003c b.N; i++ {\n // Run N-way collision and measure time\n testNCloneCollisionBench(b, n)\n }\n })\n }\n}\n```\n\n### 4. Add convergence time tests\nVerify bounded convergence:\n\n```go\nfunc TestConvergenceTime(t *testing.T) {\n // Test that convergence happens within expected rounds\n // For N clones, should converge in at most N-1 sync rounds\n \n for n := 3; n \u003c= 10; n++ {\n t.Run(fmt.Sprintf(\"N=%d\", n), func(t *testing.T) {\n rounds := measureConvergenceRounds(t, n)\n maxExpected := n - 1\n if rounds \u003e maxExpected {\n t.Errorf(\"Convergence took %d rounds, expected ≤ %d\", \n rounds, maxExpected)\n }\n })\n }\n}\n```\n\n### 5. Add edge case tests\nTest boundary conditions:\n- All N clones have identical content (dedup works)\n- N-1 clones have same content, 1 differs\n- All N clones have unique content\n- Mix of collisions and non-collisions\n\n## Acceptance Criteria\n- TestFiveCloneCollision passes with all sync orders\n- All 5 clones converge to identical content\n- Performance is acceptable (\u003c 5 seconds for 5 clones)\n- Convergence time is bounded (≤ N-1 rounds)\n- Edge cases handled correctly\n- Benchmarks show scalability to 10+ clones\n\n## Files to Create/Modify\n- beads_twoclone_test.go or beads_nway_test.go\n- Add helper functions for N-clone setup\n\n## Testing Strategy\n\n### Test Matrix\n| N Clones | Sync Orders | Expected Result |\n|----------|-------------|-----------------|\n| 3 | A→B→C | Pass |\n| 3 | C→B→A | Pass |\n| 5 | A→B→C→D→E | Pass |\n| 5 | E→D→C→B→A | Pass |\n| 5 | Random | Pass |\n| 10 | Sequential | Pass |\n\n### Performance Targets\n- 3 clones: \u003c 2 seconds\n- 5 clones: \u003c 5 seconds\n- 10 clones: \u003c 15 seconds\n\n## Dependencies\n- Requires bd-cbed9619.5, bd-cbed9619.4, bd-cbed9619.3, bd-dcd6f14b to be completed\n- TestThreeCloneCollision must pass first\n\n## Success Metrics\n- All tests pass for N ∈ {3, 5, 10}\n- Convergence time scales linearly (O(N))\n- Memory usage reasonable (\u003c 100MB for 10 clones)\n- No data corruption or loss in any scenario","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-29T19:52:05.462747-07:00","updated_at":"2025-10-31T12:00:43.198413-07:00","closed_at":"2025-10-31T12:00:43.198413-07:00"} {"id":"bd-5b40a0bf","content_hash":"fd8a94f744b6504f677cc8e196c5a8d8b5d13b230200add5a8d9b7a54a537eb9","title":"Batch test 5","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-29T15:29:02.136118-07:00","updated_at":"2025-10-31T12:00:43.181513-07:00","closed_at":"2025-10-31T12:00:43.181513-07:00"} {"id":"bd-5b6e","content_hash":"f82a86b4aae21311f23c8511a242f16e96d03836300995fadd43b8bea945cefa","title":"Add tests for helper functions (GetDirtyIssueHash, GetAllDependencyRecords, export hashes)","description":"Several utility functions have 0% coverage:\n- GetDirtyIssueHash (dirty.go)\n- GetAllDependencyRecords (dependencies.go)\n- GetExportHash, SetExportHash, ClearAllExportHashes (hash.go)\n\nThese are lower priority but should have basic coverage.","status":"open","priority":4,"issue_type":"task","created_at":"2025-11-01T22:40:58.989976-07:00","updated_at":"2025-11-01T22:40:58.989976-07:00"} -{"id":"bd-5ce8","content_hash":"784306c9d6e3b26d43a84bcd8c8b95c78ad860b73ba9fd8707688adba2970ffb","title":"Document protected branch workflow","description":"Create comprehensive documentation for protected branch workflow.\n\nTasks:\n- Add \"Protected Branch Workflow\" section to AGENTS.md\n- Create docs/PROTECTED_BRANCHES.md guide\n- Update README.md quick start\n- Add examples to examples/protected-branch/\n- Update bd init --help documentation\n- Add troubleshooting guide\n- Add migration guide for existing users\n- Record demo video (optional)\n\nEstimated effort: 2-3 days","acceptance_criteria":"- Clear quick start (\u003c 2 minutes to set up)\n- Detailed guide covers all scenarios\n- Examples work end-to-end\n- Troubleshooting answers common questions\n- Platform-agnostic (not GitHub-specific)","status":"in_progress","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.59013-08:00","updated_at":"2025-11-02T15:31:05.29603-08:00","dependencies":[{"issue_id":"bd-5ce8","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.379767-08:00","created_by":"stevey"}]} +{"id":"bd-5ce8","content_hash":"8371b74c06781a932c57c6b89a9803804d8e73e5b1abdaa5055d53197684457d","title":"Document protected branch workflow","description":"Create comprehensive documentation for protected branch workflow.\n\nTasks:\n- Add \"Protected Branch Workflow\" section to AGENTS.md\n- Create docs/PROTECTED_BRANCHES.md guide\n- Update README.md quick start\n- Add examples to examples/protected-branch/\n- Update bd init --help documentation\n- Add troubleshooting guide\n- Add migration guide for existing users\n- Record demo video (optional)\n\nEstimated effort: 2-3 days","acceptance_criteria":"- Clear quick start (\u003c 2 minutes to set up)\n- Detailed guide covers all scenarios\n- Examples work end-to-end\n- Troubleshooting answers common questions\n- Platform-agnostic (not GitHub-specific)","status":"open","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.59013-08:00","updated_at":"2025-11-02T16:44:55.863783-08:00","dependencies":[{"issue_id":"bd-5ce8","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.379767-08:00","created_by":"stevey"}]} {"id":"bd-5dae5504","content_hash":"4f2b5a203d6a7b5e38176dd6ef68afb4b7d0e11889718381e28bf006f4e83a16","title":"Export deduplication breaks when JSONL and export_hashes table diverge","description":"## Problem\n\nThe export deduplication feature (timestamp-only skipping) breaks when the JSONL file and export_hashes table get out of sync, causing exports to skip issues that aren't actually in the file.\n\n## Symptoms\n\n- `bd export` reports \"Skipped 128 issue(s) with timestamp-only changes\"\n- JSONL file only has 38 lines but DB has 149 issues\n- export_hashes table has 149 entries\n- Auto-import doesn't trigger (hash matches despite missing data)\n- Two repos on same commit show different issue counts\n\n## Root Cause\n\nshouldSkipExport() in autoflush.go compares current issue hash with stored export_hashes entry. If they match, it skips export assuming the issue is already in the JSONL.\n\nThis assumption fails when:\n1. Git operations (pull, reset, checkout) change JSONL without clearing export_hashes\n2. Manual JSONL edits or corruption\n3. Import operations that modify DB but don't update export_hashes\n4. Partial exports that update export_hashes but don't complete\n\n## Impact\n\n- **Critical data loss risk**: Issues appear to be tracked but aren't persisted to git\n- Breaks multi-repo sync (root cause of today's debugging session)\n- Auto-import fails to detect staleness (hash matches despite missing data)\n- Silent data corruption (no error messages, just missing issues)\n\n## Reproduction\n\n1. Have DB with 149 issues, all in export_hashes table\n2. Truncate JSONL to 38 lines (simulate git reset or corruption)\n3. Run `bd export` - it skips 128 issues\n4. JSONL still has only 38 lines but export thinks it succeeded\n\n## Current Workaround\n\n```bash\nsqlite3 .beads/beads.db \"DELETE FROM export_hashes\"\nbd export -o .beads/beads.jsonl\n```\n\n## Proposed Solutions\n\n**Option 1: Verify JSONL integrity before skipping**\n- Count lines in JSONL, compare with export_hashes count\n- If mismatch, clear export_hashes and force full export\n- Safe but adds I/O overhead\n\n**Option 2: Hash-based JSONL validation**\n- Store hash of entire JSONL file in metadata\n- Before export, check if JSONL hash matches\n- If mismatch, clear export_hashes\n- More efficient, detects any JSONL corruption\n\n**Option 3: Disable timestamp-only deduplication**\n- Remove the feature entirely\n- Always export all issues\n- Simplest and safest, but creates larger git commits\n\n**Option 4: Clear export_hashes on git operations**\n- Add post-merge hook to clear export_hashes\n- Clear on any import operation\n- Defensive approach but may over-clear\n\n## Recommended Fix\n\nCombination of Options 2 + 4:\n1. Store JSONL file hash in metadata after export\n2. Check hash before export, clear export_hashes if mismatch \n3. Clear export_hashes on import operations\n4. Add `bd validate` check for JSONL/export_hashes sync\n\n## Files Involved\n\n- cmd/bd/autoflush.go (shouldSkipExport)\n- cmd/bd/export.go (export with deduplication)\n- internal/storage/sqlite/metadata.go (export_hashes table)","notes":"## Recovery Session (2025-10-29 21:30)\n\n### What Happened\n- Created 14 new hash ID issues (bd-f8b764c9 through bd-f8b764c9.1) \n- bd sync appeared to succeed\n- Canonical repo (~/src/beads): 162 issues in DB + JSONL ✓\n- Secondary repo (fred/beads): Only 145 issues vs 162 in canonical ✗\n- Both repos on same git commit but different issue counts!\n\n### Bug Manifestation During Recovery\n\n1. **Initial state**: fred/beads had 145 issues, 145 lines in JSONL, 145 export_hashes entries\n\n2. **After git reset --hard origin/main**: \n - JSONL: 162 lines (from git)\n - DB: 150 issues (auto-import partially worked)\n - Auto-import failed with UNIQUE constraint error\n\n3. **After manual import --resolve-collisions**:\n - DB: 160 issues\n - JSONL: Still 162 lines\n - export_hashes: 159 entries\n\n4. **After bd export**: \n - **JSONL reduced to 17 lines!** ← The bug in action\n - export_hashes: 159 entries (skipped exporting 142 issues)\n - Silent data loss - no error message\n\n5. **After clearing export_hashes and re-export**:\n - JSONL: 159 lines (missing 3 issues still)\n - DB: 159 issues\n - Still diverged from canonical\n\n### The Bug Loop\nOnce export_hashes and JSONL diverge:\n- Export skips issues already in export_hashes\n- But those issues aren't actually in JSONL\n- This creates corrupt JSONL with missing issues\n- Auto-import can't detect the problem (file hash matches what was exported)\n- Data is lost with no error messages\n\n### Recovery Solution\nCouldn't break the loop with export alone. Had to:\n1. Copy .beads/beads.db from canonical repo\n2. Clear export_hashes\n3. Full re-export\n4. Finally converged to 162 issues\n\n### Key Learnings\n\n1. **The bug is worse than we thought**: It can create corrupt exports (17 lines instead of 162!)\n\n2. **Auto-import can't save you**: Once export is corrupt, auto-import just imports the corrupt data\n\n3. **Silent failure**: No warnings, no errors, just missing issues\n\n4. **Git operations trigger it**: git reset, git pull, etc. change JSONL without clearing export_hashes\n\n5. **Import operations populate export_hashes**: Even manual imports update export_hashes, setting up future export failures\n\n### Immediate Action Required\n\n**DISABLE EXPORT DEDUPLICATION NOW**\n\nThis feature is fundamentally broken and causes data loss. Should be disabled until properly fixed.\n\nQuick fix options:\n- Set environment variable to disable feature\n- Comment out shouldSkipExport check\n- Always clear export_hashes before export\n- Add validation that DB count == JSONL line count before allowing export\n\n### Long-term Fix\n\nNeed Option 2 + 4 from proposed solutions:\n1. Store JSONL file hash after every successful export\n2. Before export, verify JSONL hash matches expected\n3. If mismatch, log WARNING and clear export_hashes\n4. Clear export_hashes on every import operation\n5. Add git post-merge hook to clear export_hashes\n6. Add `bd validate` command to detect divergence\n","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-29T23:05:13.959435-07:00","updated_at":"2025-10-30T17:12:58.207148-07:00","closed_at":"2025-10-29T21:57:03.06641-07:00"} -{"id":"bd-5e1f","content_hash":"3e3467773e73eb9dbb8dd8f213be7157c27d72b53c6cc9776616154db96c3864","title":"Issue with desc","description":"This is a description","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-31T21:41:11.128718-07:00","updated_at":"2025-11-02T15:33:55.653959-08:00","closed_at":"2025-11-02T15:33:55.653959-08:00"} +{"id":"bd-5e1f","content_hash":"5b0aa7a2f651393bc13c46c172828acc4306d22d749ff71fbae96f0d25741847","title":"Issue with desc","description":"This is a description","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-10-31T21:41:11.128718-07:00","updated_at":"2025-11-02T16:40:27.356263-08:00","closed_at":"2025-11-02T16:40:27.356268-08:00"} {"id":"bd-5f26","content_hash":"75bc96be4d465a5eb39bdf0b636c42cdd7b8ac7daf90b47b7b2a015991b87512","title":"Refactor daemon.go into internal/daemonrunner","description":"Extract daemon runtime from daemon.go (1,565 lines) into internal/daemonrunner with focused modules: config.go, daemon.go, process.go, rpc_server.go, sync.go, git.go. Keep cobra command thin.","design":"New structure:\n- internal/daemonrunner/config.go: Config struct\n- internal/daemonrunner/daemon.go: Daemon struct + Start/Stop\n- internal/daemonrunner/process.go: PID/lock/socket handling\n- internal/daemonrunner/rpc_server.go: RPC lifecycle\n- internal/daemonrunner/sync.go: Export/import/commit/push logic\n- internal/daemonrunner/git.go: Git operations interface\n- cmd/bd/daemon.go: Thin cobra command","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-11-01T11:41:14.821017-07:00","updated_at":"2025-11-01T22:34:00.944402-07:00","closed_at":"2025-11-01T22:34:00.944402-07:00"} {"id":"bd-5f483051","content_hash":"d69f64f7f0bdc46a539dfe0b699a8977309c9c8d59f3e9beffbbe4484275a16b","title":"Implement bd resolve-conflicts (git merge conflicts in JSONL)","description":"Automatically detect and resolve git merge conflicts in .beads/issues.jsonl file.\n\nFeatures:\n- Detect conflict markers in JSONL\n- Parse conflicting issues from HEAD and BASE\n- Provide mechanical resolution (remap duplicate IDs)\n- Support AI-assisted resolution (requires internal/ai package)\n\nSee repair_commands.md lines 125-353 for design.","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-28T19:37:55.722827-07:00","updated_at":"2025-10-30T17:12:58.179718-07:00"} +{"id":"bd-6049","content_hash":"f427049a1b4a3e7ef51ec9f0d4ff56e1c5159cb2254f49f232a85e07872a116c","title":"bd doctor --json flag not working","description":"The --json flag on bd doctor command doesn't produce JSON output. It continues to show human-readable output instead. The flag is registered locally on doctorCmd but the code uses the global jsonOutput variable set by PersistentPreRun. Need to investigate why the flag isn't being honored.","status":"open","priority":2,"issue_type":"bug","created_at":"2025-11-02T17:08:18.170428-08:00","updated_at":"2025-11-02T17:08:18.170428-08:00"} {"id":"bd-6214875c","content_hash":"d4d20e71bbf5c08f1fe1ed07f67b7554167aa165d4972ea51b5cacc1b256c4c1","title":"Split internal/rpc/server.go into focused modules","description":"The file `internal/rpc/server.go` is 2,273 lines with 50+ methods, making it difficult to navigate and prone to merge conflicts. Split into 8 focused files with clear responsibilities.\n\nCurrent structure: Single 2,273-line file with:\n- Connection handling\n- Request routing\n- All 40+ RPC method implementations\n- Storage caching\n- Health checks \u0026 metrics\n- Cleanup loops\n\nTarget structure:\n```\ninternal/rpc/\n├── server.go # Core server, connection handling (~300 lines)\n├── methods_issue.go # Issue operations (~400 lines)\n├── methods_deps.go # Dependency operations (~200 lines)\n├── methods_labels.go # Label operations (~150 lines)\n├── methods_ready.go # Ready work queries (~150 lines)\n├── methods_compact.go # Compaction operations (~200 lines)\n├── methods_comments.go # Comment operations (~150 lines)\n├── storage_cache.go # Storage caching logic (~300 lines)\n└── health.go # Health \u0026 metrics (~200 lines)\n```\n\nMigration strategy:\n1. Create new files with appropriate methods\n2. Keep `server.go` as main file with core server logic\n3. Test incrementally after each file split\n4. Final verification with full test suite","acceptance_criteria":"- All 50 methods split into appropriate files\n- Each file \u003c500 LOC\n- All methods remain on `*Server` receiver (no behavior change)\n- All tests pass: `go test ./internal/rpc/...`\n- Verify daemon works: start daemon, run operations, check health\n- Update internal documentation if needed\n- No change to public API","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-28T14:21:37.51524-07:00","updated_at":"2025-10-30T17:12:58.2179-07:00","closed_at":"2025-10-28T14:11:04.399811-07:00"} {"id":"bd-6221bdcd","content_hash":"3bf15bc9e418180e1e91691261817c872330e182dbc1bcb756522faa42416667","title":"Improve cmd/bd test coverage (currently 20.2%)","description":"CLI commands need better test coverage. Focus on:\n- Command argument parsing\n- Error handling paths\n- Edge cases in create, update, close commands\n- Daemon commands\n- Import/export workflows","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-29T14:06:27.951656-07:00","updated_at":"2025-10-30T17:12:58.185819-07:00","dependencies":[{"issue_id":"bd-6221bdcd","depends_on_id":"bd-4d7fca8a","type":"blocks","created_at":"2025-10-29T19:52:05.532391-07:00","created_by":"import-remap"}]} {"id":"bd-627d","content_hash":"52adab9a06ab56b8e825266ea7cc1eec718af4a9a84ca16d2dba2cd33fdc7cb4","title":"AI-supervised database migrations for safer schema evolution","description":"## Problem\n\nDatabase 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.\n\n## Current State\n\nMigrations run blindly with:\n- No pre-flight validation\n- No data integrity verification\n- No rollback on failure\n- Limited post-migration testing\n\nRecent issues:\n- GH #201: Migration didn't set issue_prefix config, breaking commands\n- bd-d355a07d: False positive \"data loss\" warnings on collision resolution\n- Users reported migration data loss (fixed but broader problem remains)\n\n## Proposal: AI-Supervised Migration Framework\n\nUse AI to supervise migrations through structured verification:\n\n### 1. Pre-Migration Analysis\n- AI reads migration code and current schema\n- Identifies potential data loss scenarios\n- Generates validation queries to verify assumptions\n- Creates snapshot queries for before/after comparison\n\n### 2. Migration Execution\n- Take database backup/snapshot\n- Run validation queries (pre-state)\n- Execute migration in transaction\n- Run validation queries (post-state)\n\n### 3. Post-Migration Verification\n- AI compares pre/post snapshots\n- Verifies data integrity invariants\n- Checks for unexpected data loss\n- Validates config completeness (like issue_prefix)\n\n### 4. Rollback on Anomalies\n- If AI detects data loss, rollback transaction\n- Present human-readable error report\n- Suggest fix before retrying\n\n## Example Flow\n\n```\n$ bd migrate\n\n→ Analyzing migration plan...\n→ AI identified 3 potential data loss scenarios\n→ Generating validation queries...\n→ Creating pre-migration snapshot...\n→ Running migration in transaction...\n→ Verifying post-migration state...\n✓ All 247 issues accounted for\n✓ Config table complete (issue_prefix: \"mcp\")\n✓ Dependencies intact (342 relationships verified)\n→ Migration successful!\n```\n\nIf something goes wrong:\n```\n$ bd migrate\n\n→ Analyzing migration plan...\n→ AI identified issue: Missing issue_prefix config after migration\n→ Recommendation: Add prefix detection step\n→ Aborting migration - database unchanged\n```\n\n## Implementation Ideas\n\n### A. Migration Validator Tool\nCreate `bd migrate --validate` that:\n- Simulates migration on copy of database\n- Uses AI to verify data integrity\n- Reports potential issues before real migration\n\n### B. Migration Test Generator\nAI generates test cases for migrations:\n- Edge cases (empty DB, large DB, missing config)\n- Data integrity checks\n- Regression tests\n\n### C. Migration Invariants\nDefine invariants that AI checks:\n- Issue count should not decrease (unless collision resolution)\n- All required config keys present\n- Foreign key relationships intact\n- No orphaned dependencies\n\n### D. Self-Healing Migrations\nAI detects incomplete migrations and suggests fixes:\n- Missing config values (like GH #201)\n- Orphaned data\n- Index inconsistencies\n\n## Benefits\n\n1. **Catch edge cases**: AI explores scenarios humans miss\n2. **Self-documenting**: AI explains what migration does\n3. **Agent-friendly**: Agents can run migrations confidently\n4. **Fewer rollbacks**: Detect issues before committing\n5. **Better testing**: AI generates comprehensive test suites\n\n## Open Questions\n\n1. Which AI model? (Fast: Haiku, Thorough: Sonnet/GPT-4)\n2. How to balance safety vs migration speed?\n3. Should AI validation be required or optional?\n4. How to handle offline scenarios (no API access)?\n5. What invariants should always be checked?\n\n## Related Work\n\n- bd-b245: Migration registry (makes migrations introspectable)\n- GH #201: issue_prefix migration bug (motivating example)\n- bd-d355a07d: False positive data loss warnings","design":"## Architecture: Agent-Supervised Migrations (Inversion of Control)\n\n**Key principle:** Beads provides observability and validation primitives. AI agents supervise using their own reasoning. Beads NEVER makes AI API calls.\n\n## Phase 1: Migration Invariants (Pure Validation)\n\nCreate `internal/storage/sqlite/migration_invariants.go`:\n\n```go\ntype MigrationInvariant struct {\n Name string\n Description string\n Check func(*sql.DB, *Snapshot) error\n}\n\ntype Snapshot struct {\n IssueCount int\n ConfigKeys []string\n DependencyCount int\n LabelCount int\n}\n\nvar invariants = []MigrationInvariant{\n {\n Name: \"required_config_present\",\n Description: \"Required config keys must exist\",\n Check: checkRequiredConfig, // Would have caught GH #201\n },\n {\n Name: \"foreign_keys_valid\",\n Description: \"No orphaned dependencies or labels\",\n Check: checkForeignKeys,\n },\n {\n Name: \"issue_count_stable\",\n Description: \"Issue count should not decrease unexpectedly\",\n Check: checkIssueCount,\n },\n}\n\nfunc checkRequiredConfig(db *sql.DB, snapshot *Snapshot) error {\n required := []string{\"issue_prefix\", \"schema_version\"}\n for _, key := range required {\n var value string\n err := db.QueryRow(\"SELECT value FROM config WHERE key = ?\", key).Scan(\u0026value)\n if err != nil || value == \"\" {\n return fmt.Errorf(\"required config key missing: %s\", key)\n }\n }\n return nil\n}\n```\n\n## Phase 2: Dry-Run \u0026 Inspection Tools\n\nAdd `bd migrate --dry-run --json`:\n\n```json\n{\n \"pending_migrations\": [\n {\"name\": \"dirty_issues_table\", \"description\": \"Adds dirty_issues table\"},\n {\"name\": \"content_hash_column\", \"description\": \"Adds content_hash for collision resolution\"}\n ],\n \"current_state\": {\n \"schema_version\": \"0.9.9\",\n \"issue_count\": 247,\n \"config\": {\"schema_version\": \"0.9.9\"},\n \"missing_config\": [\"issue_prefix\"]\n },\n \"warnings\": [\n \"issue_prefix config not set - may break commands after migration\"\n ],\n \"invariants_to_check\": [\n \"required_config_present\",\n \"foreign_keys_valid\",\n \"issue_count_stable\"\n ]\n}\n```\n\nAdd `bd info --schema --json`:\n\n```json\n{\n \"tables\": [\"issues\", \"dependencies\", \"labels\", \"config\"],\n \"schema_version\": \"0.9.9\",\n \"config\": {},\n \"sample_issue_ids\": [\"mcp-1\", \"mcp-2\"],\n \"detected_prefix\": \"mcp\"\n}\n```\n\n## Phase 3: Pre/Post Snapshots with Rollback\n\nUpdate `RunMigrations()`:\n\n```go\nfunc RunMigrations(db *sql.DB) error {\n // Capture pre-migration snapshot\n snapshot := captureSnapshot(db)\n \n // Run migrations in transaction\n tx, err := db.Begin()\n if err != nil {\n return err\n }\n defer tx.Rollback()\n \n for _, migration := range migrations {\n if err := migration.Func(tx); err != nil {\n return fmt.Errorf(\"migration %s failed: %w\", migration.Name, err)\n }\n }\n \n // Verify invariants before commit\n if err := verifyInvariants(tx, snapshot); err != nil {\n return fmt.Errorf(\"post-migration validation failed (rolled back): %w\", err)\n }\n \n return tx.Commit()\n}\n```\n\n## Phase 4: MCP Tools for Agent Supervision\n\nAdd to beads-mcp:\n\n```python\n@server.tool()\nasync def inspect_migration(workspace_root: str) -\u003e dict:\n \"\"\"Get migration plan and current state for agent analysis.\n \n Agent should:\n 1. Review pending migrations\n 2. Check for warnings (missing config, etc.)\n 3. Verify invariants will pass\n 4. Decide whether to run bd migrate\n \"\"\"\n result = run_bd([\"migrate\", \"--dry-run\", \"--json\"], workspace_root)\n return json.loads(result.stdout)\n\n@server.tool() \nasync def get_schema_info(workspace_root: str) -\u003e dict:\n \"\"\"Get current database schema for migration analysis.\"\"\"\n result = run_bd([\"info\", \"--schema\", \"--json\"], workspace_root)\n return json.loads(result.stdout)\n```\n\n## Agent Workflow Example\n\n```python\n# Agent detects user wants to migrate\nmigration_plan = inspect_migration(\"/path/to/workspace\")\n\n# Agent analyzes (using its own reasoning, no API calls from beads)\nif \"issue_prefix\" in migration_plan[\"missing_config\"]:\n schema = get_schema_info(\"/path/to/workspace\")\n detected_prefix = schema[\"detected_prefix\"]\n \n # Agent fixes issue before migration\n run_bd([\"config\", \"set\", \"issue_prefix\", detected_prefix])\n \n# Now safe to migrate\nrun_bd([\"migrate\"])\n```\n\n## What Beads Provides\n\n✅ Deterministic validation (invariants)\n✅ Structured inspection (--dry-run, --explain)\n✅ Rollback on invariant failure\n✅ JSON output for agent parsing\n\n## What Beads Does NOT Do\n\n❌ No AI API calls\n❌ No external model access\n❌ No agent invocation\n\nAgents supervise migrations using their own reasoning and the inspection tools beads provides.","acceptance_criteria":"Phase 1: Migration invariants implemented and tested, checked after every migration, clear error messages when invariants fail.\n\nPhase 2: Snapshot capture before migrations, comparison after, rollback on verification failure.\n\nPhase 3 (stretch): AI validation optional flag implemented, AI can analyze migration code and generate custom validation queries.\n\nPhase 4 (stretch): Migration test fixtures created, all fixtures pass migrations, CI runs migration tests.","notes":"## Progress\n\n### ✅ Phase 1: Migration Invariants (COMPLETED)\n\n**Implemented:**\n- Created internal/storage/sqlite/migration_invariants.go with 3 invariants\n- Updated RunMigrations() to verify invariants after migrations\n- All tests pass ✓\n\n### ✅ Phase 2: Inspection Tools (COMPLETED \u0026 PUSHED)\n\n**Commit:** 1abe4e7 - \"Add migration inspection tools for AI agents (bd-627d Phase 2)\"\n\n**Implemented:**\n1. ✅ bd migrate --inspect --json - Shows migration plan\n2. ✅ bd info --schema --json - Returns schema details\n3. ✅ Migration warnings system\n4. ✅ Documentation updated in AGENTS.md\n5. ✅ All tests pass\n\n### ✅ Phase 3: MCP Tools (COMPLETED \u0026 PUSHED)\n\n**Commit:** 2493693 - \"Add MCP tools for migration inspection (bd-627d Phase 3)\"\n\n**Implemented:**\n1. ✅ inspect_migration(workspace_root) tool in beads-mcp\n2. ✅ get_schema_info(workspace_root) tool in beads-mcp\n3. ✅ Abstract methods in BdClientBase\n4. ✅ CLI client implementations\n5. ✅ All tests pass\n\n**All phases complete!** Migration inspection fully integrated into MCP server.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-11-02T12:57:10.722048-08:00","updated_at":"2025-11-02T14:14:27.389282-08:00","closed_at":"2025-11-02T14:14:27.389282-08:00"} -{"id":"bd-63e9","content_hash":"8d1221ee5222bd447de4dc51c2e1b12f2f61f474d5be2ef89455855f7f2f3b98","title":"Fix Nix flake build test failures","description":"Nix build is failing during test phase with same test errors as Windows.\n\n**Error:**\n```\nerror: Cannot build '/nix/store/rgyi1j44dm6ylrzlg2h3z97axmfq9hzr-beads-0.9.9.drv'.\nReason: builder failed with exit code 1.\nFAIL github.com/steveyegge/beads/cmd/bd 16.141s\n```\n\nThis may be related to test environment setup or the same issues affecting Windows tests.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-11-02T09:29:37.2851-08:00","updated_at":"2025-11-02T15:32:32.89966-08:00","closed_at":"2025-11-02T15:32:32.89966-08:00","dependencies":[{"issue_id":"bd-63e9","depends_on_id":"bd-1231","type":"blocks","created_at":"2025-11-02T09:29:37.28618-08:00","created_by":"stevey"}]} -{"id":"bd-64c05d00","content_hash":"b39e902f3ad38a806bbd2d9248ae97df1d940f4b363f9f5baf1faf53b8ed520d","title":"Multi-clone collision resolution testing and documentation","description":"Epic to track improvements to multi-clone collision resolution based on ultrathinking analysis of-3d844c58 and bd-71107098.\n\nCurrent state:\n- 2-clone collision resolution is SOUND and working correctly\n- Hash-based deterministic collision resolution works\n- Test fails due to timestamp comparison, not actual logic issues\n\nWork needed:\n1. Fix TestTwoCloneCollision to compare content not timestamps\n2. Add TestThreeCloneCollision for regression protection\n3. Document 3-clone ID non-determinism as known behavior","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-28T17:58:38.316626-07:00","updated_at":"2025-11-02T16:46:45.863822-08:00","closed_at":"2025-11-02T16:46:45.863822-08:00"} +{"id":"bd-63e9","content_hash":"7c709804b6d15ce63897344b0674dfae6a4fe97e3ae2768585e2a3407484bad0","title":"Fix Nix flake build test failures","description":"Nix build is failing during test phase with same test errors as Windows.\n\n**Error:**\n```\nerror: Cannot build '/nix/store/rgyi1j44dm6ylrzlg2h3z97axmfq9hzr-beads-0.9.9.drv'.\nReason: builder failed with exit code 1.\nFAIL github.com/steveyegge/beads/cmd/bd 16.141s\n```\n\nThis may be related to test environment setup or the same issues affecting Windows tests.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-11-02T09:29:37.2851-08:00","updated_at":"2025-11-02T16:40:27.356663-08:00","closed_at":"2025-11-02T16:40:27.356666-08:00","dependencies":[{"issue_id":"bd-63e9","depends_on_id":"bd-1231","type":"blocks","created_at":"2025-11-02T09:29:37.28618-08:00","created_by":"stevey"}]} +{"id":"bd-64c05d00","content_hash":"35bb8860b0fdb7f52cd004f6bda88c3df571454d55b9563f3fe453539a6d7011","title":"Multi-clone collision resolution testing and documentation","description":"Epic to track improvements to multi-clone collision resolution based on ultrathinking analysis of-3d844c58 and bd-71107098.\n\nCurrent state:\n- 2-clone collision resolution is SOUND and working correctly\n- Hash-based deterministic collision resolution works\n- Test fails due to timestamp comparison, not actual logic issues\n\nWork needed:\n1. Fix TestTwoCloneCollision to compare content not timestamps\n2. Add TestThreeCloneCollision for regression protection\n3. Document 3-clone ID non-determinism as known behavior","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-28T17:58:38.316626-07:00","updated_at":"2025-11-02T17:08:52.042711-08:00","closed_at":"2025-11-02T17:08:52.042713-08:00"} {"id":"bd-64c05d00.1","content_hash":"0744c30a5397c6c44b949c038af110eaf6453ec3800bff55cb027eecc47ab5b5","title":"Fix TestTwoCloneCollision to compare content not timestamps","description":"The test at beads_twoclone_test.go:204-207 currently compares full JSON output including timestamps, causing false negative failures.\n\nCurrent behavior:\n- Both clones converge to identical semantic content\n- Clone A: test-2=\"Issue from clone A\", test-1=\"Issue from clone B\"\n- Clone B: test-1=\"Issue from clone B\", test-2=\"Issue from clone A\"\n- Titles match IDs correctly, no data corruption\n- Only timestamps differ (expected and acceptable)\n\nFix needed:\n- Replace exact JSON comparison with content-aware comparison\n- Normalize or ignore timestamp fields when asserting convergence\n- Test should PASS after this fix\n\nThis blocks completion of bd-71107098.","acceptance_criteria":"- Test compares issue content (title, description, status, priority) not timestamps\n- TestTwoCloneCollision passes\n- Both clones shown to have identical semantic content\n- Timestamps explicitly documented as acceptable difference","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-28T17:58:52.057194-07:00","updated_at":"2025-10-30T17:12:58.226744-07:00","closed_at":"2025-10-28T18:01:38.751895-07:00","dependencies":[{"issue_id":"bd-64c05d00.1","depends_on_id":"bd-64c05d00","type":"parent-child","created_at":"2025-10-28T17:58:52.058202-07:00","created_by":"stevey"},{"issue_id":"bd-64c05d00.1","depends_on_id":"bd-71107098","type":"blocks","created_at":"2025-10-28T17:58:52.05873-07:00","created_by":"stevey"}]} {"id":"bd-64c05d00.2","content_hash":"b86d4c406dd6783a00683a31c8729ea08e846e0ddbc54211e1e3d6dedb96def4","title":"Document 3-clone ID non-determinism in collision resolution","description":"Document the known behavior of 3+ way collision resolution where ID assignments may vary based on sync order, even though content always converges correctly.\n\nUpdates needed:\n- Update bd-71107098 notes to mark 2-clone case as solved\n- Document 3-clone ID non-determinism as known limitation\n- Add explanation to ADVANCED.md or collision resolution docs\n- Explain why this happens (pairwise hash comparison is deterministic, but multi-way ID allocation uses sync-order dependent counters)\n- Clarify trade-offs: content convergence ✅ vs ID stability ❌\n\nKey points to document:\n- Hash-based resolution is pairwise deterministic\n- Content always converges correctly (all issues present with correct data)\n- Numeric ID assignments in 3+ way collisions depend on sync order\n- This is acceptable for most use cases (content convergence is primary goal)\n- Full determinism would require complex multi-way comparison","acceptance_criteria":"- bd-71107098 updated with notes about 2-clone solution being complete\n- 3-clone ID non-determinism documented in ADVANCED.md or similar\n- Explanation includes why it happens and trade-offs\n- Links to TestThreeCloneCollision as demonstration\n- Users understand this is expected behavior, not a bug","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-28T17:59:21.93014-07:00","updated_at":"2025-10-30T17:12:58.227375-07:00","dependencies":[{"issue_id":"bd-64c05d00.2","depends_on_id":"bd-64c05d00","type":"parent-child","created_at":"2025-10-28T17:59:21.938709-07:00","created_by":"stevey"}]} {"id":"bd-64c05d00.3","content_hash":"e006b991353a26f949bc3ae4476849ef785f399f6aca866586eb6fa03d243b35","title":"Add TestThreeCloneCollision for regression protection","description":"Add a 3-clone collision test to document behavior and provide regression protection.\n\nPurpose:\n- Verify content convergence regardless of sync order\n- Document the ID non-determinism behavior (IDs may be assigned differently based on sync order)\n- Provide regression protection for multi-way collisions\n\nTest design:\n- 3 clones create same ID with different content\n- Test two different sync orders (A→B→C vs C→A→B)\n- Assert content sets match (ignore specific ID assignments)\n- Add comment explaining ID non-determinism is expected behavior\n\nKnown limitation:\n- Content always converges correctly (all issues present with correct titles)\n- Numeric ID assignments (test-2 vs test-3) depend on sync order\n- This is acceptable if content convergence is the primary goal","acceptance_criteria":"- TestThreeCloneCollision added to beads_twoclone_test.go (or new file)\n- Tests 3 clones with same ID collision\n- Tests two different sync orders\n- Asserts content convergence (all issues present, correct titles)\n- Documents ID non-determinism in test comments\n- Test passes consistently","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-28T17:59:05.941735-07:00","updated_at":"2025-10-30T17:12:58.227089-07:00","closed_at":"2025-10-28T18:09:12.717604-07:00","dependencies":[{"issue_id":"bd-64c05d00.3","depends_on_id":"bd-64c05d00","type":"parent-child","created_at":"2025-10-28T17:59:05.942783-07:00","created_by":"stevey"}]} -{"id":"bd-6545","content_hash":"b272abdc59322459297ccbb9e50be1b0ff14e17a3b19d954a36d509db80cee4e","title":"Update daemon commit logic for separate branch","description":"Modify daemon to use worktree for commits when sync.branch configured.\n\nTasks:\n- Update internal/daemon/server_export_import_auto.go\n- Detect sync.branch configuration\n- Ensure worktree exists before commit\n- Sync JSONL to worktree\n- Commit in worktree context\n- Push to configured branch\n- Fallback to current behavior if sync.branch not set\n- Handle git errors (network, permissions, conflicts)\n\nEstimated effort: 3-4 days","acceptance_criteria":"- When sync.branch configured, commits go to separate branch\n- When sync.branch not configured, commits to current branch (backward compatible)\n- No disruption to primary worktree\n- Git errors handled gracefully with retry\n- Daemon logs show which branch was used","status":"in_progress","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.598861-08:00","updated_at":"2025-11-02T15:31:05.296322-08:00","dependencies":[{"issue_id":"bd-6545","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.375661-08:00","created_by":"stevey"}]} +{"id":"bd-6545","content_hash":"b272abdc59322459297ccbb9e50be1b0ff14e17a3b19d954a36d509db80cee4e","title":"Update daemon commit logic for separate branch","description":"Modify daemon to use worktree for commits when sync.branch configured.\n\nTasks:\n- Update internal/daemon/server_export_import_auto.go\n- Detect sync.branch configuration\n- Ensure worktree exists before commit\n- Sync JSONL to worktree\n- Commit in worktree context\n- Push to configured branch\n- Fallback to current behavior if sync.branch not set\n- Handle git errors (network, permissions, conflicts)\n\nEstimated effort: 3-4 days","acceptance_criteria":"- When sync.branch configured, commits go to separate branch\n- When sync.branch not configured, commits to current branch (backward compatible)\n- No disruption to primary worktree\n- Git errors handled gracefully with retry\n- Daemon logs show which branch was used","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.598861-08:00","updated_at":"2025-11-02T16:44:55.864183-08:00","closed_at":"2025-11-02T16:44:55.864183-08:00","dependencies":[{"issue_id":"bd-6545","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.375661-08:00","created_by":"stevey"}]} {"id":"bd-69bce74a","content_hash":"1eb7b7d60d3be1dcae7ff1e8053b4c9e7dfdfb70f200151c9298be0bb4d5dc72","title":"Platform tests: Linux, macOS, Windows","description":"Test event-driven mode on all platforms. Verify inotify (Linux), FSEvents (macOS), ReadDirectoryChangesW (Windows). Test fallback behavior on each.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T19:42:29.85636-07:00","updated_at":"2025-10-30T17:12:58.193697-07:00","closed_at":"2025-10-29T15:33:22.149551-07:00"} {"id":"bd-69fbe98e","content_hash":"b9211785e5423ab62d313590115309dab023b0c418b8d06f8bf98442c1ff740d","title":"Implement \"bd daemons logs\" subcommand","description":"Add command to view daemon logs for a specific workspace. Requires daemon logging to file (may need separate issue for log infrastructure).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-26T19:41:11.099659-07:00","updated_at":"2025-10-30T17:12:58.186556-07:00"} {"id":"bd-6ada971e","content_hash":"3979df7395526a6796508aa1ed1e89c4fedc46ee5c2b79dd85066c8a78c8487a","title":"Create cmd/bd/daemon_event_loop.go (~200 LOC)","description":"Implement runEventDrivenLoop to replace polling ticker. Coordinate FileWatcher, mutation events, debouncer. Include health check ticker (60s) for daemon validation.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-28T16:20:02.429383-07:00","updated_at":"2025-10-30T17:12:58.220612-07:00","closed_at":"2025-10-28T12:30:44.067036-07:00"} @@ -105,7 +106,7 @@ {"id":"bd-70419816","content_hash":"1ee07b713143f1abcc3c8189ae49a41e34669822a1843fe1ca823c5f69af4494","title":"Export deduplication breaks when JSONL and export_hashes table diverge","description":"## Problem\n\nThe export deduplication feature (timestamp-only skipping) breaks when the JSONL file and export_hashes table get out of sync, causing exports to skip issues that aren't actually in the file.\n\n## Symptoms\n\n- `bd export` reports \"Skipped 128 issue(s) with timestamp-only changes\"\n- JSONL file only has 38 lines but DB has 149 issues\n- export_hashes table has 149 entries\n- Auto-import doesn't trigger (hash matches despite missing data)\n- Two repos on same commit show different issue counts\n\n## Root Cause\n\nshouldSkipExport() in autoflush.go compares current issue hash with stored export_hashes entry. If they match, it skips export assuming the issue is already in the JSONL.\n\nThis assumption fails when:\n1. Git operations (pull, reset, checkout) change JSONL without clearing export_hashes\n2. Manual JSONL edits or corruption\n3. Import operations that modify DB but don't update export_hashes\n4. Partial exports that update export_hashes but don't complete\n\n## Impact\n\n- **Critical data loss risk**: Issues appear to be tracked but aren't persisted to git\n- Breaks multi-repo sync (root cause of today's debugging session)\n- Auto-import fails to detect staleness (hash matches despite missing data)\n- Silent data corruption (no error messages, just missing issues)\n\n## Reproduction\n\n1. Have DB with 149 issues, all in export_hashes table\n2. Truncate JSONL to 38 lines (simulate git reset or corruption)\n3. Run `bd export` - it skips 128 issues\n4. JSONL still has only 38 lines but export thinks it succeeded\n\n## Current Workaround\n\n```bash\nsqlite3 .beads/beads.db \"DELETE FROM export_hashes\"\nbd export -o .beads/beads.jsonl\n```\n\n## Proposed Solutions\n\n**Option 1: Verify JSONL integrity before skipping**\n- Count lines in JSONL, compare with export_hashes count\n- If mismatch, clear export_hashes and force full export\n- Safe but adds I/O overhead\n\n**Option 2: Hash-based JSONL validation**\n- Store hash of entire JSONL file in metadata\n- Before export, check if JSONL hash matches\n- If mismatch, clear export_hashes\n- More efficient, detects any JSONL corruption\n\n**Option 3: Disable timestamp-only deduplication**\n- Remove the feature entirely\n- Always export all issues\n- Simplest and safest, but creates larger git commits\n\n**Option 4: Clear export_hashes on git operations**\n- Add post-merge hook to clear export_hashes\n- Clear on any import operation\n- Defensive approach but may over-clear\n\n## Recommended Fix\n\nCombination of Options 2 + 4:\n1. Store JSONL file hash in metadata after export\n2. Check hash before export, clear export_hashes if mismatch \n3. Clear export_hashes on import operations\n4. Add `bd validate` check for JSONL/export_hashes sync\n\n## Files Involved\n\n- cmd/bd/autoflush.go (shouldSkipExport)\n- cmd/bd/export.go (export with deduplication)\n- internal/storage/sqlite/metadata.go (export_hashes table)","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-29T23:05:13.960352-07:00","updated_at":"2025-10-30T17:12:58.19679-07:00","closed_at":"2025-10-29T22:22:20.406934-07:00"} {"id":"bd-710a4916","content_hash":"3d8be03f83f87067b1aaf295b0b829d20890e47686e0da10ef81d2096f5ca974","title":"CRDT-based architecture for guaranteed convergence (v2.0)","description":"## Vision\nRedesign beads around Conflict-Free Replicated Data Types (CRDTs) to provide mathematical guarantees for N-way collision resolution at arbitrary scale.\n\n## Current Limitations\n- Content-hash based collision resolution fails at 5+ clones\n- Non-deterministic convergence in multi-round scenarios\n- UNIQUE constraint violations during rename operations\n- No formal proof of convergence properties\n\n## CRDT Benefits\n- Provably convergent (Strong Eventual Consistency)\n- Commutative/Associative/Idempotent operations\n- No coordination required between clones\n- Scales to 100+ concurrent workers\n- Well-understood mathematical foundations\n\n## Proposed Architecture\n\n### 1. UUID-Based IDs\nReplace sequential IDs with UUIDs:\n- Current: bd-1c63eb84, bd-9063acda, bd-4d80b7b1\n- CRDT: bd-a1b2c3d4-e5f6-7890-abcd-ef1234567890\n- Human aliases maintained separately: #42 maps to UUID\n\n### 2. Last-Write-Wins (LWW) Elements\nEach field becomes an LWW register:\n- title: (timestamp, clone_id, value)\n- status: (timestamp, clone_id, value)\n- Deterministic conflict resolution via Lamport timestamp + clone_id tiebreaker\n\n### 3. Operation Log\nTrack all operations as CRDT ops:\n- CREATE(uuid, timestamp, clone_id, fields)\n- UPDATE(uuid, field, timestamp, clone_id, value)\n- DELETE(uuid, timestamp, clone_id) - tombstone, not hard delete\n\n### 4. Sync as Merge\nSyncing becomes merging two CRDT states:\n- No merge conflicts possible\n- Deterministic merge function\n- Guaranteed convergence\n\n## Implementation Phases\n\n### Phase 1: Research \u0026 Design (4 weeks)\n- Study existing CRDT implementations (Automerge, Yjs, Loro)\n- Design schema for CRDT-based issue tracking\n- Prototype LWW-based Issue CRDT\n- Benchmark performance vs current system\n\n### Phase 2: Parallel Implementation (6 weeks)\n- Implement CRDT storage layer alongside SQLite\n- Build conversion tools: SQLite ↔ CRDT\n- Maintain backward compatibility with v1.x format\n- Migration path for existing databases\n\n### Phase 3: Testing \u0026 Validation (4 weeks)\n- Formal verification of convergence properties\n- Stress testing with 100+ clone scenario\n- Performance profiling and optimization\n- Documentation and examples\n\n### Phase 4: Migration \u0026 Rollout (4 weeks)\n- Release v2.0-beta with CRDT backend\n- Gradual migration from v1.x\n- Monitoring and bug fixes\n- Final v2.0 release\n\n## Risks \u0026 Mitigations\n\n**Risk 1: Performance overhead**\n- Mitigation: Benchmark early, optimize hot paths\n- CRDTs can be slower than append-only logs\n- May need compaction strategy\n\n**Risk 2: Storage bloat**\n- Mitigation: Implement operation log compaction\n- Tombstone garbage collection for deleted issues\n- Periodic snapshots to reduce log size\n\n**Risk 3: Breaking changes**\n- Mitigation: Maintain v1.x compatibility layer\n- Gradual migration tools\n- Dual-mode operation during transition\n\n**Risk 4: Complexity**\n- Mitigation: Use battle-tested CRDT libraries\n- Comprehensive documentation\n- Clear migration guide\n\n## Success Criteria\n- 100-clone collision test passes without failures\n- Formal proof of convergence properties\n- Performance within 2x of current system\n- Zero manual conflict resolution required\n- Backward compatible with v1.x databases\n\n## Timeline\n18-20 weeks total (4-5 months)\n\n## References\n- Automerge: https://automerge.org\n- Yjs: https://docs.yjs.dev\n- Loro: https://loro.dev\n- CRDT theory: Shapiro et al, A comprehensive study of CRDTs\n- Related issues: bd-e6d71828, bd-7a2b58fc,-1","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-29T10:23:57.978339-07:00","updated_at":"2025-10-30T17:12:58.182513-07:00"} {"id":"bd-71107098","content_hash":"9feb9a8dc8ae2dc65b11edeff37cf5ce48d8f28e1ced45d64ac0176937610296","title":"Make two-clone workflow actually work (no hacks)","description":"TestTwoCloneCollision proves beads CANNOT handle two independent clones filing issues simultaneously. This is the basic collaborative workflow and it must work cleanly.\n\nTest location: beads_twoclone_test.go\n\nThe test creates two git clones, both file issues with same ID (test-1), --resolve-collisions remaps clone B's to test-2, but after sync:\n- Clone A has test-1=\"Issue from clone A\", test-2=\"Issue from clone B\" \n- Clone B has test-1=\"Issue from clone B\", test-2=\"Issue from clone A\"\n\nThe TITLES are swapped! Both clones have 2 issues but with opposite title assignments.\n\nWe've tried many fixes (per-project daemons, auto-sync, lamport hashing, precommit hooks) but nothing has made the test pass.\n\nGoal: Make the test pass WITHOUT hacks. The two clones should converge to identical state after sync.","acceptance_criteria":"1. TestTwoCloneCollision passes without EXPECTED FAILURE\n2. Both clones converge to identical issue database\n3. No manual conflict resolution required\n4. Git status clean in both clones\n5. bd ready output identical in both clones","notes":"**Major progress achieved!** The two-clone workflow now converges correctly.\n\n**What was fixed:**\n--3d844c58: Implemented content-hash based rename detection\n- bd-64c05d00.1: Fixed test to compare content not timestamps\n- Both clones now converge to identical issue databases\n- test-1 and test-2 have correct titles in both clones\n- No more title swapping!\n\n**Current status (VERIFIED):**\n✅ Acceptance criteria 1: TestTwoCloneCollision passes (confirmed Oct 28)\n✅ Acceptance criteria 2: Both clones converge to identical issue database (content matches)\n✅ Acceptance criteria 3: No manual conflict resolution required (automatic)\n✅ Acceptance criteria 4: Git status clean\n✅ Acceptance criteria 5: bd ready output identical (timestamps are expected difference)\n\n**ALL ACCEPTANCE CRITERIA MET!** This issue is complete and can be closed.","status":"closed","priority":0,"issue_type":"epic","created_at":"2025-10-28T16:34:53.278793-07:00","updated_at":"2025-10-31T19:38:09.206303-07:00","closed_at":"2025-10-28T19:20:04.143242-07:00"} -{"id":"bd-7315","content_hash":"67d4830c99e0b3db2fb95e0a3c5142ad4fcda64d42dc746f19153e8c10865cbc","title":"Add validation for duplicate external_ref in batch imports","description":"Currently, if a batch import contains multiple issues with the same external_ref, the behavior is undefined. We should detect and handle this case.\n\nCurrent behavior:\n- No validation for duplicate external_ref within a batch\n- Last-write-wins or non-deterministic behavior\n\nProposed solution:\n- Detect duplicate external_ref values in incoming batch\n- Fail with clear error message OR\n- Merge duplicates intelligently (use newest timestamp)\n- Add test case for this scenario\n\nRelated: bd-1022","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-02T15:31:55.85634-08:00","updated_at":"2025-11-02T16:40:01.022143-08:00","closed_at":"2025-11-02T16:40:01.022143-08:00"} +{"id":"bd-7315","content_hash":"81137222aba60b33d3bcd7637891cf94547b5c876a1608e3e3370a578ba165f3","title":"Add validation for duplicate external_ref in batch imports","description":"Currently, if a batch import contains multiple issues with the same external_ref, the behavior is undefined. We should detect and handle this case.\n\nCurrent behavior:\n- No validation for duplicate external_ref within a batch\n- Last-write-wins or non-deterministic behavior\n\nProposed solution:\n- Detect duplicate external_ref values in incoming batch\n- Fail with clear error message OR\n- Merge duplicates intelligently (use newest timestamp)\n- Add test case for this scenario\n\nRelated: bd-1022","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-02T15:31:55.85634-08:00","updated_at":"2025-11-02T16:40:01.022143-08:00","closed_at":"2025-11-02T16:40:01.022143-08:00"} {"id":"bd-763c","content_hash":"6943cea47a7851c7d1eb316f4669fb8ae2b843a68a89b441fdca5e0be0193494","title":"~/src/beads daemon has 'sql: database is closed' errors - zombie daemon","description":"","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-31T21:08:03.388007-07:00","updated_at":"2025-10-31T21:52:04.214274-07:00","closed_at":"2025-10-31T21:52:04.214274-07:00","dependencies":[{"issue_id":"bd-763c","depends_on_id":"bd-2752a7a2","type":"discovered-from","created_at":"2025-10-31T21:08:03.388716-07:00","created_by":"stevey"}]} {"id":"bd-7a00c94e","content_hash":"b31566a4b2a84db7d24364492e8ac6ebfa1f5fc27fe270fbd58b27e17218c9c4","title":"Rapid 2","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-29T19:11:57.430725-07:00","updated_at":"2025-10-30T17:12:58.189251-07:00"} {"id":"bd-7a2b58fc","content_hash":"e887227ed9b3f477282569800eb4683b68bf1a5404f007e00ec44b2e570325b5","title":"Implement clone-scoped ID allocation to prevent N-way collisions","description":"## Problem\nCurrent ID allocation uses per-clone atomic counters (issue_counters table) that sync based on local database state. In N-way collision scenarios:\n- Clone B sees {test-1} locally, allocates test-2\n- Clone D sees {test-1, test-2, test-3} locally, allocates test-4\n- When same content gets assigned test-2 and test-4, convergence fails\n\nRoot cause: Each clone independently allocates IDs without global coordination, leading to overlapping assignments for the same content.\n\n## Solution\nAdd clone UUID to ID allocation to make every ID globally unique:\n\n**Current format:** `test-1`, `test-2`, `test-3`\n**New format:** `test-1-a7b3`, `test-2-a7b3`, `test-3-c4d9`\n\nWhere suffix is first 4 chars of clone UUID.\n\n## Implementation\n\n### 1. Add clone_identity table\n```sql\nCREATE TABLE clone_identity (\n clone_uuid TEXT PRIMARY KEY,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n);\n```\n\n### 2. Modify getNextIDForPrefix()\n```go\nfunc (s *SQLiteStorage) getNextIDForPrefix(ctx context.Context, prefix string) (string, error) {\n cloneUUID := s.getOrCreateCloneUUID(ctx)\n shortUUID := cloneUUID[:4]\n \n nextNum := s.getNextCounterForPrefix(ctx, prefix)\n return fmt.Sprintf(\"%s-%d-%s\", prefix, nextNum, shortUUID), nil\n}\n```\n\n### 3. Update ID parsing logic\nAll places that parse IDs (utils.ExtractIssueNumber, etc.) need to handle new format.\n\n### 4. Migration strategy\n- Existing IDs remain unchanged (no suffix)\n- New IDs get clone suffix automatically\n- Display layer can hide suffix in UI: `bd-cb64c226.3-a7b3` → `#42`\n\n## Benefits\n- **Zero collision risk**: Same content in different clones gets different IDs\n- **Maintains readability**: Still sequential numbering within clone\n- **No coordination needed**: Works offline, no central authority\n- **Scales to 100+ clones**: 4-char hex = 65,536 unique clones\n\n## Concerns\n- ID format change may break existing integrations\n- Need migration path for existing databases\n- Display logic needs update to hide/show suffixes appropriately\n\n## Success Criteria\n- 10+ clone collision test passes without failures\n- Existing issues continue to work (backward compatibility)\n- Documentation updated with new ID format\n- Migration guide for v1.x → v2.x\n\n## Timeline\nMedium-term (v1.1-v1.2), 2-3 weeks implementation\n\n## References\n- Related to bd-0dcea000 (immediate fix)\n- See beads_nway_test.go for failing N-way tests","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-29T20:02:47.952447-07:00","updated_at":"2025-10-31T17:53:09.075064-07:00"} @@ -115,7 +116,7 @@ {"id":"bd-7c831c51","content_hash":"192d94c432595c1051f254a25bb6325e9b98ceccfb369dc43e0619c27016feae","title":"Run final validation and cleanup checks","description":"Final validation pass to ensure all cleanup objectives met and no regressions introduced.\n\nValidation checklist:\n1. Dead code verification: `go run golang.org/x/tools/cmd/deadcode@latest -test ./...`\n2. Test coverage: `go test -cover ./...`\n3. Build verification: `go build ./cmd/bd/`\n4. Linting: `golangci-lint run`\n5. Integration tests\n6. Metrics verification\n7. Git clean check\n\nFinal metrics to report:\n- LOC removed: ~____\n- Files deleted: ____\n- Files created: ____\n- Test coverage: ____%\n- Build time: ____ (before/after)\n- Test run time: ____ (before/after)\n\nImpact: Confirms all cleanup objectives achieved successfully","acceptance_criteria":"- Zero unreachable functions per deadcode analyzer\n- All tests pass: `go test ./...`\n- Test coverage maintained or improved\n- Builds cleanly: `go build ./...`\n- Linting shows improvements\n- Integration tests all pass\n- LOC reduction target achieved (~2,500 LOC)\n- No unintended behavior changes\n- Git commit messages document all changes","notes":"## Validation Results\n\n**Dead Code:** ✅ Found and removed 1 unreachable function (`DroppedEventsCount`) \n**Tests:** ✅ All pass \n**Coverage:** \n- Main: 39.6%\n- cmd/bd: 20.2%\n- Created follow-up issues (bd-85487065 through bd-bc2c6191) to improve coverage\n \n**Build:** ✅ Clean \n**Linting:** 73 issues (up from 34 baseline) \n- Increase due to unused functions from refactoring\n- Need cleanup in separate issue\n \n**Integration Tests:** ✅ All pass \n**Metrics:** 56,464 LOC across 193 Go files \n**Git:** 2 files modified (deadcode fix + auto-synced JSONL)\n\n## Follow-up Issues Created\n- bd-85487065: Add tests for internal/autoimport (0% coverage)\n- bd-0dcea000: Add tests for internal/importer (0% coverage)\n- bd-4d7fca8a: Add tests for internal/utils (0% coverage)\n- bd-6221bdcd: Improve cmd/bd coverage (20.2% -\u003e target higher)\n- bd-bc2c6191: Improve internal/daemon coverage (22.5% -\u003e target higher)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T20:02:47.956276-07:00","updated_at":"2025-10-30T17:12:58.193468-07:00","closed_at":"2025-10-29T14:19:35.095553-07:00"} {"id":"bd-7da9437e","content_hash":"c00bf7c9fe41b90f1bd3cd1e7cf6938ca4e42f076ce45c2a3d836db97c883fc4","title":"Latency test","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-29T15:28:52.729923-07:00","updated_at":"2025-10-31T12:00:43.184758-07:00","closed_at":"2025-10-31T12:00:43.184758-07:00"} {"id":"bd-7e0d6660","content_hash":"84f212d47832be4670333dc0148e3de158ca3a2dc7cb68b992f8536409272cfb","title":"Handle unchecked errors (errcheck - 683 issues)","description":"683 unchecked error returns, mostly in tests (Close, Rollback, RemoveAll). Many already excluded in config but still showing up.","design":"Review .golangci.yml exclude-rules. Most defer Close/Rollback errors in tests can be ignored. Add systematic exclusions or explicit _ = assignments where appropriate.","notes":"Fixed all errcheck warnings in production code:\n- Enabled errcheck linter (was disabled)\n- Set tests: false in .golangci.yml to focus on production code\n- Fixed 27 total errors in production code using Oracle guidance:\n * Database patterns: defer func() { _ = rows.Close() }() and defer func() { _ = tx.Rollback() }()\n * Best-effort closers: _ = store.Close(), _ = client.Close()\n * Proper error handling for file writes, fmt.Scanln(), os.Remove()\n- All tests pass\n- Only 2 \"unused\" linter warnings remain (not errcheck)","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-27T23:20:10.392336-07:00","updated_at":"2025-10-30T17:12:58.215288-07:00","closed_at":"2025-10-27T23:05:31.945328-07:00"} -{"id":"bd-7e7ddffa","content_hash":"80a5b60d066d509bbd8d0f1340a16ea1d989d9178910155da3ff2c8df245b9c9","title":"Repair Commands \u0026 AI-Assisted Tooling","description":"Add specialized repair tools to reduce agent repair burden:\n1. Git merge conflicts in JSONL\n2. Duplicate issues from parallel work\n3. Semantic inconsistencies\n4. Orphaned references\n\nSee ~/src/fred/beads/repair_commands.md for full design doc.\n\nReduces agent repair time from 5-10 minutes to \u003c30 seconds per repair.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-28T19:30:17.465812-07:00","updated_at":"2025-11-02T16:46:49.279239-08:00","closed_at":"2025-11-02T16:46:49.279242-08:00"} +{"id":"bd-7e7ddffa","content_hash":"80a5b60d066d509bbd8d0f1340a16ea1d989d9178910155da3ff2c8df245b9c9","title":"Repair Commands \u0026 AI-Assisted Tooling","description":"Add specialized repair tools to reduce agent repair burden:\n1. Git merge conflicts in JSONL\n2. Duplicate issues from parallel work\n3. Semantic inconsistencies\n4. Orphaned references\n\nSee ~/src/fred/beads/repair_commands.md for full design doc.\n\nReduces agent repair time from 5-10 minutes to \u003c30 seconds per repair.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-28T19:30:17.465812-07:00","updated_at":"2025-11-02T17:08:52.043115-08:00","closed_at":"2025-11-02T17:08:52.043117-08:00"} {"id":"bd-7e7ddffa.1","content_hash":"df6de1f6a58a995d979a7be59c2fb38800e81b96e8fa0bd39980f8bf9f1a4f37","title":"bd resolve-conflicts - Git merge conflict resolver","description":"Automatically resolve JSONL merge conflicts.\n\nModes:\n- Mechanical: ID remapping (no AI)\n- AI-assisted: Smart merge/keep decisions\n- Interactive: Review each conflict\n\nHandles \u003c\u003c\u003c\u003c\u003c\u003c\u003c conflict markers in .beads/beads.jsonl\n\nFiles: cmd/bd/resolve_conflicts.go (new)","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-28T14:48:30.083642-07:00","updated_at":"2025-10-30T17:12:58.220145-07:00","dependencies":[{"issue_id":"bd-7e7ddffa.1","depends_on_id":"bd-7e7ddffa","type":"parent-child","created_at":"2025-10-29T19:58:28.847736-07:00","created_by":"stevey"}]} {"id":"bd-7eed","content_hash":"f491845894c23d141399b422109c45015fe725b2d5c27bd68484d2306fcf55dd","title":"Remove obsolete stale.go command (executor tables never implemented)","description":"","status":"closed","priority":2,"issue_type":"chore","created_at":"2025-10-31T21:27:05.555369-07:00","updated_at":"2025-10-31T21:27:11.427631-07:00","closed_at":"2025-10-31T21:27:11.427631-07:00"} {"id":"bd-7fe8","content_hash":"a404fb9747111bc7091d24ebdcc0bb98ceda0c8833390f2e519fa17cb068f5ed","title":"Fix linting error in migrate.go","description":"Linter reports error:\n```\ncmd/bd/migrate.go:647:37: cleanupWALFiles - result 0 (error) is always nil (unparam)\n```\n\nThe `cleanupWALFiles` function always returns nil, so the error return type should be removed or the function should actually return errors when appropriate.","status":"closed","priority":2,"issue_type":"chore","created_at":"2025-11-02T09:29:37.279747-08:00","updated_at":"2025-11-02T09:46:52.18793-08:00","closed_at":"2025-11-02T09:46:52.18793-08:00","dependencies":[{"issue_id":"bd-7fe8","depends_on_id":"bd-1231","type":"blocks","created_at":"2025-11-02T09:29:37.280881-08:00","created_by":"stevey"}]} @@ -125,11 +126,11 @@ {"id":"bd-85487065","content_hash":"637cbd56af122b175ff060b4df050871fe86124c5d883ba7f8a17f2f95479613","title":"Add tests for internal/autoimport package","description":"Currently 0.0% coverage. Need tests for auto-import functionality that detects and imports updated JSONL files.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-29T14:06:18.154805-07:00","updated_at":"2025-10-30T17:12:58.182987-07:00"} {"id":"bd-879d","content_hash":"2f291ca2adead5ee3fb7fade39c088165b5467780599f9a719dcaebc87455ae3","title":"Test issue 1","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-02T09:44:12.538697729Z","updated_at":"2025-11-02T09:45:20.76214671Z","closed_at":"2025-11-02T09:45:20.76214671Z","dependencies":[{"issue_id":"bd-879d","depends_on_id":"bd-d3e5","type":"discovered-from","created_at":"2025-11-02T09:44:22.103468321Z","created_by":"mrdavidlaing"}]} {"id":"bd-8900f145","content_hash":"4a07f36a9e5d24aaffb092c89e2273cb58f9de357d24eeb01fcde6a4079ba775","title":"Testing event-driven mode!","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-29T15:28:33.564871-07:00","updated_at":"2025-10-30T17:12:58.186325-07:00","closed_at":"2025-10-29T19:12:54.43368-07:00"} -{"id":"bd-897a","content_hash":"db35500a77224f762dd845a52dbb220bd5e9cedaec62e5c5c2b4ecb9921368ef","title":"Add UNIQUE constraint on external_ref column","description":"The external_ref column should have a UNIQUE constraint to prevent multiple issues from having the same external reference. This ensures data integrity when syncing from external systems (Jira, GitHub, Linear).\n\nCurrent behavior:\n- Multiple issues can have the same external_ref\n- GetIssueByExternalRef returns first match (non-deterministic with duplicates)\n\nProposed solution:\n- Add UNIQUE constraint to external_ref column\n- Add migration to check for and resolve existing duplicates\n- Update tests to verify constraint enforcement\n\nRelated: bd-1022","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-02T15:31:54.718005-08:00","updated_at":"2025-11-02T16:40:01.020314-08:00","closed_at":"2025-11-02T16:40:01.020314-08:00"} +{"id":"bd-897a","content_hash":"ae488407bf5e71242535f4c35b59b0981d2b8b338d1701f19acba2c8e93049f0","title":"Add UNIQUE constraint on external_ref column","description":"The external_ref column should have a UNIQUE constraint to prevent multiple issues from having the same external reference. This ensures data integrity when syncing from external systems (Jira, GitHub, Linear).\n\nCurrent behavior:\n- Multiple issues can have the same external_ref\n- GetIssueByExternalRef returns first match (non-deterministic with duplicates)\n\nProposed solution:\n- Add UNIQUE constraint to external_ref column\n- Add migration to check for and resolve existing duplicates\n- Update tests to verify constraint enforcement\n\nRelated: bd-1022","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-02T15:31:54.718005-08:00","updated_at":"2025-11-02T16:40:01.020314-08:00","closed_at":"2025-11-02T16:40:01.020314-08:00"} {"id":"bd-89e2","content_hash":"ddf4626e586440f379ff19872eac29941cecb925d0a4aae8a6f9c08c969ca05d","title":"Daemon race condition: stale export overwrites recent DB changes","description":"**Symptom:**\nMerged bd-fc2d into bd-fb05 in ~/src/beads (commit ce4d756), pushed to remote. The ~/src/fred/beads daemon then exported its stale DB state and committed (8cc1bb4), reverting bd-fc2d back to \"open\" status.\n\n**Timeline:**\n1. 21:45:12 - Merge committed from ~/src/beads (ce4d756): bd-fc2d closed\n2. 21:49:42 - Daemon in ~/src/fred/beads exported stale state (8cc1bb4): bd-fc2d open again\n\n**Root cause:**\nThe fred/beads daemon had a stale database (bd-fc2d still open) and didn't auto-import the newer JSONL before exporting. When it exported, it overwrote the merge with its stale state.\n\n**Expected behavior:**\nDaemon should detect that JSONL is newer than its last export and import before exporting.\n\n**Actual behavior:**\nDaemon exported stale DB state, creating a conflicting commit that reverted upstream changes.\n\n**Impact:**\nMulti-workspace setups with daemons can silently lose changes if one daemon has stale state and exports.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-11-01T21:53:07.930819-07:00","updated_at":"2025-11-01T22:01:25.54126-07:00","closed_at":"2025-11-01T22:01:25.54126-07:00"} {"id":"bd-89f89fc0","content_hash":"235c3bdeb45e3069167f81e7b4e798fc98547478bb16df40556100478c5e505a","title":"Remove unreachable RPC methods","description":"Several RPC server and client methods are unreachable and should be removed:\n\nServer methods (internal/rpc/server.go):\n- `Server.GetLastImportTime` (line 2116)\n- `Server.SetLastImportTime` (line 2123)\n- `Server.findJSONLPath` (line 2255)\n\nClient methods (internal/rpc/client.go):\n- `Client.Import` (line 311) - RPC import not used (daemon uses autoimport)\n\nEvidence:\n```bash\ngo run golang.org/x/tools/cmd/deadcode@latest -test ./...\n```\n\nImpact: Removes ~80 LOC of unused RPC code","acceptance_criteria":"- Remove the 4 unreachable methods (~80 LOC total)\n- Verify no callers: `grep -r \"GetLastImportTime\\|SetLastImportTime\\|findJSONLPath\" .`\n- All tests pass: `go test ./internal/rpc/...`\n- Daemon functionality works: test daemon start/stop/operations","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-28T16:20:02.432202-07:00","updated_at":"2025-10-30T17:12:58.222655-07:00"} {"id":"bd-8a39","content_hash":"77554ff8b92731806d997c37a7f624b8ea5204e69a6ed3db82449dd8658ba1fd","title":"Fix Windows-specific test failures in CI","description":"Several tests are failing on Windows but passing on Linux:\n\n**Failing tests:**\n- TestFindDatabasePathEnvVar\n- TestHashIDs_MultiCloneConverge\n- TestHashIDs_IdenticalContentDedup\n- TestDatabaseReinitialization (all 5 subtests):\n - fresh_clone_auto_import\n - database_removal_scenario\n - legacy_filename_support\n - precedence_test\n - init_safety_check\n- TestFindBeadsDir_NotFound\n- TestMetricsSnapshot/uptime (in internal/rpc)\n\n**CI Run:** https://github.com/steveyegge/beads/actions/runs/19015638968\n\nThese are likely path separator or filesystem behavior differences between Windows and Linux.","notes":"Fixed all Windows path issues:\n1. TestFindDatabasePathEnvVar - expects canonicalized paths ✅\n2. TestHashIDs tests - use platform-specific bd.exe command ✅ \n3. TestMetricsSnapshot/uptime - enforce minimum 1 second uptime ✅\n4. TestFindBeadsDir_NotFound - allow finding .beads in parent dirs ✅\n5. TestDatabaseReinitialization - fix git path conversion on Windows (git returns /c/Users/... but filepath needs C:\\Users\\...) ✅\n\nCI run in progress to verify all fixes.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-11-02T09:29:37.274103-08:00","updated_at":"2025-11-02T11:17:39.074618-08:00","closed_at":"2025-11-02T11:17:39.074618-08:00","dependencies":[{"issue_id":"bd-8a39","depends_on_id":"bd-1231","type":"blocks","created_at":"2025-11-02T09:29:37.276579-08:00","created_by":"stevey"}]} -{"id":"bd-9063acda","content_hash":"572a9f35c6b6a74f5d1ff1bb6851881ca6991de48c2238e21bea48752a323ea4","title":"Clean up linter errors (914 total issues)","description":"The codebase has 914 linter issues reported by golangci-lint. While many are documented as baseline in LINTING.md, we should clean these up systematically to improve code quality and maintainability.","design":"Break down by linter category, prioritizing high-impact issues:\n1. dupl (7) - Code duplication\n2. goconst (12) - Repeated strings\n3. gocyclo (11) - High complexity functions\n4. revive (78) - Style issues\n5. gosec (102) - Security warnings\n6. errcheck (683) - Unchecked errors (many in tests)","acceptance_criteria":"All linter categories reduced to acceptable levels, with remaining baseline documented in LINTING.md","notes":"Reduced from 56 to 41 issues locally, then to 0 issues.\n\n**Fixed in commits:**\n- c2c7eda: Fixed 15 actual errors (dupl, gosec, revive, staticcheck, unparam)\n- 963181d: Configured exclusions to get to 0 issues locally\n\n**Current status:**\n- ✅ Local: golangci-lint reports 0 issues\n- ❌ CI: Still failing (see [deleted:bd-cb64c226.1])\n\n**Problem:**\nConfig v2 format or golangci-lint-action@v8 compatibility issue causing CI to fail despite local success.\n\n**Next:** Debug [deleted:bd-cb64c226.1] to fix CI/local discrepancy","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-10-24T01:01:12.997982-07:00","updated_at":"2025-11-02T15:35:01.299635-08:00","closed_at":"2025-11-02T15:35:01.299635-08:00"} +{"id":"bd-9063acda","content_hash":"0ea4606188e376705c46a14e5d64da1b706aad47a39054a732c21330db601960","title":"Clean up linter errors (914 total issues)","description":"The codebase has 914 linter issues reported by golangci-lint. While many are documented as baseline in LINTING.md, we should clean these up systematically to improve code quality and maintainability.","design":"Break down by linter category, prioritizing high-impact issues:\n1. dupl (7) - Code duplication\n2. goconst (12) - Repeated strings\n3. gocyclo (11) - High complexity functions\n4. revive (78) - Style issues\n5. gosec (102) - Security warnings\n6. errcheck (683) - Unchecked errors (many in tests)","acceptance_criteria":"All linter categories reduced to acceptable levels, with remaining baseline documented in LINTING.md","notes":"Reduced from 56 to 41 issues locally, then to 0 issues.\n\n**Fixed in commits:**\n- c2c7eda: Fixed 15 actual errors (dupl, gosec, revive, staticcheck, unparam)\n- 963181d: Configured exclusions to get to 0 issues locally\n\n**Current status:**\n- ✅ Local: golangci-lint reports 0 issues\n- ❌ CI: Still failing (see [deleted:bd-cb64c226.1])\n\n**Problem:**\nConfig v2 format or golangci-lint-action@v8 compatibility issue causing CI to fail despite local success.\n\n**Next:** Debug [deleted:bd-cb64c226.1] to fix CI/local discrepancy","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-10-24T01:01:12.997982-07:00","updated_at":"2025-11-02T16:40:27.357516-08:00","closed_at":"2025-11-02T16:40:27.357519-08:00"} {"id":"bd-90a5","content_hash":"0c47eb0e3250e98727c52f6fa700b535a7e4bf4cdbd33df8857a55d6c107ed5c","title":"Extract hash ID generation functions to hash_ids.go","description":"Move generateHashID, getNextChildNumber, GetNextChildID to hash_ids.go","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-01T19:28:54.890883-07:00","updated_at":"2025-11-01T23:39:19.427561-07:00","closed_at":"2025-11-01T23:39:19.427561-07:00"} {"id":"bd-942469b8","content_hash":"be178337752bf9a94ac06f13d6c36752c9104585b9aef43ade971ed50437a39e","title":"Rapid 5","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-29T19:11:57.508166-07:00","updated_at":"2025-10-30T17:12:58.189947-07:00"} {"id":"bd-96142dec","content_hash":"ba00d412efdb156e0449b304096f3e075df4c66606e6283b6501e8a29acb7b28","title":"Add fallback to polling on watcher failure","description":"Detect fsnotify.NewWatcher() errors and log warning. Auto-switch to polling mode with 5s ticker. Add BEADS_WATCHER_FALLBACK env var to control behavior.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-28T16:20:02.428439-07:00","updated_at":"2025-10-30T17:12:58.220378-07:00","closed_at":"2025-10-28T19:23:43.595916-07:00"} @@ -144,21 +145,21 @@ {"id":"bd-9f20","content_hash":"523ec11b4c3e82c8d5b36deeb284ebae19eee2090a7051b599da79366c642238","title":"DetectCycles SQL query has bug preventing cycle detection","description":"The DetectCycles function's SQL query has a bug in the LIKE filter that prevents it from detecting cycles.\n\nCurrent code (line 571):\n```sql\nAND p.path NOT LIKE '%' || d.depends_on_id || '→%'\n```\n\nThis prevents ANY revisit to nodes, including returning to the start node to complete a cycle.\n\nFix:\n```sql\nAND (d.depends_on_id = p.start_id OR p.path NOT LIKE '%' || d.depends_on_id || '→%')\n```\n\nThis allows revisiting the start node (to detect the cycle) while still preventing intermediate node revisits.\n\nImpact: Currently DetectCycles cannot detect any cycles, but this hasn't been noticed because AddDependency prevents cycles from being created. The function would only matter if cycles were manually inserted into the database.","status":"closed","priority":3,"issue_type":"bug","created_at":"2025-11-01T22:50:32.552763-07:00","updated_at":"2025-11-01T22:52:02.247443-07:00","closed_at":"2025-11-01T22:52:02.247443-07:00"} {"id":"bd-9f4a","content_hash":"ff058f9bad890bee6a00df24c846f523980473d47c702097164deea7504886a4","title":"Document external_ref in content hash behavior","description":"The content hash includes external_ref, which has implications that should be documented.\n\nCurrent behavior:\n- external_ref is included in content hash calculation (collision.go:158-160)\n- Changing external_ref changes content hash\n- This means: local issue → add external_ref → different hash\n\nImplications:\n- Local issue + external_ref addition = looks like 'new content'\n- May not match by content hash in some scenarios\n- Generally correct behavior, but subtle\n\nAction items:\n- Document in code comments\n- Add to ARCHITECTURE.md or similar\n- Add test demonstrating this behavior\n- Consider if this is desired long-term\n\nRelated: bd-1022\nFiles: internal/storage/sqlite/collision.go:158-160","status":"open","priority":4,"issue_type":"task","created_at":"2025-11-02T15:32:47.715458-08:00","updated_at":"2025-11-02T15:32:47.715458-08:00"} {"id":"bd-a03d5e36","content_hash":"b4ee73e439a133a77e5df27e3e457674dbc9968fdbee0dc630175726960bb8cf","title":"Improve integration test coverage for stateful features","description":"","design":"## Context\n\nbd-70419816 revealed a critical gap: the export deduplication feature had unit tests but no integration tests simulating real-world git operations. This led to silent data loss in production.\n\n## Root Cause\n- Unit tests only tested functions in isolation\n- No integration tests for git operations (pull, reset, checkout) modifying JSONL\n- No tests validating export_hashes and JSONL stay in sync\n- Missing tests for stateful distributed system interactions (DB + JSONL + git)\n\n## Completed (bd-70419816)\n✓ TestJSONLIntegrityValidation - unit tests for validation logic\n✓ TestImportClearsExportHashes - tests import clears hashes\n✓ TestExportIntegrityAfterJSONLTruncation - simulates git reset (would have caught bd-70419816)\n✓ TestExportIntegrityAfterJSONLDeletion - tests recovery from file deletion\n✓ TestMultipleExportsStayConsistent - tests repeated exports\n\n## Still Needed (High Priority)\n1. Multi-repo sync test - two clones staying in sync after push/pull\n2. Auto-flush integration test - JSONL integrity preserved during auto-flush\n3. Daemon auto-sync integration test - complex state management\n4. Import after corruption test - recovery from partial data loss\n\n## Medium Priority\n- Partial export failure handling (disk full, network interruption)\n- Concurrent export/import race conditions\n- Large dataset performance tests (1000+ issues)\n- Export hash migration tests (version upgrades)\n\n## Testing Principles\n1. Test real-world scenarios: git ops, user errors, system failures, concurrent ops\n2. Integration tests for stateful systems (DB + files + git)\n3. Regression test for every bug fix\n4. Test invariants: JSONL count == DB count, hash consistency, etc.\n\n## Key Lesson\nStateful distributed systems need integration tests, not just unit tests.","acceptance_criteria":"- [ ] Multi-repo sync test implemented\n- [ ] Auto-flush integration test implemented \n- [ ] Daemon auto-sync integration test implemented\n- [ ] Testing guidelines added to CONTRIBUTING.md\n- [ ] CI runs integration tests\n- [ ] All critical workflows have integration test coverage","status":"open","priority":2,"issue_type":"epic","created_at":"2025-10-29T21:53:15.397137-07:00","updated_at":"2025-10-30T17:12:58.206063-07:00"} -{"id":"bd-a101","content_hash":"805d60a6f4d9205a7e0498f63e9c0bd98a36eb86800304a123cd9122f694b5ab","title":"Support separate branch for beads commits","description":"Allow beads to commit to a separate branch (e.g., beads-metadata) using git worktrees to support protected main branch workflows.\n\nSolves GitHub Issue #205 - Users need to protect main branch while maintaining beads workflow.\n\nKey advantages:\n- Works on any git platform\n- Main branch stays protected \n- No disruption to user's working directory\n- Backward compatible (opt-in via config)\n- Minimal disk overhead (sparse checkout)\n\nTotal estimate: 17-24 days (4-6 weeks with parallel work)","status":"in_progress","priority":1,"issue_type":"epic","created_at":"2025-11-02T15:21:20.098247-08:00","updated_at":"2025-11-02T15:31:05.29449-08:00","external_ref":"GH-205"} +{"id":"bd-a101","content_hash":"805d60a6f4d9205a7e0498f63e9c0bd98a36eb86800304a123cd9122f694b5ab","title":"Support separate branch for beads commits","description":"Allow beads to commit to a separate branch (e.g., beads-metadata) using git worktrees to support protected main branch workflows.\n\nSolves GitHub Issue #205 - Users need to protect main branch while maintaining beads workflow.\n\nKey advantages:\n- Works on any git platform\n- Main branch stays protected \n- No disruption to user's working directory\n- Backward compatible (opt-in via config)\n- Minimal disk overhead (sparse checkout)\n\nTotal estimate: 17-24 days (4-6 weeks with parallel work)","status":"in_progress","priority":1,"issue_type":"epic","created_at":"2025-11-02T15:21:20.098247-08:00","updated_at":"2025-11-02T15:25:01.743521-08:00","external_ref":"GH-205"} {"id":"bd-a1691807","content_hash":"23f0119ee9df98f1bf6d648dba06065c156963064ef1c7308dfb02c8bdd5bc58","title":"Integration test: mutation to export latency","description":"Measure time from bd create to JSONL update. Verify \u003c500ms latency. Test with multiple rapid mutations to verify batching.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T20:49:49.105247-07:00","updated_at":"2025-10-31T12:00:43.198883-07:00","closed_at":"2025-10-31T12:00:43.198883-07:00"} {"id":"bd-a40f374f","content_hash":"599448515198700decd2494cf0cea3335b013c573bdcbda90a151564585cf845","title":"bd validate - Comprehensive health check","description":"Run all validation checks in one command.\n\nChecks:\n- Duplicates\n- Orphaned dependencies\n- Test pollution\n- Git conflicts\n\nSupports --fix-all for auto-repair.\n\nDepends on bd-cbed9619.1, bd-0dcea000, bd-31aab707, bd-9826b69a.\n\nFiles: cmd/bd/validate.go (new)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T20:02:47.956664-07:00","updated_at":"2025-10-30T17:12:58.195108-07:00","closed_at":"2025-10-29T20:02:15.318966-07:00"} -{"id":"bd-a4b5","content_hash":"3966f6f9ab3202fe740f2936c7743f679ea42b75803c99465176ccf69ffd9dd7","title":"Implement git worktree management","description":"Create git worktree lifecycle management for separate beads branch.\n\nTasks:\n- Create internal/git/worktree.go\n- Implement CreateBeadsWorktree(branch, path)\n- Implement RemoveBeadsWorktree(path)\n- Implement CheckWorktreeHealth(path)\n- Configure sparse checkout (only .beads/)\n- Implement SyncJSONLToWorktree()\n- Handle worktree errors gracefully\n- Auto-cleanup on config change\n\nEstimated effort: 3-4 days","acceptance_criteria":"- Worktree created successfully on first use\n- Sparse checkout limits to .beads/ only\n- Health check detects and fixes broken worktrees\n- JSONL synced correctly before commits\n- Cleanup removes worktree completely","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.56423-08:00","updated_at":"2025-11-02T16:45:20.544226-08:00","closed_at":"2025-11-02T16:45:20.544231-08:00","dependencies":[{"issue_id":"bd-a4b5","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.359843-08:00","created_by":"stevey"}]} +{"id":"bd-a4b5","content_hash":"c536fc98a4e0dba1be7c690f74d3b2a01e99b1048e90e21d9f67ea1311a23913","title":"Implement git worktree management","description":"Create git worktree lifecycle management for separate beads branch.\n\nTasks:\n- Create internal/git/worktree.go\n- Implement CreateBeadsWorktree(branch, path)\n- Implement RemoveBeadsWorktree(path)\n- Implement CheckWorktreeHealth(path)\n- Configure sparse checkout (only .beads/)\n- Implement SyncJSONLToWorktree()\n- Handle worktree errors gracefully\n- Auto-cleanup on config change\n\nEstimated effort: 3-4 days","acceptance_criteria":"- Worktree created successfully on first use\n- Sparse checkout limits to .beads/ only\n- Health check detects and fixes broken worktrees\n- JSONL synced correctly before commits\n- Cleanup removes worktree completely","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.56423-08:00","updated_at":"2025-11-02T15:49:21.327975-08:00","closed_at":"2025-11-02T15:49:21.327975-08:00","dependencies":[{"issue_id":"bd-a4b5","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.359843-08:00","created_by":"stevey"}]} {"id":"bd-a5251b1a","content_hash":"1a158c823c7152ddd5dbd11e11df32a85b699a4f05bfd2effbf4c4a3655cca6b","title":"Test RPC mutation event","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-29T19:08:03.315443-07:00","updated_at":"2025-10-31T12:00:43.177494-07:00","closed_at":"2025-10-31T12:00:43.177494-07:00"} {"id":"bd-a5a8bec0","content_hash":"fb509cc456ea9de6000129ad7780e417d2f06361e577738709a9ccf1c3b1f3b1","title":"bd find-duplicates - AI-powered duplicate detection","description":"Find semantically duplicate issues.\n\nApproaches:\n1. Mechanical: Exact title/description matching\n2. Embeddings: Cosine similarity (cheap, scalable)\n3. AI: LLM-based semantic comparison (expensive, accurate)\n\nUses embeddings by default for \u003e100 issues.\n\nFiles: cmd/bd/find_duplicates.go (new)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T19:42:29.853269-07:00","updated_at":"2025-10-30T17:12:58.193143-07:00","closed_at":"2025-10-29T16:43:30.367455-07:00"} {"id":"bd-a9699011","content_hash":"87d969cf57e247ebfac4f052a9ecbd1254bc55070b87b5ffb78a2b6ee2afddb6","title":"GH#146: No color showing in terminal for some users","description":"User reports color not working in macOS (Taho 26.0.1) with iTerm 3.6.4 and Terminal.app, despite color working elsewhere in terminal. Python rich and printf escape codes work.\n\nNeed to investigate:\n- Is NO_COLOR env var set?\n- Terminal type detection?\n- fatih/color library configuration\n- Does bd list show colors? bd ready? bd init?\n- What's the output of: echo $TERM, echo $NO_COLOR","status":"open","priority":2,"issue_type":"bug","created_at":"2025-10-24T22:26:36.22163-07:00","updated_at":"2025-10-30T17:12:58.2142-07:00","external_ref":"github:146"} {"id":"bd-aec5439f","content_hash":"9ad0242285e9ef9b326468b9be34f533f27cbbaa0c698607cca0cd6228016d2c","title":"Update LINTING.md with current baseline","description":"After cleanup, document the remaining acceptable baseline in LINTING.md so we can track regression.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-27T18:53:10.38679-07:00","updated_at":"2025-10-30T17:12:58.194901-07:00"} {"id":"bd-b245","content_hash":"e160e195ded0b66cadae424da7558d201a1eb506a7742875dbee42984037c8a6","title":"Add migration registry and simplify New()","description":"Create migrations.go with Migration type and registry. Change New() to: openDB -\u003e initSchema -\u003e RunMigrations(db). This removes 8+ separate migrate functions from New().","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-01T11:41:14.862623-07:00","updated_at":"2025-11-02T12:40:45.528212-08:00","closed_at":"2025-11-02T12:40:45.528212-08:00"} -{"id":"bd-b47c034e","content_hash":"133dfd651d402bb95928091138c77a57b2f3f349587962c744209a534fb800a6","title":"Address gosec security warnings (102 issues)","description":"Security linter warnings: file permissions (0755 should be 0750), G304 file inclusion via variable, G204 subprocess launches. Many are false positives but should be reviewed.","design":"Review each gosec warning. Add exclusions for legitimate cases to .golangci.yml. Fix real security issues (overly permissive file modes).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-25T13:47:10.719134-07:00","updated_at":"2025-11-02T15:39:07.287253-08:00","closed_at":"2025-11-02T15:39:07.287253-08:00"} +{"id":"bd-b47c034e","content_hash":"1e8e5ae6388d6546f55421886bd88e7acd2fdade1052d2d7d1b193276777c05d","title":"Address gosec security warnings (102 issues)","description":"Security linter warnings: file permissions (0755 should be 0750), G304 file inclusion via variable, G204 subprocess launches. Many are false positives but should be reviewed.","design":"Review each gosec warning. Add exclusions for legitimate cases to .golangci.yml. Fix real security issues (overly permissive file modes).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-25T13:47:10.719134-07:00","updated_at":"2025-11-02T16:40:27.357887-08:00","closed_at":"2025-11-02T16:40:27.35789-08:00"} {"id":"bd-b501fcc1","content_hash":"323c3b4f2e53d707ce73e75a357bbb4e320327bea00d0b010c3dd09d1e6555cf","title":"Unit tests for Debouncer","description":"Test debouncer batches multiple triggers into single action. Test timer reset on subsequent triggers. Test cancel during wait. Test thread safety.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T19:42:29.86146-07:00","updated_at":"2025-10-31T17:54:06.880513-07:00","closed_at":"2025-10-31T17:54:06.880513-07:00"} {"id":"bd-b55e2ac2","content_hash":"44122b61b1dcd06407ecf36f57577ea72c5df6dc8cc2a8c1b173b37d16a10267","title":"Fix autoimport tests for content-hash collision scoring","description":"## Overview\nThree autoimport tests are failing after bd-cbed9619.4 because they expect behavior based on the old reference-counting collision resolution, but the system now uses deterministic content-hash scoring.\n\n## Failing Tests\n1. `TestAutoImportMultipleCollisionsRemapped` - expects local versions preserved\n2. `TestAutoImportAllCollisionsRemapped` - expects local versions preserved \n3. `TestAutoImportCollisionRemapMultipleFields` - expects specific collision resolution behavior\n\n## Root Cause\nThese tests were written when ScoreCollisions used reference counting to determine which version to keep. Now it uses content-hash comparison (introduced in commit 2e87329), which produces different but deterministic results.\n\n## Example\nOld behavior: Issue with more references would be kept\nNew behavior: Issue with lexicographically lower content hash is kept\n\n## Solution\nUpdate each test to:\n1. Verify the new content-hash based behavior is correct\n2. Check that the remapped issue (not necessarily local/remote) has the expected content\n3. Ensure dependencies are preserved on the correct remapped issue\n\n## Acceptance Criteria\n- All three autoimport tests pass\n- Tests verify content-hash determinism (same collision always resolves the same way)\n- Tests check dependency preservation on remapped issues\n- Test documentation explains content-hash scoring expectations\n\n## Files to Modify\n- `cmd/bd/autoimport_collision_test.go`\n\n## Testing\nRun: `go test ./cmd/bd -run \"TestAutoImport.*Collision\" -v`","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-28T19:17:28.358028-07:00","updated_at":"2025-10-30T17:12:58.179059-07:00"} {"id":"bd-b5a3","content_hash":"d58f635721d24b7761782f83df452a67f794080d2c41cb4f6fad2f27ef2cf0b6","title":"Extract Daemon struct and config into internal/daemonrunner","description":"Create internal/daemonrunner with Config struct and Daemon struct. Move daemon runtime logic from cmd/bd/daemon.go Run function into Daemon.Start/Stop methods.","notes":"Refactoring complete! Created internal/daemonrunner package with:\n- Config struct (config.go)\n- Daemon struct with Start/Stop methods (daemon.go)\n- RPC server lifecycle (rpc.go)\n- Sync loop implementation (sync.go)\n- Git operations (git.go)\n- Process management (process.go, flock_*.go)\n- Logger setup (logger.go)\n- Platform-specific signal handling (signals_*.go)\n- Database fingerprint validation (fingerprint.go)\n\nBuild succeeds and most daemon tests pass. Import functionality still delegated to cmd/bd (marked with TODO(bd-b5a3)).","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-01T11:41:14.843103-07:00","updated_at":"2025-11-01T20:23:46.475885-07:00","closed_at":"2025-11-01T20:23:46.475888-07:00"} -{"id":"bd-b6b2","content_hash":"c7a641bdb4c98b14816e2d85ec09db6def89aa4918ad59f4c1f8f71c6a42c6d4","title":"Feature with design","description":"This is a description","design":"Use MVC pattern","acceptance_criteria":"All tests pass","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-31T21:40:34.612465-07:00","updated_at":"2025-11-02T15:33:55.653353-08:00","closed_at":"2025-11-02T15:33:55.653353-08:00"} -{"id":"bd-b7d2","content_hash":"cd78e03d80898095a2f7f56c7f000b50e9e3be7b2416797d11f4640e5a0e583a","title":"Add sync.branch configuration","description":"Add configuration layer to support sync.branch setting via config file, environment variable, or CLI flag.\n\nTasks:\n- Add sync.branch field to config schema\n- Add BEADS_SYNC_BRANCH environment variable\n- Add --branch flag to bd init\n- Add bd config get/set sync.branch commands\n- Validation (branch name format, conflicts)\n- Config migration for existing users\n\nEstimated effort: 1-2 days","acceptance_criteria":"- Can set sync.branch via config file, env var, or CLI\n- bd config get sync.branch returns configured value\n- Invalid branch names rejected with clear error\n- Backward compatible (empty = current branch)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.560141-08:00","updated_at":"2025-11-02T16:45:20.545227-08:00","closed_at":"2025-11-02T16:45:20.54523-08:00","dependencies":[{"issue_id":"bd-b7d2","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.356847-08:00","created_by":"stevey"}]} +{"id":"bd-b6b2","content_hash":"6d2b2f1bbec6b9aa956e5e84c6b78da699a72a487d2317c6533215d574d2209f","title":"Feature with design","description":"This is a description","design":"Use MVC pattern","acceptance_criteria":"All tests pass","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-31T21:40:34.612465-07:00","updated_at":"2025-11-02T16:40:27.358258-08:00","closed_at":"2025-11-02T16:40:27.358261-08:00"} +{"id":"bd-b7d2","content_hash":"103664edc1fbb842bd3891ba6e5b3498f77b085e2614c9356aa33b23d3aeb6ea","title":"Add sync.branch configuration","description":"Add configuration layer to support sync.branch setting via config file, environment variable, or CLI flag.\n\nTasks:\n- Add sync.branch field to config schema\n- Add BEADS_SYNC_BRANCH environment variable\n- Add --branch flag to bd init\n- Add bd config get/set sync.branch commands\n- Validation (branch name format, conflicts)\n- Config migration for existing users\n\nEstimated effort: 1-2 days","acceptance_criteria":"- Can set sync.branch via config file, env var, or CLI\n- bd config get sync.branch returns configured value\n- Invalid branch names rejected with clear error\n- Backward compatible (empty = current branch)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.560141-08:00","updated_at":"2025-11-02T15:38:51.28581-08:00","closed_at":"2025-11-02T15:38:51.28581-08:00","dependencies":[{"issue_id":"bd-b7d2","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.356847-08:00","created_by":"stevey"}]} {"id":"bd-bc2c6191","content_hash":"533e56b8628e24229a4beb52f8683355f6ca699e34a73650bf092003d73c2957","title":"Audit Current Cache Usage","description":"Understand exactly what code depends on the storage cache","acceptance_criteria":"- Document showing all cache dependencies\n- Confirmation that removing cache won't break MCP\n- List of tests that need updating\n\nFiles to examine:\n- internal/rpc/server_cache_storage.go (cache implementation)\n- internal/rpc/client.go (how req.Cwd is set)\n- internal/rpc/server_*.go (all getStorageForRequest calls)\n- integrations/beads-mcp/ (MCP multi-repo logic)\n\nTasks:\n- Document all callers of getStorageForRequest()\n- Verify req.Cwd is only set by RPC client for database discovery\n- Confirm MCP server doesn't rely on multi-repo cache behavior\n- Check if any tests assume multi-repo routing\n- Review environment variables: BEADS_DAEMON_MAX_CACHE_SIZE, BEADS_DAEMON_CACHE_TTL, BEADS_DAEMON_MEMORY_THRESHOLD_MB","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T23:02:43.506373-07:00","updated_at":"2025-10-31T20:36:49.334214-07:00"} {"id":"bd-bdaf24d5","content_hash":"6ccdbf2362d22fbbe854fdc666695a7488353799e1a5c49e6095b34178c9bcb4","title":"Final validation test","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-27T18:27:28.310533-07:00","updated_at":"2025-10-31T12:00:43.184995-07:00","closed_at":"2025-10-31T12:00:43.184995-07:00"} {"id":"bd-c01f","content_hash":"b183cc4d99f74e9314f67d927f1bd1255608632b47ce0352af97af5872275fec","title":"Implement bd stale command to find abandoned/forgotten issues","description":"Add bd stale command to surface issues that haven't been updated recently and may need attention.\n\nUse cases:\n- In-progress issues with no recent activity (may be abandoned)\n- Open issues that have been forgotten\n- Issues that might be outdated or no longer relevant\n\nQuery logic should find non-closed issues where updated_at exceeds a time threshold.\n\nShould support:\n- --days N flag (default 30-90 days)\n- --status filter (e.g., only in_progress)\n- --json output for automation\n\nReferences GitHub issue #184 where user expected this command to exist.","design":"Implementation approach:\n1. Add new command in cmd/bd/stale.go\n2. Query issues with: status != 'closed' AND updated_at \u003c (now - N days)\n3. Support filtering by status (open, in_progress, blocked)\n4. Default threshold: 30 days (configurable via --days)\n5. JSON output for agent consumption\n6. Order by updated_at ASC (oldest first)","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-10-31T22:48:46.85435-07:00","updated_at":"2025-10-31T22:54:33.704492-07:00","closed_at":"2025-10-31T22:54:33.704492-07:00"} @@ -166,7 +167,7 @@ {"id":"bd-c825f867","content_hash":"27cecaa2dc6cdabb2ae77fd65fbf8dca8f4c536bdf140a13b25cdd16376c9845","title":"Add docs/architecture/event_driven.md","description":"Copy event_driven_daemon.md into docs/ folder. Add to documentation index.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-28T16:20:02.431399-07:00","updated_at":"2025-10-30T17:12:58.221939-07:00"} {"id":"bd-c947dd1b","content_hash":"79bd51b46b28bc16cfc19cd19a4dd4f57f45cd1e902b682788d355b03ec00b2a","title":"Remove Daemon Storage Cache","description":"The daemon's multi-repo storage cache is the root cause of stale data bugs. Since global daemon is deprecated, we only ever serve one repository, making the cache unnecessary complexity. This epic removes the cache entirely for simpler, more reliable direct storage access.","design":"For local daemon (single repository), eliminate the cache entirely:\n- Use s.storage field directly (opened at daemon startup)\n- Remove getStorageForRequest() routing logic\n- Remove server_cache_storage.go entirely (~300 lines)\n- Remove cache-related tests\n- Simplify Server struct\n\nBenefits:\n✅ No staleness bugs: Always using live SQLite connection\n✅ Simpler code: Remove ~300 lines of cache management\n✅ Easier debugging: Direct storage access, no cache indirection\n✅ Same performance: Cache was always 1 entry for local daemon anyway","acceptance_criteria":"- Daemon has no storage cache code\n- All tests pass\n- MCP integration works\n- No stale data bugs\n- Documentation updated\n- Performance validated","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-28T10:50:15.126939-07:00","updated_at":"2025-10-30T17:12:58.21743-07:00","closed_at":"2025-10-28T10:49:53.612049-07:00"} {"id":"bd-c9a482db","content_hash":"35c1ad124187c21b4e8dae7db46ea5d00173d33234a9b815ded7dcf0ab51078e","title":"Add internal/ai package for AI-assisted repairs","description":"Add AI integration package to support AI-powered repair commands.\n\nProviders:\n- Anthropic (Claude)\n- OpenAI\n- Ollama (local)\n\nFeatures:\n- Conflict resolution analysis\n- Duplicate detection via embeddings\n- Configuration via env vars (BEADS_AI_PROVIDER, BEADS_AI_API_KEY, etc.)\n\nSee repair_commands.md lines 357-425 for design.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-28T19:37:55.722841-07:00","updated_at":"2025-10-30T17:12:58.180177-07:00"} -{"id":"bd-caa9","content_hash":"f78e3f048259f85012a0b06ca7a5c50fcf3582a3b94083c1e1e0c19407403e4e","title":"Migration tool for existing users","description":"Ensure smooth migration for existing users to separate branch workflow.\n\nTasks:\n- Add bd migrate --separate-branch command\n- Detect existing repos, migrate cleanly\n- Preserve git history\n- Add rollback mechanism\n- Test migration on beads' own repo (dogfooding)\n- Communication plan (GitHub discussion, docs)\n- Version compatibility checks\n\nEstimated effort: 2-3 days","acceptance_criteria":"- Existing users can migrate without data loss\n- Rollback works if migration fails\n- Clear communication about breaking changes (if any)\n- beads project itself migrated successfully (dogfooding)\n- Migration tested on 5+ real-world repos","status":"in_progress","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.627388-08:00","updated_at":"2025-11-02T15:31:05.296611-08:00","dependencies":[{"issue_id":"bd-caa9","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.382619-08:00","created_by":"stevey"}]} +{"id":"bd-caa9","content_hash":"aa97994c8474a1380ff7f9c9db681c6d6dda62839b1ddc13312a6813029b6404","title":"Migration tool for existing users","description":"Ensure smooth migration for existing users to separate branch workflow.\n\nTasks:\n- Add bd migrate --separate-branch command\n- Detect existing repos, migrate cleanly\n- Preserve git history\n- Add rollback mechanism\n- Test migration on beads' own repo (dogfooding)\n- Communication plan (GitHub discussion, docs)\n- Version compatibility checks\n\nEstimated effort: 2-3 days","acceptance_criteria":"- Existing users can migrate without data loss\n- Rollback works if migration fails\n- Clear communication about breaking changes (if any)\n- beads project itself migrated successfully (dogfooding)\n- Migration tested on 5+ real-world repos","status":"open","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.627388-08:00","updated_at":"2025-11-02T16:44:55.864188-08:00","dependencies":[{"issue_id":"bd-caa9","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.382619-08:00","created_by":"stevey"}]} {"id":"bd-cb64c226.1","content_hash":"0bfd0735c8985d3b3e4906e44f22b06fb24758c6d795188226e920bd8b3e7cf8","title":"Performance Validation","description":"Confirm no performance regression from cache removal","acceptance_criteria":"- Benchmarks show no significant regression\n- Document performance characteristics\n- Confirm single SQLite connection is reused\n\nBenchmarks: go test -bench=. -benchmem ./internal/rpc/...\n\nMetrics to track:\n- Request latency (p50, p99)\n- Throughput (requests/sec)\n- Memory usage\n- SQLite connection overhead\n\nExpected results:\n- Latency: Same or better (no cache overhead)\n- Throughput: Same (cache was always 1 entry)\n- Memory: Lower (no cache structs)\n- Connection overhead: Zero (single connection reused)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-28T10:50:15.126019-07:00","updated_at":"2025-10-30T17:12:58.216721-07:00","closed_at":"2025-10-28T10:49:45.021037-07:00"} {"id":"bd-cb64c226.10","content_hash":"2dbe416cf266952236a03ed414e5f7f9eb5526d69b70d0821ca0d59b2bc22305","title":"Delete server_cache_storage.go","description":"Remove the entire cache implementation file (~286 lines)","acceptance_criteria":"- File deleted from repository\n- No compilation errors\n- No references to deleted functions\n\nFunctions being removed:\n- StorageCacheEntry struct\n- evictStaleStorage() - LRU eviction\n- evictCacheBasedOnMemory() - memory pressure eviction\n- getStorageForRequest() - cache lookup and routing\n- findDatabaseForCwd() - database discovery\n- evictStorageForRequest() - manual eviction","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:38.729299-07:00","updated_at":"2025-10-30T17:12:58.212391-07:00","closed_at":"2025-10-28T14:08:38.064592-07:00"} {"id":"bd-cb64c226.12","content_hash":"ed9fa6273973fb0c68d173564ab4814d360528f9bb035e78406a63875f8f6b43","title":"Remove Storage Cache from Server Struct","description":"Eliminate cache fields and use s.storage directly","acceptance_criteria":"- Server struct has no cache fields\n- NewServer() doesn't initialize cache\n- Start() doesn't run cache cleanup goroutines\n- Stop() only closes single s.storage\n\nChanges needed:\n- Remove cache-related fields from Server struct in server_core.go\n- Remove cache size/TTL parsing from env vars in NewServer()\n- Remove cleanup ticker goroutine from Start()\n- Remove cache cleanup logic from Stop()","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T22:55:25.474412-07:00","updated_at":"2025-10-30T17:12:58.211812-07:00","closed_at":"2025-10-28T14:08:38.061444-07:00"} @@ -194,13 +195,13 @@ {"id":"bd-dd6f6d26","content_hash":"dbcecb8b95f9f2939d97c61bd8cbe331bea866f47600bded213d3122e311c356","title":"Fix autoimport tests for content-hash collision scoring","description":"## Overview\nThree autoimport tests are failing after bd-cbed9619.4 because they expect behavior based on the old reference-counting collision resolution, but the system now uses deterministic content-hash scoring.\n\n## Failing Tests\n1. `TestAutoImportMultipleCollisionsRemapped` - expects local versions preserved\n2. `TestAutoImportAllCollisionsRemapped` - expects local versions preserved \n3. `TestAutoImportCollisionRemapMultipleFields` - expects specific collision resolution behavior\n\n## Root Cause\nThese tests were written when ScoreCollisions used reference counting to determine which version to keep. Now it uses content-hash comparison (introduced in commit 2e87329), which produces different but deterministic results.\n\n## Example\nOld behavior: Issue with more references would be kept\nNew behavior: Issue with lexicographically lower content hash is kept\n\n## Solution\nUpdate each test to:\n1. Verify the new content-hash based behavior is correct\n2. Check that the remapped issue (not necessarily local/remote) has the expected content\n3. Ensure dependencies are preserved on the correct remapped issue\n\n## Acceptance Criteria\n- All three autoimport tests pass\n- Tests verify content-hash determinism (same collision always resolves the same way)\n- Tests check dependency preservation on remapped issues\n- Test documentation explains content-hash scoring expectations\n\n## Files to Modify\n- `cmd/bd/autoimport_collision_test.go`\n\n## Testing\nRun: `go test ./cmd/bd -run \"TestAutoImport.*Collision\" -v`","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-28T19:12:56.344193-07:00","updated_at":"2025-10-30T17:12:58.178703-07:00","closed_at":"2025-10-28T19:18:35.106895-07:00","dependencies":[{"issue_id":"bd-dd6f6d26","depends_on_id":"bd-cbed9619.4","type":"discovered-from","created_at":"2025-10-28T19:12:56.345276-07:00","created_by":"daemon"}]} {"id":"bd-df11","content_hash":"aff6233eae39a337d6a49328284a56d6e553a6d52dc13ac4ab7a05d6d2033ce1","title":"Add import metrics for external_ref matching statistics","description":"Add observability for external_ref matching behavior during imports to help debug and optimize import operations.\n\nMetrics to track:\n- Number of issues matched by external_ref\n- Number of issues matched by ID\n- Number of issues matched by content hash\n- Number of external_ref updates vs creates\n- Average import time with vs without external_ref\n\nOutput format:\n- Add to ImportResult struct\n- Include in import command output\n- Consider structured logging\n\nUse cases:\n- Debugging slow imports\n- Understanding match distribution\n- Optimizing import performance\n\nRelated: bd-1022","status":"open","priority":4,"issue_type":"chore","created_at":"2025-11-02T15:32:46.157899-08:00","updated_at":"2025-11-02T15:32:46.157899-08:00"} {"id":"bd-df190564","content_hash":"4f4f22b210c0a5cabd1beebb9c291993adf25843a36ef2ea07227f35de578018","title":"bd repair-deps - Orphaned dependency cleaner","description":"Find and fix orphaned dependency references.\n\nImplementation:\n- Scan all issues for dependencies pointing to non-existent issues\n- Report orphaned refs\n- Auto-fix with --fix flag\n- Interactive mode with --interactive\n\nFiles: cmd/bd/repair_deps.go (new)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T19:42:29.852745-07:00","updated_at":"2025-10-31T18:24:19.418221-07:00","closed_at":"2025-10-31T18:24:19.418221-07:00"} -{"id":"bd-e05d","content_hash":"19140b85fdbdb91df96af6416e7aed63924e068edb58478e9726575d45ced5c5","title":"Investigate and optimize test suite performance","description":"Test suite is taking very long to run (\u003e45s for cmd/bd tests, full suite timing unknown but was cancelled).\n\nThis impacts development velocity and CI/CD performance.\n\nInvestigation needed:\n- Profile which tests are slowest\n- Identify bottlenecks (disk I/O, network, excessive setup/teardown?)\n- Consider parallelization opportunities\n- Look for redundant test cases\n- Check if integration tests can be optimized","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-02T15:37:44.529955-08:00","updated_at":"2025-11-02T16:24:36.590145-08:00","closed_at":"2025-11-02T16:24:36.590145-08:00"} +{"id":"bd-e05d","content_hash":"c2f4d60f5bd679d9bf609c35efc9c15e8dd52130fb9b68eacfe47bdda910ecd7","title":"Investigate and optimize test suite performance","description":"Test suite is taking very long to run (\u003e45s for cmd/bd tests, full suite timing unknown but was cancelled).\n\nThis impacts development velocity and CI/CD performance.\n\nInvestigation needed:\n- Profile which tests are slowest\n- Identify bottlenecks (disk I/O, network, excessive setup/teardown?)\n- Consider parallelization opportunities\n- Look for redundant test cases\n- Check if integration tests can be optimized","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-02T15:37:44.529955-08:00","updated_at":"2025-11-02T16:40:27.358938-08:00","closed_at":"2025-11-02T16:40:27.358945-08:00"} {"id":"bd-e1085716","content_hash":"f180247fd30176bb37125a69c1c9361815d52e3437f930b81ec164d4cb92c4dd","title":"bd validate - Comprehensive health check","description":"Run all validation checks in one command.\n\nChecks:\n- Duplicates\n- Orphaned dependencies\n- Test pollution\n- Git conflicts\n\nSupports --fix-all for auto-repair.\n\nDepends on bd-cbed9619.1, bd-0dcea000, bd-31aab707, bd-9826b69a.\n\nFiles: cmd/bd/validate.go (new)","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-29T23:05:13.980679-07:00","updated_at":"2025-10-30T17:12:58.19736-07:00"} {"id":"bd-e166","content_hash":"000f4f9d069ffedceae13894d967ec30fa4a89e318bfcac4847f3c3b16d44a89","title":"Improve timestamp comparison readability in import","description":"The timestamp comparison logic uses double-negative which can be confusing:\n\nCurrent code:\nif !incoming.UpdatedAt.After(existing.UpdatedAt) {\n // skip update\n}\n\nMore readable:\nif incoming.UpdatedAt.After(existing.UpdatedAt) {\n // perform update\n} else {\n // skip (local is newer)\n}\n\nThis is a minor refactor for code clarity.\n\nRelated: bd-1022\nFiles: internal/importer/importer.go:411, 488","status":"open","priority":4,"issue_type":"chore","created_at":"2025-11-02T15:32:12.27108-08:00","updated_at":"2025-11-02T15:32:12.27108-08:00"} {"id":"bd-e1d645e8","content_hash":"38eb74773fec37584ddaeb23f64a7ebbbb94893a2f1ab047740bf9f0cfca88c0","title":"Rapid 4","description":"","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-29T19:11:57.484329-07:00","updated_at":"2025-10-30T17:12:58.189715-07:00"} {"id":"bd-e55c","content_hash":"1204ddc254f51c686f5586fe540d36abe0a225176e0eb8418147e46cbd3aa298","title":"Import overwrites newer local issues with older remote versions","description":"## Problem\n\nDuring git pull + import, local issues with newer updated_at timestamps get overwritten by older versions from remote JSONL.\n\n## What Happened\n\nTimeline:\n1. 17:52 - Closed bd-df190564 and bd-b501fcc1 locally (updated_at: 2025-10-31)\n2. 17:51 - Remote pushed same issues with status=open (updated_at: 2025-10-30)\n3. 17:52 - Local sync pulled remote commit and imported JSONL\n4. Result: Issues reverted to open despite local version being newer\n\n## Root Cause\n\nDetectCollisions (internal/storage/sqlite/collision.go:67-79) compares fields but doesn't check timestamps:\n\n```go\nconflictingFields := compareIssues(existing, incoming)\nif len(conflictingFields) == 0 {\n result.ExactMatches = append(result.ExactMatches, incoming.ID)\n} else {\n // Same ID, different content - treats as UPDATE\n result.Collisions = append(result.Collisions, \u0026CollisionDetail{...})\n}\n```\n\nImport applies incoming version regardless of which is newer.\n\n## Expected Behavior\n\nImport should:\n1. Compare updated_at timestamps when collision detected\n2. Skip update if local version is newer\n3. Apply update only if remote version is newer\n4. Warn on timestamp conflicts\n\n## Solution\n\nAdd timestamp checking to DetectCollisions or importIssues:\n\n```go\nif len(conflictingFields) \u003e 0 {\n // Check timestamps\n if !incoming.UpdatedAt.After(existing.UpdatedAt) {\n // Local is newer or same - skip update\n result.ExactMatches = append(result.ExactMatches, incoming.ID)\n continue\n }\n // Remote is newer - apply update\n result.Collisions = append(result.Collisions, \u0026CollisionDetail{...})\n}\n```\n\n## Files\n- internal/storage/sqlite/collision.go\n- internal/importer/importer.go\n\n## References\n- Discovered during bd-df190564, bd-b501fcc1 re-opening","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-31T17:56:43.919306-07:00","updated_at":"2025-10-31T18:05:55.521427-07:00","closed_at":"2025-10-31T18:05:55.521427-07:00"} {"id":"bd-e652","content_hash":"6e43bbf6e0c51b81a70e56ad25a5c8f6d08e6e5fcb33e691029027e151707432","title":"bd doctor doesn't detect version mismatches or stale daemons","description":"","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-31T21:07:56.957214-07:00","updated_at":"2025-11-01T17:05:36.615761-07:00","closed_at":"2025-11-01T17:05:36.615761-07:00","dependencies":[{"issue_id":"bd-e652","depends_on_id":"bd-2752a7a2","type":"discovered-from","created_at":"2025-10-31T21:07:56.958708-07:00","created_by":"stevey"}]} -{"id":"bd-e6d71828","content_hash":"51e2a90a6200df1bf26535e7421b485a3c76e4162c5b68c165a2ad42a09df6b3","title":"Add transaction + retry logic for N-way collision resolution","description":"## Problem\nCurrent N-way collision resolution fails on UNIQUE constraint violations during convergence rounds when 5+ clones sync. The RemapCollisions function is non-atomic and performs operations sequentially:\n1. Delete old issues (CASCADE deletes dependencies)\n2. Create remapped issues (can fail with UNIQUE constraint)\n3. Recreate dependencies\n4. Update text references\n\nFailure at step 2 leaves database in inconsistent state.\n\n## Solution\nWrap collision resolution in database transaction with retry logic:\n- Make entire RemapCollisions operation atomic\n- Retry up to 3 times on UNIQUE constraint failures\n- Re-sync counters between retries\n- Add better error messages for debugging\n\n## Implementation\nLocation: internal/storage/sqlite/collision.go:342 (RemapCollisions function)\n\n```go\n// Retry up to 3 times on UNIQUE constraint failures\nfor attempt := 0; attempt \u003c 3; attempt++ {\n err := s.db.ExecInTransaction(func(tx *sql.Tx) error {\n // All collision resolution operations\n })\n if !isUniqueConstraintError(err) {\n return err\n }\n s.SyncAllCounters(ctx)\n}\n```\n\n## Success Criteria\n- 5-clone collision test passes reliably\n- No partial state on UNIQUE constraint errors\n- Automatic recovery from transient ID conflicts\n\n## References\n- See beads_nway_test.go:124 for the KNOWN LIMITATION comment\n- Related to-7c5915ae (transaction support)","notes":"## Progress Made\n\n1. Added `ExecInTransaction` helper to SQLiteStorage for atomic database operations\n2. Added `IsUniqueConstraintError` function to detect UNIQUE constraint violations\n3. Wrapped `RemapCollisions` with retry logic (up to 3 attempts) with counter sync between retries\n4. Enhanced `handleRename` to detect and handle race conditions where target ID already exists\n5. Added defensive checks for when old ID has been deleted by another clone\n\n## Test Results\n\nThe changes improve N-way collision handling but don't fully solve the problem:\n- Original error: `UNIQUE constraint failed: issues.id` during first convergence round\n- With changes: Test proceeds further but encounters different collision scenarios\n- New error: `target ID already exists with different content` in later convergence rounds\n\n## Root Cause Analysis\n\nThe issue is more complex than initially thought. In N-way scenarios:\n1. Clone A remaps bd-1c63eb84 → test-2 → test-4\n2. Clone B remaps bd-1c63eb84 → test-3 → test-4 \n3. Both try to create test-4, but with different intermediate states\n4. This creates legitimate content collisions that require additional resolution\n\n## Next Steps \n\nThe full solution requires:\n1. Making remapping fully deterministic across clones (same input → same remapped ID)\n2. OR making `handleRename` more tolerant of mid-flight collisions\n3. OR implementing full transaction support for multi-step collision resolution -7c5915ae)\n\nThe retry logic added here provides a foundation but isn't sufficient for complex N-way scenarios.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T10:22:32.716678-07:00","updated_at":"2025-11-02T16:46:45.864479-08:00","closed_at":"2025-11-02T16:46:45.864479-08:00","dependencies":[{"issue_id":"bd-e6d71828","depends_on_id":"bd-cbed9619.1","type":"related","created_at":"2025-10-29T10:44:44.14653-07:00","created_by":"daemon"}]} +{"id":"bd-e6d71828","content_hash":"954fa43e14d3302e5ba105d062b8ad48777f49cd759f9a1d827f03c29ddee9bd","title":"Add transaction + retry logic for N-way collision resolution","description":"## Problem\nCurrent N-way collision resolution fails on UNIQUE constraint violations during convergence rounds when 5+ clones sync. The RemapCollisions function is non-atomic and performs operations sequentially:\n1. Delete old issues (CASCADE deletes dependencies)\n2. Create remapped issues (can fail with UNIQUE constraint)\n3. Recreate dependencies\n4. Update text references\n\nFailure at step 2 leaves database in inconsistent state.\n\n## Solution\nWrap collision resolution in database transaction with retry logic:\n- Make entire RemapCollisions operation atomic\n- Retry up to 3 times on UNIQUE constraint failures\n- Re-sync counters between retries\n- Add better error messages for debugging\n\n## Implementation\nLocation: internal/storage/sqlite/collision.go:342 (RemapCollisions function)\n\n```go\n// Retry up to 3 times on UNIQUE constraint failures\nfor attempt := 0; attempt \u003c 3; attempt++ {\n err := s.db.ExecInTransaction(func(tx *sql.Tx) error {\n // All collision resolution operations\n })\n if !isUniqueConstraintError(err) {\n return err\n }\n s.SyncAllCounters(ctx)\n}\n```\n\n## Success Criteria\n- 5-clone collision test passes reliably\n- No partial state on UNIQUE constraint errors\n- Automatic recovery from transient ID conflicts\n\n## References\n- See beads_nway_test.go:124 for the KNOWN LIMITATION comment\n- Related to-7c5915ae (transaction support)","notes":"## Progress Made\n\n1. Added `ExecInTransaction` helper to SQLiteStorage for atomic database operations\n2. Added `IsUniqueConstraintError` function to detect UNIQUE constraint violations\n3. Wrapped `RemapCollisions` with retry logic (up to 3 attempts) with counter sync between retries\n4. Enhanced `handleRename` to detect and handle race conditions where target ID already exists\n5. Added defensive checks for when old ID has been deleted by another clone\n\n## Test Results\n\nThe changes improve N-way collision handling but don't fully solve the problem:\n- Original error: `UNIQUE constraint failed: issues.id` during first convergence round\n- With changes: Test proceeds further but encounters different collision scenarios\n- New error: `target ID already exists with different content` in later convergence rounds\n\n## Root Cause Analysis\n\nThe issue is more complex than initially thought. In N-way scenarios:\n1. Clone A remaps bd-1c63eb84 → test-2 → test-4\n2. Clone B remaps bd-1c63eb84 → test-3 → test-4 \n3. Both try to create test-4, but with different intermediate states\n4. This creates legitimate content collisions that require additional resolution\n\n## Next Steps \n\nThe full solution requires:\n1. Making remapping fully deterministic across clones (same input → same remapped ID)\n2. OR making `handleRename` more tolerant of mid-flight collisions\n3. OR implementing full transaction support for multi-step collision resolution -7c5915ae)\n\nThe retry logic added here provides a foundation but isn't sufficient for complex N-way scenarios.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T10:22:32.716678-07:00","updated_at":"2025-11-02T17:08:52.043475-08:00","closed_at":"2025-11-02T17:08:52.043477-08:00","dependencies":[{"issue_id":"bd-e6d71828","depends_on_id":"bd-cbed9619.1","type":"related","created_at":"2025-10-29T10:44:44.14653-07:00","created_by":"daemon"}]} {"id":"bd-e8be4224","content_hash":"15cf7306a1c279137aba5515692e560047a56355504285c68a5ff8a006aef3f6","title":"Batch test 3","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-29T15:29:01.964091-07:00","updated_at":"2025-10-31T12:00:43.183212-07:00","closed_at":"2025-10-31T12:00:43.183212-07:00"} {"id":"bd-e98221b3","content_hash":"39107dceb86c0f5588342036585cca9cb320d0df2814fe470e688c4172644890","title":"Update AGENTS.md and README.md with \"bd daemons\" documentation","description":"Document the new \"bd daemons\" command and all subcommands in AGENTS.md and README.md. Include examples and troubleshooting guidance.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-26T19:41:11.099254-07:00","updated_at":"2025-10-30T17:12:58.181671-07:00"} {"id":"bd-eb3c","content_hash":"6922e5dc2f24e0fb84ecdb7bea11284f38c3f9e7fed43b90eeef4d6372a96fd5","title":"UX nightmare: multiple ways daemon can fail with misleading messages","description":"","status":"closed","priority":0,"issue_type":"epic","created_at":"2025-10-31T21:08:09.090553-07:00","updated_at":"2025-11-01T20:27:42.79962-07:00","closed_at":"2025-11-01T20:27:42.79962-07:00"} @@ -222,7 +223,7 @@ {"id":"bd-f8b764c9.7","content_hash":"0cd1edbd677f73f3a21e571709eca026db7c6e0d158a3d41d7c4e37deb8bc4c2","title":"CLI accepts both hash IDs and aliases","description":"Update all CLI commands to accept both hash IDs (bd-af78e9a2) and aliases (#42, or just 42).\n\n## Parsing Logic\n```go\n// internal/utils/id_parser.go\nfunc ParseIssueID(input string) (issueID string, err error) {\n // Hash ID: bd-af78e9a2\n if strings.HasPrefix(input, \"bd-\") {\n return input, nil\n }\n \n // Alias: #42 or 42\n aliasStr := strings.TrimPrefix(input, \"#\")\n alias, err := strconv.Atoi(aliasStr)\n if err != nil {\n return \"\", fmt.Errorf(\"invalid issue ID: %s\", input)\n }\n \n // Resolve alias to hash ID\n return storage.GetIssueIDByAlias(alias)\n}\n```\n\n## Commands to Update\nAll commands that accept issue IDs:\n\n### 1. bd show\n```bash\nbd show bd-af78e9a2 # Hash ID\nbd show #42 # Alias\nbd show 42 # Alias (shorthand)\nbd show bd-af78e9a2 #42 # Mixed (multiple IDs)\n```\n\n### 2. bd update\n```bash\nbd update #42 --status in_progress\nbd update bd-af78e9a2 --priority 1\n```\n\n### 3. bd close\n```bash\nbd close #42 --reason \"Done\"\n```\n\n### 4. bd dep add/tree\n```bash\nbd dep add #42 #1 --type blocks\nbd dep tree bd-af78e9a2\n```\n\n### 5. bd label add/remove\n```bash\nbd label add #42 critical\n```\n\n### 6. bd merge\n```bash\nbd merge #42 #43 --into #41\n```\n\n## Display Format\nDefault to showing aliases in output:\n```bash\n$ bd list\n#1 Fix authentication bug P1 open\n#2 Add logging to daemon P2 open \n#42 Investigate jujutsu integration P3 open\n```\n\nWith `--format=hash` flag:\n```bash\n$ bd list --format=hash\nbd-af78e9a2 Fix authentication bug P1 open\nbd-e5f6a7b8 Add logging to daemon P2 open\nbd-1a2b3c4d Investigate jujutsu integration P3 open\n```\n\n## Files to Modify\n- internal/utils/id_parser.go (new)\n- cmd/bd/show.go\n- cmd/bd/update.go\n- cmd/bd/close.go\n- cmd/bd/reopen.go\n- cmd/bd/dep.go\n- cmd/bd/label.go\n- cmd/bd/merge.go\n- cmd/bd/list.go (add --format flag)\n\n## Testing\n- Test hash ID parsing\n- Test alias parsing (#42, 42)\n- Test mixed IDs in single command\n- Test error on invalid ID\n- Test alias resolution failure","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T21:25:06.256317-07:00","updated_at":"2025-10-31T12:32:32.609634-07:00","closed_at":"2025-10-31T12:32:32.609634-07:00","dependencies":[{"issue_id":"bd-f8b764c9.7","depends_on_id":"bd-f8b764c9","type":"parent-child","created_at":"2025-10-29T21:25:06.257796-07:00","created_by":"stevey"},{"issue_id":"bd-f8b764c9.7","depends_on_id":"bd-f8b764c9.10","type":"blocks","created_at":"2025-10-29T21:25:06.258307-07:00","created_by":"stevey"},{"issue_id":"bd-f8b764c9.7","depends_on_id":"bd-f8b764c9.8","type":"blocks","created_at":"2025-10-29T21:29:45.993274-07:00","created_by":"stevey"}]} {"id":"bd-f8b764c9.8","content_hash":"d047b706654f9e5b0cc59fde73e88fed242932c3c024d90af22327a5c2f2fced","title":"Update JSONL format to use hash IDs","description":"Update JSONL import/export to use hash IDs, store aliases separately.\n\n## Current JSONL Format\n```jsonl\n{\"id\":\"bd-1c63eb84\",\"title\":\"Fix bug\",\"status\":\"open\",...}\n{\"id\":\"bd-9063acda\",\"title\":\"Add test\",\"status\":\"open\",...}\n```\n\n## New JSONL Format (Option A: Include Alias)\n```jsonl\n{\"id\":\"bd-af78e9a2\",\"alias\":1,\"title\":\"Fix bug\",\"status\":\"open\",...}\n{\"id\":\"bd-e5f6a7b8\",\"alias\":2,\"title\":\"Add test\",\"status\":\"open\",...}\n```\n\n## New JSONL Format (Option B: Hash ID Only)\n```jsonl\n{\"id\":\"bd-af78e9a2\",\"title\":\"Fix bug\",\"status\":\"open\",...}\n{\"id\":\"bd-e5f6a7b8\",\"title\":\"Add test\",\"status\":\"open\",...}\n```\n\nStore aliases in separate .beads/aliases.jsonl (local only, git-ignored):\n```jsonl\n{\"hash\":\"bd-af78e9a2\",\"alias\":1}\n{\"hash\":\"bd-e5f6a7b8\",\"alias\":2}\n```\n\n**Recommendation**: Option B (hash only in main JSONL)\n- Cleaner git diffs (no alias conflicts)\n- Aliases are workspace-local preference\n- Main JSONL is canonical, portable\n\n## Export Changes\nFile: cmd/bd/export.go\n```go\n// Export issues with hash IDs\nfor _, issue := range issues {\n json := marshalIssue(issue) // Uses issue.ID (hash)\n // Don't include alias in JSONL\n}\n\n// Separately export aliases to .beads/aliases.jsonl\nexportAliases(issues)\n```\n\n## Import Changes \nFile: cmd/bd/import.go, internal/importer/importer.go\n```go\n// Import issues by hash ID\nissue := unmarshalIssue(line)\n// Assign new alias on import (don't use incoming alias)\nissue.Alias = getNextAlias()\n\n// No collision detection needed! Hash IDs are globally unique\n```\n\n## Dependency Reference Format\nNo change needed - already uses issue IDs:\n```json\n{\"depends_on_id\":\"bd-af78e9a2\",\"type\":\"blocks\"}\n```\n\n## Files to Modify\n- cmd/bd/export.go (use hash IDs)\n- cmd/bd/import.go (import hash IDs, assign aliases)\n- internal/importer/importer.go (remove collision detection!)\n- .gitignore (add .beads/aliases.jsonl)\n\n## Testing\n- Test export produces hash IDs\n- Test import assigns new aliases\n- Test dependencies preserved with hash IDs\n- Test no collision detection triggered","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T21:24:47.408106-07:00","updated_at":"2025-10-31T12:32:32.609925-07:00","closed_at":"2025-10-31T12:32:32.609925-07:00","dependencies":[{"issue_id":"bd-f8b764c9.8","depends_on_id":"bd-f8b764c9","type":"parent-child","created_at":"2025-10-29T21:24:47.409489-07:00","created_by":"stevey"},{"issue_id":"bd-f8b764c9.8","depends_on_id":"bd-f8b764c9.9","type":"blocks","created_at":"2025-10-29T21:24:47.409977-07:00","created_by":"stevey"},{"issue_id":"bd-f8b764c9.8","depends_on_id":"bd-f8b764c9.10","type":"blocks","created_at":"2025-10-29T21:29:45.975499-07:00","created_by":"stevey"}]} {"id":"bd-f8b764c9.9","content_hash":"5b040bec47ef5353a04d90d73ac8237f0302137c27ef7f6bfc84379b84cbb7ec","title":"Implement hash ID generation in CreateIssue","description":"Replace sequential ID generation with hash-based IDs in CreateIssue function.\n\n## Current Behavior (internal/storage/sqlite/sqlite.go)\n```go\nfunc (s *SQLiteStorage) CreateIssue(ctx context.Context, issue *types.Issue) error {\n // ID comes from auto-increment counter\n // Collisions possible across clones\n}\n```\n\n## New Behavior\n```go\nfunc (s *SQLiteStorage) CreateIssue(ctx context.Context, issue *types.Issue) error {\n // Generate hash ID if not provided\n if issue.ID == \"\" {\n issue.ID = idgen.GenerateHashID(\n issue.Title,\n issue.Description,\n time.Now(),\n s.workspaceID,\n )\n }\n \n // Assign next alias\n issue.Alias = s.getNextAlias()\n \n // Insert with hash ID + alias\n // ...\n}\n```\n\n## Workspace ID Generation\nAdd to database initialization:\n```go\n// Generate stable workspace ID (persisted in .beads/workspace_id)\nworkspaceID := getOrCreateWorkspaceID()\n```\n\nOptions for workspace ID:\n1. Hostname + random suffix\n2. UUID (random)\n3. Git remote URL hash (deterministic per repo)\n\nRecommended: Option 3 (git remote hash) for reproducibility\n\n## Hash Collision Detection\n```go\n// On insert, check for collision (unlikely but possible)\nexisting, err := s.GetIssue(ctx, issue.ID)\nif err == nil {\n // Hash collision! Add random suffix and retry\n issue.ID = issue.ID + \"-\" + randomSuffix(4)\n}\n```\n\n## Files to Create/Modify\n- internal/types/id_generator.go (new)\n- internal/storage/sqlite/sqlite.go (CreateIssue)\n- internal/storage/sqlite/workspace.go (new - workspace ID management)\n- .beads/workspace_id (new file, git-ignored)\n\n## Testing\n- Test hash ID generation is deterministic\n- Test collision detection and retry\n- Test workspace ID persistence\n- Benchmark: hash generation performance (\u003c1μs)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T21:24:29.412237-07:00","updated_at":"2025-10-31T12:32:32.610403-07:00","closed_at":"2025-10-31T12:32:32.610403-07:00","dependencies":[{"issue_id":"bd-f8b764c9.9","depends_on_id":"bd-f8b764c9","type":"parent-child","created_at":"2025-10-29T21:24:29.413417-07:00","created_by":"stevey"},{"issue_id":"bd-f8b764c9.9","depends_on_id":"bd-f8b764c9.11","type":"blocks","created_at":"2025-10-29T21:24:29.413823-07:00","created_by":"stevey"}]} -{"id":"bd-f9a1","content_hash":"4b9a24c10fcede8ca44e0fdb53eac750a96f1ef24dae36c08fda48a4f20f3c0c","title":"Add index usage verification test for external_ref lookups","description":"Currently we test that idx_issues_external_ref index exists, but we don't verify that it's actually being used by the query planner.\n\nProposed solution:\n- Add test using EXPLAIN QUERY PLAN\n- Verify that 'SEARCH TABLE issues USING INDEX idx_issues_external_ref' appears in plan\n- Ensures O(1) lookup performance is maintained\n\nRelated: bd-1022\nFiles: internal/storage/sqlite/external_ref_test.go:260","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-02T15:32:09.85419-08:00","updated_at":"2025-11-02T16:40:01.033779-08:00","closed_at":"2025-11-02T16:40:01.033779-08:00"} +{"id":"bd-f9a1","content_hash":"97f9387b20f741a9f71ee43b0671b5d970bd594098db299dc871d0b3074c5384","title":"Add index usage verification test for external_ref lookups","description":"Currently we test that idx_issues_external_ref index exists, but we don't verify that it's actually being used by the query planner.\n\nProposed solution:\n- Add test using EXPLAIN QUERY PLAN\n- Verify that 'SEARCH TABLE issues USING INDEX idx_issues_external_ref' appears in plan\n- Ensures O(1) lookup performance is maintained\n\nRelated: bd-1022\nFiles: internal/storage/sqlite/external_ref_test.go:260","status":"closed","priority":3,"issue_type":"task","created_at":"2025-11-02T15:32:09.85419-08:00","updated_at":"2025-11-02T16:40:01.033779-08:00","closed_at":"2025-11-02T16:40:01.033779-08:00"} {"id":"bd-fb05","content_hash":"1d99061e4ac1564982acc5e141674adf3bb7db789d546c12deb9108435af6450","title":"Refactor sqlite.go into focused modules","description":"Split sqlite.go (2,298 lines) into focused modules: migrations.go, ids.go, issues.go, events.go, dirty.go, db.go. This will improve maintainability and reduce cognitive load.","design":"Files to create:\n- migrations.go: Migration registry + runner\n- ids.go: ID generation/validation \n- issues.go: CRUD helpers\n- events.go: Event helpers\n- dirty.go: dirty_issues helpers\n- db.go: New/open, DSN construction\n- tx.go: Transaction helper","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-11-01T11:41:14.805895-07:00","updated_at":"2025-11-01T22:56:21.902164-07:00","closed_at":"2025-11-01T22:56:21.90217-07:00"} {"id":"bd-fb95094c","content_hash":"99f456d7a5d3a4288c3f60dd65212480c54d3b0161e57d7eccffe01875d2eb5e","title":"Code Health \u0026 Technical Debt Cleanup","description":"Comprehensive codebase cleanup to remove dead code, refactor monolithic files, deduplicate utilities, and improve maintainability. Based on ultrathink code health analysis conducted 2025-10-27.\n\nGoals:\n- Remove ~1,500 LOC of dead/unreachable code\n- Split 2 monolithic files (server.go 2,273 LOC, sqlite.go 2,136 LOC) into focused modules\n- Deduplicate scattered utility functions (normalizeLabels, BD_DEBUG checks)\n- Consolidate test coverage (2,019 LOC of collision tests)\n- Improve code navigation and reduce merge conflicts\n\nImpact: Reduces codebase by ~6-8%, improves maintainability, faster CI/CD\n\nEstimated Effort: 11 days across 4 phases","acceptance_criteria":"- All unreachable code identified by `deadcode` analyzer is removed\n- RPC server split into \u003c500 LOC files with clear responsibilities\n- Duplicate utility functions centralized\n- Test coverage maintained or improved\n- All tests passing\n- Documentation updated","status":"open","priority":2,"issue_type":"epic","created_at":"2025-10-27T20:39:22.22227-07:00","updated_at":"2025-10-30T17:12:58.210295-07:00","labels":["cleanup","epic"]} {"id":"bd-fb95094c.1","content_hash":"d28bd9b00ae5586a782aec012344d1c29eec3bc9fdfa06d5804984a3b3c78e4f","title":"Run final validation and cleanup checks","description":"Final validation pass to ensure all cleanup objectives met and no regressions introduced.\n\nValidation checklist:\n1. Dead code verification: `go run golang.org/x/tools/cmd/deadcode@latest -test ./...`\n2. Test coverage: `go test -cover ./...`\n3. Build verification: `go build ./cmd/bd/`\n4. Linting: `golangci-lint run`\n5. Integration tests\n6. Metrics verification\n7. Git clean check\n\nFinal metrics to report:\n- LOC removed: ~____\n- Files deleted: ____\n- Files created: ____\n- Test coverage: ____%\n- Build time: ____ (before/after)\n- Test run time: ____ (before/after)\n\nImpact: Confirms all cleanup objectives achieved successfully","acceptance_criteria":"- Zero unreachable functions per deadcode analyzer\n- All tests pass: `go test ./...`\n- Test coverage maintained or improved\n- Builds cleanly: `go build ./...`\n- Linting shows improvements\n- Integration tests all pass\n- LOC reduction target achieved (~2,500 LOC)\n- No unintended behavior changes\n- Git commit messages document all changes","notes":"Validation completed:\n- LOC: 52,372 lines total\n- Dead code: 4 functions in import_shared.go (tracked in bd-6fe4622f)\n- Build: ✓ Successful\n- Test coverage: ~20-82% across packages\n- Test failure: TestTwoCloneCollision (timeout issue)\n- Linting: errcheck warnings present (defer close, fmt errors)\n- Test time: ~20s\n\nIssues found:\n1. bd-6fe4622f: Remove unreachable import functions (renameImportedIssuePrefixes, etc)\n2. TestTwoCloneCollision: Daemon killall timeout causing test failure\n3. Linting: errcheck violations need fixing","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-27T20:32:00.14166-07:00","updated_at":"2025-10-30T17:12:58.209988-07:00","closed_at":"2025-10-28T14:11:25.218801-07:00","labels":["phase-4","validation"],"dependencies":[{"issue_id":"bd-fb95094c.1","depends_on_id":"bd-fb95094c","type":"parent-child","created_at":"2025-10-27T20:32:00.144113-07:00","created_by":"daemon"}]}