Skip to content

perf(cmux-tui-core): the input port's writer runs at user-interactive QoS once it carries a person's key (R-DAEMON-STATE S1.6d) - #35460

Merged
lawrencecchen merged 3 commits into
feat-cmux-nextfrom
fix/p0-typing-s1-6d-writer-qos
Nov 4, 2026
Merged

lawrencecchen merged 3 commits into
feat-cmux-nextfrom
fix/p0-typing-s1-6d-writer-qos

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

R-DAEMON-STATE stage S1 step 6d (handoff/rewrites/R-DAEMON-STATE/DESIGN.md, section 2.6.1), from the review of the S1.7 default flip (#35413). Behind the stage switch CMUX_TUI_RDS_INPUT (only the input lane uses the port).

The defect. The person's keys cross their connection's three threads at user-interactive QoS (server/input_qos.rs, TYPING FIX 2 F7), then the terminal's input port writer, which was spawned at the default QoS and never raised itself. Under full CPU it waited for a CPU between the key's acceptance (daemon.send.written) and its write to the host. DESIGN 2.6.1 asks for the writer at user-interactive while it carries the person's input; it was listed after the #34544 review and not built. In the build 3b A/B (STATUS 11804), the lane-on keys over 4 ms waited in that hop (1.21-3.90 ms from daemon.send.written to the host's PTY write), and the lane-on tail was about 1 ms longer than the old path's.

The fix. The writer raises itself (input_qos::raise_this_thread, once per thread) when it takes a frame with no waiter that is not a viewer size: InputPort::enqueue, which only the person's keys use (InputReply::Accepted). Automation's writes (InputPort::write, a waiter) and viewer sizes do not raise it, so a port only automation writes to keeps the default QoS, as automation's connections do. A writer that exits idle starts again at the default. Off macOS this sets nothing.

Testing

Focused test (macOS only; QoS is a no-op elsewhere): the_input_ports_writer_runs_at_user_interactive_qos_once_it_carries_a_persons_key (surface/tests/hosted.rs). It checks that automation's write leaves the writer at the default QoS and that after a person's key the writer runs at user-interactive.

Compile: fleet job 4ae6ea4a97f3bd342dc4ac5e at the head 0c77eb0: CmuxNext, app and cmux-tui passed (also bf8dbfe438eb0d68c30f6d19 at 3690c39).

Observed / Not run

Changelog

none

Proof

No capture: a daemon thread priority, no UI.


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


Summary by cubic

Fixes the terminal input port's writer running at default QoS while carrying a person's keystrokes, so on macOS under full CPU a key no longer waits for a CPU between its acceptance and the write to the host.

  • The writer raises itself to user-interactive QoS (once per thread) when it takes a frame with no waiter that isn't a viewer size — the path only the person's keys use.
  • Automation's writes and viewer sizes don't raise it, so a port only automation writes to keeps the default QoS.
  • Off macOS this sets nothing, and a writer that exits idle starts again at the default.

Written for commit 0c77eb0. Summary will update on new commits.

View guided diff Turn on auto-fix

… QoS once it carries a person's key (R-DAEMON-STATE S1.6d red, #35413 review)

DESIGN 2.6.1 asks for the port's writer at user-interactive QoS while it
carries the person's input, as the connection threads that carry the
key run (server/input_qos.rs, TYPING FIX 2 F7). The writer thread is
spawned at the default QoS and never raises itself, so under full CPU
the hop from daemon.send.written to the host's PTY write waits for a
CPU: the build 3b ON keys over 4 ms waited there (STATUS 11804).

Red (macOS only; QoS is a no-op elsewhere):
the_input_ports_writer_runs_at_user_interactive_qos_once_it_carries_a_persons_key.
Test seam: the writer records its QoS each time it takes a frame
(InputPort::writer_qos_for_test).
…QoS once it carries a person's key (R-DAEMON-STATE S1.6d, #35413 review)

The person's keys cross the connection's three threads at
user-interactive QoS (server/input_qos.rs, TYPING FIX 2 F7), then the
terminal's port writer, which ran at the default QoS: under full CPU it
waited for a CPU between the key's acceptance (daemon.send.written) and
its write to the host. DESIGN 2.6.1 asks for it at user-interactive
while it carries the person's input; it was listed and not built.

The writer now raises itself (input_qos::raise_this_thread, once per
thread) when it takes a frame with no waiter that is not a viewer size:
InputPort::enqueue, which only the person's keys use
(InputReply::Accepted). Automation's writes (InputPort::write, a waiter)
and viewer sizes do not raise it, so a port only automation writes to
keeps the default QoS. Off macOS this sets nothing.

Test (red at b078664, macOS):
the_input_ports_writer_runs_at_user_interactive_qos_once_it_carries_a_persons_key.
@lawrencecchen lawrencecchen added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 0c77eb0: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr35460 -f ref=fix/p0-typing-s1-6d-writer-qos -f platform=macos -f backend_mode=local

Shipped in:

…acOS test builds, where its test runs (clippy dead_code on Linux)
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Review (claude-reviewer-rds-s16d): SHIP at 0c77eb0

R-DAEMON-STATE S1.6d. I read the code and the CI logs; I did not build or run anything. Paths are under cmux-tui/crates/cmux-tui-core/src/.

The change is correct. The port's writer raises itself to user-interactive QoS when it takes a person's key, before it writes that key. It does this after next_frame has released the port lock, so the port lock stays a leaf.

The lint fix at this head is correct. It changes only test code (3690c395049..0c77eb0ac59). The writer_qos field, its recording, writer_qos_for_test and the current_input_thread_qos re-export are now under cfg(all(test, target_os = "macos")). That removes the dead_code error that cmux-tui spec inventory reported at 3690c39 (run 41841804340), and that check passes at this head (run 41842954610). On Linux test builds, note_thread_qos still uses current_thread_qos.

Answers to your three questions

1. Is "no waiter and not a control frame" exactly the person's keys? Yes.

  • Only two kinds of frames have no waiter. InputPort::enqueue makes waiter: None, control: false, and PortOrder::enqueue_after_pending makes control: true. InputPort::write always sets a waiter.
  • The only non-test caller of enqueue is the InputReply::Accepted branch at surface/input.rs:109.
  • Accepted comes only from cmd_terminal_io::input_surface, when the lane is on and the client types into the terminal. That is the same test that marks the connection's threads as the person's (mark_person_input).

2. Can a raised writer starve other work? No.

  • The raised writer also writes automation's frames to that terminal at user-interactive QoS. That is the right choice: the port is one FIFO. Without it, a person's key behind an automation frame would wait for a default-QoS write, which is a priority inversion.
  • The writer's CPU work is the frame copy and the system calls, and the port capacity (32 MiB) bounds it. Most of the time the writer waits in socket writes.

3. Does the per-thread RAISED flag work with a writer that exits idle? Yes.

  • RAISED is thread-local. A writer that exits after 30 s idle ends its thread, and the next writer is a new thread with RAISED false. It raises itself again when it takes its first person frame.
  • Nothing lowers a raised thread, so a writer stays raised for its life, as the connection threads do.

Notes (no change asked)

  • The first person key can still wait behind automation frames. A writer that has not raised itself yet writes the frames queued ahead of the person's first key at default QoS. So in a port that automation used first, that key waits for those writes. One fix: enqueue sets a flag, and the writer reads it before each frame and raises itself. That would also cover those frames.
  • Evidence that I could not see: the fleet Mac steps (b084ffa9 red, e95015db green) and the compile job.
  • Checks still running: the focused run 41843138251 and cmux-next guards at this head.

@blacksmith-sh

blacksmith-sh Bot commented Nov 4, 2026

Copy link
Copy Markdown

Found 3 test failures on Blacksmith runners:

Failures

Test View Logs
nightly cmux-tui resolve/nightly cmux-tui resolve View Logs
nightly.yml must not read vars.NIGHTLY_SIGN while nightly-sign.yml is in shadow mode/
nightly.yml must not read vars.NIGHTLY_SIGN while nightly-sign.yml is in shadow mode
View Logs
the short nightly decide gate must use the pooled Linux route with a Blacksmith fallbac
k/
the short nightly decide gate must use the pooled Linux route with a Blacksmith fallbac
k
View Logs

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

@lawrencecchen lawrencecchen added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Nov 4, 2026
@lawrencecchen
lawrencecchen merged commit 7aee9c6 into feat-cmux-next Nov 4, 2026
276 of 284 checks passed
@lawrencecchen
lawrencecchen deleted the fix/p0-typing-s1-6d-writer-qos branch November 4, 2026 14:29
lawrencecchen added a commit that referenced this pull request Nov 4, 2026
@cmux-bot cmux-bot Bot removed the stack-blocker label Nov 4, 2026

This branch was previously deployed

3 inactive deployments
artifacts — 0c77eb0a Deployed Nov 4, 2026 by lawrencecchen via publish tree-addressed cmux-tui #111952
sentry-dsyms — 0c77eb0a Deployed Nov 4, 2026 by lawrencecchen via upload cmux-tui dSYMs to Sentry #111952
ci-routing-agent — 0c77eb0a Deployed Nov 4, 2026 by lawrencecchen via cmux-tui tree preflight #111952
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant