Skip to content

ci: build cmuxTests without emitting its Swift module - #14364

Merged
teamleaderleo merged 1 commit into
mainfrom
ci/cmuxtests-emit-module
Sep 25, 2026
Merged

teamleaderleo merged 1 commit into
mainfrom
ci/cmuxtests-emit-module

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

After #14349, a one-test-file edit still cost cmuxTests 31 s, and 26 s of that was its own SwiftEmitModule job, running serially on the critical path. Nothing imports cmuxTests.swiftmodule. CI now builds cmuxTests without emitting a module, and the same edit takes 4.1 s.

Change

  • scripts/ci/compile-app-host-test-product.sh builds cmuxTests with the standalone Swift driver (SWIFT_USE_INTEGRATED_DRIVER=NO) and -no-emit-module-separately. Xcode's integrated driver always appends -experimental-emit-module-separately, so the standalone driver is the only way to pass the flag. With it, a non-WMO build plans no emit-module job, and current swift-driver has no merge-modules job to fall back on, so no module is written. Both settings are per target ($(X_$(TARGET_NAME)):default=...), so the app and every package keep their arguments.
  • cmux.xcodeproj sets SWIFT_OBJC_INTERFACE_HEADER_NAME = "" for cmuxTests. The generated cmuxTests-Swift.h comes from the module job and nothing includes it. Without this setting, the no-module build fails in SwiftMergeGeneratedHeaders (ENOENT). Local builds also stop generating the header. They keep the integrated driver and still emit the module.

Where the 26 s went

With -stats-output-dir -fine-grained-timers (canary #14352, run 36087174643; the timers roughly double the job's wall time), the emit-module job was 85% type checking. The largest slices were declaration checking, ExpandPeerMacroRequest (7,893 @Test macros), stored-property initializer expressions, and name lookup across the imported modules. Serialization was 1.3 s. Trimming the job's other outputs did not help: without the ObjC header, with -empty-abi-descriptor, or with -avoid-emit-module-source-info, it stayed at 50 to 54 s against 48 s for the control. -experimental-lazy-typecheck saved about 1 s.

Measurements

Canary #14352, run 36089490735, blacksmith-12vcpu-macos-26, Xcode 26.6 (Swift 6.3.3). Rows are cmux-unit rebuilds on the admission's DerivedData, without stats flags.

cmuxTests mode one-test-file edit, cmuxTests same edit, whole rebuild full cmuxTests rebuild
main (#14349) 31.6 to 35.3 s 47 to 55 s 137 s
this PR 4.1 s 19 s 105 s
standalone driver, module still emitted 36 s 51 s 93 s
lazy typecheck 31 s 45 s 86 s

The third row shows the gain comes from dropping the module, not from the driver switch. The built bundle is unchanged where tests are concerned: the same 11,758 enumerated tests, the same __swift5_tests section size (0x44140), and the same 332 ObjC test classes. The full-rebuild column is noisy (each series' first build also re-planned other targets), so it shows only that the full rebuild did not get worse.

What this does not change

  • Adding a top-level declaration in the app still recompiles every cmuxTests file (see ci: build cmuxTests without the compilation cache so it rebuilds incrementally #14349). That rebuild no longer waits on the module job.
  • The first admissions after this lands rebuild cmuxTests once, because its arguments changed. The seeds pick up the new arguments on their next build through this script.
  • No cmuxTests.swiftmodule in CI DerivedData. CI never debugs the test bundle.
  • app-host-test-rerun.yml compiles -target cmuxTests without these settings, so it keeps the integrated driver and emits the module. It already differs from admission (no cache setting, pruned source list), so it was not reusing admission's cmuxTests objects before this change either.
  • The canary did not measure a null rebuild. If Xcode still expects a module output from the standalone driver task, a null build would rerun the driver planning (about 3.5 s) and the link, not any compiles.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Updated automated app-host test builds to compile without producing a separate Swift module for the test target. Build checks now verify the updated configuration, while retaining the existing compilation-cache behavior. These changes affect CI and test builds only; no user-facing app functionality or behavior has changed.

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

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

Warning

Review limit reached

Next included review available in 8 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: c547d423-5591-4123-9201-945b99d00df9

📥 Commits

Reviewing files that changed from the base of the PR and between 93b6e27 and c9116b4.

📒 Files selected for processing (3)
  • cmux.xcodeproj/project.pbxproj
  • scripts/ci/compile-app-host-test-product.sh
  • tests/test_ci_test_compilation_cache_seed.sh

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 1b471ef6-ac00-4487-8070-f9d033b70102

📥 Commits

Reviewing files that changed from the base of the PR and between 4f49d67 and 93b6e27.

📒 Files selected for processing (3)
  • cmux.xcodeproj/project.pbxproj
  • scripts/ci/compile-app-host-test-product.sh
  • tests/test_ci_test_compilation_cache_seed.sh

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


📝 Walkthrough

Walkthrough

The app test build configurations set SWIFT_OBJC_INTERFACE_HEADER_NAME to an empty string. The CI script configures cmuxTests to disable the integrated Swift driver and omit separate module emission. The build test checks the expected arguments.

Changes

cmuxTests module emission

Layer / File(s) Summary
Configure cmuxTests module emission
cmux.xcodeproj/project.pbxproj, scripts/ci/compile-app-host-test-product.sh, tests/test_ci_test_compilation_cache_seed.sh
The app test build configurations set an empty interface header name. The CI script configures cmuxTests to omit separate module emission, and the build test checks the corresponding xcodebuild arguments.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Other

Merge Risk: ⚪ Minimal · up to 93b6e

No actionable merge-blocking issue is established. The empty header setting has no consumer in the target’s Objective-C source.

Architecture Summary

Architecture risk: 🔵 Low · up to 93b6e

The change affects 3 systems.

Changed systems: scripts, cmux.xcodeproj, tests

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — scripts (service) was modified; 1 changed file maps to changed impact.
  • observed — cmux.xcodeproj (service) was modified; 1 changed file maps to changed impact.
  • observed — tests (service) was modified; 1 changed file maps to changed impact.

Before / after behavior

  • observed — Modified behavior in cmux.xcodeproj/project.pbxproj: The app test build configuration adds an empty SWIFT_OBJC_INTERFACE_HEADER_NAME setting.
  • observed — Modified behavior in cmux.xcodeproj/project.pbxproj: A second app test build configuration adds the same empty SWIFT_OBJC_INTERFACE_HEADER_NAME setting.
  • observed — Modified behavior in scripts/ci/compile-app-host-test-product.sh: The comment adds that cmuxTests emits no Swift module.
  • observed — Modified behavior in scripts/ci/compile-app-host-test-product.sh: The build comments document the separate module-emission cost and generated-header behavior for cmuxTests. Its target-specific settings now disable the integrated Swift driver and pass -no-emit-module-separately, alongside the existing setting that disables compilation caching for that target.
🚥 Pre-merge checks | ✅ 24 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. (1 skipped: 1 … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (24 passed)
Check name Status Explanation
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 Cloud Persistent Session And Early Input ✅ Passed The PR changes only Xcode test-target settings, CI build arguments, and a CI assertion. The diff does not modify Cloud terminal creation, cmux-tui transport, manual panes, input routing, snapshots, au…
Cmux Swift Actor Isolation ✅ Passed The diff changes no Swift source files. It only changes cmuxTests test-target build settings, CI shell logic, and a CI test. No actor, MainActor, Sendable, model, protocol, logger, or UI-store d…
Cmux Swift Blocking Runtime ✅ Passed PASS: The pull request changes only Xcode build settings and CI shell/test scripts. It adds no Swift source files or runtime synchronization primitives. The added settings control Swift module emissio…
Cmux Browser Automation Off-Main ✅ Passed PASS: The PR changes only Xcode build settings, the CI build script, and its cache-seed test. The browser automation source files and policy tests are unchanged, and the patch adds no browser command …
Cmux Expensive Synchronous Load ✅ Passed PASS: The pull request changes only Xcode build settings, CI shell logic, and a CI test. It adds no production Swift code or synchronous agent-history load. The custom check is therefore not applicabl…
Cmux Cache Substitution Correctness ✅ Passed PASS: The pull request changes only an Xcode project file and CI shell/test scripts. The authoritative diff contains no production Swift, TypeScript, or JavaScript changes and no persistence, history,…
Cmux No Hacky Sleeps ✅ Passed PASS: The PR changes Xcode build settings, compiler flags, comments, and test assertions. The changed shell scripts add no sleep, timer, polling, fixed backoff, or wall-clock wait. Existing retry logi…
Cmux Algorithmic Complexity ✅ Passed PASS: The pull request adds Xcode settings, comments, and test assertions. It does not add nested collection scans, per-target rescans, repeated sorting/filtering, in-memory joins, or a slower data al…
Cmux Swift Concurrency ✅ Passed PASS: The pull request changes only Xcode project settings, CI shell logic, and a shell test. The authoritative diff contains no Swift source changes and introduces no Dispatch, Combine, completion-ha…
Cmux Swift @Concurrent ✅ Passed PASS: The PR changes only Xcode build settings, CI shell logic, and its shell test. The authoritative diff contains no Swift source changes and no added or removed async, nonisolated, `@concurrent…
Cmux Swift Package Boundaries ✅ Passed The pull request changes only Xcode build settings and CI/test shell scripts. It adds no Swift source or SwiftPM target and introduces no production feature logic. Therefore, it does not violate the S…
Cmux Swiftpm Lockfiles ✅ Passed PASS: The pull request changes only Swift build settings, CI script logic, and a CI test. It does not change Package.swift, any Package.resolved, .gitignore, workflow, or Xcode package reference…
Cmux Swift Logging ✅ Passed The PR changes only Xcode configuration, CI shell code, and a shell test. It adds no Swift source and no print, debugPrint, dump, NSLog, Logger, or ad hoc diagnostic logging. The Swift loggi…
Cmux User-Facing Error Privacy ✅ Passed PASS: The diff changes only CI build settings, developer comments, and a CI test success message. The script runs through the macOS admission build and writes xcodebuild output to CI logs; it has no a…
Cmux Full Internationalization ✅ Passed PASS: The pull request changes only Xcode build settings, CI script comments/configuration, and a CI test expectation. The added text is developer-only or operational CI output. It adds no user-facing…
Cmux Swiftui State Layout ✅ Passed PASS: The pull request changes only Xcode project settings, CI scripts, and a CI test. The authoritative diff contains no SwiftUI source changes and introduces none of the prohibited state, layout, ro…
Cmux Architecture Rethink ✅ Passed PASS. The diff changes only Xcode build settings, a CI shell script, and its shell test. It adds no Swift runtime code and no sleeps, delayed dispatch, polling, locks, observers, side channels, duplic…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS: The PR changes only cmux.xcodeproj/project.pbxproj, CI shell code, and a CI test. It changes cmuxTests build settings and does not add or materially change Swift window code. No NSWindow, …
Cmux Source Artifacts ✅ Passed PASS. The PR changes only three existing, established source-controlled paths: cmux.xcodeproj/project.pbxproj, scripts/ci/compile-app-host-test-product.sh, and `tests/test_ci_test_compilation_cach…
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS: The pull request changes only cmux.xcodeproj/project.pbxproj, scripts/ci/compile-app-host-test-product.sh, and tests/test_ci_test_compilation_cache_seed.sh. The authoritative diff contains…
Title check ✅ Passed The title clearly and concisely describes the primary change: building cmuxTests without emitting its Swift module.
Description check ✅ Passed The description is detailed and directly explains the problem, implementation, measurements, scope, and limitations. It provides testing evidence through canary measurements, although it does not use …
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Nothing imports cmuxTests.swiftmodule, but its separate emit-module job
type-checks every declaration and expands every @test macro: 26 s of a
31 s one-test-file rebuild, serial. The standalone driver with
-no-emit-module-separately emits no module, and an empty
SWIFT_OBJC_INTERFACE_HEADER_NAME removes the one output that needed it.
The same edit now takes cmuxTests 4.1 s (#14352, run 36089490735).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo force-pushed the ci/cmuxtests-emit-module branch from 93b6e27 to c9116b4 Compare September 25, 2026 04:05
@cursor

cursor Bot commented Sep 25, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@teamleaderleo
teamleaderleo merged commit ada4519 into main Sep 25, 2026
67 of 89 checks passed
@teamleaderleo
teamleaderleo deleted the ci/cmuxtests-emit-module branch September 25, 2026 04:20
teamleaderleo added a commit that referenced this pull request Sep 25, 2026
…14378)

* test: build cmuxTests without a Swift module in scripts/test-unit.sh

CI stopped emitting the cmuxTests module in #14364, which took a
one-test-file rebuild from 31 s to 4.1 s. The local test-compile wrapper
now passes the same cmuxTests-only settings. CMUX_TEST_EMIT_MODULE=1
keeps the module for lldb. The compile-settings test checks that the
wrapper and the CI script agree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: note that a caller's OTHER_SWIFT_FLAGS wins; keep test DerivedData out of /tmp

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 25, 2026
85a3655 ci: seed j14 DerivedData on a trusted-only owned mini (manaflow-ai#14380)
dfb9466 Merge pull request manaflow-ai#14337 from manaflow-ai/14327-team-picker-cloud
e805dc8 Merge pull request manaflow-ai#12997 from manaflow-ai/task-12947-option-dead-key
8c7670d ci: stop compile admission before compiling when the fast Linux gate declined (manaflow-ai#14374)
460bda4 test: build cmuxTests without a Swift module in scripts/test-unit.sh (manaflow-ai#14378)
206c6fb ci: keep an owned Mac warm through cancelled and failed admissions (manaflow-ai#14375)
b5798b5 test: isolate auto dead-key config coverage
753d4d4 Merge remote-tracking branch 'origin/main' into 14327-team-picker-cloud
1f09959 ci: route owned-mini root jobs to the root runner label (manaflow-ai#14357)
127d9d3 Remove filled background from Cloud team picker
ada4519 ci: build cmuxTests without emitting its Swift module (manaflow-ai#14364)
9c2cd6f Merge remote-tracking branch 'origin/main' into 14327-team-picker-cloud
687e0a4 fix: import terminal test dependencies
244f588 ci: report which cmuxTests suites an app-source change can reach (report only) (manaflow-ai#14367)
cbfa373 ci(canary): send each Cloud VM canary run to Axiom (manaflow-ai#14368)
b5a50a9 test: wait for async reload, selectionchange, and pane width in three main-red app-host tests (manaflow-ai#14366)
2adda75 Merge remote-tracking branch 'origin/main' into 14327-team-picker-cloud
40b2bec fix: respect explicit Option-as-Alt for dead keys
7b42ac7 test: cover explicit and auto Option dead-key routing
d2d64ee Merge origin/main and preserve both test references
106ecef Merge remote-tracking branch 'origin/main' into task-12947-option-dead-key
a632acb Merge remote-tracking branch 'origin/main' into 14327-team-picker-cloud
5579c08 test: isolate team picker shortcut preference
9d5b356 Merge remote-tracking branch 'origin/main' into 14327-team-picker-cloud
6099585 Merge remote-tracking branch 'origin/main' into 14327-team-picker-cloud
e761153 test: force typed Cloud flag overrides in UI fixture
dcd3d05 Merge remote-tracking branch 'origin/main' into 14327-team-picker-cloud
36688f3 test: exercise team picker in the visible account footer
73e30f1 Merge remote-tracking branch 'origin/main' into 14327-team-picker-cloud
6c8f1f8 fix: move team scope into the Cloud header
6ddba81 test: cover Cloud team picker placement for manaflow-ai#14327
456ba2a fix: preserve Option dead-key composition

# Conflicts:
#	.github/workflows/ci-guards.yml
#	.github/workflows/ci-macos.yml
#	.github/workflows/ci.yml
#	.github/workflows/cloud-vm-canary.yml
#	.github/workflows/seed-derived-data.yml
@austinywang

Copy link
Copy Markdown
Contributor

Observed a concrete build regression while verifying #14371 on 38ca93ffe0b220989c912333a62095375935c5ab: https://github.com/manaflow-ai/cmux/actions/runs/36097182723/job/107952064506. On the owned Mac's second canonical root, Xcode 26.6 successfully compiled the sources, then its Copy tasks failed because Objects-normal/arm64/cmuxTests.swiftmodule, .swiftdoc, .abi.json, and .swiftsourceinfo do not exist. The no-module driver setting appears to remove the producer while those copy consumers remain scheduled. The Computer Use package's 28 tests pass separately.

I found no open fix by searching cmuxTests.swiftmodule and no-emit-module-separately. Is there already a session repairing the missing-output consumer contract? I am investigating the smallest prerequisite fix so #14371 can pass its normal admission check, without changing the Computer Use runtime scope.

— RavenCinder (pending)
run: run_issue_14294_helper_staging_20260924
session: cmux175-14294-20260924

@austinywang

Copy link
Copy Markdown
Contributor

The prerequisite repair is committed separately in #14371 as 87bf6ae4f20: set SWIFT_INSTALL_MODULE=NO only for cmuxTests whenever -no-emit-module-separately is enabled. Both CI and scripts/test-unit.sh carry the same target-scoped value; CMUX_TEST_EMIT_MODULE=1 removes both overrides. Xcode's bundled Swift.xcspec declares SWIFT_INSTALL_MODULE with default YES, which left the Copy consumers active after the producer was disabled. The shell invocation/override regression passes; the real hosted admission now verifies the missing-output case. This preserves the no-module optimization instead of restoring its serial emit work.

— RavenCinder (pending)
run: run_issue_14294_helper_staging_20260924
session: cmux175-14294-20260924

teamleaderleo added a commit that referenced this pull request Sep 25, 2026
CMUX_RELOAD_APP_EMIT_MODULE=0 builds the app target with the standalone driver and
-no-emit-module-separately, and its Debug configuration generates no Objective-C header (nothing
includes it). Same change #14364 made for cmuxTests. The edit-loop benchmark now reruns every scenario
with and without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Sep 25, 2026
* reload: skip the app's separate Swift module emission

A dev build only runs the app: nothing imports its Swift module except
cmuxTests, which reload never builds, and no Objective-C includes its
generated header. Xcode's integrated driver still emits the module in a
separate job that type-checks every declaration in the app on every edit.
Use the standalone driver with -no-emit-module-separately for the app
target only, the change #14364 made for cmuxTests, and generate no
Objective-C header in the app's Debug configuration.

On a Blacksmith 12-vCPU runner, app body and comment edits drop from
38-40 s to 25-27 s and a no-op rebuild to 20 s. CMUX_RELOAD_APP_EMIT_MODULE=1
restores the old behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* reload: say how to get lldb expression evaluation back

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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