Consent boundaryA missing card is not approval. Recover the authentic request or cancel the turn.

One screen. Two failure chains.

A · no generationSilent dead socketno close → no reconnect → no replay

Sleep, network switching, or background throttling leaves the old path apparently open.

B · generation raceReplay then clearrequested → onConnected → resync → pending.clear()

The Host replays correctly, but the new browser wait is erased.

Three owners. Three lifetimes.

AgentLive turnTool promise waits.
HostAcross disconnectStable rpcId stays pending.
BrowserOne generationPendingWait renders card.

Recover without inventing an answer.

1Preserve evidenceSession, request, socket timeline.
2Hard refresh onceForce a real mux generation.
3Answer or cancelOnly through the authentic card.
Do not call the response API manually

That would manufacture human consent. If replay fails, cancel the turn and ask the Agent to request the decision again.

Both layers need repair.

TransportPing · pong · terminateBound silent socket death, then reuse reconnect.
RuntimeClear on generation deathNever clear fresh replay inside resync.
ProtocolStable identityReplay and answer the original rpcId once.

Twelve regression gates.

  1. Question survives resync.
  2. Approval survives resync.
  3. Old waits clear early.
  4. Settled waits stay gone.
  5. Replay deduplicates.
  6. Answer reaches Host.
  7. Cancel withdraws all cards.
  8. Dead socket is bounded.
  9. Reconnect needs no refresh.
  10. Tabs cannot double-answer.
  11. Shutdown clears pumps.
  12. No synthetic consent log.