Skip to content

cnx-ios: terminal fixes from the 2026-10-19 full verify (round 13) - #22387

Closed
azooz2003-bit wants to merge 25 commits into
feat-cnx-iosfrom
feat-cnx-ios-termfix-r13
Closed

azooz2003-bit wants to merge 25 commits into
feat-cnx-iosfrom
feat-cnx-ios-termfix-r13

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes the terminal defects the fresh verifier found on build 3e6a2b5 (cnx-ios/verify/full-verify-terminal-20261019.md on feat-cnx-ios-fullverify-terminal), against cnx-ios/verify/design/terminal/ACCEPTANCE.md.

Defect Cause Fix Tests (red → green)
D1 torn frames while following A row and the live area redrawn under it arrive as two chunks; the pump fed the first at once and the second a frame later, so Ghostty drew the row without its live area TerminalFeedPacer: a feed waits for 3 ms of quiet or 8 ms max (a flood still goes once per frame); -CnxNoBurstHold for A/B TerminalOutputBurstTests (11 issues → 6 pass), TerminalFeedPacerDrainTests
D2a signaling reset rebuilt a healthy link; reattach blank then half-drawn over top Presence "offline" during a Worker socket reset closed the peer-to-peer link; a reattach switched to the primary screen before the replay Keep the link and quick-probe it (1.5 s); the replay's vt-state sets the alternate screen before its rows LinkMachineTests.presenceOfflineKeepsAConnectedLinkAndProbesIt, DaemonTerminalSessionTests.aReattachToATUIStaysOnTheAlternateScreen
D2b link back 26.7 s after a cnx-hostd kill The redial's offer went out while the host was down and waited the 25 s dial timeout A presence frame for the linked Mac probes a live link, ends a backoff, or restarts a dial in flight; WebRTC offers have an 8 s answer deadline (DialOptions.answer_timeout) macSignalingBackRestartsADialInFlight (2 issues → pass); Rust webrtc_dial_gives_up_on_an_unanswered_offer_at_its_answer_deadline (20.0 s → < 4 s)
D3 AutoFill pill over the last rows It is the edit menu of a tapped, focused, empty composer (only item: AutoFill); text traits do not control it ComposerUITextView.buildMenu removes .autoFill verify/termqa/afprobe simulator probe: pill before, none after (verify/termfix-r13/d3-autofill-before-after.png)
D4 no offline state Nothing turned a down link into terminal state; and (live rig) the state followed the one link, which had moved to another Mac on the account TerminalConnectionState.offline per terminal's own Mac: at once when presence says offline or the link serves another Mac, after 4 s of failed dials (8 s for a first dial); last frame kept and readable terminalsShowOfflineWithinABoundedTime, aDroppedSessionShowsOfflineWhileTheMacIsGone
D5 input queued silently, ran 15.4 min later Unbounded input queue flushed on reattach Keys queued while detached are dropped all together after 2 s and input is refused until the next attach, with a visible notice; Send keeps the text in the composer marked unsent while reattaching/offline staleInputIsNeverSentAfterAReattach, noFragmentOfACommandRunsAfterAnOutage, ComposerSendGateTests
D6 grid card frozen The active card was snapshotted once when the grid opened Cards refresh while the grid is visible and not scrolling (capture ≤ 0.5 s, Mac screen text 1 s) TerminalCardLiveRefreshTests, TerminalCardFresherTextTests
D7 tabs timing and accessibility Close waited for the Mac's process-info; grid controls stayed mounted on a settled page Program info prefetched while the grid shows, prompt immediate or pending after 250 ms; TabsKit unmounts grid controls on a settled page (upstream feat-cmux-next-tabs-kit 8ef7a76, byte-identical here) TabClosePromptPlanTests; TabsKit 55 tests; AX dumps

Not fixed in code: D7 New Terminal (5.6 s) and first grid→tab switch (0.76 s) — the recording attributes most of both to the rig's tap timing (pick → prompt ≈ 1.05 s); a tabs log line now splits the Mac's create time. The grid "+" inner unlabeled button is a SwiftUI menu artifact; the menu itself is labeled.

Rig tools added (DEBUG only): -CnxTermProbe real-link echo probe (G-08) and text export (G-09) with verify/termqa/termprobe.py; replay done bytes= ms= sizing line and verify/termqa/sizelog.py (G-07).

Coordination: the feat-cnx-ios-redial-video agent owns browser video after a redial and the Mac APP restart "[unknown surface N]" case; this PR only changes link and terminal reattach timing. .offline touches the pill text and TerminalTabPage/GhosttyTerminalTabContent near that work.

Verification

  • Swift on mini-cmux11s: CnxLive, CnxTerminal, CnxWorkspaces, CnxShell suites, 498 tests passed at 43c6ef8; CnxLive 191 tests at 64dbc81.
  • Rust on rbx: fmt, clippy -D warnings, all suites green.
  • iOS Demo simulator build at 43c6ef8 succeeded (mini-cmux11s).
  • Review: see the review comment on this PR (all high and medium findings fixed).
  • Live rig over the real WebRTC link (phone simulator and hidden fleet-built Mac app cnx-e2e-e6d43df7, both on mini-cmux11s because the laptop CoreSimulator was wedged; settings via open --env only). Full table: cnx-ios/verify/termfix-r13/live-results.md.
Defect Before (3e6a2b5) After
D1 keyboard up, stream20 46 jumps / 297 reversals in 66 s 1 / 11 in 61 s (one multi-row catch-up after a stall, not the torn-row pattern)
D1 after Jump to bottom 11 jumps in 15 s 0
D2b hostd kill → tab live 26.7 s 2.35 s (repeats 4.22 s, 2.26 s); 0.15–0.40 s after hostd's signaling returns
D2 reattach over top 11 blank frames, then half-drawn 0 black, 0 flashes
D2a Worker signaling reset second link built, repaint (2/2) link kept (2/2 natural resets)
D3 AutoFill pill 67/67 s 0
D4 Mac app quit → offline label never in 20 min 0.45 s (after the per-Mac fix 64dbc81; 43c6ef8 failed it with a second Mac on the account)
D5 command typed while down ran 15.4 min later kept in the composer, marked not sent; nothing ran after relaunch
D6 grid card frozen advances, ~1 s behind the Mac
D7 close prompt / New Terminal / hidden controls 2.1–2.4 s / 5.59 s / exposed 0.97–1.04 s (rig AX polling included) / 3.36 s, ≤ 1.14 s after the pick / none
Tools — echo probe n 20 p50 23.1 ms p95 30.0 ms; crcgen 2000 rows exported: 0 lost, 0 dup, 0 CRC errors

Blocked or not scored: first grid→tab switch at the 0.15 s bar (needs an in-app timing log; no first-switch penalty seen), the grid "+" label (rig matches an inner SwiftUI button), two-host link latency.

Changelog

none

🤖 Generated with Claude Code

azooz2003-bit and others added 18 commits October 19, 2026 22:48
…one batch (r13 D1)

Red on mini-cmux11s: TerminalOutputBurstTests 5 tests, 11 issues (the
pacer feeds the first chunk of a burst alone).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A program that writes a row and then redraws its live area under it
(Codex, stream20) reaches the phone as two chunks a fraction of a
millisecond apart. The pump fed the first chunk at once and the second on
the next display frame, so Ghostty drew one frame with the row and no live
area: the page jumped a row and back (46 times in 66 s, keyboard up).

The pump now waits until the output has been quiet for 3 ms, or the oldest
chunk has waited 8 ms (a flood still goes once per frame). A backlog over
the frame budget goes on the next frame without a new wait.
-CnxNoBurstHold turns it off for A/B on the rig.

Green on mini-cmux11s: TerminalOutputBurstTests + TerminalOutputQueueTests,
9 tests passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ffline state, stale input and TUI reattach (D2, D4, D5)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… once when the Mac's host is back, honest offline state, never send stale input (D2, D4, D5)

- LinkMachine: presence offline no longer closes a connected link; it is
  probed (1.5 s) and kept when it answers (T-LIFE-17). A presence frame for
  the linked Mac (its signaling socket back, e.g. hostd restarted) probes
  the link now instead of at the 15 s heartbeat, and ends a backoff
  (T-LIFE-12). A dead link to an offline Mac waits for presence.
- Terminals show '<Mac> is offline' (pill: 'Mac offline') at once when
  presence says so, or after 4 s of no link; last frame kept (T-LIFE-13).
- DaemonTerminalSession: typed keys wait at most 2 s for the terminal;
  older ones are dropped with an inputNotSent event, never sent at the
  reattach (T-INPUT-17). The composer keeps its text, marked not sent,
  while the terminal is not attached.
- A reattach goes straight to the replay's alternate screen state: a TUI
  reattach no longer flips the page to the empty primary screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…poser says connecting vs reconnecting

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a close asks at once from programs read when the grid opened, or shows a pending question (D7)

D6 (T-TABS-01): the active card was a snapshot taken once at grid open. While
the grid is visible and not scrolling, TerminalCardLiveRefresh retakes a
streaming page's card every 0.5 s (copied on the main thread, composed off it)
and reads the Mac's screen every 1 s for a terminal whose page is off screen.

D7 (T-TABS-08): the grid reads each terminal's process-info when it opens and
every 2.5 s (TabProgramCache, 5 s max age). A close of a tab known to be busy
asks at once; otherwise the Mac is asked and, after 250 ms with no answer, the
question shows as pending and the answer fills it in or closes an idle shell.

Tests: TerminalCardLiveRefreshTests, TerminalCardFresherTextTests,
TabClosePromptPlanTests (mini-cmux11s, 30 tests green; red at the two test
commits). iOS: xcodebuild -scheme CnxShell generic iOS Simulator BUILD SUCCEEDED.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… state before its rows (no guess at attach); deterministic tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed (r13 D3)

The pill was the text view's edit menu: a tap on the focused, empty
composer shows it, and its only item was AutoFill. Text traits do not
control it (textContentType nil already). ComposerUITextView now removes
the AutoFill menu in buildMenu.

Red/green: verify/termqa/afprobe (a one-view simulator app with the
composer's traits, tapped with axe): plain UITextView shows the pill,
with the removal nothing shows (verify/termfix-r13/d3-autofill-before-after.png).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l in flight (r13 D2b)

Red on mini-cmux11s: macSignalingBackRestartsADialInFlight, 2 issues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…13 D2b)

After a cnx-hostd kill the host was back on signaling in 1.6 s, but the
phone's redial had sent its offer while the host was down and waited out
the 25 s dial timeout: the link came back 26.7 s after the kill. A presence
frame for the linked Mac (sent only when its socket connects, closes or it
is renamed) now abandons a dial in flight and dials again; the abandoned
dial's late result is ignored by generation, and a link it still brings up
is closed.

Green on mini-cmux11s: LinkMachineTests + LinkControllerTests, 18 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…grid controls out of a page's accessibility tree, D7 T-TABS-14; Close All asks first)

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

The verifier's 5.59 s from + to a prompt included about 2.9 s between the +
menu appearing (0.9 s in life-c-newtab.mp4) and the rig's New Terminal pick
(about 3.85 s); pick to prompt was about 1.05 s in the recording. This line
lets the next round split the Mac's part from the page's attach.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… deadline (r13 D2b)

Red on rbx: webrtc_dial_gives_up_on_an_unanswered_offer_at_its_answer_deadline
gave up after 20.0 s (the whole dial's timeout). answer_timeout is added to
DialOptions but not enforced yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (G-08, G-09)

-CnxTermProbe turns on TerminalDevProbe for every terminal screen:
- echo probe (M-ECHO): each printable byte sent is matched with its echo in
  the session output (TerminalEchoMatcher) and stamped at the first frame
  presented after Ghostty parsed it; samples go to
  Documents/termprobe/echo.jsonl and the termprobe log;
- text export (M-INTEG): the Darwin notification
  dev.cmux.cnx.termprobe.export writes each open terminal's whole text
  (soft wraps joined) to Documents/termprobe/<title>.txt.
verify/termqa/termprobe.py reads both (echo percentiles, export, crcgen
check). Not compiled into Production.

Green on mini-cmux11s: TerminalEchoMatcherTests, TerminalTextExportTests,
TerminalScreenRowsTests (10 tests).

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

coderabbitai Bot commented Oct 20, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@blacksmith-sh

blacksmith-sh Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Found 14 test failures on Blacksmith runners:

Failures

Test View Logs
cnx-ios-testflight.yml job testflight never runs scripts/
select-ci-xcode.sh, so it builds with the image's default Xcode
View Logs
GitHub-hosted runner label: .github/workflows/
pr-red-checks-comment.yml:16: runs-on: ubuntu-24.04
View Logs
GitHub-hosted runner label: .github/workflows/
pr-red-checks-comment.yml:16: runs-on: ubuntu-24.04
View Logs
test_every_mac_job_reads_the_placement (main.CmuxNextWiring.test_every_mac_job_read
s_the_placement) (job='cmux-scheme-compile')/
test_every_mac_job_reads_the_placement (main.CmuxNextWiring.test_every_mac_job_read
s_the_placement) (job='cmux-scheme-compile')
View Logs
test_every_mac_job_reads_the_placement (main.CmuxNextWiring.test_every_mac_job_read
s_the_placement) (job='daemon-test')/
test_every_mac_job_reads_the_placement (main.CmuxNextWiring.test_every_mac_job_read
s_the_placement) (job='daemon-test')
View Logs
test_every_mac_job_reads_the_placement (main.CmuxNextWiring.test_every_mac_job_read
s_the_placement) (job='generated-files')/
test_every_mac_job_reads_the_placement (main.CmuxNextWiring.test_every_mac_job_read
s_the_placement) (job='generated-files')
View Logs
test_every_mac_job_reads_the_placement (main.CmuxNextWiring.test_every_mac_job_read
s_the_placement) (job='release-compile')/
test_every_mac_job_reads_the_placement (main.CmuxNextWiring.test_every_mac_job_read
s_the_placement) (job='release-compile')
View Logs
test_every_mac_job_reads_the_placement (main.CmuxNextWiring.test_every_mac_job_read
s_the_placement) (job='swift-test')/
test_every_mac_job_reads_the_placement (main.CmuxNextWiring.test_every_mac_job_read
s_the_placement) (job='swift-test')
View Logs
test_every_shadow_job_is_compare_only (main.ShadowJobTests.test_every_shadow_job_is
_compare_only) (workflow='cmux-tui-artifacts.yml', shadow='macos-cross-runtime-x86_64')
/test_every_shadow_job_is_compare_only (main.ShadowJobTests.test_every_shadow_job_i
s_compare_only) (workflow='cmux-tui-artifacts.yml', shadow='macos-cross-runtime-x86_64'
)
View Logs
test_every_shadow_job_is_compare_only (main.ShadowJobTests.test_every_shadow_job_is
_compare_only) (workflow='cmux-tui-artifacts.yml', shadow='macos-cross-shadow')/
test_every_shadow_job_is_compare_only (main.ShadowJobTests.test_every_shadow_job_is
_compare_only) (workflow='cmux-tui-artifacts.yml', shadow='macos-cross-shadow')
View Logs

...and 4 more test failures. View all on Blacksmith

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

azooz2003-bit and others added 2 commits October 19, 2026 23:13
…r13 D2b)

An offer sent while the Mac's host was down or restarting is never
answered; the dial waited out the whole 25 s dial timeout. The dial side
now gives up 8 s after the offer without an answer (DialOptions.
answer_timeout), so the phone's next dial reaches the restarted host. The
Mac's answer side is unchanged.

Green on rbx: cargo fmt --check, clippy --all-targets -D warnings, cargo
test (loopback 20 passed incl. the new test; roaming 9 passed, its
wireguard_roam_takes_a_fresh_turn_allocation, flaky once, passed 3/3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The screen logs 'replay done bytes=N ms=M' when a reset's replay is parsed;
verify/termqa/sizelog.py counts resizes and resets by cause and replays from
a simulator's unified log. Resize and reset lines already carry cause=.

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

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Probably yours: CI fast guards failed: a guard step failed, FAIL 0.2s workflow-guard-tests / ci: Validate macOS jobs select a pinned Xcode.

CI failed on 580932e5ff (run 39385732946 attempt 1): 3 code, 5 unknown.
macOS jobs did not run: compile and app tests were skipped: Fast static checks failure.

Job Verdict Why
CI fast guards code a guard step failed
Fast static checks code a static check failed
guards / workflow-guard-history unknown no known signature; failed step: Validate SwiftPM lockfile policy
guards / workflow-guard-tests / preflight unknown no known signature; failed step: Validate macOS runner guards
guards / workflow-guard-tests / app-host-cache unknown no known signature; failed step: Validate iOS video recording failures
guards / workflow-guard-tests / release-ios unknown no known signature; failed step: Validate iOS simulator build-once contract
guards / workflow-guard-tests / release-tooling unknown no known signature; failed step: Validate retried Ghostty Zig package fetches
guards / workflow-guard-tests / quality-determinism code a Python test failed
Matched log lines
CI fast guards: FAIL    0.2s  workflow-guard-tests / ci: Validate macOS jobs select a pinned Xcode
Fast static checks: FAILED localization (0.87s)
guards / workflow-guard-tests / quality-determinism: FAIL: test_scans_only_test_sources (__main__.CommandLine.test_scans_only_test_sources)

Not re-run automatically: CI fast guards, Fast static checks, guards / workflow-guard-history, guards / workflow-guard-tests / preflight, guards / workflow-guard-tests / app-host-cache are not machine failures.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

CI fast guards failed on 580932e5ff (https://github.com/manaflow-ai/cmux/actions/runs/39385732946). It does not block the merge; a red guard merged into main breaks it for every open PR.

Validate macOS jobs select a pinned Xcode

Test: python3 tests/test_ci_macos_xcode_selection.py

cnx-ios-testflight.yml job testflight never runs scripts/select-ci-xcode.sh, so it builds with the image's default Xcode

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Validate macOS jobs select a pinned Xcode'

Check that push and pull_request path filters agree

Test: python3 tests/test_ci_workflow_path_filter_parity.py

Traceback (most recent call last):
  File "/home/runner/_work/cmux/cmux/tests/test_ci_workflow_path_filter_parity.py", line 245, in <module>
    test_push_and_pull_request_filter_the_same_files()
  File "/home/runner/_work/cmux/cmux/tests/test_ci_workflow_path_filter_parity.py", line 156, in test_push_and_pull_request_filter_the_same_files
    assert not drifted, (
           ^^^^^^^^^^^
AssertionError: Every workflow that filters both events must filter them identically, or declare the difference in EXEMPTIONS or PUSH_ONLY_PATTERNS with a reason.
backend.yml: push and pull_request filter different files
  paths: guarded on push, not on pull requests: scripts/cmux-next/release/prod-promote.ts, scripts/cmux-next/release/production-approvals.json

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Check that push and pull_request path filters agree'

Validate local hook trust boundary

Test: python3 tests/test_preflight_trust.py

  • PreflightTrustTests.test_annotated_tag_push_does_not_execute_candidate_code
subprocess.CalledProcessError: Command '['bash', 'scripts/install-git-hooks.sh']' returned non-zero exit status 1.
  • PreflightTrustTests.test_hook_installation_has_no_candidate_code_runner
subprocess.CalledProcessError: Command '['bash', 'scripts/install-git-hooks.sh']' returned non-zero exit status 1.
  • PreflightTrustTests.test_push_does_not_execute_candidate_check_through_unchanged_wrapper
subprocess.CalledProcessError: Command '['bash', 'scripts/install-git-hooks.sh']' returned non-zero exit status 1.
  • PreflightTrustTests.test_push_does_not_execute_candidate_runner
subprocess.CalledProcessError: Command '['bash', 'scripts/install-git-hooks.sh']' returned non-zero exit status 1.

... and 1 more failing tests in the run log.
Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Validate local hook trust boundary'

Run canonical CMUX CI guard profile

GitHub-hosted runner label: .github/workflows/pr-red-checks-comment.yml:16:    runs-on: ubuntu-24.04

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Run canonical CMUX CI guard profile'

Validate package test selection

Test: python3 tests/test_ci_select_package_tests.py

    result, count = run_package_step("CmuxUpdater", [(startup, 1), (passed, 0)])
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/_work/cmux/cmux/tests/test_ci_select_package_tests.py", line 102, in run_package_step
    count = int((root / "calls").read_text())
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/pathlib.py", line 1029, in read_text
    with self.open(mode='r', encoding=encoding, errors=errors) as f:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/pathlib.py", line 1015, in open
    return io.open(self, mode, buffering, encoding, errors, newline)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpaemnqrj8/calls'

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Validate package test selection'

Lint every workflow

/tmp/guard-steps-_2dy2kgi/runner_temp/actionlint.tar.gz: OK
/tmp/guard-steps-_2dy2kgi/runner_temp/actionlint
.github/workflows/cmux-next-defaults-guard.yml:94:28: expected scalar node for string value but found alias node with "" tag [syntax-check]
   |
94 |           sparse-checkout: *defaults-paths
   |                            ^~~~~~~~~~~~~~~
.github/workflows/nightly.yml:34:3: maximum number of inputs for "workflow_dispatch" event is 10 but 15 inputs are provided. see https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#providing-inputs [events]
   |
34 |   workflow_dispatch:
   |   ^~~~~~~~~~~~~~~~~~

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Lint every workflow'

Validate side-lane placement onto idle owned runners

  • CmuxNextWiring.test_every_mac_job_reads_the_placement (job='cmux-scheme-compile')
AssertionError: False is not true : ${{ !(github.event_name == 'pull_request' && github.base_ref == 'feat-cmux-next') && (!cancelled() && ((inputs.same_tree_sha == '' && needs.path_route.outputs.scheme == 'true' && needs.push-head-preflight.outputs.current == 'true' && needs.path_route.outputs.tree_state == 'ready' && (github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/feat-cmux-next' || startsWith(github.ref, 'refs/heads/next-batch/'))) || (inputs.same_tree_sha != '' && inputs.same_tree_state == 'ready' && contains(inputs.same_tree_tiers, 'scheme')))) }}
  • CmuxNextWiring.test_every_mac_job_reads_the_placement (job='release-compile')
AssertionError: False is not true : ${{ !(github.event_name == 'pull_request' && github.base_ref == 'feat-cmux-next') && (!cancelled() && needs.path_route.outputs.native == 'true' && needs.push-head-preflight.outputs.current == 'true' && (github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/feat-cmux-next' || startsWith(github.ref, 'refs/heads/next-batch/'))) }}
  • CmuxNextWiring.test_every_mac_job_reads_the_placement (job='swift-test')
AssertionError: False is not true : ${{ !(github.event_name == 'push' && github.ref == 'refs/heads/feat-cmux-next') && (!cancelled() && needs.path_route.outputs.swift == 'true' && needs.push-head-preflight.outputs.current == 'true' && (github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/feat-cmux-next' || startsWith(github.ref, 'refs/heads/next-batch/'))) }}
  • CmuxNextWiring.test_every_mac_job_reads_the_placement (job='daemon-test')
AssertionError: False is not true : ${{ !((github.event_name == 'push' && github.ref == 'refs/heads/feat-cmux-next') || (github.event_name == 'pull_request' && github.base_ref == 'feat-cmux-next')) && inputs.same_tree_origin != 'push' && (!cancelled() && ((inputs.same_tree_sha == '' && needs.path_route.outputs.daemon == 'true' && needs.push-head-preflight.outputs.current == 'true' && needs.path_route.outputs.tree_state == 'ready' && (github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/feat-cmux-next' || startsWith(github.ref, 'refs/heads/next-batch/'))) || (inputs.same_tree_sha != '' && inputs.same_tree_state == 'ready' && contains(inputs.same_tree_tiers, 'daemon')))) }}

... and 1 more failing tests in the run log.
Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Validate side-lane placement onto idle owned runners'

Validate every workflow guard is wired

Test: python3 tests/test_ci_workflow_guards_are_wired.py

Traceback (most recent call last):
  File "/home/runner/_work/cmux/cmux/tests/test_ci_workflow_guards_are_wired.py", line 110, in <module>
    test_every_workflow_guard_is_run_by_a_workflow()
  File "/home/runner/_work/cmux/cmux/tests/test_ci_workflow_guards_are_wired.py", line 89, in test_every_workflow_guard_is_run_by_a_workflow
    assert not unwired, (
           ^^^^^^^^^^^
AssertionError: these tests read .github/workflows/ but no workflow runs them, so the invariants they assert are not enforced:
  tests/test_cmux_tui_republish_same_commit.py
Add a step to .github/workflows/ci-guards.yml, or add an entry to UNWIRED in this file explaining why not.

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Validate every workflow guard is wired'

Validate notification semantics gates

Test: python3 tests/test_ci_notification_semantics.py

  • NotificationSemanticsTests.test_a_failing_package_does_not_hide_later_packages
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpmf7ywd0w/calls.jsonl'
  • NotificationSemanticsTests.test_packages_prebuild_in_parallel_then_test_serially
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmp3mnmewap/calls.jsonl'

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Validate notification semantics gates'

Validate the macOS cross-compile shadow jobs stay compare-only

  • ShadowJobTests.test_every_shadow_job_is_compare_only (workflow='cmux-tui-artifacts.yml', shadow='macos-cross-shadow')
AssertionError: Lists differ: ['notify-unpublished-tree'] != []

First list contains 1 additional elements.
First extra element 0:
'notify-unpublished-tree'

- ['notify-unpublished-tree']
+ [] : cmux-tui-artifacts.yml: ['notify-unpublished-tree'] must not need macos-cross-shadow
  • ShadowJobTests.test_every_shadow_job_is_compare_only (workflow='cmux-tui-artifacts.yml', shadow='macos-cross-runtime-x86_64')
AssertionError: Lists differ: ['notify-unpublished-tree'] != []

First list contains 1 additional elements.
First extra element 0:
'notify-unpublished-tree'

- ['notify-unpublished-tree']
+ [] : cmux-tui-artifacts.yml: ['notify-unpublished-tree'] must not need macos-cross-runtime-x86_64

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Validate the macOS cross-compile shadow jobs stay compare-only'

... and 2 more failed steps in the run log.

Agents: python3 scripts/ci/guard_attribution.py fix applies the mechanical fixes locally.

From the correctness review (subagent):
- D5: input expiry is all-or-nothing and only for keys queued while the
  terminal was detached; after a drop, input is refused until the next
  attach, so the last 2 s of a command (mp\r of ls -la /tmp\r) can never
  run alone. Keys typed on a slow live link never expire. Keys still queued
  when the link drops are dated from when they were typed.
  noFragmentOfACommandRunsAfterAnOutage: red on the old session (3 issues),
  green now.
- D5: a Send while a new tab's first attach is under way goes to the
  session's short hold instead of being refused.
- D2b: a presence frame sends .macSignaled only when retarget() did not just
  dial, so a Mac back from offline gets one dial, not two.
- D4: a first dial is called offline after 8 s instead of never (a redial
  after a lost link can last its whole timeout); the coordinator re-checks
  at that bound.
- D1: the burst restarts when the queue drains on an alternate screen step;
  the wake work item runs main-actor isolated.
- D6: an unchanged Mac screen text is re-dated without redrawing the card.
- cnx-link: a dial that hits the answer deadline closes its peer connection.

Green: mini-cmux11s 51 tests in 9 suites (DaemonTerminalSession, LinkMachine,
LinkController, ComposerSendGate, TerminalOutputBurst, TerminalFeedPacerDrain,
TerminalCardLiveRefresh, TerminalCardFresherText); rbx fmt, clippy -p
cnx-link -D warnings, loopback 20 passed.

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

Copy link
Copy Markdown
Collaborator Author

Correctness review (fresh review subagent) and resolution

Reviewed the diff 3e6a2b5..e6d43df read-only. Findings and what was done (fixes in 43c6ef8):

# Severity Finding Resolution
1 high Per-key 2 s expiry could drop the start of a command typed during an outage and send only its tail (mp\r of ls -la /tmp\r) Fixed: expiry is all-or-nothing; after a drop, input is refused until the next attach. New test noFragmentOfACommandRunsAfterAnOutage (red on the old session: 3 issues; green now)
2 high Keys typed on a slow but live link (a send in flight > 2 s) expired mid-word Fixed: only keys queued while detached expire; keys still queued when the link drops are dated from when they were typed
3 medium A Mac back from offline got two dials (retarget() then .macSignaled restarting it) Fixed: .macSignaled is sent only when retarget() did not just dial
4 medium Composer Send refused during a new tab's first attach Fixed: .connecting sends through the session's short hold
5 medium DispatchWorkItem closure touching main-actor state might not compile The iOS Demo build compiled it; body now runs in MainActor.assumeIsolated anyway
6 medium Offline label not guaranteed within a bound: a first-attempt redial was never "offline" Fixed: a first dial counts as offline after 8 s; the coordinator re-checks at that bound
7 low Burst hold skipped once after a drain that ended on an alternate-screen step Fixed: TerminalFeedPacer.drained(); test aDrainedQueueStartsANewBurst
8 low Live card refresh redrew unchanged screen text every second; per-tab sequential process-info prefetch Text: fixed (re-dated without a redraw). Prefetch batching: left as is (grid-only, 2.5 s cadence); follow-up
9 low Answer-deadline dial returned without closing its peer connection Fixed: pc.close() before returning

Checks after the fixes: mini-cmux11s swift test 51 tests in 9 suites green; rbx cargo fmt --check, clippy -p cnx-link -D warnings, loopback 20 passed.

azooz2003-bit and others added 4 commits October 19, 2026 23:30
Re-run: plain UITextView shows the AutoFill pill (1447 bright pixels in the
band above the field), with the fix none (0).

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

Live re-run of the verifier's scenarios on 43c6ef8 (phone simulator and
hidden Mac rig on mini-cmux11s, real WebRTC link): D1, D2, D3, D5, D6 and
most of D7 fixed with numbers; D4 not verified (a second Mac on the account
took the link; terminals' offline state follows the link's phase). Analyser
json and scenario logs in verify/termfix-r13/live/.

termprobe.py export armed its wait for the app's reply after posting the
request and missed it; it now arms the waiter first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…3 D4, live rig)

The live rig quit the Mac app with a second Mac online on the account: the
link moved to that Mac and read connected, so the quit Mac's tab said
Reattaching... for 60 s. Each terminal session now records its Mac; it is
offline when the link's phase says so for the linked Mac, and at once when
the link serves another Mac (LinkMachine.terminalOffline).

Green on mini-cmux11s: CnxLiveTests 191 tests (incl. TerminalOfflinePerMacTests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Graceful Mac quit with stream20 running: 'Mac offline' at 0.45 s (was
never), last frame kept, composer Send kept unsent, typed keys dropped
with a notice, nothing ran after the relaunch, tab live 3.88 s after the
launch call.

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

Copy link
Copy Markdown
Collaborator Author

Addendum to the review: the live rig found one more D4 gap after the review (offline state followed the single link, which had moved to the account's other Mac). Fixed in 64dbc81 (per-terminal Mac, LinkMachine.terminalOffline, test TerminalOfflinePerMacTests); the live re-run shows "Mac offline" 0.45 s after a graceful quit. This small change was not part of the subagent review.

@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Superseded by #22555, which merged this branch's head into feat-cmux-next (merge commit f3842ff) together with #22260, #22354, #22355, #22337, #22419, #22387 and #22574. Closing as folded in; the branch is kept.

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