feat(tasks): search tasks by PR number in command panel#1268
Conversation
Typing a PR number (e.g. 1243 or #1243) in the Cmd+K panel now surfaces the task that PR is associated with, alongside the existing title/description/repo search. The github store gains a workspace-scoped ListTaskIDsByPRNumber lookup over github_task_prs; the task service resolves it through an injected PRTaskResolver interface (github service wired in cmd/kandev) and merges PR matches into search results, deduped and respecting the archived/ephemeral/config filters. Keeping the lookup at the service layer avoids coupling the task repository to the github schema, so existing search queries and tests are untouched.
📝 WalkthroughWalkthroughAdds workspace-scoped PR→task lookup in the GitHub store, exposes it via a new Service method, wires the GitHub service as a PR-task resolver into the task service, augments ListTasksByWorkspace to surface PR-matched tasks with deduplication and visibility filtering, and adds tests and repository batch APIs. ChangesPR-Number Task Search
Sequence Diagram(s)sequenceDiagram
participant Client
participant TaskService
participant GitHubService
participant Store
Client->>TaskService: ListTasksByWorkspace(query="`#123`", workspaceID)
TaskService->>GitHubService: FindTaskIDsByPRNumber(ctx, workspaceID, 123)
GitHubService->>Store: ListTaskIDsByPRNumber(ctx, workspaceID, 123)
Store-->>GitHubService: []taskID
GitHubService-->>TaskService: []taskID
TaskService->>TaskService: batch-load tasks, filter, dedupe, merge, update total
TaskService-->>Client: tasks, total
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Claude finished @zeval's task in 3m 6s —— View job Code Review
|
| Severity | Count |
|---|---|
| Blocker | 0 |
| Suggestion | 2 |
Verdict: Ready to merge — both suggestions are improvements on an already-correct implementation. The architecture (interface injection, workspace-scoped store query, test coverage across dedup/filter/nil-resolver cases) is solid. The PR description's note about approximate total is accurate and acceptable for the command panel's non-paginating use.
|
| Filename | Overview |
|---|---|
| apps/backend/internal/task/service/service_tasks.go | Core PR-search augmentation logic: parsePRQuery, augmentWithPRMatches, fetchPRMatchedTasks, prMatchFilteredOut, isConfigTask — all guard conditions (page, scoped searches, nil resolver) are correctly applied; dedup and total accounting are sound. |
| apps/backend/internal/github/store.go | Adds ListTaskIDsByPRNumber with workspace-scoped JOIN and a dedicated index on pr_number; DISTINCT handles multi-repo tasks correctly; index creation errors are intentionally ignored (CREATE INDEX IF NOT EXISTS). |
| apps/backend/internal/task/repository/sqlite/task.go | GetTasksByIDs builds a parameterized IN-clause query; uses read-only connection; empty-slice guard prevents a malformed SQL edge case. |
| apps/backend/internal/task/service/service_pr_search_test.go | Comprehensive test suite covering: PR match surfaces task, dedup, non-numeric query skips resolver, nil resolver no-panic, archived filter, and skip on page>1/scoped searches. |
| apps/backend/internal/github/store_pr_lookup_test.go | New test verifies workspace isolation (cross-workspace PR number does not leak), single match, and unknown PR returns empty — the minimal critical paths are covered. |
Sequence Diagram
sequenceDiagram
participant UI as Cmd+K Panel
participant SVC as task.Service
participant REPO as task.Repository (SQLite)
participant GH as github.Service
participant GHDB as github.Store (SQLite)
UI->>SVC: "ListTasksByWorkspace(ws, query="#1243")"
SVC->>REPO: "ListTasksByWorkspace(LIKE "%#1243%")"
REPO-->>SVC: "tasks=[], total=0"
SVC->>SVC: "augmentWithPRMatches(page=1, no workflow/repo filter)"
SVC->>SVC: "parsePRQuery("#1243") → 1243"
SVC->>GH: FindTaskIDsByPRNumber(ws, 1243)
GH->>GHDB: ListTaskIDsByPRNumber(ws, 1243)
GHDB-->>GH: ["task-pr"]
GH-->>SVC: ["task-pr"]
SVC->>SVC: fetchPRMatchedTasks(dedup, filter archived/ephemeral/config)
SVC->>REPO: GetTasksByIDs(["task-pr"])
REPO-->>SVC: [task-pr]
SVC->>SVC: merge + prepend PR matches, increment total
SVC-->>UI: "tasks=[task-pr, ...], total=1"
Reviews (4): Last reviewed commit: "perf(tasks): batch-fetch PR-matched task..." | Re-trigger Greptile
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/backend/cmd/kandev/services.go (1)
105-107: ⚡ Quick winKeep the new GitHub→task wiring out of
provideServices.This works, but it adds another cross-domain setter directly into the main composer. Please move this into the same per-domain init/helper layer the file uses for service wiring so
provideServicesdoes not keep accumulating one-off integrations.Based on learnings: "Backend: Wire the service via a per-domain
init<Name>Service(...)helper incmd/kandev/services.go, not inline inprovideServices."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/backend/cmd/kandev/services.go` around lines 105 - 107, The wiring that calls taskSvc.SetRemoteBranchLister(githubBranchListerAdapter{svc: githubSvc}) and taskSvc.SetPRTaskResolver(githubSvc) should be removed from provideServices and relocated into a per-domain init helper (e.g., initTaskService or initKandevService) that lives alongside the other domain-specific service wiring; create an initTaskService(githubSvc, taskSvc, ...) helper that performs the githubBranchListerAdapter setup and PR task resolver registration and call that helper from the domain init layer instead of in provideServices so cross-domain setters are contained in the domain init.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/backend/internal/task/service/service_tasks.go`:
- Around line 1078-1086: The bug is that s.augmentWithPRMatches is being called
after the task list has already been paginated, causing PR matches to be
prepended per-page and duplicate across pages; fix by moving PR augmentation to
run on the full unsliced result before applying pagination (or alter
augmentWithPRMatches to accept the complete result set and return augmented
results which are then paginated), update calls to augmentWithPRMatches (the
call sites around service_tasks.go where prSearchOptions is passed) so
augmentation/deduplication uses a global dedupe map across the entire result set
rather than a per-page map, and ensure final slicing for pageSize happens only
after augmentation.
- Around line 1078-1086: ListTasksByWorkspace advertises workflowID/repositoryID
as hard filters but calls augmentWithPRMatches with prSearchOptions that only
carries archived/ephemeral/config flags, allowing PR-linked tasks from other
workflows/repos to leak; update prSearchOptions (used by augmentWithPRMatches)
to include workflowID and repositoryID and ensure augmentWithPRMatches and its
internal matching logic (and any checks around lines with second/third calls)
reapply those filters when considering PR matches so only tasks matching the
requested workflowID and repositoryID are returned.
---
Nitpick comments:
In `@apps/backend/cmd/kandev/services.go`:
- Around line 105-107: The wiring that calls
taskSvc.SetRemoteBranchLister(githubBranchListerAdapter{svc: githubSvc}) and
taskSvc.SetPRTaskResolver(githubSvc) should be removed from provideServices and
relocated into a per-domain init helper (e.g., initTaskService or
initKandevService) that lives alongside the other domain-specific service
wiring; create an initTaskService(githubSvc, taskSvc, ...) helper that performs
the githubBranchListerAdapter setup and PR task resolver registration and call
that helper from the domain init layer instead of in provideServices so
cross-domain setters are contained in the domain init.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 43b5600e-012a-4a8e-8ab3-17f5c8b05337
📒 Files selected for processing (7)
apps/backend/cmd/kandev/services.goapps/backend/internal/github/service_pr_watch.goapps/backend/internal/github/store.goapps/backend/internal/github/store_pr_lookup_test.goapps/backend/internal/task/service/service.goapps/backend/internal/task/service/service_pr_search_test.goapps/backend/internal/task/service/service_tasks.go
There was a problem hiding this comment.
3 issues found across 7 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Address review feedback on PR-number search: - Only augment results on the first page of an unscoped search. Running on every page re-prepended the PR match and truncated a real result off each subsequent page; running under a workflow/repository filter leaked tasks that don't satisfy the filter. - Add idx_github_task_prs_pr_number so the lookup is index-backed instead of a full scan (pr_number is the 3rd column of the existing UNIQUE constraint, unusable as a leading key). - Log instead of silently dropping a task when GetTask fails in the PR-match loop.
|
Claude finished @zeval's task in 3m 25s —— View job Code Review
|
| Severity | Count |
|---|---|
| Blocker | 0 |
| Suggestion | 1 |
Verdict: Ready to merge.
The two P2 issues raised by earlier automated reviewers (PR augmentation re-appearing on pages 2+, and workflowID/repositoryID filters bypassed for PR matches) were both addressed in commit 100af2e. The page > 1 guard, the workflow/repo early-exit, and the dedicated test case (TestListTasksByWorkspace_PRMatchSkippedOnLaterPagesAndScopedSearches) are all present and correct.
Architecture is clean: interface injection keeps the task service decoupled from the github schema, the workspace-scoped query prevents cross-workspace leakage, the pr_number index is already in place, and test coverage spans dedup, nil-resolver safety, archived-filter, and page/workflow/repo scoping.
FindingsSuggestion (recommended, doesn't block)
Summary
Verdict: Ready to merge. The two P2 issues raised by earlier automated reviewers (PR augmentation re-appearing on pages 2+, and Architecture is clean: interface injection keeps the task service decoupled from the github schema, the workspace-scoped store query prevents cross-workspace leakage, the |
Add workspace_id to newTestStore's tasks table and drop the near-identical newTestStoreWithWorkspaces helper, per review feedback.
|
Claude finished @zeval's task in 3m 20s —— View job Code Review
|
| Severity | Count |
|---|---|
| Blocker | 0 |
| Suggestion | 1 |
Verdict: Ready to merge.
All three issues raised in earlier review rounds are fully addressed in commit 100af2e:
page > 1guard prevents PR matches from re-appearing on subsequent pagesworkflowID != "" || repositoryID != ""bail prevents PR matches from bypassing scope filtersGetTaskfailures now emit aWarnlog with the task ID
Commit 21a30b8 cleaned up the duplicate newTestStoreWithWorkspaces helper by adding workspace_id TEXT to the shared newTestStore DDL.
Architecture is clean: PRTaskResolver interface keeps the task service decoupled from the github schema, the DISTINCT JOIN is workspace-scoped with a dedicated idx_github_task_prs_pr_number index, and test coverage spans dedup, nil-resolver safety, archived filter, and the page/workflow/repo scoping guards.
Add a repository GetTasksByIDs and use it in augmentWithPRMatches so PR-number search loads all matched tasks in one query instead of one GetTask per id, addressing the N+1 noted in review. Fetch+filter is extracted into a fetchPRMatchedTasks helper that preserves resolver order and dedup.
|
Addressed the remaining N+1 suggestion from the review in 67d9c77: added a repository `GetTasksByIDs` and switched `augmentWithPRMatches` to a single batch fetch (via a `fetchPRMatchedTasks` helper that preserves resolver order and dedup) instead of one `GetTask` per id. |
|
Claude finished @zeval's task in 2m 33s —— View job Code Review
|
| Severity | Count |
|---|---|
| Blocker | 0 |
| Suggestion | 0 |
Verdict: Ready to merge. All issues from prior review rounds have been addressed, and the batch-fetch followup is a clean, correct implementation.
FindingsNo new issues. The batch-fetch implementation in
Summary
Verdict: Ready to merge. All issues from prior review rounds have been addressed, and the batch-fetch followup is a clean, correct implementation. |



Searching the Cmd+K panel by a PR number used to return nothing — PR associations live in
github_task_prs, which the task search never consulted. Typing a PR number (e.g.1243or#1243) now surfaces the task that PR belongs to, alongside the existing title/description/repo search.Important Changes
githubstore:ListTaskIDsByPRNumber— workspace-scoped lookup overgithub_task_prs, exposed viaService.FindTaskIDsByPRNumber.taskservice: new injectedPRTaskResolverinterface (github service wired incmd/kandev);ListTasksByWorkspacemerges PR matches into results — deduped, respecting archived/ephemeral/config filters. Kept at the service layer so the task repository stays decoupled from the github schema and existing search SQL/tests are untouched.queryparam already flows end-to-end.Validation
go build ./...go test ./internal/github/ ./internal/task/service/golangci-lint runon the touched packagesPossible Improvements
PR matches are prepended on top of the LIKE-search page count, so
totalis approximate; the command panel only uses results for display, not precise paging.Checklist