Motivation
- Small databases (0-500 issues): Very short, readable IDs like
bd-a3f2(4 chars) - Medium databases (500-1500 issues): Slightly longer IDs like
bd-7f3a8(5 chars) - Large databases (1500+ issues): Standard IDs like
bd-7f3a86(6 chars)
How It Works
Birthday Paradox Math
The collision probability is calculated using:n= number of issues in databaseN= total possible IDs (36^length for lowercase alphanumeric)
Default Thresholds (25% max collision)
| Database Size | ID Length | Collision Probability |
|---|---|---|
| 0-500 | 4 chars | ~7% at 500 |
| 501-1500 | 5 chars | ~2% at 1500 |
| 1501+ | 6 chars | continues scaling |
Collision Resolution
If a collision occurs (rare), the algorithm automatically tries:- Base length (e.g., 4 chars)
- Base + 1 (e.g., 5 chars)
- Base + 2 (e.g., 6 chars)
Configuration
Adaptive ID length is automatically enabled when usingid_mode=hash. You can customize the behavior:
Max Collision Probability
Default: 25% (0.25)Minimum Hash Length
Default: 4 charsMaximum Hash Length
Default: 8 charsExamples
Default Configuration
Custom Configuration
Collision Probability Table
Usescripts/collision-calculator.go to explore collision probabilities:
- Collision probabilities for different database sizes and ID lengths
- Recommended ID lengths for different thresholds
- Expected number of collisions
- Adaptive scaling strategy
Implementation Details
Location
- Algorithm:
internal/storage/dolt/adaptive_length.go - ID generation:
internal/storage/dolt/dolt.go(generateHashID) - Tests:
internal/storage/dolt/adaptive_length_test.go - E2E tests:
internal/storage/dolt/adaptive_e2e_test.go
Database Schema
Configuration is stored in theconfig table:
Performance
- Collision probability calculation: ~10ns per call
- ID generation with adaptive length: ~300ns (same as before)
- Database query to count issues: ~100μs
Migration
Existing Databases
Existing databases with 6-char IDs will:- Continue using 6-char IDs by default
- Can opt into adaptive mode by setting config (new IDs will use adaptive length)
- Old IDs remain unchanged
Sequential to Hash Migration
When migrating from sequential IDs to hash IDs withbd migrate --to-hash-ids:
- Uses adaptive length algorithm for new IDs
- Preserves existing sequential IDs
- References are automatically updated
Best Practices
- Default is good: The 25% threshold works well for most use cases
- Active archival: Delete closed issues to keep database small and IDs short
- Consistency: Set
min_hash_lengthif you want all IDs to be same length - Monitoring: Run collision calculator periodically to check health
Future Enhancements
Potential improvements (not yet implemented):- Automatic scaling notifications: Warn when approaching threshold
- Per-workspace thresholds: Different configs for different projects
- Dynamic adjustment: Auto-adjust threshold based on observed collision rate
- Compaction-aware: Don’t count compacted issues in collision calculation
Alternative: Sequential Counter IDs
Adaptive hash IDs are the default, but beads also supports sequential integer IDs (bd-1, bd-2, …) for projects that prefer human-readable numbering.
Counter mode is controlled by the issue_id_mode config key:
- Hash IDs (this document): Collision-free across parallel branches and agents; IDs are less predictable but always unique.
- Counter IDs: Human-friendly and sequential; require care in multi-branch workflows where counters can diverge.
issue_id_mode=counter, including migration
guidance and per-prefix counter isolation.
Related
- Migration Guide - Converting from sequential to hash IDs
- Configuration - All configuration options