# Mystery content packages

A mystery is a self-contained, version-controlled folder: `mysteries/<slug>/mystery.json` plus a `mysteries/<slug>/assets/` sidecar for any binary assets it references by filename. A single `mystery.json` holds the whole story — the flow `narrative` (NPC cast + graph) and every `levels[]` board the graph embeds — so one directory reproduces one complete mystery.

Importing exercises the same public operations as the level editor: for each embedded level it creates a mutable authoring level, uploads assets, saves normalized exhibits, freezes an immutable template version, and instantiates a playable level; then it authors the mystery and seeds its story graph.

With the local Docker stack running and editing enabled:

```bash
npm run mystery:import -- mysteries/barricelli-files      # a folder (self-contained)
npm run mystery:import -- mysteries/glass-harbor/mystery.json  # or a single manifest
```

Importing the same content again creates a new immutable template version; it does not rewrite an earlier version.

## Syncing back from a running instance

`mystery:pull` serializes a mystery from a running instance's database into the folder format above, so you can edit on a server and bring the result back into git. It defaults to the local dev instance; pass `--prod` to pull from https://gupi.glitch.university (which requires an `OSINT_ADMIN_JWT` minted inside the `gnommo-osint-board` container).

```bash
npm run mystery:pull -- barricelli-files                 # dev → mysteries/barricelli-files/
OSINT_ADMIN_JWT=<token> npm run mystery:pull -- barricelli-files --prod
```

The pull is deterministic and round-trips: importing a pulled folder into a clean database and pulling again yields an identical `mystery.json`. Node/utterance keys are synthesized from labels, so a re-exported file is stable but need not match hand-written keys byte-for-byte — the exported file is the source of truth. (Known gaps: node music and NPC pose artwork are not yet carried through the pull.)

## Legacy single-manifest format

`glass-harbor/` and `barricelli-scene-7/` are older single-manifest packages (one level plus an optional inline `narrative`) kept as importer test fixtures — `barricelli-scene-7/fixtures/` holds OCR text used by the integration tests. `mystery:import` still accepts this shape (a file with no top-level `levels[]`); new mysteries should use the self-contained folder format.

## The Glass Harbor Diversion

This compact first mystery contains eight dated source documents in three folders, six unresolved Party concepts, and one fictional archival photograph. It intentionally starts without Party or Event exhibits: classification, dossier association, event reconstruction, working notes, and red-thread theory are the player’s work.

The source image was generated with the built-in image-generation tool for this fictional case. Its final production prompt asked for a degraded 1987 harbor-security photograph of truck `H&F 14` unloading a `CALDER OPTICAL / FRAGILE` crate at Warehouse 3, with period-correct details and no real people or brands.
