Skip to content

Stabilize git metadata FSEvents watcher - #5131

Merged
azooz2003-bit merged 5 commits into
mainfrom
issue-5130-fsevents-heap-corruption
Jun 1, 2026
Merged

azooz2003-bit merged 5 commits into
mainfrom
issue-5130-fsevents-heap-corruption

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jun 1, 2026 •

Copy link
Copy Markdown
Collaborator

Addresses the workspace git metadata FSEvents watcher side of #5130.

The issue also reports a separate Sentry/Breakpad signal-handler livelock after abort(). This PR does not change crash-handler behavior.

This hardens the workspace git metadata FSEvents watcher against noisy repositories by:

  • retaining and releasing the Swift callback box through the FSEvents context
  • sharing one utility queue across watcher instances instead of creating one serial queue per watcher
  • removing NoDefer so FSEvents can coalesce bursts
  • coalescing change refreshes so an event storm does not allocate and cancel a new DispatchWorkItem for every filesystem event

Regression proof:

Verification:

  • ./scripts/reload.sh --tag fix5130
  • full PR checks passed, including tests, tests-build-and-lag, release-build, and ui-regressions

Summary by CodeRabbit

  • Refactor

    • Optimized git metadata watcher to refresh more responsively during sustained file system activity.
  • Tests

    • Added validation test for git metadata watcher responsiveness during high file system event volumes.

@vercel

vercel Bot commented Jun 1, 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 Jun 1, 2026 11:18pm
cmux-staging Building Building Preview, Comment Jun 1, 2026 11:18pm

@coderabbitai

coderabbitai Bot commented Jun 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

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

The PR hardens the FSEvents-based git metadata watcher against event storms by introducing explicit CF retain/release callbacks for callback lifetime management, converting to static queue affinity with specific-key detection, removing the no-defer flag, switching debounce to a leading-edge throttle, and adding a DEBUG storm-simulation test helper with integration test.

Changes

FSEvents Watcher Memory Safety and Burst Handling

Layer / File(s) Summary
CFAllocator callbacks and static queue affinity
Sources/TabManager.swift
Thread-safe refresh-delay recorder and explicit CFAllocator retain/release callbacks for callback-box lifetime; static DispatchQueue and DispatchSpecificKey replace per-instance queue affinity.
FSEvent stream context and initialization
Sources/TabManager.swift
FSEventStreamContext updated with new explicit retain/release callbacks; kFSEventStreamCreateFlagNoDefer removed from flags; watcher init adjusted to use static queue/specific-key model.
Stream start/stop lifecycle and queue-affine teardown
Sources/TabManager.swift
FSEvent stream bound to static queue on start; stop() rewritten to detect queue affinity via specific-key check and perform synchronous teardown, cancelling pending debounce work and releasing the stream.
Debounce to leading-edge throttle
Sources/TabManager.swift
Debouncing changed from cancel-and-reschedule to single-schedule: arms one delayed flush only when no pending work exists; new flushScheduledChangeOnQueue() clears pending work, guards stream != nil, and calls onChange().
DEBUG test helper and storm simulation test
Sources/TabManager.swift, cmuxTests/WorkspacePullRequestSidebarTests.swift
DEBUG-only workspaceGitMetadataWatcherFirstRefreshDelayDuringStormForTesting(...) synthesizes event burst and measures first refresh delay; XCTest testGitMetadataWatcherRefreshesDuringSustainedEventStorm asserts delay is under 1 second.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • manaflow-ai/cmux#2797: Modifies sidebar Git metadata watcher FSEvents-driven refresh logic (context/stream lifecycle and debounce/throttling behavior).

Poem

