- Add detailed installation steps for Git and Jujutsu users
- Explain 3-way merge algorithm and field-level merging
- Document configuration in .gitattributes and .jjconfig.toml
- Clarify how it prevents conflicts proactively vs resolving after
- Created bd-bzfy to track integration of beads-merge tool
**Problem:**
Closed issues were silently reopening during git sync/import operations.
When importing an issue update, the importer built an updates map with
status='closed' but NO closed_at timestamp. The UpdateIssue() function's
manageClosedAt() would only set closed_at when status was CHANGING to
closed, not when it was already closed. Result: closed_at got cleared,
effectively reopening issues.
**Root Cause:**
1. Importer built updates map without closed_at field (lines 443-451, 519-528)
2. closed_at was not in allowedUpdateFields whitelist
3. manageClosedAt() only managed closed_at for status TRANSITIONS
4. Import of already-closed issue → closed_at lost → issue reopens
**Impact:**
- WASM issues (bd-44d0, bd-8507, etc.) were closed on Nov 4 (commit 0df9144)
- They reopened as 'open' status during sync on Nov 5 (commit 8c9814a)
- Users had to repeatedly close the same issues
- Data integrity violation: status=closed with closed_at=NULL
**Fix:**
1. Add closed_at to allowedUpdateFields whitelist
2. Add closed_at to importer updates maps (both external_ref and ID paths)
3. Update manageClosedAt() to skip auto-management if closed_at explicitly provided
- Preserves import timestamps while maintaining auto-management for CLI operations
**Testing:**
- All internal/importer tests pass
- All internal/storage/sqlite tests pass
- Explicitly tests timestamp preservation in TestImportWithExternalRef
**Files Changed:**
- internal/importer/importer.go: Add closed_at to updates maps
- internal/storage/sqlite/sqlite.go: Allow closed_at updates, respect explicit values
Amp-Thread-ID: https://ampcode.com/threads/T-53ed6e45-9d04-4a35-97e9-d1ec36321ab0
Co-authored-by: Amp <amp@ampcode.com>
- Added OrphanHandling type to sqlite package with 4 modes: strict/resurrect/skip/allow
- Updated EnsureIDs() to accept orphanHandling parameter and implement mode logic
- Added CreateIssuesWithOptions() that passes orphan handling through batch creation
- Made importer.OrphanHandling an alias to sqlite.OrphanHandling
- Importer now respects opts.OrphanHandling during batch issue creation
Next: Add import.orphan_handling config and wire through CLI commands
Amp-Thread-ID: https://ampcode.com/threads/T-bb7ffdd9-f444-4975-b5f7-bfff97cb92ff
Co-authored-by: Amp <amp@ampcode.com>
- Add internal/routing package with DetectUserRole and DetermineTargetRepo
- Add routing config schema (mode, default, maintainer, contributor)
- Add --repo flag to bd create for explicit override
- Integrate routing logic into create command
- Test with contributor/maintainer roles and explicit override
Part of bd-8hf (Auto-routing and maintainer detection)
For bd-307: Multi-repo hydration layer
Changes:
- Add MultiRepoConfig to internal/config
- Add GetMultiRepoConfig() to retrieve repos.primary and repos.additional
- Add source_repo field to Issue type to track ownership
- Prepare for hydration logic that reads from N repos
Addresses code review feedback:
✅ P0 (Must Fix):
- Fix JSONL lookup to return LAST match, not FIRST (resurrection.go:160-162)
- Changed from early return to scan all matches and keep last
- Respects JSONL append-only semantics
✅ P1 (Should Fix):
- Add test for multiple JSONL versions
- TestTryResurrectParent_MultipleVersionsInJSONL verifies correct behavior
- Document error message change in CHANGELOG.md
- Old: "parent issue X does not exist"
- New: "parent issue X does not exist and could not be resurrected from JSONL history"
- Marked as breaking change for script parsers
✅ P2/P3 (Nice to Have):
- Add documentation to AGENTS.md explaining auto-resurrection behavior
- Document best-effort dependency resurrection
⏸️ Deferred (P1 - Optimize batch resurrection):
- Caching optimization deferred (no batch use cases currently)
All tests pass:
- Unit tests: internal/storage/sqlite/
- Integration test: TestImportWithDeletedParent
Phase 2 of fixing import failure on missing parent issues (bd-d19a).
Implemented:
- TryResurrectParent: searches JSONL history for deleted parents
- TryResurrectParentChain: recursively resurrects entire parent chains
- Creates tombstones (status=closed) to preserve hierarchical structure
- Modified EnsureIDs and CreateIssue to call resurrection before validation
When importing a child issue with missing parent:
1. Searches .beads/issues.jsonl for parent in git history
2. If found, creates tombstone with status=closed
3. Preserves original title and metadata
4. Appends original description to tombstone
5. Copies dependencies if targets exist
This allows imports to proceed even when parents were deleted,
enabling multi-repo workflows and normal database hygiene operations.
Part of bd-d19a (fix import failure on missing parents).
Amp-Thread-ID: https://ampcode.com/threads/T-a1c9e824-885e-40ce-a179-148cf39c7e64
Co-authored-by: Amp <amp@ampcode.com>
Phase 2 of fixing import failure on missing parent issues (bd-d19a).
Implemented:
- TryResurrectParent: searches JSONL history for deleted parents
- TryResurrectParentChain: recursively resurrects entire parent chains
- Creates tombstones (status=closed) to preserve hierarchical structure
- Modified EnsureIDs and CreateIssue to call resurrection before validation
When importing a child issue with missing parent:
1. Searches .beads/issues.jsonl for parent in git history
2. If found, creates tombstone with status=closed
3. Preserves original title and metadata
4. Appends original description to tombstone
5. Copies dependencies if targets exist
This allows imports to proceed even when parents were deleted,
enabling multi-repo workflows and normal database hygiene operations.
Part of bd-d19a (fix import failure on missing parents).
Amp-Thread-ID: https://ampcode.com/threads/T-a1c9e824-885e-40ce-a179-148cf39c7e64
Co-authored-by: Amp <amp@ampcode.com>