Agent pane: an open folder trust question never blocks Send, steer or answering a question

Closed
TE
9d ago
+1795-199

What broke

Leo (2026-10-21, P0): a pending folder trust question must never block steering, sending, or answering a question.

While a chat folder's trust question was open (or after Not now, or while its trust was still being read), the agent pane:

  • turned Send off, and steer with it (useFolderTrustAsk blocked fed the composer);
  • hid the permission panel, the question card, the secret card and tool cards (holdsAsks), so a turn already running waited on an ask nobody could see;
  • kept at most one refused prompt to send again after Trust.

The daemon refuses only prompts here (trust_gate::check); it takes permission_respond whatever the folder's trust. Hiding the cards was the pane's own choice.

The fix

  • Send and steer stay on. A prompt sent while the folder's trust holds prompts waits in the pane (trustHeld.ts). Every one is held, not just one. They show at the end of the composer's queue under a "Waiting for folder trust" header, 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 trust refusal from acpmux holds the prompt again; any other refusal puts it back in the composer. A steer typed then goes as an ordinary prompt after Trust, so the held prompts keep their order.
  • Asks are never hidden behind trust. holdsAsks is gone. #22054 added it so two asks never competed for one answer. But these cards ask for a turn that is already running, and acpmux takes their answers anyway, so hiding them only stalled the turn. The waiting line ("Waiting for you: …") now names those asks too.
  • The trust card still sits at the top of the bottom stack, inline above the composer.
  • Host (Swift, one line of logic): the host kept one session/prompt gesture ticket per connection, so a second held prompt's ticket revoked the first one's. That first prompt would then have come back transport.gesture_required. AgentPaneGestureIntent.slot is now per prompt id. Each ticket still needs its own gesture.

Does the web fix alone cover the ask? For the user-facing part, yes: nothing in the pane waits on the trust question any more. What the daemon still does: a prompt from any other client (CLI, MCP, another app) to an unknown folder is refused, not queued. Making the daemon queue it and raise trust_wait::card is the possible second PR.

Known limit: a remote chat whose trust must be answered on its own Mac holds its prompts until the pane reads that folder's trust again (a chat switch or a refusal). Before this PR, Send was simply off in that case.

Tests

The red commit (7e13ff85d99) holds the tests; the fix follows.

  • webviews/test/agent-pane-trust-holds-prompts.test.ts (Chromium, dev pane against a stand-in acpmux with an untrusted folder): Send is enabled 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; a question card is visible under the open trust question and its answer reaches _acpmux/permission_respond; a steer typed mid-turn is held.
  • webviews/test/trust-held-prompts.test.tsx: the hold's ordering, edit/remove, trust refusal vs. other refusal, and per-chat scoping.
  • conversation/waitingOn.test.tsx, trust-read-keeps-permission.test.tsx, agent-pane-trust-ask-corner.test.ts, gallery bottomStack checkTrust: updated to the new rule.
  • AgentPaneSlowStartPromptTests.everyPromptHeldForTrustKeepsItsOwnTicket (Swift).

Fleet evidence (red at 7e13ff85d99, green at the head) is in the review receipt comment.

Observed / Not run

Observed: the fleet runs above, and cmux-ci compile-check --app passed at 619de4bf331 (job 0eecb766a37206522c4231d9).
Not run: no local lint (lane rules forbid bun on this Mac), so this PR's web lint CI job is the lint check. I did not dogfood in the live app.

Changelog

Fixed: A folder trust question no longer blocks sending, steering or answering an agent's question. Prompts sent before you answer wait in the queue and go after Trust.

No capture: webview-only UI; the gallery's agent-pane.bottom-stack trust variants show it.

Agent session: cosmic-gray

šŸ¤– Generated with Claude Code


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


Summary by cubic

Fixes a P0 where an open folder trust question blocked sending, steering, and answering questions in the agent pane. Send and steer now stay on: prompts sent while trust is pending wait in the composer's queue under "Waiting for folder trust" and go one at a time in order after Trust, kept across Not now with edit and remove. Permission, question, secret, and tool cards no longer hide behind the trust question, since acpmux accepts their answers regardless of folder trust; the trust card still heads the bottom stack. A chat whose agent already runs sends its prompts and steers at once, and a page holding prompts for a trust answer is kept alive instead of hibernated.

Notes

  • The host keeps one session/prompt gesture ticket per prompt id, so each held prompt keeps its own send's gesture and none clears another's; a prompt going out clears only the pick tickets.
  • A held prompt's send checks that its own chat is still selected once its ticket comes, and waits again otherwise. A new chat's held prompts stay in their folder; once their start makes a session, they belong to it with the folder's backlog and go only there, and a superseded start keeps its session even when another chat showed before its select finished.
  • A trust refusal joins the hold of the chat and folder the prompt was sent in, and replaces the Trust re-run a refused start kept so Trust starts no second chat. A prompt acpmux refuses for another reason goes back into the composer.
  • Give-backs go where the prompt was typed, as one ordered list after a refused prompt (a new chat's whole backlog), so none is left where it no longer shows; after a harness switch gave back the first prompt, the rest go behind it. When the page quits or its tab closes, the page is asked to release its held prompts while its bridge still answers before it is retired, and every held prompt returns to the shown chat's composer, another chat's draft and kept chips, or a new chat's next composer. Chips that come back on wake are never cut at the composer's cap.
  • Known limit: a remote chat whose trust must be answered on its own Mac holds prompts until the pane re-reads that folder's trust, where Send was previously simply off.