Repository navigation
Description
Why this exists
#1044 is a dropped-frame bug that a green suite could not see. Measured on 3.12.0: 8 immediate REQs after connect lost 2 EOSE, 10 lost 1, and the same code with a 1 s delay answered 4/4. The existing integration suite is sequential — connect, one subscription, assert, close — so the frames that race the socket's own setup are never in flight when an assertion is watching. #1045 adds the one test that catches it (real socket, subscribe at open, assert EOSE; it times out at base df8d3d6).
The point of this issue is that shape is not unique to that bug. Anything the server does on or just after a connection, or while another command is in flight, is untested for the same reason. These tests should assert the correct outcome, not merely that the server survives — a relay that drops a REQ has survived perfectly well.
Shapes to cover, each expected to work
- Subscribe at the open tick. A REQ sent in the same turn as the socket's
open, and N sockets doing it at once (the reconnect-storm shape). Assert EOSE per socket. This is fix(relay): buffer messages during WebSocket admission #1045; the rest are its siblings. - Pipelined commands in one write. Two REQs, or an EVENT followed by a REQ, in a single frame. Assert both answers arrive in the order they were sent. A per-connection buffer that loses its first frames fails here as it fails in 1.
- REQ followed immediately by CLOSE of the same id. Assert no events after the CLOSE and no error; a cancel that races its own subscribe must not leave a live subscription or a dropped socket.
- EVENT sent in the same turn as open. Assert the
OKarrives. Same window as 1, different reply path — worth its own test because the OK is what a publisher blocks on. - Fragmented and binary frames. A command split across two frames, and a binary frame carrying the same JSON. Assert the command is honoured and the next command on the same socket still is. Parser state that resets mid-frame loses a command and then keeps going.
- Invalid JSON mid-stream. Assert a
NOTICE(or the documented refusal) and that the socket stays usable for the next valid command. A drop here looks exactly like the bug in 1 from the client's side.
Acceptance
- Deterministic: no
sleepto "let the server catch up", because a delay is the thing that hides the bug. Where timing is inherent, repeat the case enough times (e.g. 20 iterations of shape 1 in one test) that the race is exercised, and fail if any iteration misses. - Each test must fail against the current base for the reason it names — the same bar fix(relay): buffer messages during WebSocket admission #1045 met — or it is not catching anything.
- The suite must run in CI where the existing integration job runs, so this class cannot silently regress.
Note: 3.x carries the same ordering (#1044, at src/adapters/web-socket-server-adapter.ts:137 on 3.12.0). If the 3.x line is still supported, shapes 1 and 4 belong there too; the rest can land on rewrite/main only.
Activity
tirthraj01 commentedon Nov 5, 2026
Hi @cameri @chappie-daemon,
I would like to take this up and implement the non-sequential socket test suite outlined in this issue.
Here is my plan for covering the test cases:
REQandEVENTdispatched on theopentick, along with multi-socket concurrent connect storms, asserting deterministicEOSEandOKresponses.EVENT+REQ/ dualREQ) asserting ordered processing, as well as fragmented payloads split across chunked and binary frames.CLOSEfollowing aREQfor the same subscription ID, verifying no lingering subscriptions or unhandled errors.NOTICE/rejection and confirming the socket connection remains healthy for subsequent valid commands.Implementation constraints I will follow:
sleep()delays: The suite will be strictly deterministic, using repeated iterations to reliably trigger and assert race conditions without masking timing bugs.Could you please assign this issue to me, and confirm whether you would like the PR targeted against
rewrite/mainormain? I will fork the repository and get started right away.cameri commentedon Nov 5, 2026
@tirthraj01 This targets
main. I'll assign it to you. Thanks for your interest in Nostream.tirthraj01 commentedon Nov 6, 2026
Thanks @cameri! Noted on targeting
main. I'm actively working on implementing the test cases across all shapes now and expect to have the branch ready for review within the next 12–15 hours.tirthraj01 commentedon Nov 7, 2026
Hi @cameri and @chappie-daemon,
I have completed the test suite for #1052.
Context & Problem Solved:
Previously, the adapter's real socket test suite only verified idealized, sequential happy paths (
connect→wait→send). Real-world Nostr relays frequently encounter out-of-order and asynchronous race conditions.This update introduces real
wsloopback tests verifyingWebSocketServerAdaptercorrectly handles:Quality & Reliability:
sleep()calls; uses event predicate polling (waitFor) and clean teardown..changeset/test-non-sequential-socket-cases.md.Compare Branch:
Due to active repository interaction limits, the branch is ready on my fork:
👉 Compare:
main...tirthraj01:nostream:test/1052-non-sequential-socket-casesPlease let me know if you would like any adjustments or if you can open the PR from this branch!
chappie-daemon commentedon Nov 7, 2026
Cherry-picked onto current
mainas #1072, with-xso your commit (1a63392) and authorship stay on the record. Your branch is untouched — the work was taken from the fork rather than pushed to it.Verified before picking it up:
npx mocha test/unit/adapters/web-socket-server-adapter-real.spec.tsgives 7 passing in 187 ms here, and the commit adds only the test file and its changeset.chappie-daemon commentedon Nov 7, 2026
@tirthraj01 I have posted the detailed brief on #1072 — Cameri asked for the two Greptile findings to be closed, and I added a third ask: show at least the admission shapes reddening when the buffering is broken, since a test that cannot fail is not yet evidence. Push to your fork branch as new commits and I will pick them up.
test(relay): hold admission open in the #1052 race cases
test(relay): assert the answers for commands that race the connection