Skip to content

Harden E2E recording and dual-Xcode CI routing - #7835

Closed
lawrencecchen wants to merge 15 commits into
mainfrom
fix-e2e-recording-activation
Closed

lawrencecchen wants to merge 15 commits into
mainfrom
fix-e2e-recording-activation

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 10, 2026 •

Copy link
Copy Markdown
Contributor

Recorded XCUITest could leave cmux Running Background because screen capture began before the app became frontmost. Compile a small AppKit probe and arm frame capture until the expected cmux bundle owns the foreground. Capture pauses whenever cmux is not frontmost, then resumes without a persistent AVFoundation session.

The Tart image has Xcode 26.3 only, while swift-package-tests needs SDK 15 for the universal Ghostty helper and SDK 26 for package tests. Route that single dual-Xcode job through MACOS_RUNNER_DUAL_XCODE, set to Blacksmith macOS 15.

The iPhone suite also exposed cross-suite output contamination because multiple tests used live-terminal. Give the resync test and router a unique surface ID.

Recorder failure before fix: https://github.com/manaflow-ai/cmux/actions/runs/29082615968
Recorder pass on the same AWS host after fix: https://github.com/manaflow-ai/cmux/actions/runs/29083465895
iPhone failure before isolation: https://github.com/manaflow-ai/cmux/actions/runs/29083696229
iPhone pass after isolation: https://github.com/manaflow-ai/cmux/actions/runs/29084943707

Validation: actionlint .github/workflows/test-e2e.yml; bash tests/test_ci_self_hosted_guard.sh. PR CI validates the final Tart/Blacksmith routing.


Note

Medium Risk
Mobile terminal replay barrier coordination affects live output recovery on connected devices; changes are scoped and covered by new tests. CI/workflow edits are mostly runner routing and recording harness behavior.

Overview
Hardens macOS E2E screen recording so JPEG capture runs only while com.cmuxterm.app.debug is frontmost (small AppKit probe + gated screencapture), avoiding early capture that left cmux Running Background. Startup checks use a ready marker instead of assuming the first frame succeeded.

Routes swift-package-tests through MACOS_RUNNER_DUAL_XCODE so the job can build the Ghostty helper on SDK 15 and run package tests on SDK 26; documents the new repo variable. Adds Node 22 on the focused app-host shard before CLI no-socket regressions.

On mobile terminal sync, adds requestTerminalResync so recovery can defer behind an active replay barrier (or start a new barrier when none owns the surface); legacy hosts without terminal.replay.v1 keep the unbarriered path. input_seq_behind resync uses deferral on raw-bytes transport. Tests cover legacy live output during deferred resync and tighten the sequence-ahead resync scenario with manual acknowledgements and an isolated surface ID.

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

Summary by CodeRabbit

  • Bug Fixes

    • Improved terminal output recovery when display updates arrive out of order, helping ensure refreshed terminal content is rendered correctly.
    • Improved replay and resynchronization behavior during active terminal updates, reducing missed or stale output.
  • Tests

    • Expanded coverage for terminal output recovery across multiple terminal sessions.
  • Chores

    • Improved automated macOS testing and screen-capture startup reliability.

@vercel

vercel Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Canceled Canceled Jul 10, 2026 4:54pm
cmux-staging Building Building Preview, Comment Jul 10, 2026 4:54pm

@coderabbitai

coderabbitai Bot commented Jul 10, 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 updates Tart E2E capture startup, switches package tests to a dual-Xcode runner, documents the runner variable, and adds replay-barrier-aware terminal resynchronization with parameterized terminal test fixtures.

Changes

E2E video capture

Layer / File(s) Summary
Frontmost capture gating
.github/workflows/test-e2e.yml
Tart compiles a frontmost-application helper, waits for cmuxterm.app.debug, creates RECORD_READY, and validates recorder liveness before capture proceeds.

Dual-Xcode runner configuration

Layer / File(s) Summary
Dual-Xcode runner selection
.github/workflows/ci.yml, docs/ci-runners.md
The Swift package test job uses the dual-Xcode runner, while documentation records its active value, fallback, and recovery commands.

Terminal resynchronization

Layer / File(s) Summary
Replay-barrier resync path
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TerminalReplayLifecycle.swift, Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
Terminal resync now defers surfaces owned by an active replay barrier or starts replay under a new barrier token.
Parameterized terminal fixtures
ios/cmuxPackage/Tests/cmuxFeatureTests/cmuxFeatureTests.swift
Terminal test helpers and responses now propagate configurable terminal and surface identifiers through replay, input, workspace, and render-grid data.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

Frontmost-aware capture startup

sequenceDiagram
  participant TartCaptureLoop
  participant FrontmostHelper
  participant CmuxApp
  participant ScreenCapture
  TartCaptureLoop->>FrontmostHelper: Check frontmost bundle identifier
  FrontmostHelper->>CmuxApp: Observe active application
  FrontmostHelper-->>TartCaptureLoop: Report cmuxterm.app.debug is frontmost
  TartCaptureLoop->>ScreenCapture: Start JPEG frame capture
  TartCaptureLoop->>TartCaptureLoop: Create RECORD_READY and verify recorder liveness
Loading

Terminal resync flow

sequenceDiagram
  participant ResyncTerminalOutput
  participant MobileShellComposite
  participant TerminalReplay
  ResyncTerminalOutput->>MobileShellComposite: Request resync for surface
  MobileShellComposite->>MobileShellComposite: Check replay barrier ownership
  MobileShellComposite->>TerminalReplay: Request replay with new barrier token
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 23 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description covers summary and testing, but it omits required template sections like Demo Video, Review Trigger, and Checklist. Reformat the PR body to match the template and add the missing Demo Video, Review Trigger, and Checklist sections.
✅ Passed checks (23 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 Swift Actor Isolation ✅ Passed The only production Swift change stays inside @MainActor MobileShellComposite; it adds a flag and reuses main-actor methods, with no new Sendable/shared-state or background UI access.
Cmux Swift Blocking Runtime ✅ Passed The Swift changes add state-based replay deferral and barrier reuse, with no new sleeps, waits, polling, main-syncs, or locks in production code.
Cmux Browser Automation Off-Main ✅ Passed PR only changes iOS terminal resync logic in MobileShellComposite.swift; no browser socket automation commands, policy files, or WebKit/AppKit worker routing are touched.
Cmux Expensive Synchronous Load ✅ Passed No expensive synchronous agent-history load was added or moved onto a main-actor/interactive path; the Swift changes only adjust replay barriers and test IDs.
Cmux Cache Substitution Correctness ✅ Passed No fresh authoritative read was replaced by a cached value in a persistence/history/snapshot path; the Swift changes only add barrier-aware replay coordination and test ID isolation.
Cmux No Hacky Sleeps ✅ Passed PASS: The only changed runtime code is Swift, and the rule explicitly excludes GitHub Actions YAML; the diff adds replay-barrier routing, not sleeps/polling.
Cmux Algorithmic Complexity ✅ Passed PASS: the new resync path is O(1) per surface; the only loop is the existing linear sweep over surfaceIDs with constant-time Set/Dictionary lookups.
Cmux Swift Concurrency ✅ Passed PR adds only synchronous replay-routing logic and test surface-ID plumbing; diff search found no new DispatchQueue/Combine/completion-handler or fire-and-forget Task patterns.
Cmux Swift @Concurrent ✅ Passed No changed Swift async helper needs @concurrent; the new resync path is synchronous actor-bound work, and test helpers are sync serialization only.
Cmux Swift File And Package Boundaries ✅ Passed PASS: Changes stay in package/test boundaries; production edits are tiny (+18/+1) in focused terminal-replay logic, with no new oversized or mixed-responsibility Swift file.
Cmux Swiftpm Lockfiles ✅ Passed The commit changes only MobileShellComposite.swift; no .gitignore, Package.swift, Xcode project, or Package.resolved files are in the diff, so the lockfile rule isn’t triggered.
Cmux Swift Logging ✅ Passed The Swift diff only changes resync branching; it adds no print/debugPrint/dump/NSLog or ad hoc file/stdout logging and no sensitive-data exposure.
Cmux User-Facing Error Privacy ✅ Passed PASS: The PR only adds replay-wiring and a debug log in production; no new user-facing error/recovery copy or sensitive details were introduced.
Cmux Full Internationalization ✅ Passed Changes are confined to CI workflows, tests, docs, and internal replay logic; no user-facing Swift/UI text, web copy, or locale/catalog files were added or changed.
Cmux Swiftui State Layout ✅ Passed The diff only changes tests and MobileShellComposite replay logic; no new SwiftUI view state, GeometryReader, lazy-row store refs, or render-time mutation were introduced.
Cmux Architecture Rethink ✅ Passed requestTerminalResync reuses existing replay-barrier ownership/dropped-output bookkeeping, and the added sleep is test-only; no new lifecycle owner or polling was introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The diff only changes terminal replay/resync logic; no user-visible NSWindow/NSPanel/WindowGroup code or cmuxAuxiliaryWindowIdentifiers changes are introduced.
Cmux Source Artifacts ✅ Passed Changed paths are workflows, docs, source, and tests; no logs, screenshots, caches, temp dirs, or other generated artifacts were added.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The only production Sources diff adds a runtime deferBehindActiveReplay flag and switches replay vs resync; no debug*/ForTesting seam, test guard, or widened wrapper was added.
Cmux No Ambient Global State ✅ Passed PASS: The source changes stay on MobileShellComposite instance methods; no new file-scope funcs, globals, static-only namespaces, or singletons were introduced.
Title check ✅ Passed The title is concise and matches the main changes: E2E recording hardening plus dual-Xcode CI routing.
✨ 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 fix-e2e-recording-activation

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.

@greptile-apps

greptile-apps Bot commented Jul 10, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR hardens E2E recording, updates macOS CI routing, and adjusts mobile terminal resync behavior.

  • Gates JPEG frame capture until the cmux debug app is frontmost.
  • Adds a recorder initialization marker before UI tests start.
  • Routes the Swift package lane through a dual-Xcode macOS runner.
  • Adds Node setup for focused CLI no-socket regressions.
  • Defers raw-bytes terminal resync behind active replay barriers.
  • Isolates terminal test surface IDs to avoid cross-suite output overlap.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.
  • The recorder startup path now has an initialization signal.
  • The zero-frame case still fails the workflow when capture never starts.

Important Files Changed

Filename Overview
.github/workflows/test-e2e.yml Updates the E2E recording loop to wait for cmux to become frontmost before capturing frames.
.github/workflows/ci.yml Adds Node setup for focused CLI tests and routes the Swift package lane through the dual-Xcode runner.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TerminalReplayLifecycle.swift Adds a resync entrypoint that can defer raw-bytes replay recovery behind an active barrier.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift Threads the resync deferral flag through the input sequence catch-up path.

Reviews (12): Last reviewed commit: "Split legacy replay compatibility test" | Re-trigger Greptile

Comment thread .github/workflows/test-e2e.yml
Comment thread .github/workflows/test-e2e.yml 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.

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-e2e.yml:
- Around line 405-430: Update the screencapture invocation in the recording loop
following the frontmost-application check to avoid terminating the subshell on a
single failure. Replace the `|| exit 1` behavior with diagnostic logging and
continuation to the next iteration, while preserving the loop’s liveness checks
and allowing subsequent frames to be captured.
🪄 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: 85d4e3c6-dce9-492b-9938-5e8fefcc4919

📥 Commits

Reviewing files that changed from the base of the PR and between 667cc43 and 27abda1.

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

Comment thread .github/workflows/test-e2e.yml
@lawrencecchen lawrencecchen changed the title Arm E2E recording after app activation Harden E2E recording and dual-Xcode CI routing Jul 10, 2026
Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/test-e2e.yml
Comment thread .github/workflows/test-e2e.yml Outdated
Comment thread .github/workflows/test-e2e.yml

@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-e2e.yml:
- Around line 445-457: Make the recorder liveness check non-fatal under set -e
so initialization failures reach the existing diagnostic block. Update the kill
-0 check immediately after RECORD_PID is assigned to tolerate a nonzero result,
then continue polling RECORD_READY and emit the existing error log and captured
recorder output when initialization fails.
🪄 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: 4225473a-2208-4779-b1af-4826bcd01c73

📥 Commits

Reviewing files that changed from the base of the PR and between 0c5f4ec and 1816ca3.

📒 Files selected for processing (4)
  • .github/workflows/test-e2e.yml
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TerminalReplayLifecycle.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • ios/cmuxPackage/Tests/cmuxFeatureTests/cmuxFeatureTests.swift

Comment thread .github/workflows/test-e2e.yml

@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 using default effort 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 1ece89e. Configure here.

@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — b1904ab6 Deployed Jul 10, 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