Skip to content

Fail CI on unit test failures - #5701

Closed
lawrencecchen wants to merge 9 commits into
mainfrom
feat-unit-test-failure-gate
Closed

lawrencecchen wants to merge 9 commits into
mainfrom
feat-unit-test-failure-gate

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add a CI self-test that forbids broad XCTest expected-failure masking in unit-test workflows
  • make unit-test workflow failures exit nonzero instead of treating (0 unexpected) assertion failures as a pass
  • fix hidden BrowserPanel and responder-repair unit failures exposed by the restored gate

Verification

  • tests/test_ci_self_hosted_guard.sh

Evidence


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Note

Medium Risk
CI behavior change removes a broad pass override so previously masked unit failures will fail builds; BrowserPanel DevTools and lifecycle edits affect WebKit UI paths but are mostly test- and edge-case-driven.

Overview
CI unit tests now fail on real XCTest failures instead of treating runs with (0 unexpected) as green. ci.yml, ci-macos-compat.yml, and test-depot.yml call scripts/ci/run-unit-tests-with-failure-gate.sh, which runs cmux-unit via the noninteractive xcodebuild wrapper with a configurable timeout, one SwiftPM cache-clear retry, and no expected-failure pass override. tests/test_ci_self_hosted_guard.sh and related scripts assert workflows cannot reintroduce that masking.

Supporting CI hardening: xcodebuild_noninteractive.py puts the child in its own process group and forwards SIGTERM/SIGINT; the nucleo FFI build script retries cargo build up to three times; tests-build-and-lag creates the virtual display before the CoreAnimation regression.

App and test fixes exposed once failures were no longer masked: BrowserPanel refreshes web-view lifecycle when initial navigation is skipped, observes Ghostty background on the main thread, and tightens DevTools visibility/refresh state; HeadlessWindowTestHelpers.swift adds stable key-window and background-color waits; shortcut, clipboard, terminal search, and browser DevTools tests swap fixed sleeps for waitUntil/waitFor and safer WebKit teardown.

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


Summary by cubic

Make unit tests fail CI on real XCTest errors by routing all unit-test jobs through a shared failure gate with a watchdog that can kill the whole test process group on timeout and a one-time SwiftPM retry. Also tighten BrowserPanel/DevTools lifecycle, apply Ghostty background updates on the main thread, improve xcodebuild signal handling, and deflake headless tests.

  • Bug Fixes

    • BrowserPanel: refresh lifecycle when initial navigation is skipped; DevTools respect hidden/visible intent, avoid redundant show if already visible, clear last-known-visible on hide, and allow refresh requests when recently visible; apply Ghostty background changes on the main thread with a safe NotificationCenter observer.
    • Headless tests: new HeadlessWindowTestHelpers.swift adds a reliable make-key helper and background-color waits; retain WebKit windows and inspector frontend webviews; replace sleeps with deterministic waits.
  • CI

    • All unit-test workflows call scripts/ci/run-unit-tests-with-failure-gate.sh (watchdog with kill-on-timeout of the wrapper and child process group, one SwiftPM cache-clear retry, preserves nonzero exit).
    • Guards: tests/test_ci_self_hosted_guard.sh enforces gate usage and nonzero exit preservation; tests/test_ci_unit_test_spm_retry.sh verifies the SwiftPM retry; tests/test_ci_xcodebuild_noninteractive_helper.py checks SIGTERM forwarding.
    • scripts/ci/xcodebuild_noninteractive.py puts xcodebuild in its own process group, writes the child PID, forwards SIGTERM/SIGINT to the group, and returns nonzero on termination.
    • Create the virtual display before the CoreAnimation main-thread regression; scripts/build-command-palette-nucleo-ffi.sh retries cargo build up to 3 times.

Written for commit fb6d201. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Improved web-view lifecycle when initial navigation is disabled.
    • Fixed background-theme observation and developer-tools refresh behavior.
    • Made focus/first-responder tests deterministic to reduce flakiness.
    • Adjusted inspector tests for more reliable teardown and timing.
  • Chores

    • Simplified CI unit-test failure handling to avoid masking assertion failures.
    • Increased unit-test timeout fallback.
    • Added CI validation to detect workflows that treat test failures as passing.
    • Added retrying Rust build helper in the build script.

@vercel

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

@coderabbitai

coderabbitai Bot commented Jun 9, 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

CI workflows now fail immediately on non-zero unit-test exit codes and the default unit-test timeout was increased; a CI guard prevents masking XCTest failures. BrowserPanel lifecycle/observer/devtools logic was adjusted, focus-related and inspector tests were made deterministic, and a retrying cargo build helper was added.

Changes

CI Unit Test Failure Masking Removal

Layer / File(s) Summary
CI timeout increase and log comment
.github/workflows/ci.yml
Default unit-test timeout changed from 900 to 1800 seconds in the run_unit_tests helper; log-streaming comment adjusted.
Unit test failure handling simplification
.github/workflows/ci-macos-compat.yml, .github/workflows/ci.yml, .github/workflows/test-depot.yml
All three workflows now immediately fail and exit with the test command's exit code on non-zero result, removing prior output-parsing logic that could treat XCTest assertion failures as passing runs.
Regression guard for failure masking
tests/test_ci_self_hosted_guard.sh
New check_unit_tests_do_not_mask_xctest_assertion_failures function scans CI workflows for patterns indicating XCTest failures are treated as passes (e.g., "(0 unexpected)"); check is invoked as part of validation sequence.

BrowserPanel and Test Improvements

Layer / File(s) Summary
WebView lifecycle state refresh on initialization
Sources/Panels/BrowserPanel.swift
refreshWebViewLifecycleState() is now called in both initialRequest and initialURL initialization paths when renderInitialNavigation is false.
Background theme observer rework & devtools gating
Sources/Panels/BrowserPanel.swift
Combine-based .ghosttyDefaultBackgroundDidChange subscription replaced with NotificationCenter.addObserver(...) that dispatches applyWebViewBackground to MainActor; requestDeveloperToolsRefreshAfterNextAttach now schedules refresh when developerToolsLastKnownVisibleAt is non-nil (setting preferredDeveloperToolsVisible first); revealDeveloperTools fast-path condensed while preserving state updates.
AppDelegate shortcut routing test focus synchronization
cmuxTests/AppDelegateShortcutRoutingTests.swift
Three focus-repair tests explicitly clear/set window first responder and wait for focused ownership where appropriate to reduce flakiness and remove timing races.
BrowserConfig test stability and inspector probe update
cmuxTests/BrowserConfigTests.swift
Added runloop drains after background notifications and key-window changes, changed detached-inspector fixture to add WKInspectorProbeView directly, and FakeInspector now retains frontend WKWebView instances to avoid premature deallocation.

Build script

Layer / File(s) Summary
Retrying cargo build helper
scripts/build-command-palette-nucleo-ffi.sh
Add cargo_build_with_retry() (up to 3 attempts with backoff) and replace per-target cargo build calls with this helper.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Ari4ka

Poem

🐰 I hopped through CI logs at dawn, no secret masks to find,

Failures call their names aloud, honest output now aligned.
WebViews rouse and watchers watch, devtools set to cue,
Tests that once would drift and flake now settle into view.
A rabbit cheers the steady run and nibbles on true glue.


Important

Pre-merge checks failed

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

