acpmux: typing to a paused peer's chat wakes it before the send

Merged
TE
3d ago
+90-8

Leo (2026-11-03):

Cuz the meme/dream is / You only resume when you absolutely need to / But when is that?

The model sometimes sees a delay and you sometimes see it after sending but it evens out to not much at all just a tiny bit of extra time that you mostly perceive as "thinking" / But it's all still responsive on the ui side

What changes

A chat on a peer whose link is down already asked that peer's route to wake a paused machine. It did so only when a message was refused (session/prompt, Peer::wake, ACPMUX_PEER_WAKE, as with the Freestyle pool slot's cloud-vm-up nc). So a paused machine began to resume after the person pressed Send.

Now a client's sign that a person is writing to that chat wakes it too:

  • _acpmux/typing with on: true. forward_inner answers typing itself (presence stays this daemon's own), so the wake happens there.
  • a non-blank _acpmux/composer_set

_acpmux/draft_set is deliberately not a wake: the pane saves the chat it leaves unchanged when it switches away, and that is no one writing.

The resume runs while they type, so most of it is done by the time the message goes.

Unchanged:

  • Typing off, a cleared draft and a peer daemon's forward still only want the link back, or ask nothing, as before.
  • Background reconnects still never wake a machine (HQ#5074: passive reads never wake one).
  • A draft that is never sent costs one resume. The machine's idle pause takes it back.

This is the "predictive resume" half of the policy in the owning research issue. The issue has the measurements, the transcript replay and the rest of the policy. Claude's stdio announces a tool_call only once its input is complete: p50 lead 0 s over 431k replayed calls. So the earliest usable signal for a turn's first resume is the person's typing. Within a turn it is the model's message_start.

Performance

Resume latency the person sees after Send, for a paused peer. "Before" is the measured path through the cmux app on production Freestyle. The person's typing time runs in parallel with the resume.

metricbeforeafterdeltaharness
resume started, relative to Sendat Send (refused prompt)at the first keystrokeresume starts one typing-time earlierunit test typing_to_a_down_peers_chat_wakes_it_before_the_send
resume call through the app, Freestyle small (8 cycles)0.22–0.6 s typical, 20.5 s outlierhidden behind typing when typing takes longer than the resumeabout −0.5 s per first message after a pauseguest 100 ms timestamp log, HQ research issue
user-perceived added latency per turn on active lane-days (281 days, replay, R = 1 s)p95 0.4 s once a turn runsunchanged within a turn0replay days.py, HQ research issue

No timer, observer or loop is added. The wake mark is the existing WAKE_FOR window, which lapses by itself.

Tests

  • server::peer_forward::tests::typing_to_a_down_peers_chat_wakes_it_before_the_send, new.
  • only_a_message_asks_a_down_peers_route_to_wake_it, updated for the new params argument.

cmux-ci test -- cargo test -p acpmux --lib -- peer_forward: 8 passed at bfb8cc7ec (fast checks run 41726599751). Rerun with clippy at the fixed head below.

🤖 Generated with Claude Code

Agent session: agent session