Fix getNextID bug and design collision resolution (bd-9)

Critical bug fix: getNextID() was using alphabetical MAX instead of
numerical MAX, causing "bd-9" to be treated as max when "bd-10" existed.
This blocked all new issue creation after bd-10.

Fixed by using SQL CAST to extract and compare numeric portions of IDs.
This ensures bd-10 > bd-9 numerically, not alphabetically.

Also completed comprehensive design for bd-9 (collision resolution):
- Algorithm design with 7 phases (detection, scoring, remapping, etc.)
- Created 7 child issues (bd-10, bd-12-17) breaking down implementation
- Added design documents to .beads/ for future reference
- Updated issues JSONL with new issues and dependencies

Issues created:
- bd-10: Export dependencies in JSONL
- bd-12: Collision detection
- bd-13: Reference scoring algorithm
- bd-14: ID remapping with updates
- bd-15: CLI flags and reporting
- bd-16: Comprehensive tests
- bd-17: Documentation updates
- bd-18: Add design/notes fields to update command

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-10-12 14:41:58 -07:00
parent 19cd7d1887
commit 216f640ab4
5 changed files with 515 additions and 19 deletions

View File

@@ -0,0 +1,96 @@
# BUG FOUND: getNextID() uses alphabetical MAX instead of numerical
## Location
`internal/storage/sqlite/sqlite.go:60-84`, function `getNextID()`
## The Bug
```go
err := db.QueryRow("SELECT MAX(id) FROM issues").Scan(&maxID)
```
This uses alphabetical MAX on the text `id` column, not numerical MAX.
## Impact
When you have bd-1 through bd-10:
- Alphabetical sort: bd-1, bd-10, bd-2, bd-3, ... bd-9
- MAX(id) returns "bd-9" (alphabetically last)
- nextID is calculated as 10
- Creating a new issue tries to use bd-10, which already exists
- Result: UNIQUE constraint failed
## Reproduction
```bash
# After creating bd-1 through bd-10
./bd create "Test issue" -t task -p 1
# Error: failed to insert issue: UNIQUE constraint failed: issues.id
```
## The Fix
Option 1: Cast to integer in SQL (BEST)
```sql
SELECT MAX(CAST(SUBSTR(id, INSTR(id, '-') + 1) AS INTEGER)) FROM issues WHERE id LIKE 'bd-%'
```
Option 2: Pad IDs with zeros
- Change ID format from "bd-10" to "bd-0010"
- Alphabetical and numerical order match
- Breaks existing IDs
Option 3: Query all IDs and find max in Go
- Less efficient but more flexible
- Works with any ID format
## Recommended Solution
Option 1 with proper prefix handling:
```go
func getNextID(db *sql.DB) int {
// Get prefix from config (default "bd")
var prefix string
err := db.QueryRow("SELECT value FROM config WHERE key = 'issue_prefix'").Scan(&prefix)
if err != nil || prefix == "" {
prefix = "bd"
}
// Find max numeric ID for this prefix
var maxNum sql.NullInt64
query := `
SELECT MAX(CAST(SUBSTR(id, LENGTH(?) + 2) AS INTEGER))
FROM issues
WHERE id LIKE ? || '-%'
`
err = db.QueryRow(query, prefix, prefix).Scan(&maxNum)
if err != nil || !maxNum.Valid {
return 1
}
return int(maxNum.Int64) + 1
}
```
## Workaround for Now
Manually specify IDs when creating issues:
```bash
# This won't work because auto-ID fails:
./bd create "Title" -t task -p 1
# Workaround - manually calculate next ID:
./bd list | grep -oE 'bd-[0-9]+' | sed 's/bd-//' | sort -n | tail -1
# Then add 1 and create with explicit ID in code
```
Or fix the bug first before continuing!
## Related to bd-9
This bug is EXACTLY the kind of distributed ID collision problem that bd-9 is designed to solve! But we should also fix the root cause.
## Created Issue
Should create: "Fix getNextID() to use numerical MAX instead of alphabetical"
- Type: bug
- Priority: 0 (critical - blocks all new issue creation)
- Blocks: bd-9 (can't create child issues)

View File

@@ -0,0 +1,86 @@
# Child Issues for BD-9: Collision Resolution
## Issues to Create
These issues break down bd-9 into implementable chunks. Link them all to bd-9 as parent-child dependencies.
### Issue 1: Extend export to include dependencies
**Title**: Extend export to include dependencies in JSONL
**Type**: task
**Priority**: 1
**Description**: Modify export.go to include dependencies array in each issue's JSONL output. This makes JSONL self-contained and enables proper collision resolution. Format: {"id":"bd-10","dependencies":[{"depends_on_id":"bd-5","type":"blocks"}]}
**Command**: `bd create "Extend export to include dependencies in JSONL" -t task -p 1 -d "Modify export.go to include dependencies array in each issue's JSONL output. This makes JSONL self-contained and enables proper collision resolution. Format: {\"id\":\"bd-10\",\"dependencies\":[{\"depends_on_id\":\"bd-5\",\"type\":\"blocks\"}]}"`
### Issue 2: Implement collision detection
**Title**: Implement collision detection in import
**Type**: task
**Priority**: 1
**Description**: Create collision.go with detectCollisions() function. Compare incoming JSONL issues against DB state. Distinguish between: (1) exact match (idempotent), (2) ID match but different content (collision), (3) new issue. Return list of colliding issues.
**Command**: `bd create "Implement collision detection in import" -t task -p 1 -d "Create collision.go with detectCollisions() function. Compare incoming JSONL issues against DB state. Distinguish between: (1) exact match (idempotent), (2) ID match but different content (collision), (3) new issue. Return list of colliding issues."`
### Issue 3: Implement reference scoring
**Title**: Implement reference scoring algorithm
**Type**: task
**Priority**: 1
**Description**: Count references for each colliding issue: text mentions in descriptions/notes/design fields + dependency references. Sort collisions by score ascending (fewest refs first). This minimizes total updates during renumbering.
**Command**: `bd create "Implement reference scoring algorithm" -t task -p 1 -d "Count references for each colliding issue: text mentions in descriptions/notes/design fields + dependency references. Sort collisions by score ascending (fewest refs first). This minimizes total updates during renumbering."`
### Issue 4: Implement ID remapping
**Title**: Implement ID remapping with reference updates
**Type**: task
**Priority**: 1
**Description**: Allocate new IDs for colliding issues. Update all text field references using word-boundary regex (\bbd-10\b). Update dependency records. Build id_mapping for reporting. Handle chain dependencies properly.
**Command**: `bd create "Implement ID remapping with reference updates" -t task -p 1 -d "Allocate new IDs for colliding issues. Update all text field references using word-boundary regex (\\bbd-10\\b). Update dependency records. Build id_mapping for reporting. Handle chain dependencies properly."`
### Issue 5: Add CLI flags
**Title**: Add --resolve-collisions flag and user reporting
**Type**: task
**Priority**: 1
**Description**: Add import flags: --resolve-collisions (auto-fix) and --dry-run (preview). Display clear report: collisions detected, remappings applied (old→new with scores), reference counts updated. Default behavior: fail on collision (safe).
**Command**: `bd create "Add --resolve-collisions flag and user reporting" -t task -p 1 -d "Add import flags: --resolve-collisions (auto-fix) and --dry-run (preview). Display clear report: collisions detected, remappings applied (old→new with scores), reference counts updated. Default behavior: fail on collision (safe)."`
### Issue 6: Write tests
**Title**: Write comprehensive collision resolution tests
**Type**: task
**Priority**: 1
**Description**: Test cases: simple collision, multiple collisions, dependency updates, text reference updates, chain dependencies, edge cases (partial ID matches, case sensitivity, triple merges). Add to import_test.go and collision_test.go.
**Command**: `bd create "Write comprehensive collision resolution tests" -t task -p 1 -d "Test cases: simple collision, multiple collisions, dependency updates, text reference updates, chain dependencies, edge cases (partial ID matches, case sensitivity, triple merges). Add to import_test.go and collision_test.go."`
### Issue 7: Update docs
**Title**: Update documentation for collision resolution
**Type**: task
**Priority**: 1
**Description**: Update README.md with collision resolution section. Update CLAUDE.md with new workflow. Document --resolve-collisions and --dry-run flags. Add example scenarios showing branch merge workflows.
**Command**: `bd create "Update documentation for collision resolution" -t task -p 1 -d "Update README.md with collision resolution section. Update CLAUDE.md with new workflow. Document --resolve-collisions and --dry-run flags. Add example scenarios showing branch merge workflows."`
## Additional Feature Issue
### Issue: Add design field support to update command
**Title**: Add design/notes/acceptance_criteria fields to update command
**Type**: feature
**Priority**: 2
**Description**: Currently bd update only supports status, priority, title, assignee. Add support for --design, --notes, --acceptance-criteria flags. This makes it easier to add detailed designs to issues after creation.
**Command**: `bd create "Add design/notes/acceptance_criteria fields to update command" -t feature -p 2 -d "Currently bd update only supports status, priority, title, assignee. Add support for --design, --notes, --acceptance-criteria flags. This makes it easier to add detailed designs to issues after creation."`
## Dependency Linking
After creating all child issues, link them to bd-9:
```bash
# Assuming the issues are bd-10 through bd-16 (or whatever IDs were assigned)
bd dep add <child-id> bd-9 --type parent-child
```
Example:
```bash
bd dep add bd-10 bd-9 --type parent-child
bd dep add bd-11 bd-9 --type parent-child
bd dep add bd-12 bd-9 --type parent-child
# etc.
```
## Current State
- bd-10 was created successfully ("Extend export to include dependencies")
- bd-11+ attempts failed with UNIQUE constraint errors
- This suggests those IDs already exist in the DB but may not be in the JSONL file
- Need to investigate DB/JSONL sync issue before creating more issues

303
.beads/bd-9-design.md Normal file
View File

@@ -0,0 +1,303 @@
# BD-9: Collision Resolution Design Document
**Status**: In progress, design complete, ready for implementation
**Date**: 2025-10-12
**Issue**: bd-9 - Build collision resolution tooling for distributed branch workflows
## Problem Statement
When branches diverge and both create issues, auto-incrementing IDs collide on merge:
- Branch A creates bd-10, bd-11, bd-12
- Branch B (diverged) creates bd-10, bd-11, bd-12 (different issues!)
- On merge: 6 issues, but 3 duplicate IDs
- References to "bd-10" in descriptions/dependencies are now ambiguous
## Design Goals
1. **Preserve brevity** - Keep bd-302 format, not bd-302-branch-a-uuid-mess
2. **Minimize disruption** - Renumber issues with fewer references
3. **Update all references** - Text fields AND dependency table
4. **Atomic operation** - All or nothing
5. **Clear feedback** - User must understand what changed
## Algorithm Design
### Phase 1: Collision Detection
```
Input: JSONL issues + current DB state
Output: Set of colliding issues
for each issue in JSONL:
if DB contains issue.ID:
if DB issue == JSONL issue:
skip (already imported, idempotent)
else:
mark as COLLISION
```
### Phase 2: Reference Counting (The Smart Part)
Renumber issues with FEWER references first because:
- If bd-10 is referenced 20 times and bd-11 once
- Renumbering bd-11→bd-15 updates 1 reference
- Renumbering bd-10→bd-15 updates 20 references
```
for each colliding_issue:
score = 0
// Count text references in OTHER issues
for each other_issue in JSONL:
score += count_mentions(other_issue.all_text, colliding_issue.ID)
// Count dependency references
deps = DB.get_dependents(colliding_issue.ID) // who depends on me?
score += len(deps)
// Store score
collision_scores[colliding_issue.ID] = score
// Sort ascending: lowest score = fewest references = renumber first
sorted_collisions = sort_by(collision_scores)
```
### Phase 3: ID Allocation
```
id_mapping = {} // old_id -> new_id
next_num = DB.get_next_id_number()
for collision in sorted_collisions:
// Find next available ID
while true:
candidate = f"{prefix}-{next_num}"
if not DB.exists(candidate) and candidate not in id_mapping.values():
id_mapping[collision.ID] = candidate
next_num++
break
next_num++
```
### Phase 4: Reference Updates
This is the trickiest part - must update:
1. Issue IDs themselves
2. Text field references (description, design, notes, acceptance_criteria)
3. Dependency records (when they reference old IDs)
```
updated_issues = []
reference_update_count = 0
for issue in JSONL:
new_issue = clone(issue)
// 1. Update own ID if it collided
if issue.ID in id_mapping:
new_issue.ID = id_mapping[issue.ID]
// 2. Update text field references
for old_id, new_id in id_mapping:
for field in [title, description, design, notes, acceptance_criteria]:
if field:
pattern = r'\b' + re.escape(old_id) + r'\b'
new_text, count = re.subn(pattern, new_id, field)
field = new_text
reference_update_count += count
updated_issues.append(new_issue)
```
### Phase 5: Dependency Handling
**Approach A: Export dependencies in JSONL** (PREFERRED)
- Extend export to include `"dependencies": [{...}]` per issue
- Import dependencies along with issues
- Update dependency records during phase 4
Why preferred:
- Self-contained JSONL (better for git workflow)
- Easier to reason about
- Can detect cross-file dependencies
### Phase 6: Atomic Import
```
transaction:
for issue in updated_issues:
if issue.ID was remapped:
DB.create_issue(issue)
else:
DB.upsert_issue(issue)
// Update dependency table
for issue in updated_issues:
for dep in issue.dependencies:
// dep IDs already updated in phase 4
DB.create_or_update_dependency(dep)
commit
```
### Phase 7: User Reporting
```
report = {
collisions_detected: N,
remappings: [
"bd-10 → bd-15 (Score: 3 references)",
"bd-11 → bd-16 (Score: 15 references)",
],
text_updates: M,
dependency_updates: K,
}
```
## Edge Cases
1. **Chain dependencies**: bd-10 depends on bd-11, both collide
- Sorted renumbering handles this naturally
- Lower-referenced one renumbered first
2. **Circular dependencies**: Shouldn't happen (DB has cycle detection)
3. **Partial ID matches**: "bd-1" shouldn't match "bd-10"
- Use word boundary regex: `\bbd-10\b`
4. **Case sensitivity**: IDs are case-sensitive (bd-10 ≠ BD-10)
5. **IDs in code blocks**: Will be replaced
- Could add `--preserve-code-blocks` flag later
6. **Triple merges**: Branch A, B, C all create bd-10
- Algorithm handles N collisions
7. **Dependencies pointing to DB-only issues**:
- JSONL issue depends on bd-999 (only in DB)
- No collision, works fine
## Performance Considerations
- O(N*M) for reference counting (N issues × M collisions)
- For 1000 issues, 10 collisions: 10,000 text scans
- Acceptable for typical use (hundreds of issues)
- Could optimize with index/trie if needed
## API Design
```bash
# Default: fail on collision (safe)
bd import -i issues.jsonl
# Error: Collision detected: bd-10 already exists
# With auto-resolution
bd import -i issues.jsonl --resolve-collisions
# Resolved 3 collisions:
# bd-10 → bd-15 (3 refs)
# bd-11 → bd-16 (1 ref)
# bd-12 → bd-17 (7 refs)
# Imported 45 issues, updated 23 references
# Dry run (preview changes)
bd import -i issues.jsonl --resolve-collisions --dry-run
```
## Implementation Breakdown
### Child Issues to Create
1. **bd-10**: Extend export to include dependencies in JSONL
- Modify export.go to include dependencies array
- Format: `{"id":"bd-10","dependencies":[{"depends_on_id":"bd-5","type":"blocks"}]}`
- Priority: 1, Type: task
2. **bd-11**: Implement collision detection in import
- Create collision.go with detectCollisions() function
- Compare incoming JSONL against DB state
- Distinguish: exact match (skip), collision (flag), new (create)
- Priority: 1, Type: task
3. **bd-12**: Implement reference scoring algorithm
- Count text mentions + dependency references
- Sort collisions by score ascending (fewest refs first)
- Minimize total updates during renumbering
- Priority: 1, Type: task
4. **bd-13**: Implement ID remapping with reference updates
- Allocate new IDs for colliding issues
- Update text field references with word-boundary regex
- Update dependency records
- Build id_mapping for reporting
- Priority: 1, Type: task
5. **bd-14**: Add --resolve-collisions flag and user reporting
- Add import flags: --resolve-collisions, --dry-run
- Display clear report with remappings and counts
- Default: fail on collision (safe)
- Priority: 1, Type: task
6. **bd-15**: Write comprehensive collision resolution tests
- Test cases: simple/multiple collisions, dependencies, text refs
- Edge cases: partial matches, case sensitivity, triple merges
- Add to import_test.go and collision_test.go
- Priority: 1, Type: task
7. **bd-16**: Update documentation for collision resolution
- Update README.md with collision resolution section
- Update CLAUDE.md with new workflow
- Document flags and example scenarios
- Priority: 1, Type: task
### Additional Issue: Add Design Field Support
**NEW ISSUE**: Add design field to bd update command
- Currently: `bd update` doesn't support --design flag (discovered during work)
- Need: Allow updating design, notes, acceptance_criteria fields
- This would make bd-9's design easier to attach to the issue itself
- Priority: 2, Type: feature
## Current State
- bd-9 is in_progress (claimed)
- bd-10 was successfully created (first child issue)
- bd-11+ creation failed with UNIQUE constraint (collision!)
- This demonstrates the exact problem we're solving
- Need to manually create remaining issues with different IDs
- Or implement collision resolution first! (chicken/egg)
## Data Structures Involved
- **Issues table**: id, title, description, design, notes, acceptance_criteria, status, priority, issue_type, assignee, estimated_minutes, created_at, updated_at, closed_at
- **Dependencies table**: issue_id, depends_on_id, type, created_at, created_by
- **Text fields with ID references**: description, design, notes, acceptance_criteria (title too?)
## Files to Modify
1. `cmd/bd/export.go` - Add dependency export
2. `cmd/bd/import.go` - Call collision resolution
3. `cmd/bd/collision.go` - NEW FILE - Core algorithm
4. `cmd/bd/collision_test.go` - NEW FILE - Tests
5. `internal/types/types.go` - May need collision report types
6. `README.md` - Documentation
7. `CLAUDE.md` - AI agent workflow docs
## Next Steps
1. ✅ Design complete
2. 🔄 Create child issues (bd-10 created, bd-11+ need different IDs)
3. ⏳ Implement Phase 1: Export enhancement
4. ⏳ Implement Phase 2-7: Core algorithm
5. ⏳ Tests
6. ⏳ Documentation
7. ⏳ Export issues to JSONL before committing
## Meta: Real Collision Encountered!
While creating child issues, we hit the exact problem:
- bd-10 was created successfully
- bd-11, bd-12, bd-13, bd-14, bd-15, bd-16 all failed with "UNIQUE constraint failed"
- This means the DB already has bd-11+ from a previous session/import
- Perfect demonstration of why we need collision resolution!
Resolution: Create remaining child issues manually with explicit IDs after checking what exists.

View File

@@ -1,8 +1,18 @@
{"id":"bd-1","title":"Add export/import commands","description":"Support bd export --format=jsonl and bd import for text-based git workflow","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-12T00:43:03.453438-07:00","updated_at":"2025-10-12T00:43:03.453438-07:00"}
{"id":"bd-2","title":"Add PostgreSQL backend","description":"Implement PostgreSQL storage backend as alternative to SQLite for larger teams","status":"open","priority":3,"issue_type":"feature","created_at":"2025-10-12T00:43:03.457453-07:00","updated_at":"2025-10-12T00:43:03.457453-07:00"}
{"id":"bd-10","title":"Extend export to include dependencies in JSONL","description":"Modify export.go to include dependencies array in each issue's JSONL output. This makes JSONL self-contained and enables proper collision resolution. Format: {\"id\":\"bd-10\",\"dependencies\":[{\"depends_on_id\":\"bd-5\",\"type\":\"blocks\"}]}","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-12T14:32:19.163526-07:00","updated_at":"2025-10-12T14:32:19.163526-07:00"}
{"id":"bd-11","title":"Test issue to verify fix","description":"This should be bd-11 if the fix works","status":"closed","priority":3,"issue_type":"task","created_at":"2025-10-12T14:40:21.419082-07:00","updated_at":"2025-10-12T14:40:32.963312-07:00","closed_at":"2025-10-12T14:40:32.963312-07:00"}
{"id":"bd-12","title":"Implement collision detection in import","description":"Create collision.go with detectCollisions() function. Compare incoming JSONL issues against DB state. Distinguish between: (1) exact match (idempotent), (2) ID match but different content (collision), (3) new issue. Return list of colliding issues.","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.056588-07:00","updated_at":"2025-10-12T14:40:56.056588-07:00"}
{"id":"bd-13","title":"Implement reference scoring algorithm","description":"Count references for each colliding issue: text mentions in descriptions/notes/design fields + dependency references. Sort collisions by score ascending (fewest refs first). This minimizes total updates during renumbering.","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.204518-07:00","updated_at":"2025-10-12T14:40:56.204518-07:00"}
{"id":"bd-14","title":"Implement ID remapping with reference updates","description":"Allocate new IDs for colliding issues. Update all text field references using word-boundary regex (\\bbd-10\\b). Update dependency records. Build id_mapping for reporting. Handle chain dependencies properly.","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.367596-07:00","updated_at":"2025-10-12T14:40:56.367596-07:00"}
{"id":"bd-15","title":"Add --resolve-collisions flag and user reporting","description":"Add import flags: --resolve-collisions (auto-fix) and --dry-run (preview). Display clear report: collisions detected, remappings applied (old→new with scores), reference counts updated. Default behavior: fail on collision (safe).","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.534721-07:00","updated_at":"2025-10-12T14:40:56.534721-07:00"}
{"id":"bd-16","title":"Write comprehensive collision resolution tests","description":"Test cases: simple collision, multiple collisions, dependency updates, text reference updates, chain dependencies, edge cases (partial ID matches, case sensitivity, triple merges). Add to import_test.go and collision_test.go.","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.702127-07:00","updated_at":"2025-10-12T14:40:56.702127-07:00"}
{"id":"bd-17","title":"Update documentation for collision resolution","description":"Update README.md with collision resolution section. Update CLAUDE.md with new workflow. Document --resolve-collisions and --dry-run flags. Add example scenarios showing branch merge workflows.","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-12T14:40:56.866649-07:00","updated_at":"2025-10-12T14:40:56.866649-07:00"}
{"id":"bd-18","title":"Add design/notes/acceptance_criteria fields to update command","description":"Currently bd update only supports status, priority, title, assignee. Add support for --design, --notes, --acceptance-criteria flags. This makes it easier to add detailed designs to issues after creation.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-12T14:40:57.032395-07:00","updated_at":"2025-10-12T14:40:57.032395-07:00"}
{"id":"bd-2","title":"Add PostgreSQL backend","description":"Implement PostgreSQL storage backend as alternative to SQLite for larger teams","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-12T00:43:03.457453-07:00","updated_at":"2025-10-12T14:15:04.00695-07:00","closed_at":"2025-10-12T14:15:04.00695-07:00"}
{"id":"bd-3","title":"Document git workflow in README","description":"Add Git Workflow section to README explaining binary vs text approaches","status":"closed","priority":1,"issue_type":"chore","created_at":"2025-10-12T00:43:03.461615-07:00","updated_at":"2025-10-12T00:43:30.283178-07:00","closed_at":"2025-10-12T00:43:30.283178-07:00"}
{"id":"bd-4","title":"Add demo GIF/video showing bd quickstart in action","description":"Record asciinema or create animated GIF showing the full workflow","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-12T10:50:49.500051-07:00","updated_at":"2025-10-12T10:50:49.500051-07:00"}
{"id":"bd-5","title":"Implement MCP server for Claude Desktop","description":"Complete the claude-desktop-mcp example with working TypeScript implementation","status":"open","priority":1,"issue_type":"feature","created_at":"2025-10-12T10:50:50.942964-07:00","updated_at":"2025-10-12T10:50:50.942964-07:00"}
{"id":"bd-6","title":"Add migration scripts for GitHub Issues","description":"Create scripts to import from GitHub Issues API or exported JSON","status":"open","priority":2,"issue_type":"feature","created_at":"2025-10-12T10:50:52.140018-07:00","updated_at":"2025-10-12T10:50:52.140018-07:00"}
{"id":"bd-7","title":"Add performance benchmarks document","description":"Document actual performance metrics with hyperfine tests","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-12T10:50:53.294516-07:00","updated_at":"2025-10-12T10:50:53.294516-07:00"}
{"id":"bd-8","title":"Reach 1.0 release milestone","description":"Stabilize API, finalize documentation, comprehensive testing","status":"open","priority":1,"issue_type":"epic","created_at":"2025-10-12T10:50:54.457348-07:00","updated_at":"2025-10-12T10:50:54.457348-07:00"}
{"id":"bd-9","title":"Build collision resolution tooling for distributed branch workflows","description":"When branches diverge and both create issues, auto-incrementing IDs collide on merge. Build excellent tooling to detect collisions during import, auto-renumber issues with fewer dependencies, update all references in descriptions and dependency links, and provide clear user feedback. Goal: keep beautiful brevity of numeric IDs (bd-302) while handling distributed creation gracefully.","status":"in_progress","priority":1,"issue_type":"feature","created_at":"2025-10-12T13:39:34.608218-07:00","updated_at":"2025-10-12T14:19:11.103828-07:00"}

View File

@@ -59,28 +59,29 @@ func New(path string) (*SQLiteStorage, error) {
// getNextID determines the next issue ID to use
func getNextID(db *sql.DB) int {
var maxID sql.NullString
err := db.QueryRow("SELECT MAX(id) FROM issues").Scan(&maxID)
if err != nil {
return 1 // Start from 1 if table is empty
// Get prefix from config, default to "bd"
var prefix string
err := db.QueryRow("SELECT value FROM config WHERE key = 'issue_prefix'").Scan(&prefix)
if err != nil || prefix == "" {
prefix = "bd"
}
if !maxID.Valid || maxID.String == "" {
return 1
// Find the maximum numeric ID for this prefix
// Use SUBSTR to extract numeric part after prefix and hyphen, then CAST to INTEGER
// This ensures we get numerical max, not alphabetical (bd-10 > bd-9, not bd-9 > bd-10)
var maxNum sql.NullInt64
query := `
SELECT MAX(CAST(SUBSTR(id, LENGTH(?) + 2) AS INTEGER))
FROM issues
WHERE id LIKE ? || '-%'
AND SUBSTR(id, 1, LENGTH(?)) = ?
`
err = db.QueryRow(query, prefix, prefix, prefix, prefix).Scan(&maxNum)
if err != nil || !maxNum.Valid {
return 1 // Start from 1 if table is empty or no matching IDs
}
// Parse "bd-123" to get 123
parts := strings.Split(maxID.String, "-")
if len(parts) != 2 {
return 1
}
var num int
if _, err := fmt.Sscanf(parts[1], "%d", &num); err != nil {
return 1
}
return num + 1
return int(maxNum.Int64) + 1
}
// CreateIssue creates a new issue