❌ Failed checks (6 errors, 1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Cmux Swift Actor Isolation ❌ Error BrowserPanel.swift introduces SchemeTaskState marked @unchecked Sendable without a clear safety explanation comment as required by swift-actor-isolation.md rules. Add a safety explanation comment above SchemeTaskState explaining why @unchecked Sendable is safe (e.g., NSCondition internal synchronization), or mark the class nonisolated/Sendable-conformant without @unchecked.
Cmux Swift Blocking Runtime ❌ Error BrowserPanel introduces Task.sleep for debouncing, favicon polling (600ms), and JS timeouts, violating swift-blocking-runtime.md rules that treat Task.sleep as failures in production code. Replace Task.sleep with real signals or schedulers: use debounce timers for history saves, notification observers for favicon injection, proper timeout abstractions for JS evaluation.
Cmux Cache Substitution Correctness ❌ Error requestDeveloperToolsRefreshAfterNextAttach uses cached timestamp to set persisted preferredDeveloperToolsVisible without staleness check or documented rationale. Add freshness check to developerToolsLastKnownVisibleAt or document why staleness is acceptable per cache-substitution-correctness.md.
Cmux No Hacky Sleeps ❌ Error New shell build script introduces sleep $((attempt * 5)) in cargo_build_with_retry to retry failed cargo builds—fixed delay hiding transient build failures without naming the root cause. Either fix the root cause of transient cargo failures, or implement event-based retry without fixed backoff delays to comply with the no-hacky-sleeps rule.
Cmux Swift Logging ❌ Error PR introduces 61+ NSLog statements in production Swift code outside #if DEBUG blocks and Sources/Providers/, violating swift-logging.md rules requiring Logger or unified logging instead. Replace NSLog calls with Logger(subsystem:category:).log() or appropriate unified logging, wrap debug NSLog in #if DEBUG, or move diagnostics to Sources/Providers/ if intentional observability.
Cmux Architecture Rethink ❌ Error Manual NotificationCenter observer added replacing Combine; DevTools conditionally sets flag based on another flag state, creating split ownership. Revert to Combine pattern; consolidate DevTools visibility via single state machine instead of conditional flag setting.
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Cmux Swift Concurrency ❓ Inconclusive Initial repository import with 3817 new files. Check targets "introduces or materially expands" patterns; all Swift code is added simultaneously, making incremental assessment ambiguous. Clarify if check applies to initial imports or incremental PRs only. If applicable: @Published/@observableobject (Combine) used for SwiftUI integration (allowed), actual changes migrate away from Combine patterns.
Description check ❓ Inconclusive PR description includes clear summary of changes, but lacks testing details and demo video required by template. Add 'Testing' section describing how changes were tested locally, and confirm which checklist items apply to this PR.
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fail CI on unit test failures' directly and clearly summarizes the main objective of the pull request—making CI unit tests fail on any non-zero exit code rather than masking expected failures.
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 Expensive Synchronous Load ✅ Passed No expensive synchronous loaders added to main actor paths; all production changes are O(1) state/UI updates with no I/O, syscalls, or index loads.
Cmux Algorithmic Complexity ✅ Passed No algorithmic complexity violations detected: workflows/tests excluded; build script retry loop fixed at 3; BrowserPanel uses bounded collections with no nested O(n²) patterns.
Cmux Swift @Concurrent ✅ Passed No new Swift concurrent annotation violations found in PR changes. All existing async functions with isolation issues predate this PR and fall under the "existing functions" exception in the rule.
Cmux Swift File And Package Boundaries ✅ Passed Existing oversized BrowserPanel.swift touched incidentally with small focused bug fixes (net -1 line), test improvements with small changes, no new mixed responsibilities introduced.
Cmux User-Facing Error Privacy ✅ Passed PR introduces no user-facing error privacy violations. All new text is CI diagnostics, test-only code, or internal telemetry—permitted by the rules.
Cmux Full Internationalization ✅ Passed BrowserPanel.swift user-facing strings use String(localized:) with complete xcstrings translations (19 locales). Localized README files exist and are fully translated. No web UI i18n changes needed.
Cmux Swiftui State Layout ✅ Passed Initial monolithic import of codebase (3817 files added, 0 modified). ObservableObject/@published are existing legacy code, covered by allowed exception for existing state touched incidentally.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed No new standalone windows added or materially changed without proper identifiers; test fixtures are isolated, BrowserPanel changes are internal only.
Cmux Source Artifacts ✅ Passed All 8 changed files are legitimate: Swift source, tests, CI workflows, and build scripts. No artifacts, caches, temp files, or generated logs detected.
✨ 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 feat-unit-test-failure-gate

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 Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes CI masking of real XCTest failures by routing all three unit-test workflows through a shared run-unit-tests-with-failure-gate.sh, which exits nonzero on actual failures, adds a 1800 s watchdog, and retries once on SwiftPM resolution errors. It also stabilizes the BrowserPanel and headless-test failures that were previously hidden behind the "(0 unexpected)" pass heuristic.

  • CI gate (run-unit-tests-with-failure-gate.sh, xcodebuild_noninteractive.py): new shared script with process-group-aware SIGTERM forwarding, kill-on-timeout, and one SwiftPM retry; replaces identical inline logic duplicated across ci.yml, ci-macos-compat.yml, and test-depot.yml. Three new test scripts validate gate behavior end-to-end.
  • BrowserPanel fixes: refreshWebViewLifecycleState() called when initial navigation is skipped; Ghostty background observer migrated from Combine publisher (arbitrary-thread delivery) to queue: .main + MainActor.assumeIsolated; developerToolsLastKnownVisibleAt cleared on explicit hide and a redundant-show guard added.
  • Test stabilization (HeadlessWindowTestHelpers.swift, AppDelegateShortcutRoutingTests.swift, BrowserConfigTests.swift): deterministic make-key-window helper and background-color polling wait replace fixed RunLoop sleeps; WebKit windows/frontend webviews retained to avoid teardown crashes.

Confidence Score: 5/5

Safe to merge — all changes are CI infrastructure, targeted BrowserPanel bug fixes, and test stabilization with no new production regressions found.

The core change (shared failure gate + SIGTERM forwarding) is fully covered by three new end-to-end test scripts. The BrowserPanel production changes are narrow, isolated fixes for the lifecycle and DevTools state. The headless test helpers are test-only scaffolding. No new unsafe patterns were introduced in production Swift or shell code.

No files require special attention; BrowserPanel.swift carries forward a pre-existing architectural concern in DevTools state management already tracked in a prior review thread.

Important Files Changed

Filename Overview
scripts/ci/run-unit-tests-with-failure-gate.sh New shared CI gate script: watchdog timeout, one SwiftPM retry, nonzero exit on test failure; correct PIPESTATUS capture and process-group teardown logic.
scripts/ci/xcodebuild_noninteractive.py Adds SIGTERM/SIGINT forwarding via os.killpg to child process group; returns 128+SIGTERM when wrapper is terminated and child exits 0; child calls os.setpgrp() before exec so group kill is scoped correctly.
Sources/Panels/BrowserPanel.swift refreshWebViewLifecycleState() now called when renderInitialNavigation is false; Ghostty background observer migrated to queue:.main with MainActor.assumeIsolated; developerToolsLastKnownVisibleAt cleared on hide and DevTools visibility already-shown short-circuit added.
cmuxTests/HeadlessWindowTestHelpers.swift New test-only helpers: deterministic make-key window loop, WebView containment check, and background-color polling wait; all test scaffolding, not production code.
.github/workflows/ci.yml Unit test inline script replaced with shared failure gate; virtual display step moved before CoreAnimation regression; CMUX_SKIP_ZIG_BUILD passed as env var rather than xcodebuild build-setting argument.
tests/test_ci_self_hosted_guard.sh Adds two new guard checks: workflow files must call the failure gate and must not contain the old (0 unexpected) pass heuristic; gate behavior verified via CMUX_UNIT_TEST_FAKE_COMMAND.
cmuxTests/AppDelegateShortcutRoutingTests.swift Replaces fixed RunLoop sleeps with cmuxMakeWindowKeyForTesting and waitUntil/waitFor deterministic waits; mention-suggestion fixture renamed alpha to zeta to avoid ordering sensitivity.
cmuxTests/BrowserConfigTests.swift DevTools teardown retains WebKit windows and frontend WKWebViews to avoid deallocation crashes; background color assertions replaced with deterministic polling wait.

Sequence Diagram

sequenceDiagram
    participant CI as CI Workflow (YAML)
    participant Gate as run-unit-tests-with-failure-gate.sh
    participant NI as xcodebuild_noninteractive.py
    participant XC as xcodebuild (process group)

    CI->>Gate: invoke with SOURCE_PACKAGES_DIR / env vars
    Gate->>NI: launch in background (PID file)
    NI->>XC: fork+exec (new process group via setpgrp)
    NI-->>Gate: write child PID to file

    loop Watchdog every 5s
        Gate->>Gate: check kill -0 xcodebuild_pid
        alt timeout exceeded
            Gate->>NI: SIGTERM
            NI->>XC: killpg(pgid, SIGTERM)
            Note over Gate: sleep 5
            Gate->>NI: SIGKILL
            Gate-->>CI: exit 124
        end
    end

    XC-->>NI: exit (status)
    NI-->>Gate: exit (status or 128+SIGTERM)
    Gate->>Gate: check SwiftPM resolution failure
    alt SwiftPM failure
        Gate->>Gate: clear caches + retry once
    end
    Gate-->>CI: exit nonzero on failure
Loading

Reviews (9): Last reviewed commit: "Kill unit test process group on timeout" | Re-trigger Greptile

Comment on lines 7380 to 7383
func requestDeveloperToolsRefreshAfterNextAttach(reason: String) {
guard preferredDeveloperToolsVisible else { return }
guard preferredDeveloperToolsVisible || developerToolsLastKnownVisibleAt != nil else { return }
setPreferredDeveloperToolsVisible(true)
forceDeveloperToolsRefreshOnNextAttach = true

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.

P1 DevTools preference corrupted via timestamp proxy

developerToolsLastKnownVisibleAt is a staleness-detection timestamp (used by consumeAttachedDeveloperToolsManualCloseIfNeeded and retry guards) — it is not a canonical "the user wants DevTools open" source of truth. Using it as a fallback to call setPreferredDeveloperToolsVisible(true) means any layout-transition reattach that fires this function while developerToolsLastKnownVisibleAt is still non-nil (e.g., if the timestamp was updated by noteDeveloperToolsHostAttached after the user closed DevTools but before the nil-write propagates) will silently re-enable DevTools against user intent. The invariant that preferredDeveloperToolsVisible is the authority for whether the panel should be visible is lost.

Rule Used: Flag Swift fixes that patch symptoms while leaving... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread Sources/Panels/BrowserPanel.swift Outdated
Comment on lines +5276 to +5280
let ghosttyBackgroundObserver = NotificationCenter.default.addObserver(
forName: .ghosttyDefaultBackgroundDidChange, object: nil, queue: nil
) { [weak self] notification in
MainActor.assumeIsolated { self?.applyWebViewBackground(color: GhosttyBackgroundTheme.color(from: notification)) }
}

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 queue: nil delivers the notification on whatever thread posts it. If any call site posts .ghosttyDefaultBackgroundDidChange from a non-main thread, MainActor.assumeIsolated will trap at runtime. Using queue: .main is the safe alternative — it guarantees main-queue delivery regardless of the posting thread and avoids the assumeIsolated precondition entirely.

Suggested change
let ghosttyBackgroundObserver = NotificationCenter.default.addObserver(
forName: .ghosttyDefaultBackgroundDidChange, object: nil, queue: nil
) { [weak self] notification in
MainActor.assumeIsolated { self?.applyWebViewBackground(color: GhosttyBackgroundTheme.color(from: notification)) }
}
let ghosttyBackgroundObserver = NotificationCenter.default.addObserver(
forName: .ghosttyDefaultBackgroundDidChange, object: nil, queue: .main
) { [weak self] notification in
self?.applyWebViewBackground(color: GhosttyBackgroundTheme.color(from: notification))
}

@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/Panels/BrowserPanel.swift`:
- Around line 5276-5281: The observer created as ghosttyBackgroundObserver for
.ghosttyDefaultBackgroundDidChange currently calls MainActor.assumeIsolated
unnecessarily; make the main-threading explicit by either passing queue: .main
to NotificationCenter.default.addObserver or by wrapping the handler body in
Task { `@MainActor` in ... } and remove MainActor.assumeIsolated; keep the handler
calling self?.applyWebViewBackground(color: GhosttyBackgroundTheme.color(from:
notification)) and preserve the AnyCancellable removal logic to unregister the
observer.
🪄 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: be4e52ee-b4c0-468f-9e38-00cb0dcfe279

📥 Commits

Reviewing files that changed from the base of the PR and between e5e80f3 and 0f3b506.

📒 Files selected for processing (6)
  • .github/workflows/ci-macos-compat.yml
  • .github/workflows/ci.yml
  • .github/workflows/test-depot.yml
  • Sources/Panels/BrowserPanel.swift
  • cmuxTests/AppDelegateShortcutRoutingTests.swift
  • cmuxTests/BrowserConfigTests.swift

Comment thread Sources/Panels/BrowserPanel.swift Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88419deb80

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmuxTests/BrowserConfigTests.swift Outdated
Comment on lines +3283 to +3284
inspectorWindow.contentView?.addSubview(
WKInspectorProbeView(frame: inspectorWindow.contentView?.bounds ?? .zero)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep the fake inspector frontend wired

In this close-button regression test, replacing the frontend WKInspectorProbeWebView with only a plain probe view leaves FakeInspector.inspectorWebView() returning nil because setFrontendWebView is no longer called. The close-action path checks BrowserPanel.detachedDeveloperToolsWindowBelongsToPanel, which requires webView.cmuxInspectorFrontendWebView() to be a descendant of this window before it will close the inspector, so NSApp.sendAction(...) returns false and inspector.closeCount stays 0. This re-breaks the unit-test gate this commit is trying to restore.

Useful? React with 👍 / 👎.

Comment thread cmuxTests/BrowserConfigTests.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 `@scripts/build-command-palette-nucleo-ffi.sh`:
- Around line 65-67: Remove the fixed sleep-based backoff (the sleep $((attempt
* 5)) line) and instead wait for an explicit readiness signal or remove
timing-based retry entirely: after the failing cargo build echo/retry block,
replace the fixed-delay retry mechanism with a loop that checks a concrete
readiness condition (for example, existence of the expected build artifact, a
readiness FIFO/lock file, or a blocking readiness command) and only retries when
that condition indicates the target is not yet ready; keep the retry counter
(attempt) and the echo for diagnostics but do not use fixed sleep for
synchronization.
- Around line 58-63: The script currently sets status=$? after the if...fi block
which can mask the real cargo build exit code; change the logic to capture the
exit code immediately after running cargo build (store it in status right after
the cargo build command returns), then test status to decide whether to return 0
or retry, and on the final attempt return "$status" so the actual cargo failure
code is preserved (use the existing variables CRATE_DIR, target, attempt, and
status to locate and update the cargo build branch).
🪄 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: 749668c6-1cb5-453f-a922-15e7a60cd5cf

📥 Commits

Reviewing files that changed from the base of the PR and between 0f3b506 and 88419de.

📒 Files selected for processing (7)
  • .github/workflows/ci-macos-compat.yml
  • .github/workflows/ci.yml
  • .github/workflows/test-depot.yml
  • Sources/Panels/BrowserPanel.swift
  • cmuxTests/AppDelegateShortcutRoutingTests.swift
  • cmuxTests/BrowserConfigTests.swift
  • scripts/build-command-palette-nucleo-ffi.sh

Comment thread scripts/build-command-palette-nucleo-ffi.sh
Comment thread scripts/build-command-palette-nucleo-ffi.sh Outdated

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

♻️ Duplicate comments (2)
scripts/build-command-palette-nucleo-ffi.sh (2)

65-66: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fixed sleep-based retry backoff still violates the runtime synchronization policy (duplicate of past review).

The sleep $((attempt * 5)) on line 66 implements timing-based retry logic, which is explicitly disallowed for production/build shell scripts. As per coding guidelines, retry logic must not depend on wall-clock time. Consider immediate retry (remove sleep) or a readiness-based wait.

🤖 Prompt for 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.

In `@scripts/build-command-palette-nucleo-ffi.sh` around lines 65 - 66, Remove the
time-based backoff sleep in the retry loop that uses sleep $((attempt * 5)) —
instead implement a non-wall-clock retry strategy: either retry immediately by
deleting the sleep line, or replace it with a readiness check that polls a
deterministic condition (e.g., test artifacts, cargo lock/state, or a specific
command that indicates tool readiness) before the next attempt; update the loop
around the cargo build invocation that references ${target} and ${attempt} to
use this readiness-based check or immediate retry so no wall-clock sleep
remains.

Source: Coding guidelines


58-63: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Status capture still occurs after the if statement (duplicate of past review).

The status=$? on line 61 captures the exit code after the if compound command completes. While this works in bash, capturing immediately after cargo build is more explicit and reliable across shell variations.

🤖 Prompt for 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.

In `@scripts/build-command-palette-nucleo-ffi.sh` around lines 58 - 63, Move the
exit-code capture so it happens immediately after running the cargo build
command: run cargo build --manifest-path "${CRATE_DIR}/Cargo.toml" --release
--target "$target" then immediately assign status=$? and use that status in the
subsequent conditional checks (instead of relying on the compound if returning
code); update the existing if/return logic that references status and attempt to
use this captured value.
🤖 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.

Duplicate comments:
In `@scripts/build-command-palette-nucleo-ffi.sh`:
- Around line 65-66: Remove the time-based backoff sleep in the retry loop that
uses sleep $((attempt * 5)) — instead implement a non-wall-clock retry strategy:
either retry immediately by deleting the sleep line, or replace it with a
readiness check that polls a deterministic condition (e.g., test artifacts,
cargo lock/state, or a specific command that indicates tool readiness) before
the next attempt; update the loop around the cargo build invocation that
references ${target} and ${attempt} to use this readiness-based check or
immediate retry so no wall-clock sleep remains.
- Around line 58-63: Move the exit-code capture so it happens immediately after
running the cargo build command: run cargo build --manifest-path
"${CRATE_DIR}/Cargo.toml" --release --target "$target" then immediately assign
status=$? and use that status in the subsequent conditional checks (instead of
relying on the compound if returning code); update the existing if/return logic
that references status and attempt to use this captured value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 28981568-68e5-47c1-8a1a-24fba48033b8

📥 Commits

Reviewing files that changed from the base of the PR and between 88419de and eb88dd6.

📒 Files selected for processing (7)
  • .github/workflows/ci-macos-compat.yml
  • .github/workflows/ci.yml
  • .github/workflows/test-depot.yml
  • Sources/Panels/BrowserPanel.swift
  • cmuxTests/AppDelegateShortcutRoutingTests.swift
  • cmuxTests/BrowserConfigTests.swift
  • scripts/build-command-palette-nucleo-ffi.sh

@lawrencecchen
lawrencecchen force-pushed the feat-unit-test-failure-gate branch from eb88dd6 to bb59727 Compare June 9, 2026 15:03
@socket-security

socket-security Bot commented Jun 9, 2026 •

Copy link
Copy Markdown

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bb5972755c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +61 to +63
status=$?
if [ "$attempt" -eq 3 ]; then
return "$status"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve cargo's failing exit status

When cargo build fails on the final retry, this captures $? after the if ... fi has completed, not after cargo itself; Bash documents that an if with no true branch exits zero when no condition matched, which I confirmed with help if. In incremental Xcode/CI builds where target/<triple>/release/libcmux_command_palette_nucleo_ffi.dylib already exists from an earlier build, three failed cargo attempts will therefore return success and package the stale dylib instead of failing the build.

Useful? React with 👍 / 👎.

@lawrencecchen
lawrencecchen force-pushed the feat-unit-test-failure-gate branch from b32efc2 to 40dc885 Compare June 9, 2026 16:58

@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 7b5c370. Configure here.

Comment thread cmuxTests/HeadlessWindowTestHelpers.swift

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb6d201f08

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

check_unit_tests_do_not_mask_xctest_assertion_failures() {
local file
for file in "$CI_FILE" "$COMPAT_FILE" "$ROOT_DIR/.github/workflows/test-depot.yml"; do
if ! grep -Fq "scripts/ci/run-unit-tests-with-failure-gate.sh" "$file"; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Replace grep-only workflow guard

/workspace/cmux/AGENTS.md says not to add tests that only verify source text or grep-style patterns, but this new guard decides whether the workflow is correct by grepping YAML strings rather than exercising the unit-test workflow behavior. In CI this can fail or pass based on spelling/placement changes while missing regressions in the actual failure gate; please cover the behavior through the shared script/harness instead of source-text checks.

Useful? React with 👍 / 👎.

@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — fb6d201f Deployed Jun 9, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants