anthropics / anthropics/claude-code
Cross-session messages held for approval are indistinguishable from delivered ones at both sender and recipient
- Lingua principale
- Python
- Stelle
- 145k
- Fork
- 23.1k
- Metriche di merge delle PR
- Metriche PR in attesa
Descrizione
### Summary
When `crossSessionInbound` is unset and the recipient session runs with bypassed permissions, inbound peer messages are **held for approval** and dropped at `dialogExpiry`. That behaviour is documented and correct.
The problem is that **a held message is indistinguishable from a delivered one at the sender, and an approval dialog is indistinguishable from a delivered card at the recipient.** Nothing either side can observe separates "waiting for approval" from "delivered".
This is a discoverability report, not a claim that delivery is broken.
### What we observed
Four concurrent local sessions on one machine, messaging each other. For two days:
- The **sender** received `success: true` naming the correctly-resolved recipient.
- The **recipient's** client rendered something that looked like an ordinary message card.
- Nothing was written to the recipient's transcript, and nothing entered its context.
- Roughly 173 consecutive sends were affected.
Every hypothesis we formed was about the transport, because the transport is what the observable surface described. We disproved twelve of them — stale addresses, socket rotation, session identity, registry staleness, fork artefacts, warm-up races — before finding that `crossSessionInbound` was simply not set.
Setting `"crossSessionInbound": "accept"` fixed it immediately: both push transports delivered within 15 seconds after two days of failure.
### Why it took two days
The answer was in front of us the entire time, in two places:
1. **On every send receipt**, which included the words *"it may be waiting for approval there"*.
2. **In the changelog**, which stated that messages to a session with bypassed permissions are held for approval.
Neither is wrong. Both were read past, repeatedly, by four sessions, because:
- `success: true` is the dominant signal and reads as delivery. The approval caveat is a subordinate clause in the same string.
- The held state has **no distinct surface**. There is no "1 message awaiting approval" indicator, no distinguishing marker on the card, nothing in the transcript, and no error at expiry.
- The failure is **silent and delayed**. The message does not bounce; it expires quietly at `dialogExpiry` (default 5 minutes), long after the sender has moved on.
- The default depends on **permission mode**, which is a property of the *recipient*, so the sender has no local reason to suspect it.
The result is a failure mode where the sender believes the message landed, the recipient believes nothing was sent, and no artefact anywhere records the disagreement.
### Suggested changes
Any one of these would likely have saved the two days:
1. **Make the held state visible to the recipient** — an indicator that N inbound messages are awaiting approval, rather than only a dialog that can be missed or dismissed.
2. **Make expiry observable.** When a held message expires, surface it somewhere: recipient-side notice, sender-side notification, or a transcript record. Currently expiry produces no artefact at all.
3. **Differentiate the sender receipt.** If the recipient's configuration means the message will be held, say so distinctly rather than returning the same `success` shape as a delivered message. The sender's side already knows enough to distinguish the cases.
4. **Consider whether the permission-mode-derived default is the right one**, or at least warn once per session when a message is held because `crossSessionInbound` is unset.
### Environment
- macOS, four concurrent local sessions, Claude Code CLI
- `crossSessionInbound` unset (no user settings entry), recipients running with bypassed permissions
- Affected both `SendMessage` (peer socket) and the session-channel transport
- A filesystem-based fallback we used as a control was unaffected — correctly, since it has no delivery step to hold
### Note on scope
We initially diagnosed this as a delivery/commit defect and were wrong. The setting behaves exactly as documented. We are filing only the discoverability finding, and the cost of that finding is the evidence for it: four sessions, two days, twelve disproved hypotheses, with the correct answer printed on every receipt throughout.
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Direzione di ricerca
Start with the SendMessage and session-channel transport entry points, then inspect handling of crossSessionInbound, bypassed permissions, and dialogExpiry. Compare sender receipts, recipient approval UI, transcript behavior, and expiry handling; done means the held state and expiry are visibly distinct from delivery on the affected surfaces.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Ambito
- backend, cli
- Tipo di issue
- Funzionalità
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Attiva
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100