Fix multiple issues and renumber database

- bd-170: Implement hybrid sorting for ready work (recent 48h first, then oldest)
- bd-87: Use safer null-byte placeholders in ID remapping
- bd-92: Make auto-flush debounce configurable via BEADS_FLUSH_DEBOUNCE
- bd-171: Fix nil pointer dereference in renumber command
- Delete spurious test issues (bd-7, bd-130-134)
- Renumber database from 171 down to 144 issues
This commit is contained in:
Steve Yegge
2025-10-18 09:58:35 -07:00
parent 9d78a66dc3
commit 6811d1cf42
6 changed files with 133 additions and 17 deletions

View File

@@ -43,7 +43,6 @@ var (
needsFullExport = false // Set to true when IDs change (renumber, rename-prefix)
flushMutex sync.Mutex
flushTimer *time.Timer
flushDebounce = 5 * time.Second
storeMutex sync.Mutex // Protects store access from background goroutine
storeActive = false // Tracks if store is available
flushFailureCount = 0 // Consecutive flush failures
@@ -189,6 +188,24 @@ var rootCmd = &cobra.Command{
},
}
// getDebounceDuration returns the auto-flush debounce duration
// Configurable via BEADS_FLUSH_DEBOUNCE (e.g., "500ms", "10s")
// Defaults to 5 seconds if not set or invalid
func getDebounceDuration() time.Duration {
envVal := os.Getenv("BEADS_FLUSH_DEBOUNCE")
if envVal == "" {
return 5 * time.Second
}
duration, err := time.ParseDuration(envVal)
if err != nil {
fmt.Fprintf(os.Stderr, "Warning: invalid BEADS_FLUSH_DEBOUNCE value '%s', using default 5s\n", envVal)
return 5 * time.Second
}
return duration
}
// shouldAutoStartDaemon checks if daemon auto-start is enabled
func shouldAutoStartDaemon() bool {
// Check environment variable (default: true)
@@ -737,7 +754,7 @@ func markDirtyAndScheduleFlush() {
}
// Schedule new flush
flushTimer = time.AfterFunc(flushDebounce, func() {
flushTimer = time.AfterFunc(getDebounceDuration(), func() {
flushToJSONL()
})
}
@@ -761,7 +778,7 @@ func markDirtyAndScheduleFullExport() {
}
// Schedule new flush
flushTimer = time.AfterFunc(flushDebounce, func() {
flushTimer = time.AfterFunc(getDebounceDuration(), func() {
flushToJSONL()
})
}

View File

@@ -114,9 +114,8 @@ func TestAutoFlushDebounce(t *testing.T) {
storeMutex.Unlock()
// Set short debounce for testing (100ms)
originalDebounce := flushDebounce
flushDebounce = 100 * time.Millisecond
defer func() { flushDebounce = originalDebounce }()
os.Setenv("BEADS_FLUSH_DEBOUNCE", "100ms")
defer os.Unsetenv("BEADS_FLUSH_DEBOUNCE")
// Reset auto-flush state
autoFlushEnabled = true

View File

@@ -46,6 +46,22 @@ Risks:
os.Exit(1)
}
// Renumber command needs direct access to storage
// Ensure we have a direct store connection
if store == nil {
var err error
if dbPath == "" {
fmt.Fprintf(os.Stderr, "Error: no database path found\n")
os.Exit(1)
}
store, err = sqlite.New(dbPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: failed to open database: %v\n", err)
os.Exit(1)
}
defer store.Close()
}
ctx := context.Background()
// Get prefix from config, or derive from first issue if not set