Agent pane: an open folder trust question never blocks Send or steer (prompts wait, then go after Trust)

Merged
TE
3d ago
+1816-64

What broke

Leo, 2026-10-21, while a folder trust question bricked his chats:

  • "IT'S SO FING BAD IT SENDS YOU TO THE CHAT IN THE SAME FING PANE THEN BREAKS AND THIS TRUST F***ING HARDLOCKS EVERYTHING WTF KIND OF BULLSHIT MNOTHERFCKNG TRUST EVEN WAS THAT"
  • "IT'S LITERALLY THE ENTIRE F***ING UI IS BUSTED"

The rule that came out of it (Leo, P0): a pending folder trust question must never block steering, sending, or answering a question.

This is PR 2 of 2. PR 1 (#32074, merged) made every ask card stay answerable under the trust question. Here, Composer turned Send off, and steer with it, whenever useFolderTrustAsk blocked had a reason: the question open (trust.answerFirst) or Not now (trust.notTrustedNoPrompts). Nothing could be typed and sent until trust was answered. Only one refused prompt was kept to send again after Trust.

The fix

Ported from the closed #24023, rebuilt on current feat-cmux-next.

  • Send and steer stay on. A prompt sent while the folder's trust holds prompts waits in the pane (trustHeld.ts), each with its own send's gesture ticket (transport.gesture for session/prompt with its promptId). Held prompts show at the end of the composer's queue after one "Waiting for folder trust" note, where each can be edited or deleted. After Trust they go one at a time, in order, each once acpmux took the one before. Not now keeps them; nothing is dropped.
  • A chat whose agent already runs (working, or has turns) sends at once. acpmux lets those prompts through while the question is open (#23792, trust_gate pending_passes).
  • Refusals: a trust refusal from acpmux adds the prompt to the hold; any other refusal gives it back to the composer. A prompt kept as its own failed row with Retry stays there.
  • Held prompts are kept. A page holding prompts is not hibernated (pane.wakeState holdsPrompts, AgentPageHibernation). Closing its tab (AgentPageRetirer) or quitting puts them back into their chats' drafts. Continue without folder (#28198) puts a new chat's held prompts back into the composer first. A web update reload waits while prompts are held. One case is not covered, as on base for a new chat's typed text: a new chat's held prompts are lost if its tab then opens another chat and closes or quits, because the host clears a tab's new-chat draft on any session change. Follow-up: #32276 (and #32277 for hibernation re-planning).

Deviations from #24023, where base moved:

  • A send while the trust read is still in flight still goes out (#28088). Held prompts wait for the read before they send.
  • No gesture-slot change: base already has per-prompt session/prompt#<promptId> tickets (#29745). Known limit: a prompt held more than 10 minutes loses its ticket and comes back to the composer after Trust, to be sent with a click.
  • Remote chats (answered on their own Mac) and the floating chat's Start Agent keep Send off under the question, as before. Start Agent's hand-off has no path for a held prompt yet; that is a follow-up.

Tests

  • webviews/test/agent-pane-trust-holds-prompts.test.ts (Chromium, dev pane against a stand-in acpmux with an untrusted folder): Send is on under the question; two prompts are held and arrive at acpmux in order after Trust; after Not now the held prompts stay, one can be deleted, and Trust later sends the rest; closing the tab keeps a held prompt in the chat's draft; a running chat's steer goes at once.
  • webviews/test/trust-held-prompts.test.tsx: the hold's ordering, edit and remove, trust refusal vs. other refusal, per-chat scoping, a failed row kept, continue without folder.
  • agent-pane-trust-ask-corner.test.ts (Send now enabled under the open question), trust-refusal-asks-without-read.test.tsx.
  • Swift: AgentPageHibernationTests.aChatHoldingPromptsForATrustAnswerKeepsItsPage.

Risk

Normal, next to the trust boundary. The daemon still gates every prompt (trust_gate.rs); the pane only holds them and sends nothing to an untrusted folder. A held prompt goes only with its own send's gesture ticket.

Related, already on base

  • The "SENDS YOU TO THE CHAT IN THE SAME PANE" half: the Needs-you arrow opens the waiting chat in its own tab or on the right (#23849, #24035, #28989).
  • #32113: an answer to one ask never revokes another ask's gesture ticket.

Leo-ask: ask-a7ca5abf63
Leo-ask: ask-770be15c61

šŸ¤– Generated with Claude Code

Agent session: agent session