diff options
Diffstat (limited to 'CLAUDE.md')
| -rw-r--r-- | CLAUDE.md | 27 |
1 files changed, 22 insertions, 5 deletions
@@ -471,11 +471,28 @@ anything that assumes one key per person. next visit to the tab, since the node had stored it and answered. Every line of `chat-app.js` is correct and every routed message in `transport.js` is routed correctly; the defect is in the seam, which is why - `tests/harness/chat_send_probe.py` drives the two together. `ack` is now - matched by request type (`chat_msg`, or the keypair-bundle store/delete that - name themselves in `detail`). Anything left to the "oldest pending" guess is - a latent version of this bug: a request type deserves a key, and a reply - deserves something to key it by + `tests/harness/chat_send_probe.py` drives the two together. `ack` was matched + by request type (`chat_msg`, or the keypair-bundle store/delete that name + themselves in `detail`), and that closed the instance — **but it left the + class open, and it came back on 2026-09-06 through the other door.** A + refusal has no type of its own to key on: `_dispatch_message`'s catch-all + answers every unforeseen failure with `{"type": "error", "detail": "Request + failed"}`, and 238 of `webrtc_server.py`'s 240 error sends name nothing + either. So a chat send the node refused was routed by luck all over again — + same frozen composer, same 30 s, and rare enough (it needs an older request + still waiting, which a `music_meta_req` behind a failing third-party lookup + supplies for over a hundred seconds) to look like once every couple of days. + The keys were never the fix, only a workaround for a protocol that carried no + correlation id at all: `_seqId` existed, indexed `_pending`, and was never put + on the wire. It is now (`req_id`, see `protocol.py`) — the node stamps it on + the reply from `_send`, via a ContextVar so a handler's spawned work still + answers under the right id, and never on a broadcast, which answers nothing. + With that, the arrival-order fallback is gone for any node that stamps. + The lesson is not "key the replies": it is that **matching by arrival order + is a guess that fails silently and asymmetrically** — the victim is never + the request that was answered wrongly, it is the unrelated one that now + waits for a reply already delivered elsewhere. A reply needs an identifier + the protocol guarantees, not a field it happens to have - **A refusal that never rejects.** Denying Chromium's `fullscreen` permission does not make `requestFullscreen()` throw — the promise never settles. The |