Skip to content

fix(sync,ready): distinguish MultiplayerTimeoutError from other wait() rejections - #45

Merged
jodeleeuw merged 5 commits into
mainfrom
fix/multiplayer-wait-timeout-error-distinction
Jul 21, 2026
Merged

fix(sync,ready): distinguish MultiplayerTimeoutError from other wait() rejections#45
jodeleeuw merged 5 commits into
mainfrom
fix/multiplayer-wait-timeout-error-distinction

Conversation

@htsukamoto5

Copy link
Copy Markdown
Member

Summary

  • jsPsych#3694 now exports a typed MultiplayerTimeoutError from wait()/communicate(), resolving a TODO both plugins carried since before that was finalized.
  • plugin-multiplayer-sync and plugin-multiplayer-ready previously treated every wait() rejection as a timeout — a throwing wait_for predicate or an adapter/backend error would silently finish the trial with timed_out: true, hiding the real failure in wait_error's message.
  • Now only a rejection with error.name === "MultiplayerTimeoutError" is recorded as a timeout; anything else propagates and fails the trial loudly, matching how a push() failure is already handled in both plugins.

Why this is its own PR

This changes trial data/behavior for a non-timeout failure (previously recorded as data, now throws), so it's a judgment call worth its own review rather than folding into the #3694-tracking SHA/update() housekeeping in #41/#43/#44.

Test plan

  • Updated both plugins' mock wait() to reject with a MultiplayerTimeoutError-named error, matching the real API
  • Rewrote the "non-timeout rejection" tests in both specs to assert propagation instead of mislabeling
  • npx jest green for both packages (11/11 sync, 15/15 ready)
  • tsc --noEmit clean for both packages
  • npm run build clean for both packages
  • Updated both README wait_error descriptions and added a changeset

htsukamoto5 and others added 2 commits July 15, 2026 17:16
…) rejections

Previously both plugins labeled every wait()/communicate() rejection as
timed_out: true (a leftover from before #3694 exported a typed
MultiplayerTimeoutError), which silently masked non-timeout failures
(a throwing wait_for predicate, an adapter error) as ordinary timeouts.
Now only a rejection named "MultiplayerTimeoutError" is recorded as a
timeout; anything else propagates and fails the trial loudly, matching
how a push() failure is already handled.
…ror typing

plugin-multiplayer-role called the now-removed MultiplayerAPI.communicate()
convenience method; it now calls push() followed by wait() directly. Also
applies the same MultiplayerTimeoutError distinction already fixed in
plugin-multiplayer-sync/ready (21e0909): only a rejection named
"MultiplayerTimeoutError" is recorded as timed_out: true, so a throwing
ready predicate or a push/adapter failure propagates and fails the trial
loudly instead of being silently mislabeled a timeout.

Docs cleanup: removed stale communicate() references from
plugin-multiplayer-sync and adapter-multiplayer-jatos READMEs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
htsukamoto5 and others added 3 commits July 17, 2026 13:40
…ction

The MultiplayerApiLike.wait() doc read as though a throwing `condition` also
rejects with a MultiplayerTimeoutError; per jsPsych#3694 it rejects with the
error the predicate threw (name != MultiplayerTimeoutError), which is exactly
what the plugins' name-based guard depends on. Reword to say so plainly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…on timeout path

On a genuine timeout the adapter may already be torn down, so api.getAll()
throws ("connect() must be called…"), which escaped and rejected the trial
instead of finishing it as timed_out. Wrap the snapshot read in the same
safeGetAll fallback plugin-multiplayer-ready already had, and mirror ready's
"getAll throws on the rejection path" regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract the "MultiplayerTimeoutError" name match into a
MULTIPLAYER_TIMEOUT_ERROR_NAME constant + isMultiplayerTimeoutError()
type guard in each package's multiplayer-api.ts (sync/ready/role), and use
it in the plugin guards and spec mocks. The literal previously appeared at
six sites; an upstream rename in jsPsych#3694 is now a three-line change
(one per package — the packages stay standalone by design).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jodeleeuw
jodeleeuw merged commit 2f4b712 into main Jul 21, 2026
4 checks passed
@github-actions github-actions Bot mentioned this pull request Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants