Skip to content

fix(ai-vault-search): own buffered transcript rows before they pin the parent - #22563

Merged
nwparker merged 2 commits into
mainfrom
credit/session-search-parent-strings
Sep 23, 2026
Merged

nwparker merged 2 commits into
mainfrom
credit/session-search-parent-strings

Conversation

@nwparker

@nwparker nwparker commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​47 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​47
Prod 1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​3 $\color{#cf222e}{\Huge{\mathbf{−}}}$​3 0

ELI5

Agent Session History indexing already stopped holding onto huge transcript lines, but the person who first fixed that was not named on the merge. This records their fix the way the rest of the app copies those strings, and adds the test that proves the big lines are actually released.

What Changed

Before, the search writer made its own UTF-16 copy of each buffered row. That copy did release the parent transcript, which is why large Codex logs stopped crashing the indexer. It was the same idea as the open pull request, written a second time, and that pull request's author was not on the commit.

After, the writer uses the shared string-copy helper the rest of the app already uses for this, and a regression test buffers 70 large tool rows, checks that the retained heap stays small, then confirms every capped row is still searchable.

Why

The open pull request was right. A capped tool row is a slice of the original message, so keeping the short slice keeps the whole message alive. Copying through the existing helper is the same detach the merged code did inline, and it skips the copy for strings that are already too short to pin a parent. The new test fails if that copy is removed: retained heap stays about 280 MiB instead of under 16 MiB.

Linked Issue

Follow-up to #22296, which is already fixed. Credits #22378.

Visual Proof

N/A — indexing memory only, no screen or interaction change.

Testing

  • Automated tests added/updated, or explained why not below
  • pnpm test src/main/ai-vault-search/session-search-index-writer.test.ts — 9 passed, including the new retention test.
  • Removing the copy fails that test with retained heap of about 280 MiB.
  • oxlint and oxfmt --check are clean on the two files.

AI Disclosure

Review

The helper preserves JavaScript code units, including unpaired surrogates, which is what the inline copy was doing. Search text, caps, and commit behavior are unchanged. No SSH, remote wire, or path changes. The writer runs on the execution host for local session history.

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

Ensure no issues in: Security, Cross-platoform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

Co-authored-by: fancivez fancivez@gmail.com

…e parent

#22378 had the right fix: capped search rows are slices of the transcript, so the writer has to own the text before buffering it. Use the shared copier, and land the heap regression that fails while a slice still keeps the tool output alive.

Co-authored-by: fancivez <fancivez@gmail.com>

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes

  • session-search-index-writer.ts: reuse the shared string-owner helper — the inline Buffer.from(row.text, 'utf16le').toString('utf16le') detach is replaced by ownRetainedString(row.text), which performs the same V8 SlicedString detach, skips the copy for strings under the sliced-string threshold, and falls back to the code-unit block copier where Buffer is absent.
  • session-search-index-writer.test.ts: forced-GC retention test — 70 tool rows with ~2 MiB of discarded output capped to 3072 chars each, asserting retained heap stays under 16 MiB and that every capped row remains searchable after commit.

The helper is equivalent to the inline copy for every input this path produces: the main process always has Buffer, and the helper's round-trip probe already covers lone surrogates and NUL, so code units survive byte-for-byte. The new test is real coverage rather than theatre — without the copy each 3072-char slice pins its full multi-megabyte parent, so the retained-heap bound fails. --expose-gc is pinned in config/vitest.config.ts, matching the retention-test convention across the repo. No wire, SSH, path, or platform surface is touched.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 1bfd09ef-d0bd-4ddf-836e-aab258f65089

📥 Commits

Reviewing files that changed from the base of the PR and between e6d4336 and 7724306.

📒 Files selected for processing (1)
  • src/renderer/src/components/sidebar/Sidebar.test.tsx

Included review availability: Your plan provides up to 10 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

SessionSearchIndexWriter now uses ownRetainedString to copy FTS row text before buffering it. A new test adds 70 tool rows with approximately 2 MiB text each, checks heap growth after garbage collection, commits the rows, and verifies the indexed text length and error count. The sidebar test mock now includes the detectedWorktreesByRepo map.

Merge Risk: ⚪ Minimal · up to 77243

The search and sidebar changes preserve their intended behavior, and the regression test is supported by the standard test setup. No actionable merge risk remains.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: copying buffered transcript rows so they do not retain large parent strings.
Description check ✅ Passed The description is mostly complete. It explains the change, reason, linked issues, lack of visual impact, testing, scope, and compatibility considerations. Some checklist items remain unchecked, but t…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The toolchain banner reads detectedWorktreesByRepo, and the real store always has that map. The sidebar test left it out, so a rerender with a repo crashed before the scan assertion.

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes

  • Sidebar.test.tsx: sidebar harness gains the worktree listing map — the mocked store in setSidebarState now supplies detectedWorktreesByRepo: {}. LocalGitToolchainScanBanner reads s.detectedWorktreesByRepo and indexes it by repo id, so tests that seed repos with ids would otherwise dereference undefined. The fixture matches the shape every other renderer test harness uses, and the suite passes locally (6/6).

This delta is test-harness-only; the memory-ownership change in session-search-index-writer.ts was reviewed previously (review 5297597363) and is unchanged. The fixture addition is a reasonable green-CI fix, though it is unrelated to the indexing fix in the PR title.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

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.

1 participant