Skip to content

perf(web): hoist transcript search normalization out of filter loop - #972

Merged
groupthinking merged 2 commits into
mainfrom
bolt/optimize-text-filtering-15414235492514692486
Jul 24, 2026
Merged

perf(web): hoist transcript search normalization out of filter loop#972
groupthinking merged 2 commits into
mainfrom
bolt/optimize-text-filtering-15414235492514692486

Conversation

@google-labs-jules

@google-labs-jules google-labs-jules Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

💡 What: Extracted .toLowerCase() calls outside of .filter and .map loops in InteractiveTranscript.tsx and TranscriptViewer.tsx, adding short-circuit boolean checks and null-safety guards.

🎯 Why: To prevent redundant memory allocations and costly string operations on every React re-render (like keystroke updates in a search box), improving main-thread performance for large transcript datasets.

📊 Impact: Removes N toLowerCase() allocations per keystroke update while hardening the application against unexpected null or undefined strings.

🔬 Measurement: Exact head a67c01db16fb7a9000a736dddfed924522a5e078 completed CI, Coverage, CodeQL, Security Scan, Secret Scan, and Dependency Review successfully; E2E was repository-skipped. Zero inline review threads exist. Verified READY preview: dpl_FMc3BKd92aTFCpyvMaxYruEpE9mb.

Program reconciliation — 2026-07-24

Execution receipt:

  • Agent login/run: google-labs-jules[bot] / 15414235492514692486
  • Canonical reconciler: groupthinking / eventrelay-blocker-watch-20260724T1609Z
  • Branch/PR: bolt/optimize-text-filtering-15414235492514692486 / perf(web): hoist transcript search normalization out of filter loop #972
  • Claimed timestamp: 2026-07-24T15:20:58Z
  • Latest verified heartbeat: 2026-07-24T16:11:57Z
  • Exact implementation head: a67c01db16fb7a9000a736dddfed924522a5e078
  • Production merge head: ded0eccf3f94b4e6e8f9316fdf7ee73d9fb55bf4

PR created automatically by Jules for task 15414235492514692486 started by @groupthinking

@google-labs-jules

Copy link
Copy Markdown
Contributor Author

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v0-uvai Ready Ready Preview, Comment, Open in v0 Jul 24, 2026 3:26pm

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown

🔍 PR Validation

✅ Current validation passed.

@github-actions github-actions Bot added the javascript Pull requests that update javascript code label Jul 24, 2026
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA a67c01d.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown

Agent Completion Truth Gate: BLOCKED

Reasons: invalid_payload

Machine-readable verdict
{
  "details": {
    "invalid_fields": [
      "issue.number",
      "policy.agent_login",
      "policy.run_id"
    ]
  },
  "reasons": [
    "invalid_payload"
  ],
  "verdict": "blocked"
}

Workflow evidence

The perf change touches only two React components; the regenerated
lockfile (1391 lines of transitive dependency churn) was unrelated
scope-creep. Restoring package-lock.json to main keeps this PR a
minimal, reviewable performance change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HP1GUE359AT6A6Tg4Wgqc9
@groupthinking groupthinking changed the title ⚡ Bolt: Optimize text filtering performance perf(web): hoist transcript search normalization out of filter loop Jul 24, 2026

Copy link
Copy Markdown
Owner

Automated review — code is clean; the "Large PR" warning is a false alarm

Adversarially reviewed the actual diff on head 577ec45.

Real change (vs. current merge-base): 2 files, +17/−7.

  • InteractiveTranscript.tsx — hoists searchQuery.toLowerCase() out of the .filter loop and short-circuits the speaker check. Semantically equivalent to the prior matchesSpeaker && matchesSearch, plus a seg.text null-guard. No behavior change for valid inputs.
  • TranscriptViewer.tsx — hoists the lowercased query into searchConfig and null-guards each part in highlight(). The searchQuery ? … : '' guard is redundant (the useMemo already returns early when searchQuery is falsy) but harmless. Equivalent output.

