Skip to content

Make mystery cases mislead instead of pointing straight at the culprit - #62

Merged
antiv merged 2 commits into
mainfrom
claude/mystery-game-complex-plot-g018p6
Aug 9, 2026
Merged

Make mystery cases mislead instead of pointing straight at the culprit#62
antiv merged 2 commits into
mainfrom
claude/mystery-game-complex-plot-g018p6

Conversation

@antiv

@antiv antiv commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Generated mysteries were solvable in one move: every clue pointed the same way, no witness ever said anything untrue, and the murder method named the culprit's profession outright. The inspector then closed what little gap was left by interpreting each piece of evidence out loud.

What was wrong

  • The generation prompt asked for a straight line. It required evidence and testimony to "form a logical chain pointing to the killer" — so the model wrote exactly that.
  • The method identified the culprit. Digitalis "dosed only under medical supervision" → the doctor. Generated cases copied the pattern.
  • Testimony was a reliable oracle. Suspects lied only about their own secret; everything else they said was true, so no clue could lead anywhere but the solution.
  • Red herrings were not competing explanations. An affair or a theft is dismissed in one step and never looks like murder.
  • A wrong accusation taught more than good detective work. check_accusation answered with the innocent's full not_killer_note, which reasons from the very facts that solve the case.
  • The culprit was identifiable from behaviour alone. Every innocent was scripted to crack under pressure and the killer never did, so "three cracked, one didn't" gave it away whatever the plot did.

What changed

Misdirection is now required. No single clue may identify the killer — guilt follows only from combining two independent sources. The means must be available to at least three of the four suspects. One innocent is framed hard enough to be accused mid-game, and their exoneration depends on a detail the player has to dig up.

New false_lead per suspect — a claim they state as fact but which is wrong, with at least one appearing to clear the real killer. It reaches the actor through get_my_character, with instructions to hold it until confronted and then relativise rather than admit it.

Split rebuttal. A wrong accusation now returns only a one-line rebuttal — a single verified fact that blocks the accusation and explains nothing. The full not_killer_note moves to the debrief, where check_accusation also returns cleared_suspects so every thread closes at once. solution gained red_herring and turning_point, so the reveal explains the trail the player was meant to follow.

Transparency is verified, not requested. After generation, a probe call sees exactly what a player sees — dossier, suspect cards, evidence, no secrets and no solution — and names who it would accuse. If it fingers the real killer and can say why, a revision pass rewrites only the surface. The solution, secrets and testimony are never sent back for rewriting, so whodunit cannot drift, and a revision failing validation is discarded. Both steps are best-effort: a probe failure still yields a playable game.

Two behavioural leaks closed. Evidence reports are findings-only — no "which means only a doctor could obtain it". The killer is written as the cooperative suspect, and exactly one innocent stonewalls to the end.

The inspector stopped solving the case. He may no longer rank suspects, confirm or reject a theory, say what a clue means, or highlight the decisive detail. He may note that two statements contradict each other, but not who is wrong.

The featured villa case was rewritten to the same standard. The poison is now the victim's own missing heart drops, so anyone in the house had access. A fourth evidence item puts the victim alive on the phone describing his own symptoms. The culprit is reachable only by intersecting the glass, the onset window and the butler's testimony — and Viktor looks guilty for most of the game.

Case generation runs on openrouter/deepseek/deepseek-v4-flash; the inspector and the four actors keep their existing model_name.

Compatibility

validate_case now requires the new fields, so a case held in an existing session no longer validates. This is handled: _get_case silently replaces it with the current default rather than failing, so a game in progress resets to the villa instead of erroring.

The template is at version 1.3. A project already imported keeps running on its old instructions until it is synced — and _sync_template overwrites instruction and tool_config unconditionally, so any local edits to those agents would be replaced (recoverable from agent_config_versions).

murder-mystery.json and murder-mystery-en.json are untouched — separate templates with the story hardcoded in agent instructions and memory blocks.

Tests

536 pass (python -m unittest discover -s shared/test -p "test_*.py"), 17 of them new: schema requirements for the misdirection fields, that a wrong accusation withholds the solving facts, that rebuttals share no fact with turning_point/evidence_chain, and six for the probe — that it sees only player-visible material, survives a model failure, ignores a lucky guess, and cannot change the solution.


Generated by Claude Code

claude added 2 commits August 9, 2026 16:14
…asking nicely

The misdirection rules added earlier are instructions, and the generator
satisfies their letter while still writing cases whose evidence names the
killer outright. Nothing measured the result, so nothing improved.

Generation now ends with a probe: a second call sees exactly what a player
sees — dossier, suspect cards, evidence, no secrets and no solution — and
names who it would accuse. If it fingers the real killer and can say what
gave it away, the case is explaining itself, and a revision pass rewrites
only the surface: dossier, cards and evidence contents. The solution,
secrets and testimony are never sent back for rewriting, so whodunit cannot
drift, and a revision that fails validation is discarded. Both steps are
best-effort — a probe failure still yields a playable game.

Two behavioural leaks are closed alongside it. Evidence reports were writing
the inference for the player ("which means only a doctor could obtain it"),
so reports are now findings-only. And with every innocent scripted to crack
under pressure while the killer never does, the culprit was identifiable from
demeanour whatever the plot did: the killer is now written as the cooperative
one, and exactly one innocent stonewalls to the end.

Generation can now take three calls, so the inspector quotes 30-60 seconds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ToCUNy2SqwvfTq4a6xfSk1
Switches the case generator in both places that named a model: the template's
mystery_gm tool_config, which is what an imported project actually uses, and
the env fallback for agents configured without one. The probe and the surface
revision follow the same setting.

The benchmark comment is kept but no longer reads as the reason for the
current value — it ranked candidates on latency and cost, never on how well
the resulting plot held up.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ToCUNy2SqwvfTq4a6xfSk1
@antiv
antiv merged commit b4d86a9 into main Aug 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants