Skip to content

Fix Files find result aggregation - #3818

Merged
austinywang merged 14 commits into
mainfrom
issue-3817-find-in-folder-one-result
May 11, 2026
Merged

austinywang merged 14 commits into
mainfrom
issue-3817-find-in-folder-one-result

Conversation

@austinywang

@austinywang austinywang commented May 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds a regression test proving Files find publishes every match from a folder with three matching files.
  • Fixes result finalization so stdout, the match stream, gates the final accumulated snapshot while stderr remains diagnostic-only.
  • Preserves the typing-lag optimization: the query input stays debounced and result parsing stays off the input path.
  • Removes the redundant idle Find prompt under the search field before a query is typed.

Regressing Commit

Regression from 52db9e358f9073526de98c10ba424275751c06fe (Fix right sidebar Find typing lag (#3739)).

Testing

  • Built and launched main repro with ./scripts/reload.sh --tag repro-3817-main --launch.
  • Confirmed the Find panel can be revealed/focused in the launched repro build via the tagged debug socket (debug.right_sidebar.focus returned visible/focused true). Local AX/screen-capture access was unavailable, so direct visual row-count capture could not be collected from this environment.
  • git diff --check -- cmuxTests/FileExplorerStoreTests.swift
  • git diff --check -- Sources/FileExplorerSearchController.swift cmuxTests/FileExplorerStoreTests.swift

Not Tested

  • Local XCTest execution, per repo policy.
  • XCUITests, per repo policy.

Checklist

  • Regression coverage added for multi-match folder searches.
  • Tagged dogfood build completed with ./scripts/reload.sh --tag issue-3817-find-in-folder-one-result.
  • PR branch merged with latest origin/main.
  • User dogfood approval before merge.

Fixes #3817


Note

Medium Risk
Touches the ripgrep process I/O/concurrency path and search refresh scheduling; mistakes could cause hangs, missed results, or extra process churn, but changes are localized and covered by new tests.

Overview
Fixes Files Find result aggregation by switching ripgrep output handling to chunked POSIX pipe reads with stdout line buffering/flush-on-finish, preserving the terminal .limited update and treating stderr as diagnostic-only (only awaited on error exits).

Adjusts Find refresh behavior so root/provider scope changes still refresh immediately, but content revision changes during an active search are deferred until the current stream settles; also removes the idle “Type to search” prompt. Adds regression tests for multi-file/nested match completeness, early limiting to 500 results, pipeline finish behavior with buffered trailing lines, and avoiding mid-stream restarts on content revision changes.

Reviewed by Cursor Bugbot for commit 741ff5a. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Fixes Files Find to publish all matches and prevent stalls or lost results during folder searches and content refreshes. Completion is now gated on ripgrep stdout, drained independently; same-query content refreshes run after the current search settles, and the terminal limited state is preserved on finish.

  • Bug Fixes
    • Drain stdout via retained read handles and POSIX reads on a dedicated queue; frame lines in an actor, flush a trailing line on finish, remember the terminal limited update, gate completion on stdout, and await stderr only on non‑0/1 exits.
    • Defer same‑query content refreshes until the current search settles (scope changes still refresh immediately). Add tests for multi‑file/nested results, high‑volume limit publication, terminal limited‑state preservation, and avoiding restarts on content revisions; fix a test by removing async from XCTUnwrap. Remove the redundant idle Find prompt. Fixes Find-in-folder only shows one result (regression from typing-lag optimization) #3817.

Written for commit 741ff5a. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes

    • Ensure all search matches are captured by flushing trailing output and handling diagnostic/error output without blocking final results.
  • Behavior

    • Defer refreshes while search results stream; content-revision changes mid-search wait until streaming settles. Hiding or closing search cancels pending refreshes; scheduled debounces clear pending flags.
  • Tests

    • Added tests for accurate match results (including nested folders) and ensuring active searches are not restarted by reloads.

Review Change Stack

The find-in-folder regression needs a behavior-level assertion that the search controller publishes every match from a folder, not just the first streamed row. This creates a temporary folder with three matching files and asserts the settled snapshot includes exactly those results.

Constraint: Issue #3817 requires a failing regression test before the production fix

Confidence: high

Scope-risk: narrow

Directive: Keep this test on the real FileSearchController path so result aggregation regressions fail before UI-only symptoms

Tested: git diff --check -- cmuxTests/FileExplorerStoreTests.swift

Not-tested: Local XCTest execution skipped because this task forbids direct xcodebuild
The typing-lag refactor made final result publication depend on both ripgrep stdout and stderr stream completion. Stdout is the only stream that defines match completeness; stderr is diagnostic and can otherwise keep the controller on the first throttled snapshot. Drain stderr in a side task, wait for process termination plus stdout drain, then publish the accumulated pipeline results.

Constraint: Preserve the valid typing-lag optimization by keeping query debounce and background result parsing intact

Rejected: Collecting or limiting results in the view | the controller already owns aggregation and the UI should receive complete snapshots

Rejected: Waiting for stderr before final publication | stderr does not define match completeness and can block replacement of the first streamed result

Confidence: medium

Scope-risk: narrow

Directive: FileSearchOutputPipeline stdout is the source of truth for match aggregation; keep stderr diagnostic-only unless failures need a separate bounded contract

Tested: git diff --check -- Sources/FileExplorerSearchController.swift cmuxTests/FileExplorerStoreTests.swift

Not-tested: Local XCTest execution skipped because this task forbids direct xcodebuild
@vercel

vercel Bot commented May 10, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 11, 2026 5:14am
cmux-staging Building Building Preview, Comment May 11, 2026 5:14am

@coderabbitai

coderabbitai Bot commented May 10, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

stderr is drained concurrently while stdout is streamed for matches; completion waits on stdout (stderr awaited only on non-success). The view defers content-driven refreshes while searches stream. Tests verify full match publication and that contentRevision reloads don't restart active find searches.

Changes

Search result synchronization fix, UI refresh deferral, and tests

Layer / File(s) Summary
View: pending refresh state
Sources/FileExplorerView.swift
Adds pendingSearchRefreshAfterSettled and clears it when search visibility changes or on close.
View: refresh scheduling & header update
Sources/FileExplorerView.swift
Refactors updateHeader, adds refreshSearchAfterContentRevisionIfNeeded, and clears pending flag when scheduling debounced refreshes.
SearchPipeline: stdout buffering
Sources/FileExplorerSearchController.swift
Add stdoutBuffer, incremental consumeStdout/consumeBufferedStdout, replace line entry with consumeStdoutLine, and drain trailing stdout in finish(status:).
SearchController: concurrent stderr draining
Sources/FileExplorerSearchController.swift
Start a concurrent stderrTask to drain stderr diagnostics; cancel on scope exit and await it only for non-success exit codes.
Low-level streaming
Sources/FileExplorerSearchController.swift
Rewrite streamStdout/streamStderr to use Darwin.read with EINTR handling, feed byte chunks into the pipeline, and emit formatted stderr on read errors.
Tests: search behavior & spy helper
cmuxTests/FileExplorerStoreTests.swift
Adds testSearchPublishesAllMatchingFilesInFolder, testContentRevisionChangeDoesNotRestartActiveFindSearch, and SpyFileSearchController.publish(_:) helper.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant FileSearchController
  participant StdoutTask
  participant StderrTask
  participant Process
  Client->>FileSearchController: start search request
  FileSearchController->>StdoutTask: stream stdout (matches)
  FileSearchController->>StderrTask: start stderr drain (concurrent)
  StdoutTask-->>Client: publish matches progressively
  Process->>FileSearchController: terminationSignal
  FileSearchController->>StdoutTask: await stdoutDone
  alt non-success exit
    FileSearchController->>StderrTask: await stderrTask.value
  else success or code 1
    FileSearchController->>StderrTask: cancel/ignore stderr
  end
  FileSearchController->>FileSearchController: pipeline.finish(status)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • manaflow-ai/cmux#3739: Both PRs modify FileExplorerSearchController.swift's process output and termination handling.

Poem

🐰 I nibbled bytes from stdout's trail,

stderr now sips on its own pale ale.
Matches arrive, no crumbs left behind,
Deferred refresh waits till the stream's aligned.
Tests hop in, and count every find.


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Actor Isolation ❌ Error Raw Int32 file descriptors passed from @MainActor to nonisolated functions without capturing FileHandle/Pipe. FileHandle lifetime not anchored in Task.detached, violating Sendable safety. Capture FileHandles in Task.detached: [weak self, pipeline, terminationSignal, stdoutHandle, stderrHandle] and anchor with _ = stdoutHandle at task end, per review comment proposal.
Cmux Swift File And Package Boundaries ❌ Error FileExplorerSearchController.swift captures raw fds without retaining FileHandle objects. This creates fd-reuse bugs during search cancellation. Capture stdoutHandle and stderrHandle in Task.detached closure. Add '_ = stdoutHandle/stderrHandle' to keep FileHandles alive during reads, preventing fd reuse on cancellation.
Cmux Architecture Rethink ❌ Error Detached task captures only Int32 fd, not Pipe/FileHandle. When search cancels, Pipe releases and fd recycles. Stale task consumes new search bytes. Socket race violates rules. Fix not applied. Capture stdoutHandle/stderrHandle in detached closure to anchor Pipe lifetime and prevent fd reuse.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (11 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix Files find result aggregation' directly summarizes the main change: addressing the regression where Find-in-folder only showed one result instead of all matches.
Linked Issues check ✅ Passed Code changes fully address issue #3817 requirements: regression test added for multi-file folder searches [3817], stdout-gated finalization prevents result loss [3817], and content-revision deferral prevents search restart during streaming [3817]. Typing-lag debounce preserved.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the Find-in-folder regression: pipeline buffering, stdout/stderr handling, result finalization, and Find refresh behavior align with issue #3817 objectives and do not introduce unrelated modifications.
Cmux Swift Blocking Runtime ✅ Passed Darwin.read() in detached tasks is standard for stream I/O. No semaphores, sleeps, sync, or thread-blocking waits introduced. FileSearchTerminationSignal.wait() uses CheckedContinuation, not blocking.
Cmux No Hacky Sleeps ✅ Passed Check applies to TypeScript, JavaScript, shell, and non-Swift runtime scripts. PR modifies only Swift files, which are explicitly excluded and covered by swift-blocking-runtime.md instead.
Cmux Swift Concurrency ✅ Passed PR introduces no legacy async patterns. Uses modern Task.detached with proper lifecycle management; fire-and-forget Tasks only at required OS/AppKit/Combine boundaries.
Cmux Swift @Concurrent ✅ Passed File I/O-heavy async functions have explicit actor hops via Task.detached. No missing @concurrent annotations or invalid usage. Proper isolation boundaries maintained.
Cmux Swift Logging ✅ Passed No logging violations found. Code uses proper internal pipeline buffering for ripgrep diagnostics rather than print/NSLog. Tests use benign file creation operations.
Cmux Swiftui State Layout ✅ Passed No SwiftUI state layout violations. Pre-existing @ObservedObject used only for AppKit bridge (allowed). New state uses private Bool flags. Search results pass value snapshots correctly.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed No standalone windows. Changes are to file search controller and NSView-based UI components. No NSWindow, NSPanel, NSWindowController, or SwiftUI Window creations detected.
Description check ✅ Passed The pull request description covers all major required sections: a clear summary of changes, testing methodology, verification steps, and a comprehensive checklist.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-3817-find-in-folder-one-result

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 and usage tips.

@greptile-apps

greptile-apps Bot commented May 10, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes the Files Find result aggregation regression from #3739. It switches stdout handling from FileHandle.bytes.lines (which could stall mid-stream) to chunk-based POSIX reads on a dedicated DispatchQueue, frames lines in an actor-backed buffer, flushes a trailing partial line on completion, and preserves the terminal .limited state through finish(). Content-revision refreshes are now deferred until the current ripgrep stream settles, and scope changes still trigger an immediate restart.

  • Core I/O fix: FileSearchOutputPipeline now buffers stdoutBuffer, drains via consumeBufferedStdout, and retains a terminalUpdate so finish() returns the correct .limited status even when the limit is hit by a trailing unflushed line.
  • Concurrency rework: FileSearchPipeReader dispatches Darwin.read() onto a private concurrent DispatchQueue with withCheckedContinuation, keeping blocking syscalls off Swift's cooperative executor. The outer task gates on stdout completion; stderr is only awaited for non-0/1 exits.
  • Deferred refresh: pendingSearchRefreshAfterSettled defers content-revision-triggered re-searches until applySearchSnapshot fires with isSearching: false, with regression tests verifying both multi-file aggregation and the no-restart behavior.

Confidence Score: 4/5

The I/O overhaul correctly fixes the aggregation bug and the previously-flagged trailing-line .limited issue; one minor deferred-refresh flag gap remains in direct refreshSearchIfNeeded() call sites.

The pipe-read rewrite, buffer framing, and terminalUpdate/trailingUpdate flow in finish() are all correctly implemented. The only remaining gap is refreshSearchIfNeeded() not clearing pendingSearchRefreshAfterSettled, which can cause an extra harmless re-search via focusSearchField() — not a correctness break, but a visible UX flicker in a narrow path.

Sources/FileExplorerView.swift — specifically refreshSearchIfNeeded() and its interaction with pendingSearchRefreshAfterSettled in paths that bypass scheduleSearchRefresh().

Important Files Changed

Filename Overview
Sources/FileExplorerSearchController.swift Major I/O overhaul: replaces AsyncSequence line iteration with POSIX chunked reads on a DispatchQueue, adds stdoutBuffer framing actor, preserves terminalUpdate through finish(). Both previously-flagged P1s (blocking cooperative thread pool; finish() discarding .limited trailing update) are fixed.
Sources/FileExplorerView.swift Adds pendingSearchRefreshAfterSettled flag with correct reset in didSet, scheduleSearchRefresh, scope-change path, and search cancellation. Deferred refresh triggers via applySearchSnapshot when isSearching becomes false. refreshSearchIfNeeded() does not clear the flag, leaving a minor gap for paths that call it directly.
cmuxTests/FileExplorerStoreTests.swift Adds regression coverage for multi-file nested-folder aggregation, 500-result limit publication, and deferred content-revision refresh semantics.
cmuxTests/FileSearchRipgrepParserTests.swift Adds FileSearchOutputPipelineTests covering trailing-buffered-line .limited preservation and streaming-limit .limited preservation through finish().

Sequence Diagram

sequenceDiagram
    participant UI as FileExplorerContainerView
    participant SC as FileSearchController
    participant OT as searchTask (outer Task.detached)
    participant ST as stdoutTask (Task.detached)
    participant ER as stderrTask (Task.detached)
    participant PL as FileSearchOutputPipeline (actor)
    participant PR as FileSearchPipeReader (DispatchQueue)

    UI->>SC: search(query:rootPath:)
    SC->>SC: spawn Process (rg --json)
    SC->>OT: Task.detached
    OT->>ST: Task.detached streamStdout
    OT->>ER: Task.detached streamStderr (utility)
    OT->>OT: await terminationSignal.wait()

    loop Read 32 KB chunks
        ST->>PR: FileSearchPipeReader.read()
        PR-->>ST: .chunk(data)
        ST->>PL: consumeStdout(data)
        PL-->>ST: update? (throttled by snapshotInterval)
        ST->>SC: applyPipelineUpdate(update, generation)
    end

    Note over ST: EOF from rg stdout
    ST-->>OT: stdoutTask completes
    Note over OT: rg exits, terminationSignal fires
    OT->>OT: await stdoutTask.value
    OT->>PL: finish(status)
    PL->>PL: flush stdoutBuffer trailing line
    PL-->>OT: terminalUpdate ?? trailingUpdate ?? normal
    OT->>SC: finish(generation:update:)
    SC->>UI: onSnapshotChanged(.matches / .limited / .noMatches)
Loading

Reviews (8): Last reviewed commit: "Avoid async XCTest unwrap autoclosure" | Re-trigger Greptile

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 33b7cfd. Configure here.

Comment thread Sources/FileExplorerSearchController.swift Outdated
Review feedback correctly noted that successful searches do not need stderr for result completeness, but failed ripgrep exits still use stderr to format the visible error. Keep stdout as the success/no-match completion gate and wait for the diagnostic stream only on non-0/1 statuses before finishing the pipeline.

Constraint: Preserve complete successful result publication without regressing failed-search diagnostics

Rejected: Await stderr for every search | reintroduces the one-result regression by letting diagnostic stream completion gate successful results

Confidence: high

Scope-risk: narrow

Directive: Only failure statuses may wait on stderr; stdout remains the match-completeness stream

Tested: git diff --check -- Sources/FileExplorerSearchController.swift

Not-tested: Local XCTest execution skipped because this task forbids direct xcodebuild
@austinywang

Copy link
Copy Markdown
Contributor Author

Reviewed the latest Greptile medium-classified summary: it marks this as safe to merge and does not request a code change. The noted unstructured stderr task is intentionally bounded by the surrounding search task via defer cancellation; the only awaited stderr path runs after rg has exited and is needed to preserve failure diagnostics.

A content revision from the Files sidebar can arrive while find-in-folder is still streaming results. The regression test pins that a same-query content refresh is queued instead of immediately issuing another search request and clearing the active stream.

Constraint: Local xcodebuild is prohibited in this workspace; validation is limited to diff checks before CI.

Confidence: high

Scope-risk: narrow

Tested: git diff --check -- cmuxTests/FileExplorerStoreTests.swift

Not-tested: XCTest execution, deferred to CI per repository policy
Find-in-folder was still showing one live result because file-tree content revisions and same-mode sidebar updates could reissue the same query while ripgrep was streaming. That cancelled the current process, cleared accumulated results, and restarted before the stream reached the rest of stdout.

This keeps query/root/provider changes immediate, but queues same-query content refreshes until the active search settles. The result stream can now accumulate normally, and file changes still trigger one follow-up search after the current pass.

Constraint: Preserve typing-lag optimization by debouncing query input and not debouncing result output.

Rejected: Remove contentRevision refresh entirely | would miss file changes after an existing query.

Confidence: high

Scope-risk: narrow

Tested: git diff --check -- Sources/FileExplorerView.swift cmuxTests/FileExplorerStoreTests.swift

Not-tested: XCTest execution, deferred to CI per repository policy
@austinywang

Copy link
Copy Markdown
Contributor Author

Follow-up for the live repro screenshot: the one-result behavior was caused by same-query Find searches being restarted by Files sidebar content revisions while rg was still streaming. Added c02aa84 to cover that starvation path and dd25a5d to queue content-refresh reruns until the active search settles, so query/root changes still refresh immediately but result streaming is no longer cancelled by tree reloads.

The new Files find lifecycle regression test lives in FileSearchControllerTests, so it needs its own condition-based wait helper instead of calling the FileExplorerStoreTests helper from another XCTest class. This keeps the regression coverage executable in CI without changing the production fix.

Constraint: Local direct xcodebuild is forbidden for this task; CircleCI provided the failing compile diagnostic.

Rejected: Use a fixed sleep | the test should wait for the observable search request count.

Confidence: high

Scope-risk: narrow

Tested: git diff --check -- cmuxTests/FileExplorerStoreTests.swift Sources/FileExplorerView.swift

Not-tested: Local unit suite, per repository/task policy.
The live dev build showed ripgrep still running with its stdout pipe full while the Find UI stayed at one match. This regression test exercises the behavior-level contract for high-volume folder searches: the controller must drain enough stdout to publish the 500-result limit instead of waiting for ripgrep to finish naturally.

Constraint: Local direct xcodebuild is forbidden for this task; the test is committed for CI to exercise.

Confidence: medium

Scope-risk: narrow

Tested: git diff --check -- cmuxTests/FileExplorerStoreTests.swift

Not-tested: Local unit suite, per repository/task policy.
The second dogfood repro showed the real failure mode: the app had a live ripgrep child with stdout pipe full while the Find UI stayed at one match. The async line reader introduced by the typing-lag optimization could stop draining stdout, leaving ripgrep blocked and the search permanently in the streaming state.

This keeps the typing-lag intent by parsing stdout off the main actor and publishing throttled snapshots through the existing pipeline, but it no longer depends on FileHandle.AsyncBytes.lines. A detached POSIX-read pump drains stdout as bytes, the actor owns line framing and result accumulation, and the controller still cancels only on query/scope changes or the 500-result limit.

Constraint: Build must use scripts/reload.sh only; no direct xcodebuild.

Rejected: Revert to the old MainActor readabilityHandler | it fixed draining but reintroduced the typing-lag path.

Rejected: Raise or collect the result limit | the bug is stdout starvation, not the limit size.

Confidence: high

Scope-risk: moderate

Directive: Keep query debounce separate from stdout draining; result aggregation must continue even when UI snapshot publishing is throttled.

Tested: git diff --check -- Sources/FileExplorerSearchController.swift cmuxTests/FileExplorerStoreTests.swift

Not-tested: Local unit suite, per repository/task policy.
coderabbitai[bot]
coderabbitai Bot previously requested changes May 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@Sources/FileExplorerSearchController.swift`:
- Around line 363-397: The detached read tasks capture raw Int32 fds
(stdout.fileHandleForReading.fileDescriptor /
stderr.fileHandleForReading.fileDescriptor) without retaining the
Pipe/FileHandle, leading to fd reuse races; fix by retaining the read FileHandle
(or the Pipe) in the Task capture list so the closure keeps the read end alive
for the lifetime of streamStdout/streamStderr — e.g. capture
stdout.fileHandleForReading and stderr.fileHandleForReading (or the Pipe
instances) in the Task.detached closures used by searchTask and pass those
FileHandle objects into Self.streamStdout and Self.streamStderr instead of raw
Int32 fds, ensuring terminationSignal, process, searchGeneration, and pipeline
logic remain unchanged.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 99892fdb-6523-4ba5-962a-af667d3654a2

📥 Commits

Reviewing files that changed from the base of the PR and between 8fa0d1f and 853ae94.

📒 Files selected for processing (2)
  • Sources/FileExplorerSearchController.swift
  • cmuxTests/FileExplorerStoreTests.swift

Comment thread Sources/FileExplorerSearchController.swift
Merged origin/main into the PR branch before processing review feedback and checks so CI validates against the latest shared code.

Constraint: iterate-pr workflow requires syncing the PR branch with its base before feedback and CI work
Confidence: high
Scope-risk: narrow
Reversibility: clean
Tested: Merge completed cleanly with ort strategy
Not-tested: Local tests not run per repo testing policy
Detached search stream tasks now retain read handles for stdout and stderr while blocking reads run on a dedicated Dispatch queue instead of Swift's cooperative executor. The search pipeline also preserves a final limited update when the last buffered stdout line reaches the result cap.

Constraint: Review bots flagged fd reuse risk, cooperative executor blocking, and final trailing-line limit misreporting
Rejected: Returning to FileHandle.bytes.lines | prior PR changed away from line iteration to avoid result-completeness coupling with stderr/process exit timing
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Keep file search completion defined by stdout EOF; stderr is diagnostic-only except non-0/1 exits
Tested: git diff --check; tagged reload queued for compile verification
Not-tested: Local unit tests not run per repo testing policy
@austinywang

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

The find panel already has the search-field placeholder, so the idle status line repeated the same instruction and added visual noise before the user has typed anything.

Constraint: Keep non-idle search status text unchanged

Confidence: high

Scope-risk: narrow

Tested: ./scripts/reload.sh --tag issue-3817-find-in-folder-one-result

Not-tested: Local test suite per repository policy; CI will run after push
The search pipeline can hit the result cap before the outer process task finishes. Remembering the terminal limited update makes finish(status:) return the same terminal state instead of relying on the controller generation guard to discard later completion updates.

Constraint: Keep stdout-gated finalization and early process-stop behavior unchanged

Rejected: Only document the generation-guard invariant | review feedback identified this as a future refactor hazard

Confidence: high

Scope-risk: narrow

Tested: ./scripts/reload.sh --tag issue-3817-find-in-folder-one-result

Not-tested: Local XCTest execution per repository policy; CI will run after push
The pipeline limit regression test awaited inside XCTUnwrap's synchronous autoclosure, which can fail test compilation even though the app target builds. Split the awaited optional from the assertion so XCTest sees a plain value.

Constraint: Local XCTest execution is disabled by repository policy

Confidence: medium

Scope-risk: narrow

Tested: git diff --check -- cmuxTests/FileSearchRipgrepParserTests.swift

Tested: ./scripts/reload.sh --tag issue-3817-find-in-folder-one-result

Not-tested: Local XCTest execution per repository policy; CircleCI macOS unit tests will verify
@austinywang
austinywang dismissed coderabbitai[bot]’s stale review May 11, 2026 05:24

Dismissed as stale: the CodeRabbit fd-retention finding was addressed by retaining read handles, the inline thread is resolved, and the latest CodeRabbit check is passing on 741ff5a.

@austinywang
austinywang merged commit 45b21e4 into main May 11, 2026
24 checks passed

This branch was successfully deployed

1 active deployment
Preview – cmux — 741ff5a7 Deployed May 11, 2026 by vercel[bot]
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.

Find-in-folder only shows one result (regression from typing-lag optimization)

1 participant