mirror of
https://github.com/tiennm99/noitu.git
synced 2026-10-11 03:13:45 +00:00
docs(journal): record the phase 7 online play session
This commit is contained in:
1 parent
b2cad42b0c
commit
67e7405252
1 file changed
+70
+70
@@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
title: "Phase 7: online play, and a room that had to outlive its game"
|
||||||
|
date: 2026-09-05
|
||||||
|
summary: "Shipped online 1v1, browser E2E and the container image; review found two defects caused by keeping a room alive past game over, plus a pre-existing room leak."
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 7: online play, and a room that had to outlive its game
|
||||||
|
|
||||||
|
## What happened
|
||||||
|
|
||||||
|
Phase 7 in one pass: a rematch protocol, online 1v1 in the browser, 21 Playwright
|
||||||
|
specs, a container image, CI, and deployment docs.
|
||||||
|
|
||||||
|
The one real design change was on the server. Rooms used to die the instant
|
||||||
|
`engine.Over()` was true, so a rematch needed the room to survive its own game.
|
||||||
|
It does now, but only while both seats hold live connections — a bot room still
|
||||||
|
closes immediately, because there is nothing to negotiate with a bot and keeping
|
||||||
|
it alive leaks a goroutine and an engine per finished game.
|
||||||
|
|
||||||
|
## What that new state broke
|
||||||
|
|
||||||
|
Two of the three defects review found were direct consequences of it:
|
||||||
|
|
||||||
|
- **A game ending on the turn clock never offered a rematch.** The offer was
|
||||||
|
opened from the message arm of the room loop, and the timer branch `return`ed
|
||||||
|
before reaching it. Resign and no-legal-move endings worked; the most common
|
||||||
|
natural ending did not, and the UI still showed the button. The end-of-game
|
||||||
|
decision now sits after the whole `select`.
|
||||||
|
|
||||||
|
- **A second connection with the same resume token killed the room.**
|
||||||
|
`resumeFrom` retired the old connection as soon as `r.send` succeeded, but the
|
||||||
|
room decides asynchronously and refuses a resume into a finished game — which
|
||||||
|
is exactly the rematch window. A duplicated tab was enough. The room now
|
||||||
|
retires the old connection only once it has agreed to the swap.
|
||||||
|
|
||||||
|
The third predated the phase: `attach` overwrote the session's room pointer and
|
||||||
|
nothing told the old room, so one connection creating four rooms stranded three
|
||||||
|
of them forever. Fixed here because this is the phase that puts the server on
|
||||||
|
the internet.
|
||||||
|
|
||||||
|
## What building the browser suite found
|
||||||
|
|
||||||
|
Four more, none of which the unit tests could reach: a refreshed tab could not
|
||||||
|
rejoin its game, a restored opponent never cleared the other player's disconnect
|
||||||
|
banner, a socket that failed without closing was invisible to the client, and
|
||||||
|
the nickname typed on the online screen never reached the server because the
|
||||||
|
handshake had already gone out.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
Two testing tools do not work here, and both are now documented in
|
||||||
|
`e2e/socket-cut.js` rather than left to be rediscovered. Offline emulation does
|
||||||
|
not cut a loopback socket. A routed socket's close does not reliably reach the
|
||||||
|
server, so the grace window never starts — those tests take the page away
|
||||||
|
instead.
|
||||||
|
|
||||||
|
## A duplicate I wrote and removed
|
||||||
|
|
||||||
|
I added a bot difficulty-ladder test to satisfy a plan criterion, then found
|
||||||
|
`simulate_test.go` had covered it since phase 3 with better thresholds and a
|
||||||
|
real corpus variant. I had grepped one file and concluded the coverage was
|
||||||
|
missing. Deleted mine.
|
||||||
|
|
||||||
|
## Next steps
|
||||||
|
|
||||||
|
- CI has never run on GitHub; every step passes locally.
|
||||||
|
- The Dockerfile's upstream-downloading branch is unexercised — only the fixture
|
||||||
|
branch has been built.
|
||||||
|
|
||||||
|
> Historical work record — not durable authority. Prefer docs/specs/ADRs for current decisions.
|
||||||
Reference in new issue
Block a user