Gate view-state broadcasts on the view-tree handshake#32
Merged
Conversation
A client that connected but had not yet requested the view tree could receive an incremental update_view prop diff before its snapshot. The client materializes unknown view uids from the diff alone, producing a view with only the changed props — no callback props — which crashes the client renderer on the first missing-prop access (seen as 'undefined is not an object (evaluating props.onSelectCategory.mutate)' in the wmux TUI during dev-server startup, where category status churn broadcasts diffs continuously while the TUI connects). Track per-client handshake completion and withhold update_view/delete_view from clients that have not requested the tree; the snapshot supersedes everything they missed, and views created afterwards still arrive as full-prop creates.
bunx playwright resolved the registry's latest playwright (no root bin exists with isolated installs), installing a chromium_headless_shell revision that does not match @playwright/test from the lockfile. Every demo suite has failed at browserType.launch since March because of this. Run the install through demo/todo-app's local binary instead; all demos pin the same @playwright/test version.
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.
Problem
The wmux TUI crashes during dev-server startup with:
Root cause is a connect-time race in the echoform view-sync protocol (
singleInstancemode):update_viewprop diffs to every connected client (reconcileExistingSharedView→broadcast), including clients that have not yet completed therequest_views_treehandshake and therefore have no base state.applyViewUpdateupserts an unknown view uid from the diff'screatearray alone. A diff carrying only a changed data prop (e.g.categories) materializes a view with none of its callback/event props.ViewsRendererbuilds component props strictly from the view entry, so the component renders with its callback props missing and crashes on the first.mutateaccess.The window is "client connected → snapshot response received". wmux hits it reliably at dev-server startup: the sidebar's
categoriesprop embeds live per-process status, so the rootWmuxAppview broadcasts diffs continuously while processes flipidle → running— exactly while the TUI is connecting and the server's event loop is busy spawning services.Fix
Track handshake completion per client and withhold view-state events (
update_view,delete_view) from clients that have not yet requested the view tree:request_views_treeis handled (snapshot sent in the same tick, so no interleaving).broadcastskips unsynced clients for view-state events only; stream events and the per-clientserver.emitpath (non-singleInstancemode, where mount-time full-prop creates deliver the initial state) are unchanged.This is lossless: everything an unsynced client doesn't receive is superseded by its snapshot, and views created after the handshake still arrive as full-prop creates on the same ordered socket. The client-side unknown-uid upsert keeps working as the legitimate new-view delivery path.
Verification
packages/echoform/tests/view-sync-handshake.test.ts(same harness style asstream-replay.test.ts):type: "event"callback entries (the props whose absence crashed wmux).broadcastgate, the first test fails by receiving exactly the bug's payload: anupdate_viewfor an unknown uid whosecreatecontains only thelabeldata prop.bun test tests/(5 pass),bun run typecheck,bun run build,bun run lint(0 errors; the 2 touched files lint clean in isolation) all green locally.Also: repair the CI browser install
Every CI run has failed since March at
browserType.launch: Executable doesn't exist … chromium_headless_shell-1208.bunx playwright installresolves the registry's latest playwright (no root bin exists with isolated installs) and installs a browser revision that doesn't match the lockfile's@playwright/test. The install step now runs the workspace-pinned binary (demo/todo-app/node_modules/.bin/playwright), so this PR's CI actually runs the demo suites again. Happy to split this into its own PR if preferred.