🐰 A watcher once wary of storms now stands tall,
With callbacks that grip and a queue shared by all.
No deferral delays—just a single flush waits,
While rabbits test bursts at dramatic rates! 🌪️✨


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (1 error, 1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error PR introduces DispatchQueue.asyncAfter in production code (Sources/TabManager.swift:209), which violates the blocking-runtime rule treating asyncAfter as failures by default in shipped code. Remove explicit asyncAfter delay or document as required safety deferral with unavailable alternatives per allowed exceptions in swift-blocking-runtime.md.
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description covers what changed, why, and includes regression proof and verification steps, but lacks the structured sections from the template (Summary, Testing, Demo Video, Review Trigger, Checklist). Restructure the description to match the template sections: add a formal Summary block, explicit Testing section, and complete the Checklist to improve clarity and consistency.
✅ Passed checks (15 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main change—stabilizing the FSEvents watcher—which is the core focus of the changeset in TabManager.swift and the test validation.
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.
Cmux Swift Actor Isolation ✅ Passed Callback properly bridges background watcher queue to @MainActor; @unchecked Sendable types justified with synchronization; testing function correctly marked nonisolated DEBUG-only.
Cmux No Hacky Sleeps ✅ Passed PR modifies only Swift files. Rule scope covers TypeScript, JavaScript, shell, and non-Swift build scripts—Swift is explicitly out of scope per the rule.
Cmux Algorithmic Complexity ✅ Passed PR changes to WorkspaceGitMetadataWatcher are O(1) per event with no nested scans; debouncing improvement reduces allocate-cancel churn; test code is DEBUG-only with bounded parameters.
Cmux Swift Concurrency ✅ Passed DispatchQueue usage is at required OS boundary (FSEvents API); test-only helper uses DispatchSemaphore/DispatchQueue.global for synchronization which are explicitly allowed for test scaffolding.
Cmux Swift @Concurrent ✅ Passed Synchronous test helper correctly lacks @concurrent. Async functions retain proper @concurrent annotations. No concurrent annotation rule violations.
Cmux Swift File And Package Boundaries ✅ Passed PR adds 169 lines (under 250 threshold) to existing TabManager.swift; focused FSEvents bug fix with internal-only changes and DEBUG-only test helpers.
Cmux Swift Logging ✅ Passed No logging violations found: DEBUG-only code wrapped in #if DEBUG, test helpers exempt, FileManager only in test code, no print/debugPrint/dump/NSLog in production.
Cmux User-Facing Error Privacy ✅ Passed No user-facing errors are added; all changes are internal FSEvents watcher implementation, DEBUG-only testing code (guarded by #if DEBUG), and test-only additions. No sensitive information is exposed.
Cmux Full Internationalization ✅ Passed PR only adds DEBUG-only test infrastructure and test code with no new user-facing text; no string catalog or web locale changes required.
Cmux Swiftui State Layout ✅ Passed PR modifies internal FSEvents watcher plumbing only; no new SwiftUI state patterns, GeometryReader, lazy/list store references, or render-time mutations.
Cmux Architecture Rethink ✅ Passed PR makes targeted FSEvents memory management and coalescing fixes with clear documented invariants; test-only timing patterns are allowed; no symptom patches introducing architectural debt.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only modifies internal FSEvents watcher implementation and adds DEBUG-only test helper and test case—no NSWindow/NSPanel/NSWindowController/SwiftUI Window definitions or modifications.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-5130-fsevents-heap-corruption

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.

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 1 file

Re-trigger cubic

@greptile-apps

greptile-apps Bot commented Jun 1, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR hardens the workspace git metadata FSEvents watcher against high-frequency filesystem events by replacing the trailing-edge debounce (cancel-and-reschedule on every event) with a leading-edge throttle, sharing one serial queue across all watcher instances, removing kFSEventStreamCreateFlagNoDefer to let FSEvents coalesce bursts, and adding proper retain/release callbacks to the FSEventStreamContext so the callback box lifetime is correctly managed by the stream itself.

  • Retain/release fix: FSEventStreamContext now holds its own ARC-managed retain on WorkspaceGitMetadataWatcherCallbackBox via the new context callbacks, preventing a potential use-after-free if the Swift-side strong reference is released before the stream delivers its last event.
  • Leading-edge throttle: scheduleChangeOnQueue now guards with debounceWorkItem == nil, coalescing all events during the 0.25 s window into a single onChange call rather than allocating and cancelling a new DispatchWorkItem per event — the root cause of the event-storm regression.
  • Test coverage: A new testGitMetadataWatcherRefreshesDuringSustainedEventStorm test drives 80 synthetic events at 20 ms intervals and asserts the first refresh arrives within 1.0 s, proving in-burst delivery rather than wait-for-quiet semantics.

Confidence Score: 5/5

Safe to merge — changes are narrowly scoped to the watcher's internal scheduling and memory management, with no impact on external API or callers.

The retain/release context callbacks are correctly paired with passUnretained, the shared serial queue eliminates per-watcher thread overhead without introducing new data races, the leading-edge throttle correctly resets debounceWorkItem before calling onChange, and the regression test exercises the exact failure mode from the issue report.

No files require special attention.

Important Files Changed

Filename Overview
Sources/TabManager.swift Adds retain/release FSEvents context callbacks, shared static queue, leading-edge throttle in scheduleChangeOnQueue, and DEBUG-only test scaffolding; logic is sound, teardown and memory management are correctly handled.
cmuxTests/WorkspacePullRequestSidebarTests.swift Adds testGitMetadataWatcherRefreshesDuringSustainedEventStorm, which validates the leading-edge throttle fires during an 80-event storm with appropriate timeout headroom for CI jitter.

Sequence Diagram

sequenceDiagram
    participant FS as FSEvents (kernel)
    participant CB as watcher callback
    participant Q as Self.queue (shared serial)
    participant Throttle as scheduleChangeOnQueue
    participant Flush as flushScheduledChangeOnQueue
    participant OC as onChange

    FS->>CB: deliver events (coalesced, ~0.25s latency)
    CB->>Q: async scheduleChangeOnQueue()
    Q->>Throttle: "run (debounceWorkItem == nil?)"
    alt first event in window
        Throttle->>Q: asyncAfter(0.25s, flushScheduledChangeOnQueue)
        Note over Throttle: debounceWorkItem set
    else pending flush exists
        Throttle-->>Q: guard fails, no-op coalesced
    end
    Q->>Flush: run after 0.25s
    Flush->>Flush: "debounceWorkItem = nil"
    Flush->>OC: onChange() spawns MainActor Task
    Note over FS,OC: Worst-case latency ~0.5s
Loading

Reviews (6): Last reviewed commit: "Merge remote-tracking branch 'origin/iss..." | Re-trigger Greptile

Comment thread Sources/TabManager.swift
Comment on lines 131 to +138
private func scheduleChangeOnQueue() {
debounceWorkItem?.cancel()
guard stream != nil, debounceWorkItem == nil else { return }
let workItem = DispatchWorkItem { [weak self] in
self?.onChange()
self?.flushScheduledChangeOnQueue()
}
debounceWorkItem = workItem
queue.asyncAfter(deadline: .now() + 0.25, execute: workItem)
Self.queue.asyncAfter(deadline: .now() + 0.25, execute: workItem)
}

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 Leading-edge rate-limiter doubles worst-case latency to ~0.5 s

scheduleChangeOnQueue now acts as a leading-edge throttle: the first event in a window fires onChange 0.25 s later, then the window reopens for the next batch. But the FSEventStreamCreate latency parameter is also 0.25 s, so the real worst-case delay from a filesystem event to onChange is now ~0.5 s (FSEvents coalescing + rate-limiter). More importantly, during a prolonged burst each FSEvents delivery that arrives after the rate-limiter window reopens schedules a new 0.25 s work item—so onChange fires roughly every 0.5 s throughout the storm. The previous trailing-edge debounce fired once, 0.25 s after the storm ended. Both behaviours are acceptable for git metadata, but callers relying on "fires after quiet period" semantics will see more frequent refreshes. A comment here capturing the intended contract ("fires at most once per 0.5 s window, not once per quiet period") would help future readers.

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.

Done in 80bcbdc — added a comment above scheduleChangeOnQueue capturing the leading-edge throttle contract: the first event arms a single 0.25s flush, events arriving while it's pending are coalesced (no-op), worst-case event→onChange is ~0.5s (0.25s FSEvents latency + 0.25s throttle), and it fires at most once per ~0.25s window rather than waiting for the repo to go quiet.

— Claude Code

Comment thread Sources/TabManager.swift
Comment on lines 101 to 108
func stop() {
if DispatchQueue.getSpecific(key: queueSpecificKey) != nil {
if DispatchQueue.getSpecific(key: Self.queueSpecificKey) != nil {
stopOnQueue()
} else {
queue.sync {
Self.queue.sync {
stopOnQueue()
}
}

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 stop() blocks calling thread on shared serial queue

Self.queue.sync { stopOnQueue() } blocks the calling thread until all in-flight work on the shared queue finishes. Because TabManager is @MainActor and calls stop() synchronously (via stopWorkspaceGitMetadataWatcher → removeValue(forKey:)?.stop() and stopAllWorkspaceGitMetadataWatchers), every stop() from the main actor blocks the main thread. With a per-instance queue (the old design) the risk was scoped to one watcher's work; with Self.queue shared across all watcher instances, a slow onChange body on any watcher serialises all stops. The current onChange closure (Task creation + return) is fast, so in practice this is negligible—but the contract is fragile and not captured in the type. This falls under the cmux-swift-blocking-runtime concern for DispatchQueue.sync from a UI-bound context.

Rule Used: Flag new blocking or timing-based synchronization ... (source)

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.

Documented the contract rather than changing the sync semantics, because the Self.queue.sync is required for correct teardown. stop() is invoked from deinit (and via removeValue(forKey:)?.stop() on a temporary), where an async hop would let the watcher deallocate before the FSEventStream is invalidated — the [weak self] teardown would no-op and leak the stream. I added comments on the shared queue and on stop() capturing that, because teardown synchronizes on the shared queue, onChange must stay non-blocking — and it does: the production closure only spawns a @MainActor Task and returns, so the critical section is bounded. (80bcbdc)

— Claude Code

@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: 3

🤖 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 `@cmuxTests/WorkspacePullRequestSidebarTests.swift`:
- Around line 1646-1650: The assertion currently checks XCTAssertLessThan(delay,
1.0) which equals the waitTimeout and leaves no margin for CI jitter; change the
asserted bound to a value comfortably below the timeout (for example assert
delay < 0.8) and ensure the helper's waitTimeout remains higher than that bound
(e.g., keep waitTimeout at 1.0 or increase it to 1.2) so the measured delay and
XCTUnwrap have headroom; update the assertion call (XCTAssertLessThan with
variable delay) and, if necessary, the waitTimeout passed into the helper used
to measure delay so the test is robust against timing jitter.
- Around line 1635-1651: The assertion in
testGitMetadataWatcherRefreshesDuringSustainedEventStorm uses
XCTAssertLessThan(delay, 1.0) which is exactly the waitTimeout and can be flaky;
update the assertion in this test
(testGitMetadataWatcherRefreshesDuringSustainedEventStorm) to use a safer
threshold (e.g., XCTAssertLessThan(delay, 0.9) or 0.95) when checking the value
returned by
TabManager.workspaceGitMetadataWatcherFirstRefreshDelayDuringStormForTesting(...)
so the test has slack against CI timing jitter.

In `@Sources/TabManager.swift`:
- Around line 5022-5065: The helper is nondeterministic because it starts timing
before creating the watcher, uses NSTemporaryDirectory() (sharing unrelated FS
events), and leaves the background producer running after timeout; fix by
creating a unique temporary directory (e.g.,
FileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString)) and
pass that into WorkspaceGitMetadataWatcher.Descriptor instead of
NSTemporaryDirectory(), start the startedAt clock only after createdWatcher is
non-nil (i.e., after watcher is constructed), and run the producer as a
cancellable DispatchWorkItem (store it, call workItem.cancel() in the defer that
calls watcher.stop()) so the loop checks workItem.isCancelled and exits to avoid
enqueueing events after the helper returns; ensure semaphore.wait timeout still
returns nil as before.
🪄 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: ea5d2fdf-fb36-4246-8f85-0b51d59d4eff

📥 Commits

Reviewing files that changed from the base of the PR and between 31f3c17 and 264f621.

📒 Files selected for processing (2)
  • Sources/TabManager.swift
  • cmuxTests/WorkspacePullRequestSidebarTests.swift

Comment thread cmuxTests/WorkspacePullRequestSidebarTests.swift
Comment thread cmuxTests/WorkspacePullRequestSidebarTests.swift
Comment thread Sources/TabManager.swift

@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: 2

🤖 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 @.github/workflows/test-depot.yml:
- Around line 142-143: Update the workflow input description for
inputs.test_filter to clearly state that the filter applies to both unit and UI
tests (it sets the TEST_FILTER env var used in the unit test job and is also
applied to the UI test job), so users know a single value will filter both test
runs; locate the input named test_filter and change its description to mention
both "unit and UI tests" and that it sets TEST_FILTER (inputs.test_filter ->
env: TEST_FILTER) so the intent matches its use in the jobs (including the UI
test step that reads the same input).
- Around line 148-158: The unit-test invocation fails under bash -u because
ONLY_TESTING is an empty array and "${ONLY_TESTING[@]}" expansion can be treated
as an unbound variable on older macOS bash; change the logic to use a string arg
instead of an empty array: initialize ONLY_TESTING_ARG="" and if [ -n
"$TEST_FILTER" ]; then ONLY_TESTING_ARG="-only-testing:cmuxTests/$TEST_FILTER";
fi, then pass "$ONLY_TESTING_ARG" into the xcodebuild invocation (replace
"${ONLY_TESTING[@]}" with "$ONLY_TESTING_ARG"); alternatively, keep the array
but use a safe expansion pattern like "${ONLY_TESTING[@]:-}" to avoid the
unbound variable error.
🪄 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: add64c3a-83a9-489e-b6fc-c25e3ed001c7

📥 Commits

Reviewing files that changed from the base of the PR and between 264f621 and 1f8d078.

📒 Files selected for processing (1)
  • .github/workflows/test-depot.yml

Comment thread .github/workflows/test-depot.yml Outdated
Comment thread .github/workflows/test-depot.yml Outdated
@azooz2003-bit
azooz2003-bit force-pushed the issue-5130-fsevents-heap-corruption branch from 1f8d078 to 264f621 Compare June 1, 2026 21:22
@azooz2003-bit
azooz2003-bit force-pushed the issue-5130-fsevents-heap-corruption branch from 264f621 to 5b89f05 Compare June 1, 2026 21:24
@azooz2003-bit
azooz2003-bit force-pushed the issue-5130-fsevents-heap-corruption branch from 5b89f05 to 117b67a Compare June 1, 2026 21:31
coderabbitai[bot]
coderabbitai Bot previously requested changes Jun 1, 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 @.github/workflows/test-depot.yml:
- Around line 148-157: The workflow assumes expanding ${ONLY_TESTING[@]} is safe
under all runner shells, but the reviewer noted the failure claim applies only
to Bash 3.2; instead make the invocation robust regardless of shell by
conditionally appending the array only when it contains elements. Update the
block that builds and calls xcodebuild (symbols: ONLY_TESTING, TEST_FILTER,
scripts/ci/xcodebuild_noninteractive.py, xcodebuild ... test) so you check if [
"${`#ONLY_TESTING`[@]}" -gt 0 ] and, if true, include "${ONLY_TESTING[@]}" in the
command; otherwise call the same command without that expansion—this removes
dependence on shell-specific empty-array expansion semantics and avoids
unbound-variable problems under set -u.
🪄 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: c7b1054c-4c57-4565-bdb8-e8c0ceb959f3

📥 Commits

Reviewing files that changed from the base of the PR and between 1f8d078 and 5b89f05.

📒 Files selected for processing (3)
  • .github/workflows/test-depot.yml
  • Sources/TabManager.swift
  • cmuxTests/WorkspacePullRequestSidebarTests.swift

Comment thread .github/workflows/test-depot.yml Outdated
- Make the storm test helper deterministic: watch a unique temp dir
  (not the shared NSTemporaryDirectory), start the delay clock when the
  synthetic storm actually begins, and cancel the producer on teardown so
  a timeout can't leave events landing on the shared queue and bleed into
  later tests.
- Document the watcher contracts: the leading-edge throttle semantics
  (~0.5s worst case, fires at most once per ~0.25s window rather than
  after a quiet period), and why stop() must synchronize on the shared
  queue (deinit teardown safety) with the implied non-blocking onChange
  contract.
- Give the storm-test assertion margin against CI jitter: waitTimeout
  1.0 -> 2.0 so the XCTUnwrap/comparison have headroom while
  XCTAssertLessThan(delay, 1.0) stays the meaningful in-burst assertion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@azooz2003-bit
azooz2003-bit dismissed coderabbitai[bot]’s stale review June 1, 2026 22:55

Stale CodeRabbit review on an earlier workflow diff. Current PR diff is only Sources/TabManager.swift and cmuxTests/WorkspacePullRequestSidebarTests.swift; checks are green and latest bot reviews mark it safe to merge.

@azooz2003-bit
azooz2003-bit merged commit d60a4a2 into main Jun 1, 2026
18 checks passed
@azooz2003-bit
azooz2003-bit deleted the issue-5130-fsevents-heap-corruption branch June 1, 2026 23:22
@austinywang austinywang mentioned this pull request Jun 2, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — 03ec344a Deployed Jun 1, 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.

2 participants