anthropics / anthropics/claude-code

Cross-session messages held for approval are indistinguishable from delivered ones at both sender and recipient

Aperta
#91,372 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
area:permissions enhancement platform:macos user-experience
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

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.