anthropics / anthropics/claude-code
Cross-session messages held for approval are indistinguishable from delivered ones at both sender and recipient
- Ngôn ngữ chính
- Python
- Star
- 145k
- Fork
- 23.1k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
### 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.
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Hướng nghiên cứu
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.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Lĩnh vực
- backend, cli
- Loại issue
- Tính năng
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức độ hoạt động
- Sôi nổi
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 35/100