0.4.0 — fix queue-add race + per-item remove button (#10, #11)

This commit is contained in:
2026-10-11 16:09:29 +00:00
parent 3287bcaca4
commit ef27b59762
14 changed files with 448 additions and 29 deletions
+22 -2
View File
@@ -284,6 +284,7 @@ function genericUnclearEvent(state: GameState): TurnEventSpec {
*/
export function applyTurnResult(state: GameState, result: TurnResult): GameState {
const next: GameState = JSON.parse(JSON.stringify(state));
next.version = (state.version ?? 0) + 1; // every mutation is a new revision
const actingTurn = state.turn; // this action resolves the current turn
next.turn = state.turn + 1; // then we advance to the next turn to play
next.date = isDateLike(result.date) ? result.date : addDays(state.date, 2);
@@ -325,15 +326,34 @@ export function applyTurnResult(state: GameState, result: TurnResult): GameState
/**
* Immutably queue one item onto a round: append it to `pending` and return a new
* state. This never advances the turn or the date — that only happens when a
* round is committed via runTurn. Exported so the append-without-advance behavior
* is unit-testable, and reused by the server's /action and /diplomacy routes.
* round is committed via runTurn. Bumps `version` (a new revision, so stale SSE
* snapshots can never clobber it client-side). Exported so the append-without-
* advance behavior is unit-testable, and reused by the /action and /diplomacy
* routes.
*/
export function queueRoundItem(state: GameState, item: RoundItem): GameState {
const next: GameState = JSON.parse(JSON.stringify(state));
next.version = (state.version ?? 0) + 1;
next.pending.push(item);
return next;
}
/**
* Immutably remove one item from the pending round by index and return a new
* state (bumping `version`). Returns `null` when the index is missing or not a
* valid, in-bounds integer position, so the route can answer 400 without
* mutating anything. Reused by the server's /queue/remove route.
*/
export function removeRoundItem(state: GameState, index: number | undefined): GameState | null {
if (index === undefined || !Number.isInteger(index) || index < 0 || index >= state.pending.length) {
return null;
}
const next: GameState = JSON.parse(JSON.stringify(state));
next.version = (state.version ?? 0) + 1;
next.pending.splice(index, 1);
return next;
}
/**
* Run one turn end-to-end against the (injectable) LLM: build prompts, call the
* model ONCE over the whole pending batch, parse/validate, retry once with a