Summary
In Game Mode 1.5.6, clicking Start Game on a freshly-set-up game shows the intro typewriter, then snaps back to the Start Game screen mid-stream. The user clicks Start again and the chat ends up with two [Start the game] user messages — the GM frames the second one as a session continuation and the game starts at "scene 2".
Expected behavior
After clicking Start Game once on a new Game Mode chat, the intro typewriter plays through, the GM streams the opening scene, the Continue button replaces the Start screen, and the chat history contains exactly one [Start the game] user message.
Actual behavior
After clicking Start Game:
- Intro typewriter appears with the world overview (correct).
- Mid-stream the screen falls back to the idle Start Game screen (genre/setting tags + Start Game button, no overview visible).
- User has to click Start Game again.
- Chat persists two
[Start the game] user messages and the GM treats the second one as a "session continuation" framing — the game effectively starts at "scene 2".
Reproduces consistently across Opus, GPT, and DeepSeek as the GM model, so this is not a model-output issue.
Steps to reproduce
- Create a new Game Mode chat.
- Run through
/game/setup (any genre / setting / tone — reproduced with Fantasy / Adventure / Smut / Harem / Heroic).
- Wait for the world overview to be ready and the Start Game button to appear.
- Click Start Game.
- Observe: intro shows briefly, then the screen snaps back to the Start Game button mid-stream.
- Click Start Game a second time.
- Open the chat history — there are two
[Start the game] user messages, and the GM is narrating "scene 2".
Environment
- Marinara Engine version: 1.5.6
- Install type: source (VPS, git clone)
- OS + version: Ubuntu (VPS host)
- Browser or app shell: Chromium-based browser
Logs, screenshots, or video
Screen state when the bug fires (idle Start Game phase reappearing after the first click):
Additional context
Likely root cause (server-side race):
packages/server/src/routes/generate.routes.ts captures chat.metadata once at request start (~line 397) and writes the parsed copy back later via chats.updateMetadata. updateMetadata replaces the metadata column wholesale (see packages/server/src/services/storage/chats.storage.ts:105-110).
/game/start flips gameSessionStatus from "ready" → "active" while the [Start the game] generation is in flight.
- Several stream-side persistence sites (preset entry-state-overrides, lorebook entry-state-overrides x3,
lastMapPosition, game-state-patch gameMap sync, chat_summary, mariContext) do NOT re-fetch metadata before merging, so they clobber the freshly-set gameSessionStatus: "active" back to "ready" when they fire mid-stream.
- The combat agent at
generate.routes.ts:6361-6365 already handles this correctly with a re-fetch-then-merge pattern.
When the stale write lands first, the client's chatMeta refetches "ready" again. GameSurface's clearing effect at packages/client/src/components/game/GameSurface.tsx:5159-5164 had already fired (it ran while status was briefly "active") and cleared startGameRequested. With sessionStatus === "ready" and introPresented === false, the surface drops back to the idle Start Game phase — the visible bug.
A previous attempt at this bug (3e13514, reverted by 518dc92 on a contributor's fork) tried to fix this client-side via query invalidation. That couldn't have worked because the actual race is server-side metadata clobbering.
PR with proposed fix: #320.
Template check
Please uncheck (untick) the box below before submitting so we know you read the template. It is intentionally pre-checked:
Summary
In Game Mode 1.5.6, clicking Start Game on a freshly-set-up game shows the intro typewriter, then snaps back to the Start Game screen mid-stream. The user clicks Start again and the chat ends up with two
[Start the game]user messages — the GM frames the second one as a session continuation and the game starts at "scene 2".Expected behavior
After clicking Start Game once on a new Game Mode chat, the intro typewriter plays through, the GM streams the opening scene, the Continue button replaces the Start screen, and the chat history contains exactly one
[Start the game]user message.Actual behavior
After clicking Start Game:
[Start the game]user messages and the GM treats the second one as a "session continuation" framing — the game effectively starts at "scene 2".Reproduces consistently across Opus, GPT, and DeepSeek as the GM model, so this is not a model-output issue.
Steps to reproduce
/game/setup(any genre / setting / tone — reproduced with Fantasy / Adventure / Smut / Harem / Heroic).[Start the game]user messages, and the GM is narrating "scene 2".Environment
Logs, screenshots, or video
Screen state when the bug fires (idle Start Game phase reappearing after the first click):
Additional context
Likely root cause (server-side race):
packages/server/src/routes/generate.routes.tscaptureschat.metadataonce at request start (~line 397) and writes the parsed copy back later viachats.updateMetadata.updateMetadatareplaces the metadata column wholesale (seepackages/server/src/services/storage/chats.storage.ts:105-110)./game/startflipsgameSessionStatusfrom"ready"→"active"while the[Start the game]generation is in flight.lastMapPosition, game-state-patchgameMapsync,chat_summary,mariContext) do NOT re-fetch metadata before merging, so they clobber the freshly-setgameSessionStatus: "active"back to"ready"when they fire mid-stream.generate.routes.ts:6361-6365already handles this correctly with a re-fetch-then-merge pattern.When the stale write lands first, the client's
chatMetarefetches"ready"again.GameSurface's clearing effect atpackages/client/src/components/game/GameSurface.tsx:5159-5164had already fired (it ran while status was briefly"active") and clearedstartGameRequested. WithsessionStatus === "ready"andintroPresented === false, the surface drops back to the idle Start Game phase — the visible bug.A previous attempt at this bug (3e13514, reverted by 518dc92 on a contributor's fork) tried to fix this client-side via query invalidation. That couldn't have worked because the actual race is server-side metadata clobbering.
PR with proposed fix: #320.
Template check
Please uncheck (untick) the box below before submitting so we know you read the template. It is intentionally pre-checked: