Doppelganger discoveries model
Design decisions made 2026-08-24 for doppelganger-project, recorded inDISCOVERIES.md (49 discoveries + 7 unlock texts, extracted from the outline).
- Discoveries, not routes. GT/OC/OCD/BT are not lanes to lock into — they
are shorthand for which cluster of facts a player ends up holding. The engine
already implements this: grants_discoveries, prerequisites {all/any/none},
excluded_by, unlocks, blocks_events.
- The spine is linear and one-way. You can't go back. What differs per
playthrough is what you're carrying, not where you are.
- Losing is allowed. A dead end is a result, not a bug — start over. So
facts don't need redundant sources; missing one gives a worse ending.
- The phone is the second chance. A clue missed live should be findable
later by digging through the apps. That's what makes replay different rather
than merely shorter.
- The Unavailable texts are unlocks, not discoveries. They're pressure, not
knowledge. They go in dynamic_messages, fired by scene progress. Each one
must prove the sender knows what the player just did.
Why discoveries beat scenes: a scene assumes a room and a moment and is
hard to put on a phone. A fact isn't — "Carrie is getting texts from Jackie"
can arrive eight ways. Decide the fact once; decide the surface later.
validate_story.py (repo root) checks the graph: WALLS (required, never
granted), ORPHANS, SINGLE SOURCE, DANGLING, UNREACHED, TERMINAL. Its UNREACHED
is meaningless for timeline_basic.json, which is command-driven — progression
doesn't live in the JSON.