Phase 1 — unblocked, and the highest-value attrition fix. Explicitly does not need a presence API.
The problem
The survivor of a dropout does not hang — they grind, which is worse, because it burns their time before they give up.
round_timeout sets its timer at round start. When it fires, the round ends with ended_by: "timeout" and a null assignment, feedback shows, and the timeline advances to the next round, starting a fresh timer. There is no cross-round abort and no presence check:
|
per-round dead wait |
rounds left if partner drops on round 1 |
total dead time |
| Hawkins |
60 s |
71 |
~71 min |
| C&WG |
180 s |
5 |
~15 min |
And the survivor is never told anything — the plugin has no partner-status copy, no disconnected state, no UI affordance at all. They see a normal, fully interactive board that simply never responds, 72 times over. They abandon, so one dropout burns two payments and generates a support ticket.
Work
There is an upgrade path to real disconnect detection once a presence API exists, but this work should not wait on it.
See READINESS.md section 2.
Phase 1 — unblocked, and the highest-value attrition fix. Explicitly does not need a presence API.
The problem
The survivor of a dropout does not hang — they grind, which is worse, because it burns their time before they give up.
round_timeoutsets its timer at round start. When it fires, the round ends withended_by: "timeout"and a null assignment, feedback shows, and the timeline advances to the next round, starting a fresh timer. There is no cross-round abort and no presence check:And the survivor is never told anything — the plugin has no partner-status copy, no disconnected state, no UI affordance at all. They see a normal, fully interactive board that simply never responds, 72 times over. They abandon, so one dropout burns two payments and generates a support ticket.
Work
ended_by: "timeout"rounds. Two or three in a row is a perfectly good dropout proxy with no presence API.conditional_functionongameLoopis evaluated once, so a mid-game abort needs either a per-roundconditional_functionongameRoundorjsPsych.abortCurrentTimeline()from the round'son_finish.n_trials_completedso partial dyads can be filtered. The partial-data policy decision determines whether the abort path salvages or discards.There is an upgrade path to real disconnect detection once a presence API exists, but this work should not wait on it.
See
READINESS.mdsection 2.