- Removed SyncAllCounters() and all call sites (already no-op with hash IDs)
- Removed AllocateNextID() and getNextIDForPrefix() - sequential ID generation
- Removed collision remapping logic in internal/storage/sqlite/collision.go
- Removed rename collision handling in internal/importer/importer.go
- Removed branch-merge example (collision resolution no longer needed)
- Updated EXTENDING.md to remove counter sync examples
These were all deprecated code paths for sequential IDs that are obsolete
with hash-based IDs. Hash ID collisions are handled by extending the hash,
not by remapping to new sequential IDs.
- Removed nextSequentialID() and getIDMode() functions
- Removed issue_counters table from schema
- Made SyncAllCounters() a no-op for backward compatibility
- Simplified ID generation to hash-only (adaptive length)
- Removed id_mode config setting
- Removed sequential ID tests and migration code
- Updated CONFIG.md and AGENTS.md to remove sequential ID references
Follow-up bd-2a70 will remove obsolete test files and renumber command.
- Add GetNextChildID to storage interface for generating child IDs
- Implement in SQLiteStorage with atomic counter using child_counters table
- Implement in MemoryStorage with in-memory counter
- Add --parent flag to bd create command
- Support hierarchical IDs (bd-a3f8e9.1, bd-a3f8e9.1.5) in CreateIssue
- Validate parent exists when creating hierarchical issues
- Enforce max depth of 3 levels
- Update ID validation to accept hierarchical IDs with dots
- Add comprehensive tests for child ID generation
- Manual testing confirms: sequential children, nested hierarchies, depth enforcement
## Problem
Export deduplication feature broke when JSONL and export_hashes diverged
(e.g., after git pull/reset). This caused exports to skip issues that
weren't actually in the file, leading to silent data loss.
## Solution
1. JSONL integrity validation before every export
- Store JSONL file hash after export
- Validate hash before export, clear export_hashes if mismatch
- Automatically recovers from git operations changing JSONL
2. Clear export_hashes on all imports
- Prevents stale hashes from causing future export failures
- Import operations invalidate export_hashes state
3. Add Storage interface methods:
- GetJSONLFileHash/SetJSONLFileHash for integrity tracking
- ClearAllExportHashes for recovery
## Tests Added
- TestJSONLIntegrityValidation: Unit tests for validation logic
- TestImportClearsExportHashes: Verifies imports clear hashes
- TestExportIntegrityAfterJSONLTruncation: Simulates git reset (would have caught bd-160)
- TestExportIntegrityAfterJSONLDeletion: Tests recovery from file deletion
- TestMultipleExportsStayConsistent: Tests repeated export integrity
## Follow-up
Created bd-179 epic for remaining integration test gaps (multi-repo sync,
daemon auto-sync, corruption recovery tests).
Closes bd-160
- Created internal/importer package with all import logic
- Moved import phases from cmd/bd to internal/importer
- Implemented real importFunc in daemon's checkAndAutoImportIfStale()
- Added single-flight concurrency guard to prevent parallel imports
- Added fast mtime check to avoid unnecessary file reads (99% of requests <0.1ms)
- Fixed import options: RenameOnImport=true instead of SkipPrefixValidation
- Added export trigger after ID remapping to prevent collision loops
- Fixed memory storage interface: added GetDirtyIssueHash, GetExportHash, SetExportHash
- Updated GetDependencyTree signature for reverse parameter
Performance:
- Mtime check: ~0.01ms per request
- Import when needed: ~10-100ms (rare, only after git pull)
- Throughput maintained: 4300+ issues/sec
- No duplicate work with single-flight guard
Fixes critical data corruption bug where daemon served stale data after
git pull, causing fresh JSONL changes to be overwritten.
Amp-Thread-ID: https://ampcode.com/threads/T-71224a2d-b2d7-4173-b21e-449b64f9dd71
Co-authored-by: Amp <amp@ampcode.com>
- bd-175: Added comprehensive test coverage for internal/storage/memory backend
- All CRUD operations, dependencies, labels, comments
- Thread safety with race detection
- LoadFromIssues and counter sync
- Fixed batch duplicate detection
- bd-176: Documented corruption vs collision distinction
- Added FAQ entry explaining logical vs physical corruption
- Updated TROUBLESHOOTING with clear guidance
- Clarified when to use collision resolution vs reimport
- bd-177: Added prefix validation in SQLite mode
- Validates explicit IDs match configured prefix
- Works in both CreateIssue and CreateIssues
- Comprehensive tests for single and batch operations
Implement --no-db mode to avoid SQLite database corruption in scenarios
where the same .beads directory is accessed from multiple processes
(e.g., host + container, multiple containers).
Changes:
- Add in-memory storage backend (internal/storage/memory/memory.go)
- Implements full Storage interface using in-memory data structures
- Thread-safe with mutex protection for concurrent access
- Supports all core operations: issues, dependencies, labels, comments
- Add JSONL persistence layer (cmd/bd/nodb.go)
- initializeNoDbMode(): Load .beads/issues.jsonl on startup
- writeIssuesToJSONL(): Atomic write-back after each command
- detectPrefix(): Smart prefix detection with fallback hierarchy
1. .beads/nodb_prefix.txt (explicit config)
2. Common prefix from existing issues
3. Current directory name (fallback)
- Integrate --no-db flag into command flow (cmd/bd/main.go)
- Add global --no-db flag to all commands
- PersistentPreRun: Initialize memory storage from JSONL
- PersistentPostRun: Write memory back to JSONL atomically
- Skip daemon and SQLite initialization in --no-db mode
- Extract common writeJSONLAtomic() helper to eliminate duplication
- Update bd init for --no-db mode (cmd/bd/init.go)
- Create .beads/nodb_prefix.txt instead of SQLite database
- Create empty issues.jsonl file
- Display --no-db specific initialization message
Code Quality:
- Refactored atomic JSONL writes into shared writeJSONLAtomic() helper
- Used by both flushToJSONL (SQLite mode) and writeIssuesToJSONL (--no-db mode)
- Eliminates ~90 lines of code duplication
- Ensures consistent atomic write behavior across modes
Usage:
bd --no-db init -p myproject
bd --no-db create "Fix bug" --priority 1
bd --no-db list
bd --no-db update myproject-1 --status in_progress
Benefits:
- No SQLite corruption from concurrent access
- Container-safe: perfect for multi-mount scenarios
- Git-friendly: direct JSONL diffs work seamlessly
- Simple: no daemon, no WAL files, just JSONL
Test Results (go test ./...):
- ✓ github.com/steveyegge/beads: PASS
- ✗ github.com/steveyegge/beads/cmd/bd: 1 pre-existing failure (TestAutoFlushErrorHandling)
- ✓ github.com/steveyegge/beads/internal/compact: PASS
- ✗ github.com/steveyegge/beads/internal/rpc: 1 pre-existing failure (TestMemoryPressureDetection)
- ✓ github.com/steveyegge/beads/internal/storage/sqlite: PASS
- ✓ github.com/steveyegge/beads/internal/types: PASS
- ⚠ github.com/steveyegge/beads/internal/storage/memory: no tests yet
All test failures are pre-existing and unrelated to --no-db implementation.
The new --no-db mode has been manually tested and verified working.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>