fix(rust): skip servers known down for a link code, hold syncs while offline (F6, F7)
All checks were successful
PR Checks / client-build (pull_request) Successful in 23s
PR Checks / frozen-manifest (pull_request) Successful in 47s
PR Checks / server-tests (pull_request) Successful in 7m57s

Two findings of the step-2 player walk (2026-09-27, both rigs).

F6, option (b) of the org lead (D186): a code no recent issuer holds -
every made-up one - was still asked of every other enabled server, and
while any of them was down the redeem waited out its whole timeout
(12 s on both rigs). The second pass now skips the servers the board
poll last saw without a connected game; they count as offline without
the wait. Issuers are still asked whatever their state, so a good code
on a down server stays "unsure". Live on the walk core: 338 ms with five
servers down, 360 ms with a rig stopped as well.

F7 (D187): on Carbon a due audit sync went out the moment the sidecar
reconnected, 80 s before "Server startup complete". The worldReady hold
reads the stored hello, which is the OLD boot's until the poll reads the
new one. reasonToSync now also holds while the stored state says the
game is not connected (online 0), which the poll writes the moment the
server goes away. titleSync already held on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-09-27 03:14:10 -05:00
parent 31b99fab61
commit 263be1df45
4 changed files with 115 additions and 3 deletions

View File

@@ -63,9 +63,13 @@ function withCore({ select = [], onInsert = null } = {}) {
* `issuers` are the servers the site saw mint a link code in the last few
* minutes (`account.link.requested`, F5) — none by default, which is also what a
* code typed before its frame was ingested looks like.
*
* `down` are the servers the board poll last saw without a connected game
* (`online: 0`); every other server has no state row, which is asked like an up one.
*/
function fleetOf(replies, issuers = []) {
function fleetOf(replies, issuers = [], down = []) {
const servers = require('../model/servers/servers.model')
const serversDb = require('../model/servers/servers.db')
const sidecar = require('../sidecarClient')
const linksDb = require('../model/links/links.db')
@@ -73,6 +77,7 @@ function fleetOf(replies, issuers = []) {
const ids = Object.keys(replies)
servers.listForPolling = async () => ids.map((id) => ({ id, baseUrl: `http://${id}`, token: 't' }))
serversDb.listState = async () => down.map((serverId) => ({ serverId, online: 0 }))
linksDb.recentLinkIssuers = async () => [...issuers]
sidecar.confirmLink = async (server, code) => {
@@ -375,3 +380,52 @@ test('the fleet is asked in parallel, not one dead server after another (F6)', a
assert.equal(result.ok, true)
assert.equal(most, 5, 'every server was being asked at once')
})
test('a server the poll saw go down is not waited on for a code nobody minted (F6, option b)', async () => {
// The step-2 walk: with one rig stopped, a made-up code took twelve seconds on
// both frameworks — in parallel, but still one whole timeout on the dead server.
withCore()
const links = require('../model/links/links.model')
const asked = fleetOf({ a: linkRefused, b: unreachable, c: linkRefused }, [], ['b'])
assert.equal((await links.redeem({ code: 'ZZZZZZ', userId: 4 })).reason, 'rejected')
assert.deepEqual(asked.map((x) => x.server).sort(), ['a', 'c'], 'the server known down was not asked')
})
test('an issuer is asked even when the poll saw it go down, so a good code stays "unsure"', async () => {
// Skipping is for the servers that cannot hold the code. A server that minted
// one in the window might — and a player whose code is on it must not be told
// the code is wrong.
withCore()
const links = require('../model/links/links.model')
const asked = fleetOf({ a: unreachable, b: linkRefused }, ['a'], ['a'])
assert.equal((await links.redeem({ code: 'K7M2PQ', userId: 4 })).reason, 'unsure')
assert.ok(asked.some((x) => x.server === 'a'), 'the down issuer was still asked')
})
test('a fleet the poll saw all go down is offline, without asking any of it', async () => {
withCore()
const links = require('../model/links/links.model')
const asked = fleetOf({ a: unreachable, b: unreachable }, [], ['a', 'b'])
assert.equal((await links.redeem({ code: 'ZZZZZZ', userId: 4 })).reason, 'offline')
assert.equal(asked.length, 0)
})
test('a state read that fails asks everybody, which is slow and never wrong', async () => {
withCore()
const links = require('../model/links/links.model')
const serversDb = require('../model/servers/servers.db')
const asked = fleetOf({ a: linkRefused, b: linkRefused })
serversDb.listState = async () => {
throw new Error('pool closed')
}
assert.equal((await links.redeem({ code: 'ZZZZZZ', userId: 4 })).reason, 'rejected')
assert.equal(asked.length, 2)
})