test: pin the join-adjacent stream-removal race and its real blast radius (#96) - #136
Open
pinetops wants to merge 6 commits into
Open
test: pin the join-adjacent stream-removal race and its real blast radius (#96)#136pinetops wants to merge 6 commits into
pinetops wants to merge 6 commits into
Conversation
…dius (#96) Investigation results, all reproducible via --include issue_96: 1. The loss recipe is join-adjacent timing, not diff shape: a stream diff (delete-only OR reset) broadcast within ~100ms of a join/rejoin sometimes never applies, while the row survives in the DOM. Two shapes reproduce it: reload+rejoin (variant A, ~60% under load) and deletion of a row the client learned via a post-join stream_insert (variant B). 2. ATTRIBUTION: UPSTREAM. A new vanilla Phoenix.LiveView fixture (zero lavash on the page, raw Phoenix.PubSub + stream_delete_by_dom_id) reproduces the same survival. 3. THE RESET WORKAROUND IS ALSO AFFECTED — resets ride the same stream-tuple channel, so the #96 mitigation only narrows the window, it doesn't close it. The old e2e never noticed because it dropped browser-level removal assertions entirely. 4. Heisenbug-grade: every instrumentation attempt (test-side onMessage installs, layout-baked capture) suppresses it. Shipped: the vanilla attribution fixture + route; three browser removal tests (the stable plain-delete shape runs by default, restoring removal coverage; the two racy shapes + the vanilla repro are tagged :issue_96, excluded by default); a permanent pre-connect wire capture in the test layout for future evidence dumps; failure paths dump the full wire trace. Runtime unchanged (reset path kept — least-bad until the upstream fix). Next step recorded in #96: minimal upstream report with the runnable repro.
Mix.install + phoenix_playground, self-triggering (the LiveView schedules its own stream_delete via Process.send_after — no PubSub, no second process), delivery-aware self-judging (counts incoming diff messages, so FAIL = diff arrived and the row survived, distinct from NODIFF delivery artifacts), verdicts logged server-side per page load. This is the artifact for the eventual upstream phoenix_live_view report — their issue template requires exactly this single-file shape.
phoenix_playground never exposes window.liveSocket, so the repro's self-judging script waited forever and no VERDICT lines were ever logged. The rework owns the layout (Mix.install + Bandit + bare Endpoint), installs the wire capture before connect, anchors the delete broadcast to the dead render so sweeps cross the join handshake, and logs SUB/BCAST ordering to classify NODIFF verdicts. Requires Plug.Parsers in the endpoint: without it dead-render mounts see empty params and every trial silently runs the default delay.
The node --check temp file was named by a content hash, so two concurrent compiles of the same project (parallel test runs) produced the same path — one process's cleanup deleted the file out from under the other's validator, failing compilation with 'Cannot find module'. OS pid + unique_integer make the name unique per invocation.
Ash.DataLayer.Ets.stop tears the table-owner process down asynchronously; under load the next create can look up the dying owner and insert into a dead table (:table_not_found). Seen as intermittent seed failures in full-suite runs. One bounded retry scoped to that error.
Pulls the onPatchEnd callback-registry rework (wallabidi#72), the microtask-deferred query checker (wallabidi#73), and the DOMContentLoaded visit default (wallabidi#78) — the driver no longer restores stale patch hooks or does synchronous query work inside LiveView's patch-end stack.
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.
The #96 investigation, packaged. Does not close #96 — the bug is upstream and still live; this lands the evidence, the coverage, and the report artifact.
Findings (full detail in the issue comment)
What lands
test_vanilla_stream_fixture.ex+ route) — plain LV, raw PubSub:issue_96(excluded by default — they fail intermittently by design;mix test --include issue_96to investigate)docs/issue96_repro.exs— standalone single-file repro (Mix.install + phoenix_playground, self-triggering viasend_after, delivery-aware self-judging with server-logged verdicts) in exactly the shape phoenix_live_view's issue template requires. Driver validation pending; once it demonstrably fires it goes upstream verbatim.Runtime unchanged — the reset path stays (least-bad). Re-test the tagged repros on every LiveView upgrade.
🤖 Generated with Claude Code