test(chaos): K2 concurrent-stream cursor-contiguity regression (guards #169)#170
Merged
Conversation
…169) Convert the PR #169 K2 fix (per-connection localCursor in handleBlocks) from a manual mutation-verify into a committed node:test regression. Two new cases drive concurrent /stream connections through the real runtime and assert each connection's emitted block-number sequence is strictly contiguous off its OWN fromBlock, regardless of interleaving: - two overlapping windows (101.. and 201..) via Promise.all: each turn awaits streamTurnDelay, so the two handleBlocks turns interleave on the timer queue. - a mid-flight reconnect at a fresh fromBlock (300) while an earlier stream (110) is still delivering: the reconnect must honor its own fromBlock. Both assert via assertContiguous (n, n+1, …); both include a deepEqual/first- block sanity to keep the pass non-vacuous. Mutation-verified against the genuine pre-#169 form (loop reads the shared module-level `streamCursor` instead of the per-connection `localCursor`): - current code: 14/14 pass. - pre-fix mutation: both new tests FAIL — connection A streams [101,202,204,206] (B's interleaved writes stomp A's cursor across the delay) and the reconnect streams [300,302,304], skipping blocks — exactly the 101→103 skip #169 fixed. - mutation reverted (git checkout mock-portal.mjs): 14/14 pass again. Harness-only: no product code under portal/ touched; mock-portal.mjs unchanged. biome (2.5.2) clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ee nit) All three review seats (reviewer/codex/glm-standin) independently flagged that the K2 reconnect test asserted only the first block + contiguity, weaker than test 1's full-sequence deepEqual. Pin the exact window [300, 301, 302] so the guard also catches a wrong count / truncated stream, symmetric with test 1. Re-verified: baseline 14/14 green; pre-#169 mutation (loop off shared streamCursor) still fails both new tests; revert clean; biome 2.5.2 clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a committed
node:testregression toharness/chaos/realtime/mock-portal.test.mjsthat guards the concurrent-stream cursor-contiguity fix landed in #169. Until now that fix was proven only by manual mutation-verification and full orchestrate runs — this converts it into an automated guard.The bug it guards (from #169)
mock-portal.mjshandleBlockspreviously drove streamed block numbers off a module-level sharedstreamCursor. When two overlapping/streamconnections interleaved (turn-delayed steps), connection 2 read connection 1's advanced cursor and emitted a non-contiguous sequence (e.g.101 → 103, skipping102), which the product correctly fataled on (streamed block has an unknown parent). #169 fixed it by driving the loop off a per-connectionlocalCursor.The tests (2 new cases, +135 lines, test-file only)
Both use the existing
createRuntime+runtime.stream(body, res)idiom (no HTTP server, no orchestrate):fromBlockwindow, fired viaPromise.allso they interleave across the realstreamTurnDelay— asserts each connection's emitted block-number sequence is strictly contiguous (n, n+1, n+2, …).fromBlockmid-flight — asserts the reopened stream starts at its ownfromBlock, not the shared cursor.Each has a non-vacuity guard (full-window / first-block check) so a connection emitting nothing cannot pass trivially.
Mutation-verification
streamCursorinstead oflocalCursor): both new tests FAIL — connection A streams[101, 202, 204, 206]and the reconnect streams[300, 302, 304], exactly the skip harness(rg3): fix K2 baseline block-skip race + empty-string MOCK_TRACE guard #169 describes; the 12 pre-existing tests stay green.mock-portal.mjsbyte-identical tomain.Harness-only: no product code under
portal/touched;mock-portal.mjsunchanged. biome (2.5.2) clean.Candor / known limitation
The interleave is timing-shaped (relies on Node timer-queue FIFO under
turnDelayMs), matching how the bug actually manifests (only under overlapping delayed turns). It reproduces the skip reliably; if a future Node timer-scheduling change ever de-flaked the interleave, the test would go green-on-mutation (false-safe, never false-fail).