From d5b64bf35148d8a2cdd874469b09296dcd5d471f Mon Sep 17 00:00:00 2001 From: Wayne Smith Date: Sat, 28 Mar 2026 16:55:40 +0200 Subject: [PATCH 1/5] Fix search to be cross-board by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit search called defaultBoard() which injected the configured default board into every query, silently scoping results to a single board. This made --tag and --assignee filters appear broken when matching cards existed on other boards. Search should be cross-board by default — only scope to a board when --board is explicitly passed. Closes #113 Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/commands/search.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/commands/search.go b/internal/commands/search.go index 21e3007..aa93fec 100644 --- a/internal/commands/search.go +++ b/internal/commands/search.go @@ -42,10 +42,10 @@ var searchCmd = &cobra.Command{ params = append(params, "terms[]="+term) } - // Add optional filters - boardID := defaultBoard(searchBoard) - if boardID != "" { - params = append(params, "board_ids[]="+boardID) + // Add optional filters (search is cross-board by default; + // only scope to a board when explicitly requested via --board) + if searchBoard != "" { + params = append(params, "board_ids[]="+searchBoard) } if searchTag != "" { params = append(params, "tag_ids[]="+searchTag) From dc254ddc94d0094f5c1ec3157666d495ae3dd542 Mon Sep 17 00:00:00 2001 From: Wayne Smith Date: Sat, 28 Mar 2026 17:10:16 +0200 Subject: [PATCH 2/5] Add test: search does not inject default board Verifies that setting cfg.Board does not cause board_ids[] to appear in the search path when --board is not explicitly passed. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/commands/search_test.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/internal/commands/search_test.go b/internal/commands/search_test.go index 4cdace6..54256bd 100644 --- a/internal/commands/search_test.go +++ b/internal/commands/search_test.go @@ -122,6 +122,29 @@ func TestSearch(t *testing.T) { } }) + t.Run("does not inject default board into search", func(t *testing.T) { + mock := NewMockClient() + mock.GetWithPaginationResponse = &client.APIResponse{ + StatusCode: 200, + Data: []any{}, + } + + SetTestModeWithSDK(mock) + SetTestConfig("token", "account", "https://api.example.com") + cfg.Board = "default-board-id" + defer resetTest() + + searchBoard = "" + err := searchCmd.RunE(searchCmd, []string{"bug"}) + searchBoard = "" + + assertExitCode(t, err, 0) + path := mock.GetWithPaginationCalls[0].Path + if path != "/cards.json?terms[]=bug" { + t.Errorf("expected no board_ids in path, got '%s'", path) + } + }) + t.Run("requires authentication", func(t *testing.T) { mock := NewMockClient() SetTestModeWithSDK(mock) From d022b45120eb679865cddabb8c5571942d9245dc Mon Sep 17 00:00:00 2001 From: Wayne Smith Date: Sat, 28 Mar 2026 17:16:38 +0200 Subject: [PATCH 3/5] Assert call count before indexing in search test Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/commands/search_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/commands/search_test.go b/internal/commands/search_test.go index 54256bd..018c1f5 100644 --- a/internal/commands/search_test.go +++ b/internal/commands/search_test.go @@ -139,6 +139,9 @@ func TestSearch(t *testing.T) { searchBoard = "" assertExitCode(t, err, 0) + if len(mock.GetWithPaginationCalls) != 1 { + t.Fatalf("expected 1 GetWithPagination call, got %d", len(mock.GetWithPaginationCalls)) + } path := mock.GetWithPaginationCalls[0].Path if path != "/cards.json?terms[]=bug" { t.Errorf("expected no board_ids in path, got '%s'", path) From 36b26906123efe354abd78f24c883967cb341eb5 Mon Sep 17 00:00:00 2001 From: Wayne Smith Date: Sun, 29 Mar 2026 08:05:07 +0200 Subject: [PATCH 4/5] Add tests for cross-board --tag and --assignee search Verify that --tag and --assignee filters work cross-board when a default board is configured: the request path includes tag_ids[]/assignee_ids[] but not board_ids[]. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/commands/search_test.go | 52 ++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/internal/commands/search_test.go b/internal/commands/search_test.go index 018c1f5..79b9439 100644 --- a/internal/commands/search_test.go +++ b/internal/commands/search_test.go @@ -148,6 +148,58 @@ func TestSearch(t *testing.T) { } }) + t.Run("tag filter works cross-board with default board set", func(t *testing.T) { + mock := NewMockClient() + mock.GetWithPaginationResponse = &client.APIResponse{ + StatusCode: 200, + Data: []any{}, + } + + SetTestModeWithSDK(mock) + SetTestConfig("token", "account", "https://api.example.com") + cfg.Board = "default-board-id" + defer resetTest() + + searchTag = "tag-123" + err := searchCmd.RunE(searchCmd, []string{"bug"}) + searchTag = "" + + assertExitCode(t, err, 0) + if len(mock.GetWithPaginationCalls) != 1 { + t.Fatalf("expected 1 GetWithPagination call, got %d", len(mock.GetWithPaginationCalls)) + } + path := mock.GetWithPaginationCalls[0].Path + if path != "/cards.json?terms[]=bug&tag_ids[]=tag-123" { + t.Errorf("expected tag filter without board_ids, got '%s'", path) + } + }) + + t.Run("assignee filter works cross-board with default board set", func(t *testing.T) { + mock := NewMockClient() + mock.GetWithPaginationResponse = &client.APIResponse{ + StatusCode: 200, + Data: []any{}, + } + + SetTestModeWithSDK(mock) + SetTestConfig("token", "account", "https://api.example.com") + cfg.Board = "default-board-id" + defer resetTest() + + searchAssignee = "user-456" + err := searchCmd.RunE(searchCmd, []string{"bug"}) + searchAssignee = "" + + assertExitCode(t, err, 0) + if len(mock.GetWithPaginationCalls) != 1 { + t.Fatalf("expected 1 GetWithPagination call, got %d", len(mock.GetWithPaginationCalls)) + } + path := mock.GetWithPaginationCalls[0].Path + if path != "/cards.json?terms[]=bug&assignee_ids[]=user-456" { + t.Errorf("expected assignee filter without board_ids, got '%s'", path) + } + }) + t.Run("requires authentication", func(t *testing.T) { mock := NewMockClient() SetTestModeWithSDK(mock) From c9c2d91c866054170b14daf0819e263d2a36d617 Mon Sep 17 00:00:00 2001 From: Wayne Smith Date: Sun, 29 Mar 2026 08:08:55 +0200 Subject: [PATCH 5/5] Remove redundant searchBoard assignments in tests Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/commands/search_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/commands/search_test.go b/internal/commands/search_test.go index 79b9439..be4feea 100644 --- a/internal/commands/search_test.go +++ b/internal/commands/search_test.go @@ -134,9 +134,7 @@ func TestSearch(t *testing.T) { cfg.Board = "default-board-id" defer resetTest() - searchBoard = "" err := searchCmd.RunE(searchCmd, []string{"bug"}) - searchBoard = "" assertExitCode(t, err, 0) if len(mock.GetWithPaginationCalls) != 1 {