No correctness, security, or performance regressions found in the changed code.

On the "⚠️ Large PR detected (1,415 lines changed)" validation warning: that figure comes from diffing against the PR's recorded base SHA, which has diverged from current main due to the repo's rewritten/force-pushed history (see CLAUDE.md → Repo Hygiene). Against the current merge-base the change is only 17 insertions / 7 deletions. The large-PR warning can be disregarded here.

Still blocking (not code issues):

  • agent-completion/truth-gateinvalid_payload (missing issue.number, policy.agent_login, policy.run_id). This is the completion gate working fail-closed by design (scripts/ci/agent_completion_gate.py) because no linked issue / tracked agent run resolved for this PR — link a governance issue or override per policy.
  • Vercel deployment was canceled from the dashboard, not failed on the code.

Merge decision and the truth-gate resolution require a human maintainer; this comment is review evidence only.


Generated by Claude Code

@groupthinking
groupthinking merged commit ded0ecc into main Jul 24, 2026
31 of 37 checks passed
@groupthinking
groupthinking deleted the bolt/optimize-text-filtering-15414235492514692486 branch July 24, 2026 15:30
@github-actions github-actions Bot mentioned this pull request Jul 24, 2026
groupthinking added a commit that referenced this pull request Aug 7, 2026
Issue #908 marks "Null and empty search behavior is preserved" as an accepted
criterion, but nothing enforced it. The perf work landed via merged PR #972
(ded0ecc) and is correct; however both components carrying it had zero test
coverage:

- InteractiveTranscript.tsx - 0 tests
- TranscriptViewer.tsx      - 0 tests

Both ship in production via dashboard/panels.tsx. The refactor *added* the
null guards (`seg.text ? ... : false`, `part ? ... : ''`) because nullish text
was a live risk - so the guards were load-bearing from day one, yet a future
refactor could drop them and every check would stay green.

This is not a competing implementation. Behavior is byte-for-byte preserved;
the logic is only relocated so it can be tested.

Approach: extract the pure search logic into src/lib/transcript-search.ts and
test it in vitest's `node` environment. apps/web/vitest.config.ts deliberately
avoids jsdom ("Add a jsdom project later if/when component rendering tests
land"), so introducing jsdom/RTL would be an unasked-for architectural change.
Precedent for the extraction already exists: src/lib/timestamp.ts is shared
pure logic imported by these same two components.

Rejected alternative: replicating the predicate inside the test. That validates
a copy rather than the shipped code - a vacuous test.

Covered invariants (16 tests):
  - empty / null / undefined query returns ALL segments, never zero
  - nullish seg.text is a non-match, never a thrown TypeError
  - case-insensitive matching in both directions
  - speaker + search compose as AND
  - regex metacharacters are escaped ("a.b" must not match "axb")
  - invalid raw patterns ( "(", "[" ) do not throw
  - highlight regex omits /g so .test() cannot desync via lastIndex
  - query is lowercased exactly ONCE per pass, not once per segment

That last one asserts the actual performance property PR #972 shipped, so a
regression to per-segment normalization now fails the suite instead of silently
costing N allocations per keystroke.

Non-vacuous by negative control - each guard reverted individually in the
shipped module:

  NC-1  drop `seg.text ?` guard        -> 1 failed / 15 passed
  NC-2  drop empty-query guard         -> 2 failed / 14 passed
  NC-3  drop regex escaping            -> 2 failed / 14 passed
  NC-4  add /g flag                    -> 1 failed / 15 passed
  NC-5  normalize inside the loop      -> 1 failed / 15 passed
  NC-6  drop null short-circuit        -> 1 failed / 15 passed
  restore                              -> 16 passed

A/B against a stashed baseline (apps/web, ambient AI_GATEWAY_API_KEY unset):

  baseline       44 files / 245 passed / 0 failed
  with changes   45 files / 261 passed / 0 failed

Zero new failures. tsc --noEmit and eslint both clean.

Refs #908, #972

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants