feat(search): cross-session FTS search for triage context and prior art - #324
feat(search): cross-session FTS search for triage context and prior art#324tstapler wants to merge 5 commits into
Conversation
…6.1) sdd:6-verify's architecture review flagged that Story 1.6.1's GWT for the no-live-Instance worktree case describes an outcome the plan's own literal code sample never implements. Documents the deliberate shipped behavior (exclude rather than keep) and why the two GWTs aren't simultaneously satisfiable from entry.Project alone. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QFjiqYD6vPT9TV3TATahh7
Extends SearchClaudeHistory/GetClaudeHistoryMessages/ListClaudeHistory with additive fields for session-level dedup, ±5-message context windows with bookends, best-effort automation-session exclusion (live Instance.Hidden), project scoping with worktree resolution, and anchor-based scroll paging. Surfaces a "Find related past work" search box in the backlog triage panel, pre-populated with the item title, session-deduped and repo-scoped, with click-through to the session's history page anchored on the matched message. - server/services/search_related_work.go: pure helper functions (dedup, context window, automation/project filters), reused by both SearchClaudeHistory and the ListClaudeHistory browse-mode path - proto: additive optional fields only, wire-compatible with existing callers - web-app: TriageRelatedWorkSection.tsx composed into TriageReviewPanel, useHistoryFullTextSearch.ts extended additively, history/page.tsx gains a ?sessionId=&messageIndex= deep link - backlog_debug_seed_handler.go: e2e-test-only `ended` seed flag so the triage e2e spec can exercise the live (non-readOnly) TriageReviewPanel Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QFjiqYD6vPT9TV3TATahh7
The reviewer flagged that the e2e spec dropped the actual click-through assertion AC #10 requires ("an e2e test covers the triage panel's search-and-click-through flow end to end") — the prior spec only verified the search box auto-populates, deliberately skipping the click assertion because the real SearchClaudeHistory index build on a real dev machine's ~/.claude/projects tree is unbounded and non-deterministic. Adds a second e2e test that mocks the SearchClaudeHistory ConnectRPC call (page.route, an established pattern already used by vcs-widget.spec.ts) to deterministically produce one hit, then verifies clicking the result card opens a new tab at /history?sessionId=&messageIndex= and leaves the original tab's triage panel state untouched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QFjiqYD6vPT9TV3TATahh7
✅ Registry ValidationTest Coverage: 27/181 features have
|
|
Closing as superseded: this branch's last known commit (654c601) is already present on main, so this item's work has already shipped through another path. No further fix is needed here. |
Go Benchmarks (Tier 1) |
E2E RPC Latency |
Frontend Terminal Throughput |
UX Analysis
|
🎬 E2E Feature Demos2 shard(s) recorded feature flows for this PR. recordings shard 1 Demo preview opens directly in browser (single-file HTML). Raw WebM recordings in ZIP. Expires after 30 days. |
- Fix TestGetClaudeHistoryMessages_AnchorIndexCentersWindow: it only asserted message count/length, which would pass even if anchor-centering were silently broken (all seeded messages had identical content). Now asserts actual window position via unique per-message content. - Remove a vacuous not.toHaveFocus() assertion in the empty-itemTitle test (nothing in the component ever sets focus, so it was always true) and add a real, dedicated focus-management test with populated results instead. - Drop includeContext:true from the triage panel's search query: the backend context_window/bookend fields it fetches are parsed by the hook but never rendered by SessionHitCard (v1 ships snippet-only cards per project_plans/session-search-fts5/design/ux.md) — was paying a full conversation-file read per hit on every debounced keystroke for unused data. - Parallelize per-hit context-window enrichment (enrichWithContext) so future callers that do set include_context don't pay N sequential full-file reads. - Extract SearchClaudeHistory's project/automation/dedup/truncate/context pipeline into applyResultPostProcessing, shrinking the handler and making the pipeline unit-testable independent of the RPC. - DRY up three identical filter-in-place loops (filterAutomationSessions, filterByProject, filterHistoryEntriesByAutomation) into a shared filterInPlace[T] generic, per this repo's own interface-pollution-checklist rule 5 (generalize once 2+ call sites need identical logic — now three do). - Reject offset>0 combined with group_by_session/exclude_automation_sessions/ project (previously just a documented, unenforced limitation) and reject anchor_index+tail combined (previously an unenforced "mutually exclusive" comment), each with CodeInvalidArgument, plus regression tests for both. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QFjiqYD6vPT9TV3TATahh7
|
Reopening — the auto-close was a false positive. |
…-session-search-fts5-ship # Conflicts: # web-app/src/gen/session/v1/session_pb.ts
✅ Registry ValidationTest Coverage: 27/181 features have
|
📊 Feature E2E CoverageFeature coverage report unavailable
|
✅ Registry ValidationTest Coverage: 36/186 features have
|
Summary
When triaging a new backlog item, there's no way to see whether similar work has been attempted before — no visibility into prior decisions or failed approaches. This extends the existing BM25 history-search engine (
SearchClaudeHistory,GetClaudeHistoryMessages,ListClaudeHistory) with session-level dedup, ±5-message context windows, best-effort automation-session exclusion, project scoping (with worktree resolution), and anchor-based scroll paging — all additive, wire-compatible extensions, not a new RPC (per this repo's own architecture-review precedent: adding a parallelSearchSessionsRPC would have duplicated ~90% of the existing handler). Surfaces a "Find related past work" search box in the backlog triage panel.Closes backlog item
3141f49f-5ea7-4839-a848-5670635bff9e.What Changed
server/services/search_related_work.go(new): pure helper functions —groupResultsBySession,contextWindowAndBookends,isAutomationSession/filterAutomationSessions(also reused byListClaudeHistory's new automation filter),resolvedProject/filterByProject(worktree-aware via liveInstance.MainRepoPath)server/services/search_service.go: wires the above intoSearchClaudeHistory(project → automation → dedup → truncate → context-enrich, with oversampled raw fetch so a smalllimitdoesn't starve dedup) andGetClaudeHistoryMessages(newanchor_indexscroll paging + an out-of-bounds-offset bug fix), and addsexclude_automation_sessionstoListClaudeHistoryproto/session/v1/session.proto: additiveoptionalfields only onSearchClaudeHistoryRequest/Response,GetClaudeHistoryMessagesRequest,ListClaudeHistoryRequest— existing callers (useHistoryFullTextSearch.ts,HistorySearchResults.tsx) see byte-identical behavior when unsetweb-app/src/components/backlog/TriageRelatedWorkSection.tsx(new): the triage panel's search box — pre-populated with the item title, debounced, session-deduped, click-through opens/history?sessionId=&messageIndex=in a new tab via a real<a>elementweb-app/src/app/history/page.tsx: reads that deep link viauseSearchParams(wrapped inSuspense, matching this repo's ownbacklog/page.tsxprecedent)server/services/backlog_debug_seed_handler.go: small e2e-test-only addition (anendedflag) so the triage e2e spec can exercise the live (non-readOnly)TriageReviewPanelTest plan
go build ./...— cleango test ./server/services/...— all pass (dedup, context/bookend incl. a boundary-overlap regression, automation filtering on bothSearchClaudeHistoryandListClaudeHistory, project scoping incl. worktree resolution, anchor paging incl. out-of-bounds regression)go test ./...(full suite) — all packages passmake lint— 0 issuescd web-app && npx tsc --noEmit— cleancd web-app && npx jest --no-coverage— 268 suites pass (2 pre-existing failures unrelated to this change, confirmed viagit stashagainst the clean baseline)make registry-diff— 0% divergencecd tests/e2e && npx playwright test triage-related-work.spec.tsagainst a live isolated test server — both specs pass, including a deterministic click-through test (mocks the search RPC viapage.route, same patternvcs-widget.spec.tsalready uses) verifying the result card opens a new tab anchored on the message index without disturbing the triage panel's own statesdd:6-verifyran 4 parallel review agents (Go idioms, React idioms, architecture, refactor-candidates) — all MUST FIX findings resolved, including a real bookend-overlap correctness bug and an accessibility regression from a<label>/aria-labelconflict I'd introduced🤖 Generated with Claude Code
https://claude.ai/code/session_01QFjiqYD6vPT9TV3TATahh7