From d51ddb0b036fc74242543a8c5edb17b322d40911 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Wed, 26 Nov 2025 23:44:04 -0800 Subject: [PATCH] fix(beads): also fix FindJSONLPath to skip deletions.jsonl (bd-tqo) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code review follow-up: - Fix misleading docstring in FindJSONLInDir (does not return empty) - Fix same bug in beads.FindJSONLPath (also fell back to matches[0]) - Add comprehensive tests for FindJSONLPath skipping deletions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- internal/autoimport/autoimport.go | 2 +- internal/beads/beads.go | 20 +++++++++- internal/beads/beads_test.go | 62 +++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/internal/autoimport/autoimport.go b/internal/autoimport/autoimport.go index f82bf6bf..7cc0f96a 100644 --- a/internal/autoimport/autoimport.go +++ b/internal/autoimport/autoimport.go @@ -298,7 +298,7 @@ func CheckStaleness(ctx context.Context, store storage.Storage, dbPath string) ( // FindJSONLInDir finds the JSONL file in the given directory. // It prefers issues.jsonl over other .jsonl files to prevent accidentally // reading/writing to deletions.jsonl or merge artifacts (bd-tqo fix). -// Returns empty string if no suitable JSONL file is found. +// Always returns a path (defaults to issues.jsonl if nothing suitable found). func FindJSONLInDir(dbDir string) string { pattern := filepath.Join(dbDir, "*.jsonl") matches, err := filepath.Glob(pattern) diff --git a/internal/beads/beads.go b/internal/beads/beads.go index 8e07464e..7c0aba99 100644 --- a/internal/beads/beads.go +++ b/internal/beads/beads.go @@ -281,8 +281,24 @@ func FindJSONLPath(dbPath string) string { return match } } - // Return the first .jsonl file found if issues.jsonl not present - return matches[0] + // bd-tqo: Fall back to beads.jsonl for legacy support + for _, match := range matches { + if filepath.Base(match) == "beads.jsonl" { + return match + } + } + // bd-tqo: Skip deletions.jsonl and merge artifacts to prevent corruption + for _, match := range matches { + base := filepath.Base(match) + if base == "deletions.jsonl" || + base == "beads.base.jsonl" || + base == "beads.left.jsonl" || + base == "beads.right.jsonl" { + continue + } + return match + } + // If only deletions/merge files exist, fall through to default } // bd-6xd: Default to issues.jsonl (canonical name) diff --git a/internal/beads/beads_test.go b/internal/beads/beads_test.go index 63a7d515..bd9a5fc3 100644 --- a/internal/beads/beads_test.go +++ b/internal/beads/beads_test.go @@ -220,6 +220,68 @@ func TestFindJSONLPathMultipleFiles(t *testing.T) { } } +// TestFindJSONLPathSkipsDeletions verifies that FindJSONLPath skips deletions.jsonl +// and merge artifacts to prevent corruption (bd-tqo fix) +func TestFindJSONLPathSkipsDeletions(t *testing.T) { + tests := []struct { + name string + files []string + expected string + }{ + { + name: "prefers issues.jsonl over deletions.jsonl", + files: []string{"deletions.jsonl", "issues.jsonl"}, + expected: "issues.jsonl", + }, + { + name: "skips deletions.jsonl when only option", + files: []string{"deletions.jsonl"}, + expected: "issues.jsonl", // Falls back to default + }, + { + name: "skips merge artifacts", + files: []string{"beads.base.jsonl", "beads.left.jsonl", "issues.jsonl"}, + expected: "issues.jsonl", + }, + { + name: "prefers issues over beads", + files: []string{"beads.jsonl", "issues.jsonl"}, + expected: "issues.jsonl", + }, + { + name: "uses beads.jsonl as legacy fallback", + files: []string{"beads.jsonl", "deletions.jsonl"}, + expected: "beads.jsonl", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpDir, err := os.MkdirTemp("", "beads-jsonl-test-*") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + // Create test files + for _, file := range tt.files { + path := filepath.Join(tmpDir, file) + if err := os.WriteFile(path, []byte("{}"), 0644); err != nil { + t.Fatal(err) + } + } + + dbPath := filepath.Join(tmpDir, "test.db") + result := FindJSONLPath(dbPath) + expected := filepath.Join(tmpDir, tt.expected) + + if result != expected { + t.Errorf("FindJSONLPath() = %q, want %q", result, expected) + } + }) + } +} + func TestFindDatabasePathHomeDefault(t *testing.T) { // This test verifies that if no database is found, it falls back to home directory // We can't reliably test this without modifying the home directory, so we'll skip