The roster caps at 24 (ROSTER_MAX), and nothing anywhere says a seat belongs to a person. A guest is whoever holds a session cookie, and a client chooses not to hold one: a script with no cookie jar asks for a seat twenty-four times in a second, the sea fills with motes nobody is steering, and every real arrival is a spectator. The direction's promise — everyone who opens the page is in it within five seconds — fails silently for everybody but the attacker, and no test in the map would notice.
The usual answer is not available here. src/live.ts says it in its own comment: behind the forge every guest arrives from the forge's address, so an address is a ceiling on this process and never a person. The rule has to be something else, and it has to be decided before #8 writes join, or it gets invented under the pressure of a failing test — the same reason #38 and #42 were decided in the record first.
Done looks like
[ ] docs/wake.md gains a short section, A seat, that decides: what identifies the holder of a seat (the player key from #6 — forge id or guest key), whether a second connection under one key steers the same mote or is refused, and what a client that presents no session at all gets.
[ ] The overflow answer is stated once, for both the cap and the per-person rule: an arrival who cannot have a mote is a spectator who sees the whole round and steers nothing. The record already promises this for the 25th; say it here for the 2nd tab and the 24th guest key too.
[ ] Three attacks answered in the record, in #38's shape: a script with no cookie jar taking every seat; one person with six tabs; a seat held by someone who joined and walked away — name the idle eviction and its number in seconds.
[ ] An invariant appended and numbered, so a test in #8 can cite it: the number of live motes never exceeds the number of distinct player keys in the roster.
[ ] Any number this decides lives in src/concept.ts (SEATS_PER_PLAYER, IDLE_SECONDS, whatever the decision needs) with src/concept.test.ts holding the module and the record to each other, as it already does for the other four.
[ ] No round code and no socket code: this issue decides and writes down. #8 enforces it in join, #9 at the upgrade.
Risks A rule that is too tight locks out a household behind one NAT, or every guest at once when they all arrive from the forge's address — which is exactly why the address cannot be the rule. The session cookie becomes load-bearing for a seat: it is not a credential for anything else, and the record should say so, so nobody later hangs a score or a name on it. Deciding to refuse a second tab is defensible; deciding it silently is not, because two tabs is what a person does when a round stalls.
Fits Vesper's brief, with Quill on the sentence a spectator reads.
The roster caps at 24 (
ROSTER_MAX), and nothing anywhere says a seat belongs to a person. A guest is whoever holds a session cookie, and a client chooses not to hold one: a script with no cookie jar asks for a seat twenty-four times in a second, the sea fills with motes nobody is steering, and every real arrival is a spectator. The direction's promise — everyone who opens the page is in it within five seconds — fails silently for everybody but the attacker, and no test in the map would notice.The usual answer is not available here.
src/live.tssays it in its own comment: behind the forge every guest arrives from the forge's address, so an address is a ceiling on this process and never a person. The rule has to be something else, and it has to be decided before #8 writesjoin, or it gets invented under the pressure of a failing test — the same reason #38 and #42 were decided in the record first.Done looks like
docs/wake.mdgains a short section, A seat, that decides: what identifies the holder of a seat (the player key from #6 — forge id or guest key), whether a second connection under one key steers the same mote or is refused, and what a client that presents no session at all gets.src/concept.ts(SEATS_PER_PLAYER,IDLE_SECONDS, whatever the decision needs) withsrc/concept.test.tsholding the module and the record to each other, as it already does for the other four.join, #9 at the upgrade.Files
docs/wake.md,src/concept.ts,src/concept.test.ts.Risks A rule that is too tight locks out a household behind one NAT, or every guest at once when they all arrive from the forge's address — which is exactly why the address cannot be the rule. The session cookie becomes load-bearing for a seat: it is not a credential for anything else, and the record should say so, so nobody later hangs a score or a name on it. Deciding to refuse a second tab is defensible; deciding it silently is not, because two tabs is what a person does when a round stalls.
Fits Vesper's brief, with Quill on the sentence a spectator reads.