Fix bd-166: Prevent duplicate issues with wrong prefix

Critical fix for silent data corruption where database created 173
duplicate issues with wrong prefix (beads- instead of bd-).

Root cause: When issue_prefix config was missing, CreateIssue fell
back to deriving prefix from database filename (beads.db → 'beads'),
while auto-import imported bd- issues from git with SkipPrefixValidation.
This created duplicates.

Changes:
1. Removed derivePrefixFromPath() - never derive prefix from filename
2. CreateIssue/CreateIssues now REJECT if issue_prefix config missing
   - Fail-fast with clear error message
3. Auto-import now SETS issue_prefix from first imported issue if missing
   - Handles fresh clone scenario safely
4. Added newTestStore() helper that sets issue_prefix for tests
5. Updated test setup in multiple files to prevent test failures

Follow-ups filed: bd-167, bd-168, bd-169

Closes bd-166

Amp-Thread-ID: https://ampcode.com/threads/T-b2ee0738-b90b-40ef-ae44-f2d93729842c
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Steve Yegge
2025-10-26 21:55:01 -07:00
parent 669c054332
commit 09e881022e
11 changed files with 108 additions and 40 deletions

View File

@@ -161,10 +161,7 @@ func TestDaemonIntegration(t *testing.T) {
}
testDBPath := filepath.Join(dbDir, "test.db")
testStore, err := sqlite.New(testDBPath)
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
testStore := newTestStore(t, testDBPath)
oldStore := store
oldDBPath := dbPath
@@ -305,10 +302,7 @@ func TestDaemonRPCServerIntegration(t *testing.T) {
}
testDBPath := filepath.Join(dbDir, "test.db")
testStore, err := sqlite.New(testDBPath)
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
testStore := newTestStore(t, testDBPath)
defer testStore.Close()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
@@ -342,10 +336,7 @@ func TestDaemonConcurrentOperations(t *testing.T) {
}
testDBPath := filepath.Join(dbDir, "test.db")
testStore, err := sqlite.New(testDBPath)
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
testStore := newTestStore(t, testDBPath)
defer testStore.Close()
ctx := context.Background()
@@ -410,10 +401,7 @@ func TestDaemonSocketCleanupOnShutdown(t *testing.T) {
socketPath := filepath.Join(tmpDir, "test.sock")
testDBPath := filepath.Join(tmpDir, "test.db")
testStore, err := sqlite.New(testDBPath)
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
testStore := newTestStore(t, testDBPath)
server := newMockDaemonServer(socketPath, testStore)
@@ -543,10 +531,7 @@ func TestDaemonGracefulShutdown(t *testing.T) {
socketPath := filepath.Join(tmpDir, "test.sock")
testDBPath := filepath.Join(tmpDir, "test.db")
testStore, err := sqlite.New(testDBPath)
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
testStore := newTestStore(t, testDBPath)
server := newMockDaemonServer(socketPath, testStore)