Skip to content

ci: run E2E tests on the runner that built them - #14667

Merged
teamleaderleo merged 3 commits into
mainfrom
ci/e2e-single-runner
Sep 25, 2026
Merged

teamleaderleo merged 3 commits into
mainfrom
ci/e2e-single-runner

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

An E2E dispatch used to queue for a macOS runner twice. The build job compiled (or adopted) the app-host and UI test product and uploaded it. Then the test job queued again for a runner of the same label, downloaded the product and ran the tests. With the pools saturated, that second wait decided how long a run took. Across the 20 successful runs on 2026-09-25, the test job itself ran for 2–3 min. The ~11 runs from 09:19Z on then waited 1.3–96 min for its runner. Run 36130355245 finished its build at 12:14, and its test job was still queued when it was cancelled at 12:26.

Now build runs the tests itself, on the runner that just built the product.

  • Test steps move into a composite action. They live in .github/actions/e2e-run-tests and cover the virtual display, ffmpeg and TCC, the capture preflight, bun and tmux, the product restore into a RUNNER_TEMP DerivedData, the app-host home, selector resolution, the test run, recording, uploads, the summary and cleanup. The always() upload and cleanup steps keep their if:.

  • Where the tests run:

    • build runs the action after it uploads the product and cleans the canonical DerivedData. It restores from the archive it just packaged (CMUX_PRODUCT_FROM_PRODUCER, the same path compile admission uses for changed suites), so the tests run the exact uploaded bytes.
    • test stays as the fallback. It runs only when needs.build.outputs.tested != 'true', and CI_E2E_TEST_IN_BUILD=0 hands the tests back to it.
  • Old refs still work. Both jobs sparse-check the action out at github.workflow_sha into .e2e-workflow, so a dispatch (or bisect probe) of a ref older than the action still runs its tests. The scripts the action calls come from the tested revision, as before.

  • Test environment. The action exports CMUX_CI_APP_HOST_ISOLATION_REQUIRED=1, CMUX_APP_HOST_SHARD=1 and CMUX_APP_HOST_CAPTURE_XCRESULTS=1 after the compile, wherever the tests run. CMUX_CI_XCODE_APP is the build's own pin.

  • Timeout. build's timeout is 2 × job_timeout, since it now covers compiling and testing. The filter job computes it and rejects a non-integer value.

  • Product upload stays. Later dispatches adopt it. Since build now ends after the tests, e2e_sibling_build.py and reuse_app_host_products.py count an E2E producer as done once Upload the compiled test product has succeeded. A sibling no longer waits out another run's tests, and a failing test no longer makes an intact product unadoptable.

  • Bisect verdicts. main_regression_bisect.py reads a probe's verdict from failed top-level step names, and the jobs API doesn't list a composite's inner steps. So both jobs name the action step Run selected tests, and a top-level Resolve selectors against the built tests step fails when the action recorded an unresolvable selector. classify() now checks that step first.

  • Cleanup after a skipped preparation. When the build job has removed its canonical DerivedData, it clears CMUX_DERIVED_DATA_PATH. A failure that skips the tests' own preparation (a failed screen-capture preflight, as in run 36168944875) then leaves their always() cleanup nothing to refuse.

Guard tests that read the old test job now read the action. The app-host home, pipe-capture and no-masking guards also scan composite actions, so the E2E steps can't drop out of their coverage silently.

Known cost: the Cache Swift packages post-save only runs when the job succeeds, so a run whose tests fail no longer saves a SwiftPM cache miss. The E2E compilation cache is saved by an explicit step before the tests and is unaffected.

Owned Macs: glaeda's runner hook gives test-e2e's build and test jobs the unknown-job "compile" class, which never takes the mini's gui token. That was already true of the old test job. The fix belongs in glaeda and is being done separately.

Verification

  • Local guard tests: all 170 linux-guard tests from tests/test-execution.toml ran on this branch and on main at the same base. The results match, apart from test_swift_testing_suite_timeout.py, which failed on main and passed here.
    • Seven tests fail identically on this Mac on both, including test_ci_e2e_compilation_cache.py::test_a_missing_manifest_fails_instead_of_silently_compiling (macOS bash 3.2, ONLY_TESTING[@] under set -u).
    • A mutation check confirmed the no-masking guard now rejects continue-on-error inside the action.
  • CI dispatches used this branch's workflow at main's 4f0ac55da15:

Before and after, single-class runs. Across the 20 successful runs on 2026-09-25, build ran 6–22 min. test ran a further 2–3 min, most of it checkout, product download and restore, after a second queue of 1.3–96 min from 09:19Z onward. With this change there is one queue and one job. In the cmuxTests run above, the tests added 0.8 min to build, against the 2–3 min the old test job spent. Per run, that saves about 2 macOS runner-minutes (the second checkout and download) and the entire second queue, which was the part that decided the wall time on saturated pools.

  • Review: a read-only subagent reviewed the change. Its one regression (the bisect step names) is fixed in the second commit.

— Quillmoor g1 🌊

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 2 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: 6a6321f5-e10a-4abb-ad25-e55b481910cb

📥 Commits

Reviewing files that changed from the base of the PR and between ce2a516 and d42b52a.

📒 Files selected for processing (13)
  • .github/actions/e2e-run-tests/action.yml
  • .github/workflows/test-e2e.yml
  • scripts/ci/e2e_sibling_build.py
  • scripts/ci/main_regression_bisect.py
  • scripts/ci/reuse_app_host_products.py
  • tests/test_ci_app_host_home_isolation.py
  • tests/test_ci_app_host_pipe_capture.py
  • tests/test_ci_e2e_compilation_cache.py
  • tests/test_ci_focused_test_selectors.py
  • tests/test_ci_main_regression_bisect.py
  • tests/test_ci_self_hosted_guard.sh
  • tests/test_e2e_sibling_build.py
  • tests/test_reuse_app_host_products.py

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.

@github-actions

Copy link
Copy Markdown
Contributor

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

@blacksmith-sh

blacksmith-sh Bot commented Sep 25, 2026

Copy link
Copy Markdown

Found 1 test failure on Blacksmith runners:

Failure

Test View Logs
test_paid_and_downstream_jobs_checkout_only_the_resolved_sha (main.IOSWorkflowDispa
tchRefTests.test_paid_and_downstream_jobs_checkout_only_the_resolved_sha)/
test_paid_and_downstream_jobs_checkout_only_the_resolved_sha (main.IOSWorkflowDispa
tchRefTests.test_paid_and_downstream_jobs_checkout_only_the_resolved_sha)
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

teamleaderleo and others added 3 commits September 25, 2026 14:30
A test-e2e.yml run held two macOS runners in sequence. The build job
compiled (or adopted) the app-host and UI test product and uploaded it;
the test job then queued again for a runner of the same label, downloaded
the product and ran the tests. With the macOS pools saturated that second
queue took 10 to 60 minutes: run 36130355245's build finished at 12:14
and its test job sat queued until it was cancelled at 12:26.

The test steps move into a composite action, .github/actions/e2e-run-tests,
and the build job runs it right after it uploads the product, restoring
from the archive it just packaged as compile admission does for its
changed suites. The test job stays as the fallback, running only when the
build job reports tested != 'true' (CI_E2E_TEST_IN_BUILD=0 hands the tests
back to it). Both jobs check the action out at github.workflow_sha, so a
dispatch of a ref older than the action still runs its tests. The app-host
test environment (isolation, shard 1, xcresult capture) is exported by the
action after the compile, wherever the tests run. The build job's timeout
is twice job_timeout, since it now covers compiling and testing.

The upload stays: later dispatches adopt it. Because the build job now
ends after the tests, the sibling wait and cross-run reuse count an E2E
producer as done once "Upload the compiled test product" succeeded, so a
sibling does not wait out another run's tests, and a failing test no longer
makes an intact product unadoptable.

Guards that read the old test job's steps now read the action; the
app-host home, pipe-capture and no-masking guards scan it too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main_regression_bisect.py classifies a probe run by its failed top-level
step names, and the jobs API never lists a composite action's own steps.
Both E2E jobs now name the action's step "Run selected tests", and a
top-level "Resolve selectors against the built tests" step fails when the
action recorded a selector that matched no built test. classify() checks
that step first, since both fail together in that case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Run 36168944875 failed its screen-capture preflight, which skipped the
tests' "Prepare isolated DerivedData". Their always() cleanup then found
the build's canonical DerivedData path still in CMUX_DERIVED_DATA_PATH and
refused it, adding a second error. The build's cleanup now hands the
variable over empty once it has removed that DerivedData.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo merged commit 18e7750 into main Sep 25, 2026
90 of 99 checks passed
@teamleaderleo
teamleaderleo deleted the ci/e2e-single-runner branch September 25, 2026 18:41
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for d42b52a3ff: every check was green at merge (12 verified; 15 skipped by policy). Full suite runs on main after merge.

rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 25, 2026
a1ac750 Predictive local echo for remote terminals (manaflow-ai#13967)
e8e6a1a Split a single-argument tmux command string in __tmux-compat (manaflow-ai#14670)
eb3f0b3 ci: reuse the resolve's manifests on the first scheme build (manaflow-ai#14674)
56a1d4e test(ci): check each iOS checkout step's ref, anchor job lookup (manaflow-ai#14676)
0a51482 docs: keep contributor agent docs free of internal machines and apps (manaflow-ai#14672)
64939a3 ci: count the org glaeda-minis runners in the live pool picker (manaflow-ai#14678)
18e7750 ci: run E2E tests on the runner that built them (manaflow-ai#14667)
20cda9e Merge pull request manaflow-ai#12956 from manaflow-ai/12938-orbstack-daemon-bootstrap
1ee8b22 Merge pull request manaflow-ai#12834 from manaflow-ai/issue-12791-sidebar-rendering-stalls
5b87c90 ci: bisect package test failures across main's history, with a skill (manaflow-ai#14533)
ce2a516 ci: accept the hosted-runner cla.yml from manaflow-ai#14668 as the reviewed CLA base (manaflow-ai#14675)
e142cac test: count the seed-retry checkouts in the iOS dispatch ref test (manaflow-ai#14671)
465ccf3 Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
e5441eb fix: preserve sidebar cache app target wiring
d4ca913 Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
5a30066 fix(cloud): import shared route policy
6d49c7f refactor(cloud): isolate private port route policy
1322537 style(ssh): format browser proxy regression harness
1d9676d test: align remote Git metadata with directory trust policy
3e8a382 Merge remote-tracking branch 'origin/main' into 12938-orbstack-daemon-bootstrap
fbb338b fix(ssh): route browser identities through guest loopback
da813a5 Wire AgentChatProseStreamWakeDriver.swift into the app target
5b4b943 Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
6a90db3 Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
91d432e ci: execute sidebar Git watcher regression tests
c473752 test: keep sidebar regression on the standard run loop
45e344c merge: preserve import coordinator while syncing current main
260f261 fix(ssh): use portable chmod syntax for macOS carriers
f90723f fix(ssh): keep stale projections out of Cloud image routing
f8838da fix(ssh): preserve remote file drops and IPv6 loopback routes
aea7e9d fix(ssh): carry remote loopback URLs through native browser routing
cb7221b test(ssh): cover loopback port preview ownership
8806879 Merge remote-tracking branch 'origin/main' into 12938-orbstack-daemon-bootstrap
272453c fix(ssh): keep targeted reconnects scoped to their native viewer
fe0a782 test(ssh): reject unrelated pane reconnects in native workspaces
6e15d80 fix(ssh): preserve main behavior and TUI arguments after package merge
940cd10 Merge latest origin/main for CI compatibility
768e434 Merge latest origin/main into SSH TUI migration
c40ab2d chore(ssh): retain authentication localization entries
21db702 Merge concurrent SSH compatibility fixes
aee57ba fix: preserve compatible local SSH uploads without a companion target
6ee35b4 test: retain local SSH bootstrap for unsupported companion targets
41924e0 Merge origin/main into SSH TUI migration
7fe5fa8 Merge remote-tracking branch 'origin/12938-orbstack-daemon-bootstrap' into issue-13648-ssh-workspace-selection
bccce36 test: verify managed SSH respawn with runtime ownership checks
a37d876 Merge origin/main into SSH TUI migration
1136940 test: request UUID output for managed SSH runtime harness
2232f0a fix: aggregate native and legacy SSH session listings
7d42c80 test: retain legacy dispatch when no native SSH workspaces exist
0ff7f62 fix: localize shared SSH authentication errors
6feb176 fix: honor SSH profiles for provider-created terminals
afc61cb test: cover SSH provider default command and profile
b3d7cbf test(ssh): serialize shared catalog lifecycle fixtures
295dbf5 fix(ssh): replace native remote workloads through their TUI provider
6ce447c test(ssh): require provider-backed respawn with stable surface identity
460a007 test(ssh): identify Linux workload owners by executable path
ebb223b fix(ssh): lint loopback proxy policy plumbing
f8bf123 Merge remote-tracking branch 'origin/12938-orbstack-daemon-bootstrap' into 12938-orbstack-daemon-bootstrap
18ac212 fix(ssh): thread loopback permission through proxy handlers
590dff5 Merge remote-tracking branch 'origin/main' into issue-13648-ssh-workspace-selection
7bd65e8 Merge remote-tracking branch 'origin/12938-orbstack-daemon-bootstrap' into issue-13648-ssh-workspace-selection
d4b16de fix(ssh): fail closed before native remote respawn reaches local exec
ac59a10 test(ssh): reject local respawn of native remote projections
d999e65 fix(ssh): treat TUI projections as remote image targets
5967c75 fix(ssh): route native agent forks through cmux-tui providers
f9c6797 test(ssh): prevent native agent forks from creating local terminals
3f684bf Merge remote-tracking branch 'origin/12938-orbstack-daemon-bootstrap' into issue-13648-ssh-workspace-selection
cd0f1f4 style(ssh): format browser proxy regression test
20a1198 fix: bundle the published TUI client matching tagged source inputs
fe4f257 fix(ssh): allow authenticated loopback browser proxy routes
b05aa3e Merge remote-tracking branch 'origin/main' into 12938-orbstack-daemon-bootstrap
c2ba696 fix(ssh): share terminal catalog metadata and link routing
15656d0 test: keep direct ownership probe separate from detached tmux control
88ebcfe Merge remote-tracking branch 'origin/12938-orbstack-daemon-bootstrap' into issue-13648-ssh-workspace-selection
be56208 test: measure hidden SSH reads and renderer presentation across selection
553cdd0 fix: classify native SSH projections through their authoritative owner
00750ab test: classify restored native SSH terminals as remote
365a6eb test: support isolated jump-host SSH selection fixtures
67b9fe3 Merge remote-tracking branch 'origin/12938-orbstack-daemon-bootstrap' into issue-13648-ssh-workspace-selection
0b14eb0 Merge branch '12938-orbstack-daemon-bootstrap' of https://github.com/manaflow-ai/cmux into issue-13648-ssh-workspace-selection
c2ce009 fix: preserve session and SSH options in managed TUI links
5e8bf78 test: preserve managed SSH session identity in TUI link launch
3983f4c test: require cmux-tui ownership across managed SSH selection
460950d Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
ec6a650 Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
634509f Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
a71b3dc fix: retain initial sidebar snapshot observation
414e47f chore: normalize merged source whitespace
6734ee9 merge: sync latest main
264c7da test: pump common run loop modes for sidebar harness
8662152 Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
d386ce0 Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
13d30fa Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
4092d91 Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
de85594 fix: handle blank browser import identifiers
fa8e093 Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue-12791-sidebar-rendering-stalls
1d9afef fix: instantiate browser destination resolver adapter
110d737 fix: expose Foundation UUID in browser resolver API
4d4c8ea refactor: move browser destination resolution into CmuxBrowser
a73b116 merge origin/main into issue-12791-sidebar-rendering-stalls
4a6a7df test: isolate shared watcher lifecycle fixture
511d198 fix: import process identity from CmuxFoundation
683ca09 fix: close browser import review findings
c9de46c merge origin/main into issue-12791-sidebar-rendering-stalls
bb48a38 test: inject browser import coordinator in wizard coverage
3ee91b2 fix: preserve watcher on failed discovery and browser automation contracts
d790f65 test: reproduce installed watcher loss on descriptor failure
642c86a fix: scope browser import automation helper
f9f67f4 merge origin/main into issue-12791-sidebar-rendering-stalls
79e6a1a fix: continue issue 12791 rendering stall repairs
9ee3bb1 test: preserve Git metadata monitoring when watcher replacement fails
0bffb5f fix: construct sidebar snapshots only at lifecycle and event boundaries
2e683ce test: import Cloud fixture remote configuration from its owning module
8d16430 Merge remote-tracking branch 'origin/main' into issue-12791-sidebar-rendering-stalls
50b7233 fix: restore pairing preparation recovery lost in upstream merge
f165b33 test: split nested Cloud assertion to unblock hosted suites
d5464d0 test: verify native callback lifetime through queued teardown
ccfe1cd Merge remote-tracking branch 'origin/main' into issue-12791-sidebar-rendering-stalls
ad3672a fix: retain the FSEvents receiver through native registration
fee5924 fix: isolate sidebar discovery and bound workspace snapshot lifetime
dbba283 test: reproduce sidebar snapshots surviving workspace replacement

# Conflicts:
#	.github/workflows/ci-guards.yml
#	.github/workflows/ci-macos.yml
#	.github/workflows/ci.yml
#	.github/workflows/test-e2e.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant