Skip to content

feat(site/src/pages/AIBridgePage/SessionThreadsPage): add in-session search across event types - #28054

Open
johnstcn wants to merge 2 commits into
mainfrom
cian/aigov-462-featsite-add-in-session-search-across-all-event-types
Open

feat(site/src/pages/AIBridgePage/SessionThreadsPage): add in-session search across event types#28054
johnstcn wants to merge 2 commits into
mainfrom
cian/aigov-462-featsite-add-in-session-search-across-all-event-types

Conversation

@johnstcn

@johnstcn johnstcn commented Aug 12, 2026

Copy link
Copy Markdown
Member

Adds a search input to the AI Gateway session detail view that filters the session timeline across all event types: Bridge prompts, tool calls, and Agent Firewall network activity.

The search matches prompt text, tool names, tool input JSON, and network call destinations. While a query is active, the timeline shows only matching threads and network rows, the network panel header/blocked counts reflect the matches, and a "No events match your search." empty state appears when nothing matches. Clearing the search restores the full session.

Dogfood screenshots

Validated end to end against a local dev instance with a real provider and live AI session data.

Login:

Login

Sessions list:

Sessions list

Session detail (initial state):

Session detail initial

Searching "authentication" keeps the matching thread:

Search authentication match

A query with no match shows the empty state:

Search no match

Clearing the search restores the thread:

Search cleared

Non-matching session shows the empty state too:

Other session no match

Implementation plan
  • SessionThreadsPageView.tsx holds the searchQuery state and renders a reusable SearchField; it passes the query to the timeline.
  • SessionTimeline.tsx filters threads and networkCalls via useMemo, derives the network-panel summary counts from matching rows while searching (preserving the server-scoped summary/truncation note when idle), and shows the empty state.
  • sessionSearch.ts adds pure matchesThreadSearch / matchesNetworkCallSearch helpers with the strict field scope from the issue.
  • Tests: 9 unit tests for the pure helpers, plus Storybook interaction stories for both the page view and the timeline (search, clear, and no-match states). sessionSearch.ts is a pure-logic file, so its vitest coverage is appropriate per frontend conventions.

Notes:

  • The issue's dependency AIGOV-464 (render boundary events inline) is merged on main as a separate NetworkCallsTable panel above the threads (the unified inline-timeline refactor AIGOV-459 was canceled). This search filters the same entity arrays the timeline renders, so it works now and continues to work once boundary events move inline.
  • Sibling AIGOV-461 (event-type and allow/blocked filters) is intentionally out of scope to keep this PR single-purpose.

Refs https://linear.app/codercom/issue/AIGOV-462

Coder Agents generated. Please review and mark ready when satisfied.

@linear-code

linear-code Bot commented Aug 12, 2026

Copy link
Copy Markdown

AIGOV-462

Copy link
Copy Markdown
Member Author

test

@johnstcn
johnstcn marked this pull request as ready for review August 12, 2026 13:53
Copilot AI lite review requested due to automatic review settings August 12, 2026 13:53
@johnstcn

Copy link
Copy Markdown
Member Author

Smoke-tested in browser

@coder-tasks

coder-tasks Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Documentation Check

This PR adds a user-facing search input to the AI Gateway Session detail view that filters the timeline (prompts, tool calls, and Agent Firewall network activity). That view is documented, but the docs don't mention the search capability yet.

Updates Needed

  • docs/ai-coder/ai-gateway/audit.md - In the Navigating the UI → Session detail section, document the new search input: it filters the session timeline across all event types (prompt text, tool names, tool input JSON, and network call destinations), the network panel header/blocked counts reflect matches while a query is active, and a "No events match your search." empty state appears when nothing matches.
  • docs/ai-coder/ai-gateway/audit.md - In the Conducting a forensic audit steps ("Locate the thread" / "Trace the causal chain"), consider noting that auditors can use search to quickly find matching threads or network calls within a session.

Automated review via Coder Agents

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds client-side, in-session search for the AI Gateway session detail timeline, filtering both session threads (prompts and tool calls) and Agent Firewall network activity based on a single query string.

Changes:

  • Introduces a SearchField to the session threads page and threads the query down into the timeline component.
  • Adds filtering logic in SessionTimeline for threads and network calls, including adjusted network summary counts while searching and a no-match empty state.
  • Adds pure search helpers (sessionSearch.ts) with unit tests, plus Storybook interaction stories covering search behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
site/src/pages/AIBridgePage/SessionThreadsPage/SessionTimeline/SessionTimeline.tsx Applies query-driven filtering across threads and network calls, updates network summary while searching, and renders an empty state.
site/src/pages/AIBridgePage/SessionThreadsPage/SessionTimeline/SessionTimeline.stories.tsx Adds Storybook interaction coverage for filtered threads, filtered network calls, and no-match state.
site/src/pages/AIBridgePage/SessionThreadsPage/SessionTimeline/sessionSearch.ts Implements pure helper functions for matching threads and firewall logs against a query.
site/src/pages/AIBridgePage/SessionThreadsPage/SessionTimeline/sessionSearch.test.ts Adds vitest unit tests for the pure search helper behavior.
site/src/pages/AIBridgePage/SessionThreadsPage/SessionThreadsPageView.tsx Adds the search input and passes searchQuery to SessionTimeline.
site/src/pages/AIBridgePage/SessionThreadsPage/SessionThreadsPageView.stories.tsx Adds Storybook interaction coverage for page-level search, clear, and no-match behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +594 to +601
{isSearching && !hasAnyMatches && (
<p
className="m-0 py-4 text-sm font-normal text-content-secondary"
role="status"
>
No events match your search.
</p>
)}
@johnstcn

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Chat: Review posted | View chat
Requested: 2026-08-12 14:20 UTC by @johnstcn

Review history
  • R1 (2026-08-12): 14 reviewers, 5 Nit, 2 Note, 3 P2, 3 P3, REQUEST_CHANGES. Review

deep-review v0.9.0 | Round 1 | 6765731..801cbc0

Last posted: Round 1, 13 findings (3 P2, 3 P3, 5 Nit, 2 Note), REQUEST_CHANGES. Review

Finding inventory

Finding inventory

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 Nit Open SessionTimeline.tsx:602 Em-dash (U+2014) in infinite scroll sentinel comment R1 Netero Yes
CRF-2 P3 Open SessionTimeline.tsx:594 "No events match your search." can render mid-pagination while hasNextPage=true R1 Netero Yes
CRF-3 P2 Open SessionTimeline.tsx:571 Search-time summary override suppresses the server truncation footer for network_call_logs (cap 1000); silent false negative on audit surface R1 Hisoka P2, Nami P2, Pariston P2, Mafuuu P3, Luffy P3, Zoro P3 Yes
CRF-4 P2 Open SessionTimeline.tsx:461 Infinite-scroll cascade: zero-match filter drains every remaining page until hasNextPage=false because sentinel is always intersecting R1 Hisoka P2, Nami P3 Yes
CRF-5 P2 Open SessionThreadsPageView.tsx:142 Placeholder/aria-label and searchQuery prop JSDoc promise "prompts, tool calls, and network calls" / "all event types" but only prompt text, tool name, tool input JSON, and network detail are searched; visible fields (method, matched_rule, model, provider) yield false negatives R1 Leorio P2, Pariston P3, Gon P2, Melody Note, Luffy Note Yes
CRF-6 P3 Open SessionTimeline.stories.tsx:179 SearchFiltersThreads negative assertion is tautologically true (looks for string that never rendered); mutation testing proves the story passes with filtering bypassed R1 Bisky P3 Yes
CRF-7 P3 Open SessionTimeline.tsx:586 Tool-name / tool-input match surfaces the thread but the match is invisible: agentic loop and ToolCallBlock start collapsed R1 Luffy P3 Yes
CRF-8 Nit Open SessionTimeline.tsx:445 Two useMemo calls on a React-Compiler-compiled path (AIBridgePage/ is in the vite include filter); violates site/AGENTS.md Performance rule R1 Nami Nit Yes
CRF-9 Nit Open SessionTimeline.stories.tsx:184 Stale story comment: describes "github.com" scenario but story searches "npmjs.org" R1 Melody Nit, Gon P2 Yes
CRF-10 Nit Open sessionSearch.ts:9 Module doc cites Linear ticket AIGOV-462 in source; readers cannot open it and enumeration already carries the scope R1 Leorio Nit, Gon P2 Yes
CRF-11 Nit Open SessionThreadsPageView.tsx:141 onClear={() => setSearchQuery("")} duplicates SearchField's default; other in-tree callers omit it R1 Nami Note, Zoro Nit Yes
CRF-12 Note Open SessionThreadsPageView.tsx:65 searchQuery state not keyed by sessionId; carries across URL-to-URL navigation between session detail pages R1 Pariston Note Yes
CRF-13 Note Open sessionSearch.ts:11 Docstring says "network call destinations"; code matches full URL detail (host + path + query) R1 Zoro Note Yes
CRF-14 Nit Open (commit body) Commit message body is empty; sibling AIBridgePage feat commits carry substantive bodies R1 Leorio Nit Body
CRF-15 Note Open (multiple story/test files) mockThread fixture duplicated across three files; consolidate to testHelpers/entities.ts R1 Robin Nit Body
CRF-16 Note Open (multiple story/test files) Comment quality pattern: 12 in-scope comments restate the code beneath them R1 Gon Note, Ging-ts P2 Body

Contested and acknowledged

None.

Round log

Round 1

Netero + panel (14 reviewers). 3 P2, 3 P3, 5 Nit, 5 Note. Reviewed against 6765731..801cbc0.

Cross-check disposition notes:

  • CRF-3: 6-way convergence, severities split 3xP2 / 3xP3. Higher wins; kept at P2 because the consequence (silent false negative on the Agent Firewall audit surface when network_call_logs hits the server 1000-cap) is the exact failure mode the pre-existing truncation footer was added to prevent.
  • CRF-4: Hisoka P2, Nami P3. Higher wins; kept at P2. Cascade drains every remaining page on a single keystroke; scope of resource cost is bounded only by hasNextPage. Related to CRF-2 (visible symptom); Nami option (a) fix (skip fetch while isSearching) resolves both.
  • CRF-5: Leorio P2, Pariston P3, Gon P2 on the parallel prop JSDoc scope drift. Higher wins; kept at P2. Placeholder, aria-label, and JSDoc all promise a wider scope than the filter delivers. Absorbs Luffy Note (matched_rule not searchable), Melody Note, and Leorio Note on the prop JSDoc.
  • CRF-9: Gon P2, Melody Nit. Downgraded to Nit. Keep-argument at P2: the stale comment misleads readers into tracing a "count=2" scenario that the play function does not exercise. Downgrade-argument: one-line comment fix, no runtime behavior; Gon rated every comment finding P2 this round.
  • CRF-10: Gon P2 (source ticket ID), Leorio Nit. Downgraded to Nit for the same calibration reason.
  • CRF-16: Rolled up Gon's remaining 11 P2 comment-quality findings into one Note, per the "comment quality is a pattern" observation Gon and Ging-ts both flagged. Body observation, not inline.

Findings dropped/absorbed during cross-check:

  • Luffy Note (matched_rule not searchable): absorbed into CRF-5.
  • Melody Note (placeholder scope mismatch): absorbed into CRF-5.
  • Leorio Note (searchQuery prop JSDoc drift): absorbed into CRF-5.

Pre-existing but tracked: CRF-1 (em-dash) predates this PR at SessionTimeline.tsx:602 (blame ed908ed019, 2026-06-22), but the file is modified in this diff and AGENTS.md forbids the character.

About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Komugi flake/determinism
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In-session search lands as a clean, well-tested addition: pure predicates in sessionSearch.ts with negative-case unit tests, Storybook interaction coverage for the timeline and page view, the shared SearchField primitive reused instead of hand-rolled, and dogfood screenshots for every state. Nice work on the scope discipline (AIGOV-461 explicitly deferred, boundary-events dependency documented).

Requesting changes on three P2 findings that undercut the audit workflow this feature exists to serve, plus process notes on comments and coverage.

Findings this round: 3 P2, 3 P3, 5 Nit, 4 Note (16 total).

The P2s concentrate on the same theme: what the feature promises vs what it delivers when a real session hits real limits.

  • [CRF-3] During search, NetworkCallsTable gets a synthesized summary whose total equals the filtered count, so hiddenCount = summary.total - calls.length is always 0 and the "Showing the first X of Y network calls" truncation footer disappears. enterprise/coderd/aibridge.go:54 caps network_call_logs at 1000 per session and explicitly warns "Sessions past the cap need pagination to see the remainder"; the footer is the sole UI signal of that. A destination that lives only in the truncated tail now returns "Network calls (0)" or No events match your search. with no indication the search was incomplete. Six reviewers converged (Hisoka P2, Nami P2, Pariston P2, Mafuuu P3, Luffy P3, Zoro P3).
  • [CRF-4] The pagination effect deps include isFetchingNextPage, so each fetch remounts the IntersectionObserver, whose initial callback re-fires as soon as the sentinel intersects. Before this PR the sentinel was buried under many rendered rows; after this PR, a zero-match filter renders just a one-line paragraph above the sentinel, so the observer always fires on remount and fetchNextPage cascades until hasNextPage is false. On a 400-thread session that is ~20 back-to-back page loads per keystroke that hits nothing. Skipping the fetch while isSearching also resolves the visible UX side of CRF-2.
  • [CRF-5] The placeholder ("Search prompts, tool calls, and network calls"), the aria-label ("Search session events"), and the SessionTimelineProps.searchQuery JSDoc ("across all event types") all describe a broader search than the code implements. matchesNetworkCallSearch looks at call.detail only; method, proto, matched_rule, model, provider are all visible on the page and untouched by search. The tests lock this in (POST and allow api.github.com are asserted to not match). Either narrow the copy to the real scope or widen the filter.

Code paths to know about while reviewing the fix:

  • The truncation contract is documented on codersdk.AIBridgeSessionThreadsResponse.NetworkCallLogs in site/src/api/typesGenerated.ts:209-215 and the enterprise handler enterprise/coderd/aibridge.go:50-55. Preserving networkCallSummary.total while searching (and letting NetworkCallsList render the note with a search-adjusted phrasing) restores the signal without a server round-trip.
  • Nami's option (a) fix for CRF-4 (skip fetchNextPage() while isSearching) also closes Netero's CRF-2 (empty-state visible mid-pagination) because there is no in-flight pagination to compete with.

Process observations, not blockers:

  • Commit body is empty; sibling feat commits under site/src/pages/AIBridgePage/ (a60f393, 3f3fd1c, f17d488) each carry a paragraph. git log and git blame show only the subject line without one, so move the first two paragraphs of the PR description into the commit body.
  • mockThread: AIBridgeThread is now duplicated across SessionTimeline/SessionTimeline.stories.tsx, SessionThreadsPageView.stories.tsx, and sessionSearch.test.ts, with the same tool call and near-identical fields. A shared MockAIBridgeThread in testHelpers/entities.ts would let each site override only what it needs.
  • Comment quality across the new stories is a pattern, not a per-line lapse. Roughly a dozen in-scope comments restate the code beneath ("Both threads are visible before searching" above two getByText assertions; "Search by prompt text: only the matching thread stays" above a userEvent.type and a matching assertion). Keep only the traps and the whys the code cannot state itself.
  • coder-tasks flagged docs/ai-coder/ai-gateway/audit.md for a search-input update (Session detail navigating + forensic-audit steps). Worth doing in this PR since the docs already describe the surface.

Bisky pinned down the coverage gap with a mutation test: "I replaced threads.filter((thread) => matchesThreadSearch(thread, searchQuery)) with threads.filter(() => true) and re-ran the file. Every search story in SessionTimeline.stories.tsx failed as expected, except this one, which still passed." That's CRF-6; one line fixes it.

🤖 This review was automatically generated with Coder Agents.

No events match your search.
</p>
)}
{/* infinite scroll sentinel — sits 200px below the last thread */}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit [CRF-1] Em-dash (U+2014) in the infinite scroll sentinel comment. (Netero)

{/* infinite scroll sentinel — sits 200px below the last thread */}

Predates this PR (blame ed908ed019, 2026-06-22) but sits in a file this diff modifies. make lint/emdash catches it; the AGENTS.md rule forbids the character in comments. Replace with a period or restructure the sentence.

🤖

/>
))}
</div>
{isSearching && !hasAnyMatches && (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 [CRF-2] No events match your search. renders while hasNextPage may still be true, so the definitive negative is actually a mid-pagination snapshot. (Netero)

{isSearching && !hasAnyMatches && (
  <p ... role="status">
    No events match your search.
  </p>
)}

isSearching && !hasAnyMatches fires whenever the currently-loaded arrays yield no filter hits. While hasNextPage, the sentinel is still rendered below the message, the IntersectionObserver keeps firing onFetchNextPage, and matches can appear on the next batch. In the meantime the user reads a definitive negative that will lie if pagination stalls. Related to CRF-4: the fix suggested there (skip fetchNextPage() while isSearching) also resolves this, since then there is no next batch to wait for. Alternative: soften to "No matches so far." while hasNextPage, or hold the message until pagination drains.

🤖

// the matching rows. Otherwise the session-scoped summary is
// preserved so the server truncation note stays accurate.
summary={
isSearching

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 [CRF-3] Search-time summary override suppresses the server-truncation footer on the Agent Firewall audit surface; a search over a large session looks exhaustive when it is not. (Hisoka P2, Nami P2, Pariston P2, Mafuuu P3, Luffy P3, Zoro P3)

summary={
  isSearching
    ? {
        total: filteredNetworkCalls.length,
        blocked: filteredNetworkCalls.filter(
          (call) => !call.allowed,
        ).length,
      }
    : networkCallSummary
}
calls={filteredNetworkCalls}

network_call_logs is capped at 1000 per session server-side (enterprise/coderd/aibridge.go:54; comment: "Sessions past the cap need pagination to see the remainder"), and NetworkCallsList uses hiddenCount = summary.total - calls.length to render "Showing the first X of Y network calls" (NetworkCallsTable.tsx:65-79). That footer is the only UI signal the list is truncated.

While searching, this PR replaces both sides of the identity with the same filtered subset, so hiddenCount is always 0 and the footer never renders during a search. Consequences:

  • Session with, say, 2,000 network calls (server returned the first 1,000). A query for a destination that lives in the truncated tail returns Network calls (0) or No events match your search. (the network panel is hidden by the filteredNetworkCalls.length > 0 guard at line 564). The operator concludes the call never happened.
  • Same session, a query that hits 3 rows in the loaded prefix. Header reads Network calls (3), no truncation note, no indication the true match count could be many multiples higher.

This is the failure mode the truncation footer was added to prevent, on the audit surface where the answer to "did this destination ever appear?" has to be right. Keep networkCallSummary (or the true network_call_logs length) as summary.total during search so NetworkCallsList still emits the footer, or render a search-specific note like "N matches within the first M of Y loaded network calls." blocked can stay derived from filteredNetworkCalls.

🤖

Comment on lines +445 to 461
const filteredThreads = useMemo(
() => threads.filter((thread) => matchesThreadSearch(thread, searchQuery)),
[threads, searchQuery],
);

const filteredNetworkCalls = useMemo(
() =>
networkCalls.filter((call) =>
matchesNetworkCallSearch(call, searchQuery),
),
[networkCalls, searchQuery],
);

const hasAnyMatches =
filteredThreads.length > 0 || filteredNetworkCalls.length > 0;

useEffect(() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 [CRF-4] The pre-existing pagination effect at line 461 (deps [hasNextPage, isFetchingNextPage, onFetchNextPage]) tears down and re-creates the IntersectionObserver on every isFetchingNextPage transition. IntersectionObserver.observe() delivers an initial notification with the current intersection state, so each re-attach fires the callback. When these new filteredThreads and filteredNetworkCalls empty out, the sentinel sits at the top of the panel and is always intersecting the 200px rootMargin. (Hisoka P2, Nami P3)

const filteredThreads = useMemo(...);
const filteredNetworkCalls = useMemo(...);
const hasAnyMatches =
  filteredThreads.length > 0 || filteredNetworkCalls.length > 0;

Sequence with a zero-match query on a paginated session:

  1. Effect runs; sentinel is inside the 200px rootMargin because the only visible content is the "No events match your search." paragraph; callback fires -> onFetchNextPage().
  2. isFetchingNextPage flips true; effect re-runs; new observer fires immediately; guard fails, no fetch.
  3. Page returns; isFetchingNextPage flips false; effect re-runs; new observer fires; sentinel still intersecting; onFetchNextPage() fires again.
  4. Loop until hasNextPage is false.

SESSION_THREADS_INFINITE_PAGE_SIZE = 20 (api/queries/aiBridge.ts), so a 400-thread session runs ~20 fetches back-to-back for a typo that yields no matches. Cheapest fix: skip fetchNextPage() while isSearching. Server pagination cannot help a client-only search anyway, and this also resolves the visible UX side of CRF-2 (the empty state no longer competes with in-flight pagination).

None of the new stories combine hasNextPage: true with an active searchQuery, so the play runs do not surface this. Add e.g. SearchNoMatchesWithNextPage: { hasNextPage: true, searchQuery: "no-such-event" } to make the cascade visible in Storybook.

🤖

value={searchQuery}
onChange={setSearchQuery}
onClear={() => setSearchQuery("")}
placeholder="Search prompts, tool calls, and network calls"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 [CRF-5] Placeholder and aria-label promise a search scope the code does not deliver, and the visible columns tell the same lie. (Leorio P2, Pariston P3, Gon P2, Melody Note, Luffy Note)

placeholder="Search prompts, tool calls, and network calls"
aria-label="Search session events"

The placeholder sits above NetworkCallsTable, which renders method, proto, and matched_rule as visible columns (NetworkCallsTable.tsx:100,136,144). matchesNetworkCallSearch only checks call.detail, and the test suite locks that in: matchesNetworkCallSearch(call, "POST") -> false, matchesNetworkCallSearch(call, "allow api.github.com") -> false (sessionSearch.test.ts:88-91), and matchesThreadSearch rejects "claude-opus" and "anthropic" on the thread side. So an operator staring at a POST cell or an allow api.github.com matched-rule cell types the exact string they can see, gets "No events match your search.", and concludes the search is broken. It isn't broken; it lies about its scope.

Same drift shows up in the SessionTimelineProps.searchQuery JSDoc ("Search query applied across all event types") which the caller can't distinguish from the placeholder.

Pick one and mean it. Either widen scope so visible columns are searchable (add method, proto, matched_rule to matchesNetworkCallSearch; model, provider, server_url, etc. on the thread side), or narrow the copy to what actually matches, e.g. placeholder="Search prompt text, tool names, tool inputs, and network destinations" (and update the aria-label and JSDoc to match). The current aria-label ("Search session events") is the only hint a screen-reader user gets and is even vaguer than the placeholder.

🤖

Comment on lines +184 to +185
// While searching, the network panel header and rows reflect matches only.
// "github.com" appears in two of the mock calls (api.github.com and the DNS

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit [CRF-9] Stale story comment: describes a "github.com" scenario but the story searches "npmjs.org". (Melody, Gon)

// While searching, the network panel header and rows reflect matches only.
// "github.com" appears in two of the mock calls (api.github.com and the DNS
// lookup for api.github.com), so the panel header shows the filtered count.

The story sets searchQuery: "npmjs.org" (line 191) and asserts Network calls (1) (line 194) with the npmjs row. Only netcall-2 (https://registry.npmjs.org/lodash) contains that substring; the count=2 github.com scenario the comment narrates does not run. Either rewrite the comment to match npmjs.org, or switch the story to searchQuery: "github.com" and assert Network calls (2).

🤖

Comment on lines +7 to +11
/**
* Pure session-search helpers. Matching is case-insensitive substring
* matching over the strict field scope from AIGOV-462: prompt text, tool
* names, tool input JSON, and network call destinations.
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit [CRF-10] Module doc cites Linear ticket AIGOV-462 in source. (Leorio, Gon)

/**
 * Pure session-search helpers. Matching is case-insensitive substring
 * matching over the strict field scope from AIGOV-462: prompt text, tool
 * names, tool input JSON, and network call destinations.
 */

grep -rn "AIGOV-" site/src returns exactly this hit; no other site/src file references Linear tickets. External readers cannot open it, and the sentence already enumerates the four fields. Drop from AIGOV-462; the ticket ref already lives in the PR description as Refs https://linear.app/codercom/issue/AIGOV-462.

🤖

<SearchField
value={searchQuery}
onChange={setSearchQuery}
onClear={() => setSearchQuery("")}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit [CRF-11] onClear prop duplicates SearchField's built-in default. (Nami, Zoro)

onClear={() => setSearchQuery("")}

SearchField.handleClear already falls back to onChange("") when onClear is omitted (components/SearchField/SearchField.tsx). Every other in-tree caller (FilterPopover.tsx, ModuleSelectStep.tsx, MultiUserSelect.tsx, Chart.tsx) omits the prop. Drop the line; keep only onChange={setSearchQuery}.

🤖

isAISessionsEntitled,
onBackClicked,
}) => {
const [searchQuery, setSearchQuery] = useState("");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note [CRF-12] searchQuery state is not keyed by sessionId, so a query carries across direct URL-to-URL navigation between session detail pages. (Pariston)

const [searchQuery, setSearchQuery] = useState("");

The route /ai-gateway/sessions/:sessionId reuses this component, so the useState("") persists across sessionId changes. Recording this as a note because the in-app Back button unmounts the page; only direct URL-to-URL nav hits it, and clearing the field is one click. If session-to-session linking is added later, either add key={sessionId} on the timeline or reset searchQuery in an effect keyed to sessionId.

🤖

* Pure session-search helpers. Matching is case-insensitive substring
* matching over the strict field scope from AIGOV-462: prompt text, tool
* names, tool input JSON, and network call destinations.
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note [CRF-13] Docstring calls the network scope "network call destinations" but the code matches against call.detail. (Zoro)

MockAIBridgeSessionNetworkCalls shows detail: "https://api.github.com/repos/coder/coder" for HTTP boundary logs; that means a search for /repos/ matches, which is wider than "destination" implies. Either tighten the comment to "network call detail (URL for HTTP, host for DNS)", or parse the URL host-only if the ticket really means destination. Prefer the doc fix unless the ticket says otherwise.

🤖

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants