The state lives in the engine: cards, players, tokens, castle goals. The model is sent a JSON portrait of the state (player, hand, tokens, what has happened) and returns a decision. The engine checks whether that decision is legal and, if it is, applies it. Never the other way round: the model does not touch the state.
Every card effect is a hand-written function over the state. The model does not know how a card effect works: it only knows that an option with that name exists. Everything that can get it wrong sits outside the rules, and the rules do not depend on anybody.
The engine is deterministic when the AI is not involved. The dice come from a seeded generator, so a game is repeatable: if something breaks on round sixty-three, you replay round sixty-three and look at it. Without that, debugging a game by simulation is impossible.
Five instruction texts: one with the game rules and four different strategic profiles (team player, team dealer, conservative player, conservative dealer), because the same model has to play like a different style depending on who it represents.
game state (engine, seeded)
→ JSON portrait · 4 role prompts
→ POST /api/generate · format="json" · temperature 0.25 · no streaming
→ strict json.loads · if it fails, trim { … }
→ normalise against the vocabulary of the game
→ the engine validates legality · applies · next player
→ 2 failures in a row ⇒ AI off, local heuristic for the rest of the game