# The Creator Suite & the Mind Palace

V5 is one open world worn five ways — Urban Crime, Period Drama, Frontier,
Monster Hunter, Sci-Fi — and two of its subsystems exist precisely to bind those
cells back together rather than let them drift into five disconnected games. The
**creator suite** is the in-editor tooling that lets a designer (or, through
Workshop, a player) author a playable detective case — clues placed in a world,
an interrogation tree, a publish package — without writing engine code, and have
that case validated by the _same_ rules the runtime will judge it under. The
**Mind Palace** is the cross-cell deduction layer: a graph of evidence orbs and
authored deduction threads, a volumetric "memory room" to manipulate them, and
an accusation system that resolves a case into a branching outcome. It is V5's
signature, the one screen where a clue picked up in the 1940s Period cell can be
dragged against a clue from the Sci-Fi cell and — if the player has earned the
Bureau XP to unlock it — snap into a cross-era deduction. The two systems are a
matched pair: the creator suite authors the cases, the Mind Palace is where they
are solved. This page is the deep companion to
[../V5_ARCHITECTURE.md](../V5_ARCHITECTURE.md); the monolith's "Creator Suite
Architecture" and "Mind Palace Deduction Architecture" sections carry the
data-contract tables this expands on.

## What ships, honestly

The **C++ logic, the JSON content catalogs, and the automation tests are real,
committed, and compiled**; the _3-D art_ those systems point at is the
manifest-referenced surface that, per the V5 posture, is not checked in as
binary `.uasset`. Four honest layers:

- **Real, built, and tested.** `V5CaseAuthor`, `V5MindPalace`, and
  `V5DetectiveMindPalace` are genuine UE5 C++ modules that compile to committed
  Linux editor binaries (`V5/ue/Binaries/Linux/libUnrealEditor-V5CaseAuthor.so`,
  `…-V5MindPalace.so`, `…-V5DetectiveMindPalace.so`, built as the `ueagent`
  user). Each ships `IMPLEMENT_SIMPLE_AUTOMATION_TEST` suites that assert
  specific authored counts and computed verdicts — not truthiness. The Mind
  Palace deduction graph, the weak-edge derivation, the breadth-first hypothesis
  walk, the evidence-chain accusation gate, the Bureau-XP cross-era gate, the
  daily-puzzle rotation math, and the leaderboard scoring are all real
  domain-specific algorithms.
- **Authored content is JSON, validated on load.** The 110 authored deduction
  pairs and 15 accusation outcomes are committed data
  (`V5/ue/Content/V5MindPalace/Data/`), parsed and schema-checked at load, not
  hard-coded. The case-author templates and Mind-Palace mode counts are likewise
  committed manifests with a `schemaVersion` gate.
- **Honest fail-loud seams.** Workshop publish and Mind-Palace cloud-sync build
  **real** requests (a real `FHttpModule` POST for cloud-sync) but their
  backends are the seam: an unhealthy service returns `503` and queues offline,
  a missing JWT returns `401`, and the live round-trip test is gated on
  `V5_ONLINE_LIVE=1`. These refuse to fabricate a success they didn't get.
- **Art referenced, not committed.** Preview worlds
  (`/Game/V5/Editor/CaseAuthor/L_HomicideCasePreview`), the 100 examinable 3-D
  evidence assets the Mind Palace mode validates the _count_ of, and the
  MetaHuman interrogation faces are asset **paths** named by manifest. They are
  the UE-art surface V5 keeps out of git; the logic that consumes them is here,
  the binary art is not.

## The creator suite: authoring inside the editor

The monolith lists nine creator tools (Mission Editor, Heist Author, Case
Author, Contract Author, Ship Loadout, Bestiary, Cinematic Director, Replay
Editor, Workshop Publisher), each emitting "a typed data file (USTRUCT-based)
that the runtime loads." The committed, deeply-implemented one — and the one
that ties the suite to the Mind Palace — is **Case Author**, the `V5CaseAuthor`
module. Its `Build.cs` is the tell: it depends on `V5Investigation`,
`V5Interrogation`, and `V5OnlineServices` alongside `Slate`/`SlateCore`, so the
editor tool is built on the very runtime types a played case uses, not a
parallel authoring model.

### A typed authoring model, not a blob

`V5CaseAuthorTypes.h` defines the whole authoring surface as `USTRUCT`s. An
`FV5CaseAuthorTemplate` carries a `CaseId`, a `BaseInterrogationSceneId`, an
`EV5Cell`, a `PreviewWorldPath`, a `WorkshopCategoryTag`, and floor requirements
(`RequiredClueCount = 4`, `RequiredInterrogationQuestionCount = 3`). An
`FV5CaseAuthorDraft` is the editable document: a `CaseId`, an array of
`FV5CaseAuthorCluePlacement` (each wrapping a real
`FV5InvestigationClueDefinition` plus a world transform and interaction radius),
the `FV5InterrogationSceneDefinition`s, and an array of
`FV5CaseAuthorInterrogationBranch` mapping a source question to an
`EV5InterrogationChoice`, a required-evidence id, and success/failure
next-question ids. The `FV5CaseAuthorCatalog` ships three launch templates —
`case.vice.homicide.001`, `case.vice.narcotics.001`, `case.vice.corruption.001`
(`V5CaseAuthorSystems.cpp:254`) — the "Vice-Squad-style case authoring" the
monolith names.

### Build-from-template wires real interrogation primitives

`BuildDraftFromTemplate` (`V5CaseAuthorSystems.cpp:309`) is where the tool earns
trust. It loads the template's interrogation scene through the runtime's own
`UV5_Interrogation_TellLibrary::FindScene`, falling back to a fully-formed
`FallbackScene` if none is authored yet. It then synthesizes clue placements
from the scene's required-evidence ids _and_ a rotating set of extra clues
(`scene_photo`, `timeline_note`, `witness_pin`, `lab_report`) until the
template's `RequiredClueCount` is met, each clue stamped with four
`FV5InvestigationDetailSpot`s (powder residue, maker mark, transfer stain,
hidden note). Finally `BuildBranches` walks the scene's questions and, for each
one, derives the **correct** authored choice from the question's truth-state:
`CorrectChoiceForQuestion` maps `Truthful→Truth`, `Withholding→Doubt`,
`Lying→Lie` (`:63`). The draft a designer starts from is therefore already a
self-consistent, runtime-shaped case.

### Validation is the contract, and it's domain-specific

`ValidateDraft` (`V5CaseAuthorSystems.cpp:324`) is the heart of the tool, and it
is not a shape check. It runs three graded sub-passes that set
`bCluePlacementValid` / `bInterrogationValid` / `bBranchValid` independently:

- **Clues** — at least four placements, ids unique, each clue belonging to the
  active case, each carrying a scene id, **at least three detail spots**, and a
  positive interaction radius.
- **Interrogation** — every scene belongs to the case; at least three questions;
  and the load-bearing rule — **a `Lying` question must be answerable with
  placed evidence**, checked by calling the runtime's
  `UV5_Interrogation_EvidenceBackedLie::CanChallengeWithLie(Question, EvidenceInventory)`
  (`:357-360`) against an inventory built from the draft's own clue placements.
  A lie the player can't catch with a planted clue fails authoring.
- **Branches** — every branch maps to a source question that exists, and that
  branch's `(question, expected-choice, has-evidence)` triple must
  `ResolveInput` to `bCorrect` through
  `UV5_Interrogation_TruthDoubtLie::ResolveInput` (`:376`); every question needs
  a branch and every branch needs a success path.

Because both checks call the **same** `V5Interrogation` resolvers the runtime
uses, a case that passes the editor is guaranteed solvable under the live rules.
That is the difference between authoring tooling and a CRUD form: the validator
is the game's own logic, run at edit time.

### Publish: a real request with a fail-loud seam

`BuildWorkshopPublishPlan` (`V5CaseAuthorSystems.cpp:454`) assembles an
`FV5OnlineServiceRequest` via `UV5_Online_WorkshopClient::BuildPublishRequest`,
targets `/v5/workshop/case-author/publish`, and serializes a payload carrying
the clue/scene/branch counts, the `valid` flag, and
`moderationState: "pending"`. `bReadyToPublish` is true only when the draft is
valid **and** an account id and JWT are present. `PublishToWorkshop` (`:477`)
hands the request to `UV5_Online_ServiceCatalog::ExecuteRequest`, whose
automation test (`V5CaseAuthorTests.cpp:141`) pins the honest seam: `202` on a
healthy service, `503` + `bQueuedOffline` on an outage, `401` when the JWT is
empty. The Workshop _service_ is elsewhere; the editor's job is a correct, gated
request and it does exactly that.

The visible tool is `SV5CaseAuthorPanel` (`SV5CaseAuthorPanel.cpp`), a real
Slate widget: an `SBorder` over a four-column `SHorizontalBox` (Clues /
Interrogation / Branches / Validation+Workshop) inside `SScrollBox`es, with
`Validate`, `Preview`, and `Publish` `SButton`s whose `IsEnabled` is wired to
`bSupportsCluePlacement && bSupportsInterrogationTree` and
`WorkshopPlan.bReadyToPublish`. The committed `case_author_manifest.json`
mirrors the module's content counts and system flags under `schemaVersion: 1`.

## The Mind Palace: a cross-cell deduction graph

The Mind Palace is "a graph database + a UI shell," and conceptually a
**side-car to all five cells**: each cell's investigation gameplay pushes
evidence into it through one interface. `IV5_Investigation_MindPalacePush`
(`V5InvestigationMindPalacePush.h`) declares a single
`EmitEvidenceNodeEvent(FV5InvestigationEvidenceNodeEvent)`; the graph implements
it (`V5MindPalaceGraph.cpp:21`), translating an in-cell evidence event into an
`FV5MindPalaceEvidenceNode` tagged to the `MindPalace` cell. That is how a clue
examined in any cell becomes an orb in the shared room.

### The data model

`V5MindPalaceTypes.h` defines the graph. An `FV5MindPalaceEvidenceNode` is the
monolith's `V5_Evidence_Node` — `NodeId`, `CaseId`, source cell, location,
`TimestampInFiction`, `Tags`, `Description`, an `Image` soft path, examined
details, and a `bFalseLead` flag. An `FV5MindPalaceDeductionEdge` is the
`V5_Deduction_Edge` — a `from`/`to` node pair with their cells, `DeductionText`,
a `Confidence` float, a `Kind` (`Authored` or `Weak`), `bCrossEra`, a
`RequiredBureauTier`, and an `UnlockFlag`. An `FV5MindPalaceAccusationOutcome`
(`V5_Accusation_Outcome`) carries the `EvidenceChain`, the `RequiredEdgeIds` it
demands, a `Rating` (`Brilliant`/`Good`/`Doubtful`/`Wrong`) and an
`OutcomeBranch` (`TruthRevealed`/`PlausibleConviction`/`PoliticalCoverup`/
`Unproven`). The `FV5MindPalaceState` is the `V5_MindPalace_State`: nodes,
edges, accusations, and unlock flags.

### The deduction mechanic is authored-first with a weak fallback

`AttemptDeduction(NodeA, NodeB, BureauLedger)` (`V5MindPalaceGraph.cpp:78`) is
the "drag two orbs onto the pedestal" action, and its logic is specific. After
rejecting same-node or non-existent pairs, it looks up an **authored** edge for
the unordered pair via `FindAuthoredEdge`. If none exists it calls
`BuildWeakEdge` (`:271`), which only succeeds when the two nodes **share a
tag**: it mints a `weak.<a>.<b>` edge at `Confidence 0.35`, `Kind = Weak`,
marked `bCrossEra` when the cells differ and given `RequiredBureauTier 5` +
`UnlockFlag MindPalace.CrossEraPairs` in that case. So a pairing is either a
known authored insight or an honest "weak thematic connection… needs stronger
corroboration" — never a fabricated certainty. The candidate then passes through
the cross-era gate before being committed to `State.Edges`; the result reports
`bSuccess`, `bGateBlocked`, a `FailureReason`, and the resolved `Edge`.

The gate itself is `UV5_MindPalace_CrossEraGate::CanUnlockDeduction`
(`V5MindPalaceCrossEraGate.cpp`): a non-cross-era edge is always allowed; a
cross-era edge requires `BureauLedger.CurrentTier >= max(1, RequiredBureauTier)`
**or** that the ledger's `Unlocks` already contains the edge's `UnlockFlag`.
This is the spine connecting the Mind Palace to progression — the cross-cell
"aha" moments are earned through Bureau XP, the same ledger detailed in the
[Hunter, Period & Bureau spine](./hunter-period-systems-and-bureau-spine.md).

```mermaid
flowchart TD
  subgraph cells["Five cells push evidence"]
    INV["V5Investigation (per cell)<br/>player examines a clue"]
  end
  INV -->|"EmitEvidenceNodeEvent<br/>(IV5_Investigation_MindPalacePush)"| ADD[AddEvidenceNode<br/>upsert into State.Nodes]
  CAT[(deduction_pairs.json<br/>110 authored edges)] -->|ApplyAuthoredDeductionCatalog| GRAPH
  ADD --> GRAPH{{UV5_MindPalace_Graph}}
  GRAPH -->|AttemptDeduction A,B| FIND{authored edge<br/>for pair?}
  FIND -- yes --> GATE{cross-era gate<br/>CanUnlockDeduction}
  FIND -- no, shared tag --> WEAK[BuildWeakEdge<br/>Confidence 0.35]
  WEAK --> GATE
  GATE -- Tier &lt; required --> BLOCK[bGateBlocked<br/>fail loud]
  GATE -- unlocked --> EDGE[add edge to State.Edges]
  EDGE --> CHAIN[BuildHypothesisChain<br/>breadth-first walk]
  EDGE --> ACC[MakeAccusation<br/>requires full RequiredEdgeIds chain]
  ACC --> OUT["authored Rating + OutcomeBranch<br/>or Wrong/Unproven"]
  EDGE -.->|BuildGraphDiffPayload| SYNC[(mindpalace-cloud-sync :4220)]
```

### Hypothesis chains and the accusation gate

`BuildHypothesisChain(start, maxDepth)` (`V5MindPalaceGraph.cpp:112`) is a real
breadth-first traversal over the committed edges: a frontier expands outward
(depth clamped to 1–12), collecting reachable node and edge ids and accumulating
an `AverageConfidence`. It is the "UI helper for visualizing" a line of
reasoning, and the test asserts an authored chain carries
`AverageConfidence >= 0.80` (`V5MindPalaceTests.cpp:99`).

`MakeAccusation(case, accused, chain)` (`:165`) defaults to the worst outcome —
`Wrong` / `Unproven` — then searches the authored catalog for a matching
`(case, accused)` outcome. The match only "sticks" with its authored `Rating`
and `OutcomeBranch` if the player's `EvidenceChain` **contains every**
`RequiredEdgeId`; a chain missing a required link collapses back to
`Wrong`/`Unproven` with "lacked the required evidence chain." This is a real
proof-of-work gate, not a coin flip: the end-to-end test
(`V5MindPalaceTests.cpp:161`) completes each of the 15 authored outcomes'
required deductions and asserts the accusation resolves the **expected** branch,
covering three distinct branches across the arc.

### The volumetric memory room

`UV5_MindPalace_View_Volumetric::BuildViewState`
(`V5MindPalaceViewVolumetric.cpp:33`) renders the monolith's "circular memory
room with evidence orbs in concentric rings by cell of origin." It first filters
the node set through the filter rail, then places each surviving node on a ring
whose radius is a function of its cell (`RingForCell = 220 + cell·70`), at an
angle evenly distributed around the circle, lifted in z by index. The selected
orb scales up (`1.35`) and glows; each orb takes a per-cell accent color
(`ColorForCell`). Deduction threads are drawn only between two **visible** orbs;
an authored thread's intensity tracks its confidence while cross-era threads are
gold. `UV5_MindPalace_FilterRail::FilterNodes` (`V5MindPalaceFilterRail.cpp:19`)
is the left rail: filter by cell, by case, by an in-fiction timestamp range, and
by required tags (all must be present). The test drives this end-to-end —
filtering to one node by cell+tag, then building a view with "two evidence orbs"
and "one thread."

### Authored content is data, validated on load

The 110 deduction pairs and 15 accusation outcomes are **not** hard-coded.
`UV5_MindPalace_Catalog::LoadDeductionPairs` (`V5MindPalaceCatalog.cpp:121`)
reads `V5/ue/Content/V5MindPalace/Data/deduction_pairs.json` and validates it: a
`schemaVersion` of 1, required string/number fields, no duplicate edge ids, no
self-loops, positive confidence. The JSON is a compact generator spec —
`pairGroups` whose `count`s sum to exactly 110 (one cross-era group of 30
spanning all five cells at `requiredBureauTier 5`, plus five per-cell groups of
16 = 80) — matching the test's `Deductions.Num() == 110`, `CrossEraCount == 30`,
`PerCellCount == 80` (`V5MindPalaceTests.cpp:57`). `accusation_outcomes.json`
holds 15 outcomes — five anchor cases × three authored branches, an even
`PlausibleConviction` / `PoliticalCoverup` / `TruthRevealed` split.

### Cloud sync and the companion app

`V5MindPalaceCloudSyncHttp::BuildHttpRequest` (exercised at
`V5MindPalaceTests.cpp:248`) is a genuine `FHttpModule` POST to
`@v5/service-mindpalace-cloud-sync` at `/v5/mindpalace-cloud-sync/graph-diff` on
port `:4220`, a `Bearer` JWT header, `application/json`, and a body carrying a
CRDT-style version-vector graph diff; `ParseResult` maps `2xx→success`,
`503→failure`. A second, latent test (`V5_ONLINE_LIVE=1`) does a real round-trip
against the running service and asserts the response acknowledges the merged
diff. The companion-app path (`V5MindPalaceCompanionAppRead`) builds a read-only
snapshot for the AR overlay and an editable snapshot exposing `add-clue` /
`annotate-clue`, queuing append-only edit drafts for cloud-sync — the Year-1
Companion-App Mind Palace Editor.

## The Detective Mind Palace mode: dailies, crossovers, scoring

`V5DetectiveMindPalace` is the runtime _mode_ plugin built on the graph. Its
`ValidateCatalog` (`V5DetectiveMindPalaceSystems.cpp:589`) enforces the shape of
the main arc — ten one-hour beats totalling ten hours, covering all 30 cross-era
deductions, 80 per-cell deductions, and 100 examinable 3-D evidence assets
(count validated; the assets themselves are the referenced art surface). On top
sit two live-service systems:

- **Daily puzzles.** `BuildDailyPuzzleForDate` (`:541`) is deterministic: it
  takes the floor of days since the rotation start (`2027-06-07Z`), wraps it
  modulo 365 (with a correct negative-safe `((d % n) + n) % n`), and indexes the
  365 authored puzzles — so day 0 → puzzle 001, day 1 → 002, day 365 wraps back
  to 001, exactly as the test pins (`V5DetectiveMindPalaceTests.cpp:115`).
  `EvaluateDailyPuzzleSolve` (`:550`) computes a leaderboard score —
  `50000 + tier·1500 + timeBonus − hintPenalty`, floored at 1 — but only when
  the solve is clean: `bSolved && bAntiCheatClean && positive time`. A dirty
  solve scores zero and is leaderboard-ineligible. Scores submit through the
  shared leaderboards service.
- **Crossover pack.** A Year-1 "Black Archive" six-hour, six-beat arc adding 12
  new cross-era deductions, each validated as authored, cross-era, Bureau-gated,
  and referenced by exactly the beats that need it.

`ScoreConnection` (`:705`) grades a single thread: `Confidence·100` clamped to
0–100, `Strong` only when the edge is authored **and** ≥70 **and** the cross-era
gate is unlocked, and `bCanSupportAccusation` follows from `Strong + unlocked`.
The five automation tests (`Catalog`, `DailyPuzzleRotation`,
`Year1CrossoverPackExpansion`, `ConnectionScoring`,
`CrossEraUnlockMultiAccusation`) assert these computed values directly.

## Edge cases & connections

- **A pairing with no authored edge and no shared tag** yields "No meaningful
  connection found" (`V5MindPalaceGraph.cpp:91`) — the system refuses to invent
  a deduction. Shared-tag pairings produce only a low-confidence _weak_ edge,
  never a confident one.
- **A cross-era deduction below the Bureau tier** returns `bGateBlocked` with
  the candidate edge attached but **not** committed to state — the gate fails
  loud and leaves the graph unchanged until the player earns the unlock.
- **An accusation with an incomplete chain** can never reach an authored
  conviction branch; the missing-link path is the explicit `Wrong`/`Unproven`
  collapse, so the outcome is always backed by the evidence the player actually
  assembled.
- **Authoring a lie with no catchable evidence** fails `ValidateDraft` via the
  runtime's evidence-backed-lie resolver — the creator suite will not let a
  designer ship an unsolvable interrogation.
- **Offline / unhealthy backends** surface as `503 + queued-offline` (Workshop
  publish, cloud-sync) or `401` (missing JWT); the live cloud-sync round-trip is
  opt-in behind `V5_ONLINE_LIVE`, so the default test run never depends on a
  service being up.
- **Where the cases get played and judged.** The interrogation rig the Case
  Author validates against — MotionScan tells, the Truth/Doubt/Lie call, scoring
  — and the Heist Author that shares the Mission Editor are detailed in
  [Interrogation, Dialogue & Heist](./interrogation-dialogue-and-heist.md).
- **Platform substrate.** The shared online services these systems target
  (Workshop, leaderboards, the Mind-Palace cloud-sync domain) and the Bureau-XP
  ledger they gate against are catalogued in
  [Oshun Domain Libraries](../../platform/oshun-domain-libraries.html).

Together the creator suite and the Mind Palace are V5's answer to the open-world
anthology problem: a tool that authors a detective case under the runtime's own
rules, and a deduction layer that lets evidence cross cell boundaries — real in
logic, honest about the art they reach for.
