- Remove unreachable function DroppedEventsCount from RPC server
- Add TestMutationToExportLatency for event-driven daemon validation
- Test currently skipped pending full bd-85 implementation
- Create test coverage improvement issues (bd-114 through bd-118)
- All validation checks pass: tests, build, linting baseline
Completed: bd-74, bd-77
Amp-Thread-ID: https://ampcode.com/threads/T-24404401-6c5b-466d-9045-0da3a70cff9a
Co-authored-by: Amp <amp@ampcode.com>
- Scans all issues for dependencies pointing to non-existent issues
- Reports orphaned dependencies with issue ID, depends_on ID, and type
- --fix flag automatically removes all orphaned dependencies
- --interactive mode prompts for each orphan before removal
- Uses direct SQL deletion to avoid foreign key errors on missing issues
- JSON output support with --json flag
- 4 comprehensive tests covering scan, fix, and multiple dependency types
Amp-Thread-ID: https://ampcode.com/threads/T-942a3e75-f90b-45b4-9f88-c7f1b8298cef
Co-authored-by: Amp <amp@ampcode.com>
- Test batching of multiple triggers into single action
- Test timer reset on subsequent triggers
- Test cancellation during wait and immediately after trigger
- Test thread safety with deterministic concurrent trigger batching
- All tests use t.Cleanup to prevent goroutine leaks
- Tests pass with -race detector
- Test JSONL change detection with fsnotify
- Test multiple changes debounced into single action
- Test git ref change detection (platform-aware, skips if unsupported)
- Test file removal/recreation handling (platform-aware)
- Test polling fallback mode
- Test polling detects file disappearance
- Test proper cleanup with Close()
All 7 tests pass. Two tests skip gracefully on platforms where
fsnotify doesn't support git ref watching or file removal/recreation
events. No linter warnings for new test file.
Closes bd-78
Amp-Thread-ID: https://ampcode.com/threads/T-76e7b2ba-150c-461f-83e2-4a6d509d6b53
Co-authored-by: Amp <amp@ampcode.com>
- Add mutation events for label/dep/comment operations
- Create separate export-only and import-only functions
- Add dropped events counter with safety net export
- Complete bd-80 mutation channel implementation
Event-driven mode now:
- Emits mutation events for ALL write operations (not just create/update/close)
- Uses createExportFunc() for mutations (export+commit/push only, no pull)
- Uses createAutoImportFunc() for file changes (pull+import only, no export)
- Tracks dropped events and triggers safety export every 60s if any dropped
- Achieves <500ms latency target by avoiding full sync on each trigger
Behind BEADS_DAEMON_MODE=events flag (poll is still default)
- Add AllocateNextID() public method to SQLiteStorage for cross-package ID allocation
- Enhance handleRename() to handle collision during rename with retry logic
- Fix stale ID map issue by removing deleted IDs from dbByID after rename
- Update edge case tests to use convergence rounds consistently
- All N-way collision tests now pass (TestFiveCloneCollision, TestEdgeCases)
- Added ExecInTransaction helper for atomic database operations
- Added IsUniqueConstraintError to detect UNIQUE constraint violations
- Wrapped RemapCollisions with retry logic (3 attempts with counter sync)
- Enhanced handleRename to detect race conditions where target ID exists
- Added defensive checks for when old ID has been deleted by another clone
Progress: Improves N-way collision handling, though full solution requires
more work (tracked in bd-108). Tests now reach later convergence rounds
before hitting complex collision scenarios.
Amp-Thread-ID: https://ampcode.com/threads/T-2b850a80-f8bd-4e38-b661-e33d1cfa7281
Co-authored-by: Amp <amp@ampcode.com>
Created four issues to address N-way collision limitations:
- bd-109: Add transaction + retry logic (P1, immediate fix)
- bd-110: Implement clone-scoped ID allocation (P2, medium-term)
- bd-111: Investigate jujutsu VCS for better merging (P2, research)
- bd-112: CRDT-based architecture for v2.0 (P3, long-term)
These address the KNOWN LIMITATION documented in beads_nway_test.go
where 5+ clone collisions fail during convergence with UNIQUE constraint
violations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Created beads_nway_test.go with generalized N-clone collision testing
- Implemented TestFiveCloneCollision with 3 sync order variations
- Added TestTenCloneCollision for scaling verification
- Added TestEdgeCases (identical content, one different, mixed collisions)
- Added TestConvergenceTime for bounded convergence verification
- Tests document known limitation: UNIQUE constraint failures during
convergence when multiple clones remap to same target ID
- Pattern matches TestThreeCloneCollision approach of documenting
current behavior for future improvement
Amp-Thread-ID: https://ampcode.com/threads/T-012146d5-1841-4187-8619-230063e7711d
Co-authored-by: Amp <amp@ampcode.com>
- Refactored upsertIssues to match by content hash first, then by ID
- Added buildHashMap, buildIDMap, and handleRename helper functions
- Import now detects and handles renames (same content, different ID)
- Importing same data multiple times is idempotent (reports Unchanged)
- Exported BuildReplacementCache and ReplaceIDReferencesWithCache for reuse
- All 30+ existing import tests pass
- Improved convergence for N-way collision scenarios
Changes:
- internal/importer/importer.go: Content-first matching in upsertIssues
- internal/storage/sqlite/collision.go: Exported helper functions
- internal/storage/sqlite/collision_test.go: Updated function names
Amp-Thread-ID: https://ampcode.com/threads/T-3df96ad8-7c0e-4190-87b5-6d5327718f0a
Co-authored-by: Amp <amp@ampcode.com>
- Add ResolveNWayCollisions function for deterministic global resolution
- Replace pairwise ScoreCollisions approach with content-hash-based sorting
- Implement helper functions: groupCollisionsByID, deduplicateVersionsByContentHash, extractNumber
- Update importer.go to use new resolution flow
- Add applyNWayResolution to create remapped issues
- Export UpdateReferences for use by importer
- Add comprehensive tests for N-way collision resolution
- All tests pass including TestTwoCloneCollision
This enables proper convergence for N-way (3+) collision scenarios where
multiple clones create issues with the same ID but different content.
The algorithm groups all versions, deduplicates by content, sorts by hash,
and assigns sequential IDs deterministically.
Amp-Thread-ID: https://ampcode.com/threads/T-3e649e13-792c-4fb5-a342-58fa805eb517
Co-authored-by: Amp <amp@ampcode.com>
After 2 weeks of collision/stale-data fixes, reviewed all changes to identify
spurious code that is no longer needed after content-hash resolution was implemented.
**Removed:**
1. countReferences() function from collision.go (lines 274-328)
- Was used for reference-count based collision scoring
- Completely unused after switching to content-hash based resolution (commit 2e87329)
- Still exists in duplicates.go for deduplication (different use case)
2. ReferenceScore field from CollisionDetail struct
- Marked as DEPRECATED but never removed
- No longer used by ScoreCollisions() which now uses content hashing
3. TestCountReferences and TestCountReferencesWordBoundary tests
- Tested the now-deleted countReferences() function
- No longer relevant
**Fixed:**
- Updated CheckpointWAL comments to remove misleading "staleness detection" claim
- Staleness detection uses metadata (last_import_time), NOT file mtime
- CheckpointWAL is still valuable for data persistence and WAL size reduction
- Comments now accurately reflect actual benefits
**Verified:**
- All tests pass (internal/storage/sqlite)
- Content-hash collision resolution still works correctly
- No behavioral changes, just cleanup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Detect fsnotify.NewWatcher() errors and auto-fallback to polling mode
- Add BEADS_WATCHER_FALLBACK env var to control behavior (default: enabled)
- Poll every 5 seconds with comprehensive change detection:
- Track file existence, size, and mtime to catch all changes
- Handle file disappearance/reappearance correctly
- Trigger on file recreation even with older timestamps
- Fix goroutine leak: Close() now stops background goroutines via cancel context
- Tighten git refs filtering to only trigger for events under .git/refs/heads
- Trigger after successful JSONL rewatch on rename/remove events
- Improve logging to show actual poll interval in warnings
All tests passing.
Amp-Thread-ID: https://ampcode.com/threads/T-8f5edc23-4b78-4b80-b8f3-66050f45eb61
Co-authored-by: Amp <amp@ampcode.com>
- Add RenameDetail type to track content matches with different IDs
- Remove deletion logic from DetectCollisions (now read-only)
- Create ApplyCollisionResolution to handle all modifications
- Update importer.go to use two-phase approach (detect then apply)
- Fix dependency preservation in RemapCollisions
- Collect all dependencies before CASCADE DELETE
- Recreate with updated IDs after remapping
- Add tests: TestDetectCollisionsReadOnly, TestApplyCollisionResolution
- Update collision tests for content-hash scoring behavior
- Create bd-100 to track fixing autoimport tests
The test was comparing full JSON output including timestamps, causing
false negative failures. The 2-clone collision resolution actually works
correctly - both clones converge to identical semantic content.
Changes:
- Added compareIssuesIgnoringTimestamps helper to compare issue content
- Compares ID, title, description, status, priority, type (not timestamps)
- Added filterTrackedChanges to ignore untracked files in git status
- Test now passes, proving collision resolution works for 2-clone case
Closes bd-91
Amp-Thread-ID: https://ampcode.com/threads/T-a58284d2-f39f-482a-9db0-bec31c19e9e5
Co-authored-by: Amp <amp@ampcode.com>
- Replace timestamp-based collision scoring with deterministic content hashing
- Add hashIssueContent() using SHA-256 of all substantive fields
- Modify ScoreCollisions to compare hashes and set RemapIncoming flag
- Update RemapCollisions to handle both directions (remap incoming OR existing)
- Add CollisionDetail.RemapIncoming field to control which version gets remapped
- Add unit tests for hash function and deterministic collision resolution
Status: Hash-based resolution works correctly, but TestTwoCloneCollision still
fails due to missing rename detection. After Clone B resolves collision,
Clone A needs to recognize its issue was remapped to a different ID.
Next: Add content-based rename detection during import to prevent
re-resolving already-resolved collisions.
Progress on bd-86.
Amp-Thread-ID: https://ampcode.com/threads/T-b19b49e8-b52a-463d-b052-8a526a500260
Co-authored-by: Amp <amp@ampcode.com>