Ariadne mints a mystery in two halves — a symbolic skeleton that Clew proposes and Minos proves uniquely solvable, and an experienced surface that Anansesɛm and Loom realize into prose, art, voice, and living suspects. This page is about the last mile and the run time: the three subsystems that carry a verified, realized case the rest of the way to a player and keep the whole thing operable. Daedalus is the compiler — it lowers a proven case into the exact V5 data structures the shipping detective game already reads, so the playable game needs no rewrite. Theseus is the automated playtester — an autonomous solver that plays the compiled case to prove its fairness survived the compile, then grades it on an eight-dimension quality panel and decides, all-or-nothing, whether it may ship. The Oracle is the drama manager — it models each player, paces difficulty into their flow channel, and keeps a warm queue of verified cases minting against a bounded budget, so the Bureau Case Board is never empty and never bankrupts itself.
The throughline is the solve-first thesis read from the delivery side: fairness and quality are properties the system proves in game data, not attestations it hopes for. Daedalus refuses to compile a case Minos did not pass; Theseus refuses to publish a case it cannot itself solve in the compiled structs; the Oracle refuses to mint past its budget ceiling. Each refusal is specific, located, and tested. The realization half they depend on is its own page, ./realization-and-living-suspects.md, and the disciplines that wrap every case — budget, journal, determinism, provenance, localization — are ./cross-cutting-pipeline-and-localization.md. For the feature map this page belongs to, see ../V8_features.md.
What ships, honestly#
- Daedalus's compile is real, deterministic, and tested.
compileCase(libs/yemaya/case-compiler/src/compile.ts:59) lowers a verifiedMysterySession+ ground truth into theFV5*Mind-Palace structs and a v2cold_cases_manifest.json; the CLI test forges a real case from seed 5 and proves the emitted manifest validates (apps/v8/daedalus-compiler/src/cli.test.ts:9). On a publish it runs the authoritativevalidate-cold-cases.py --generatedas a build gate (compile.ts:108). - Theseus is equally real. Its solver reasons over the compiled structs,
not the IR (
libs/yemaya/case-eval/src/solver.ts:30); G4 in-game solvability is proven to fail when a required edge is dropped (eval.test.ts:67); the diagnostic judge's PCA aggregation is a genuine power-iteration eigenvector, not a mean (pca.ts:40); a wired LLM judge that throws propagates rather than being swallowed (eval.test.ts:108). The platform seven-gate suite (libs/v8/case-gates) and the C2PA-stamping bundle forge (libs/v8/case-bundle) are real and spec-anchored too. - The honest seams are seams, not fabrications. The LLM judge is an injected
JudgeFnthat refines deterministic heuristic scores; absent, the heuristic still grades from real case structure (judge.ts:158). The media providers in the bundle forge are injectedCaseMediaGeneratorboundaries — an absent provider yields anot-configuredslot, never a fabricated asset (case-bundle.ts:262). - The Oracle is real and green, but a library, not yet a wired run time.
@yemaya/case-directoris fully implemented — a genuine online-rating player model, streak-aware pacing, a budget-throttled mint queue, deterministic placement, a seasonal calendar — with 33 passing tests across five files. But no run-time app imports it yet: the Loom service'sPOST /v8/cases/mintmints from aCaseSpecthe caller supplies (apps/v8/loom-service/src/server.ts:43). Treat its decision logic as tested, not as a director already steering a shipped game. - Two divergences from the architecture prose, labeled. The compiler app is
apps/v8/daedalus-compiler(a thin CLI wrapper); the compile core lives in@yemaya/case-compilerso libs and apps import it without a lib↔app dependency (daedalus-compiler/src/index.ts:7), and the "runtime relay" is really the separateapps/v8/loom-service. And the shipping V5 deduction-Kindenum is only'Authored' | 'Weak'— there is noGeneratedvalue — so the compiler maps confidence to those two real values rather than inventing a third.
Daedalus — compiling a proof into the shipping game#
Daedalus's contract is narrow and strict: turn a MysterySession Minos
already proved (plus an optional AssetManifest) into a CompiledCase — the
FV5* structs, the v2 manifest, and a resolved asset bundle. Because the output
is V5's existing authored-case format, the game's deduction UI, interrogation
rig, and world streaming consume a generated case unchanged; the
backward-compatible v2 schema still validates the 25 hand-authored launch packs
and only adds a generation-provenance block.
The one-command local pipeline#
The CLI is the whole offline pipeline in a single invocation
(apps/v8/daedalus-compiler/src/cli.ts:55):
daedalus --seed 42 --cell Period --difficulty standard --suspects 4 --out ./out
runCli builds a CaseSpec from the flags (difficulty drives the bands, so
standard ⇒ 4 suspects, 11 clues, cli.ts:38), calls Clew's
generateCaseSync, then Minos's verifyCase. It prints the verdict and
refuses to compile a case that failed verification, returning exit code 1
(cli.ts:85); only on a green verdict does it compile to
<caseId>.compiled.json and .manifest.json.
The FV5 mapping#
compileCase builds a shared context, then runs four deterministic mappers — no
randomness, no LLM. Evidence: one FV5MindPalaceEvidenceNode per clue,
carrying a t+NN% fiction timestamp (which Theseus reads to score pacing), a
bFalseLead flag mirroring isRedHerring, and an Image bound to the
generated asset when the manifest has one. Deductions: the culprit chain
pairs the incrimination clues in surfacing order (means → opportunity → motive →
broken alibi) with confidence climbing toward the alibi flaw, and each
herring↔clearance pair links a refuted red herring to its suspect's clearance;
Kind is Authored at high confidence else Weak — the two real V5 values.
Accusations: the culprit's outcome is Rating: 'Brilliant' carrying the
culprit chain's edge ids as RequiredEdgeIds (the spine Theseus G4 walks), and
each innocent gets a plausible-wrong outcome — the wrongful-conviction hook
Palimpsest's write-back later seizes.
A final guard: resolveBundle throws if any FSoftObjectPath the structs
reference is unresolved (compile.ts:91) — a case cannot compile pointing at
art that does not exist.
Draft vs. release, and the Python build gate#
The draft-vs-release distinction is load-bearing. A standalone compile is a
draft: Minos's G1–G3 are proven here, but G4–G7 (Theseus, safety, canon) are
downstream, so a bare invocation labels it a draft and skips the Python build
gate unless --release is passed with every gate asserted green (cli.ts:95,
compile.ts:108). A draft produces exactly the structs Theseus needs to play
the case without pretending it cleared gates it has not run. The honest seam:
the CLI does not itself run Theseus — --release asserts G4–G7; the genuine
verdicts are computed by @yemaya/case-eval and supplied by the full publish
path (the Loom service), not synthesized by the compiler.
On a publish, two gates bite. The in-process validateGeneratedManifest mirrors
the Python validator — ≥3 evidence nodes, ≥2 deduction pairs, no duplicate ids,
a provenance block citing a verifier report and C2PA root, and every release
gate green; a draft filters not-yet-green release-gate problems out, a publish
does not (compile.ts:100). Then runPythonBuildGate runs
validate-cold-cases.py --generated, throwing CompileError on a non-zero exit
(compile.ts:125).
Theseus — proving the case is good enough to ship#
Theseus (@yemaya/case-eval) answers V8's version of V2's shipping question —
how do you know a generated case is good enough to ship? — with proofs in game
data. Its defining choice: it reasons over the compiled FV5* data, not the
IR. Minos proved the IR admits a unique solution; Theseus proves that property
survived the compile, catching a dropped edge, a mis-bound node, or a herring
that lost its clearance — losses an IR-level proof structurally cannot see.
The autonomous solver and G4 in-game solvability#
solveCompiledCase(compiled, skill) (solver.ts:30) is a deterministic graph
solver. It scores each suspect by the confidence of the deduction edges
converging on them; a herring↔clearance edge refutes (subtracts), modeling
"looked guilty, then cleared" (solver.ts:63). The skill ∈ [0,1] parameter is
a confidence floor — (1−skill)·0.6 — so a low-skill solver ignores buried
chains and may miss the answer. It accuses the highest positive-net suspect and
reports decisive only when the margin over the runner-up is ≥ 0.5
(solver.ts:88). The full-skill solver is authoritative; an LLM "detective" is
an optional realism layer, never required to prove solvability.
checkInGameSolvable(compiled) is the end-to-end proof: it finds the
Brilliant outcome and demands the solver accuses that culprit, decisively,
with every RequiredEdgeIds edge present and walkable (both endpoints
resolving to real evidence nodes). The teeth are in the test — remove one
required edge from a verified case and G4 flips to false (eval.test.ts:67),
the exact compile-loss class this gate exists to catch.
The eight-dimension judge diagnostic and G5 calibration#
scoreHeuristic (judge.ts:81) grades eight rubric dimensions — coherence,
surprise, fairness-feel, pacing, character, prose, voice-fit,
difficulty-accuracy — each from real structure, never a random number.
Coherence runs the solver (culprit + decisive ⇒ 0.9); surprise peaks at a ~⅓
red-herring density; pacing is 1 − normalized std-dev of the evidence staging
gaps. An injected JudgeFn may refine any subset, and a judge that throws
propagates (judge.ts:158). judgePanel learns weights across a batch via
real PCA — pca1Weights mean-centers the score matrix, builds the covariance,
and takes its top eigenvector by power iteration (pca.ts:40) — with a default
pass threshold of 0.6.
The heuristic and PCA outputs remain diagnostics. G5 requires independently
calibrated human-aligned judge evidence bound to the exact artifact, with
licensed gold, current approval, bias probes, held-out champion/challenger
evidence, and a clean contamination analysis (calibratedG5EvidenceProblems,
release.ts). A high diagnostic score cannot satisfy G5 by itself.
calibrateDifficulty (calibration.ts:24) runs Theseus at five skill levels
(0.2 … 1.0) to estimate a solve-rate, then reports the empirical difficulty
1 − solveRate and the drift from Minos's a-priori grade — a case the
strongest solver cannot crack is mis-graded; one every weak solver cracks is
easier than its grade claims. That drift is the signal designed to feed the
Oracle's player model, though the write-back wire is still spec.
runRegressionCorpus (corpus.ts:26) anchors the suite: every corpus case must
be G4-solved and judged above threshold — V5's 25 authored cases are the
intended golden fixtures once cooked.
Operating a case end-to-end: the Loom relay and the two gate framings#
At run time the UE5 client never holds provider keys — it reaches everything
through the Loom relay (apps/v8/loom-service), and POST /v8/cases/mint
runs the full pipeline and returns the compiled pack only if all eight
ReleaseDecision gates pass: HTTP 200 with the manifest, or 422 with the
blocking reasons (server.ts:40). runPipeline (pipeline.ts:127) is the
composition that ties the last mile together — Minos verify (G1–G3) →
narrative/asset realize → Daedalus draft-compile → Theseus G4 + calibrated
G5 → G6 safety + G7 canon → G8 preregistered human-quality launch evidence →
decideRelease, and only on an all-green decision a publish re-compile with
the Python validator enforced (the diagram below).
One thing to internalize before reading any gate code: V8 has a seven-gate
platform suite and a distinct eight-gate pipeline release decision. The
runtime Loom pipeline uses the Theseus ReleaseDecision framing
(release.ts:40), ordered by the pipeline stage that produces each verdict;
decideRelease publishes only when all eight pass and attaches a specific
blocking reason per failure (eval.test.ts:179 confirms a single failing G6
blocks). The platform suite @oshun/v8-case-gates is a different numbering,
ordered by kind of check, and registers seven GateDefinitions on the shared
@oshun/content-release-gates service — composed, not forked:
| # | Theseus ReleaseDecision (case-eval/src/release.ts) |
Platform suite (@oshun/v8-case-gates, case-gates/src/index.ts) |
|---|---|---|
| G1 | Minos formal uniqueness | fair-play (every solution clue presented before the reveal) |
| G2 | deductive completeness | solvability (the CSP proved one solution) |
| G3 | fair-play + mechanic balance | clue-grounding (every cited clue exists) |
| G4 | Theseus in-game solvable | suspect voice-distinctiveness |
| G5 | calibrated human-aligned judge evidence | misdirection (≥1 herring, ≤ max — fair, not a maze) |
| G6 | Sekhmet safety | prose quality |
| G7 | canon consistency | content safety |
| G8 | preregistered human-quality launch evidence | — |
evaluateV8Case (case-gates/src/index.ts:183) returns cleared only when all
seven pass. The case-bundle forge is where that suite earns its keep:
forgeCaseBundle proves uniqueness before any generation (throwing
CaseNotSolvableError, case-bundle.ts:237), fails loud with no prose writer,
C2PA-stamps each produced asset with a verifiable Ed25519 manifest, and runs the
assembled case through evaluateV8Case, leaving blocked: true on any failure.
Its spec proves no media is generated for an unsolvable skeleton and that
tampering any signed field flips verification to false.
Oracle — directing which labyrinth a player meets next#
The Oracle's job is to keep one player in their flow channel — cases neither trivial nor impossible — while honoring their taste, avoiding repetition, weaving their open story threads back in, and never letting the mint bill run away. It is real, tested decision logic, though no runtime app has wired it in yet, and this section is honest about that boundary.
Player model, pacing, and the mint-ahead queue#
updateFromOutcome (player-model.ts:139) is a genuine Elo-style update, not a
moving average of a label. Each finished case carries an actual score in
[0,1] (wrong→0, partial→0.45, correct→0.8, brilliant→1), and the model
nudges the skill estimate by K · (actual − expected) where expected is the
Elo logistic against the difficulty's implied rating. The K-factor decays
with evidence — 0.12 + 0.4/(1+n) runs from 0.52 on a player's first case to a
~0.12 asymptote — so provisional ratings find a player fast and settled ones
don't tank on one bad night. The model also keeps theme/cell taste counters and
weight-sorted open threads (e.g. "wrongly accused Dockhand Mara, now freed")
that pacing weaves into the next case's priorOutcomeHooks.
The pacer's nextCaseSpec reconciles three pressures into one deterministic
CaseSpec: difficulty tracks skill but is nudged by the recent streak (one
band up after strong solves, down after weak ones); anti-repetition drops
every theme and cell used in the last K cases; and canon weaving writes
the strongest open thread into the spec. MintQueue.refill
(mint-queue.ts:131) keeps N verified cases warm per (player, cell) lane so
a player at the Case Board never waits on the pipeline — real water-mark
scheduling against a live budget: it reserves the per-request cost before
emitting (DEFAULT_MINT_COST = 4000 tokens, 3 asset-jobs), and the first
reservation the budget cannot grant stops the refill short, leaving the lane
partially warm with budgetLimited set. The Oracle thus throttles its own mint
rate against the remaining envelope.
Placement, seasonal cadence, and the honest boundary#
placeCase decides where a verified case surfaces, in priority order: a
commissioned case is always honored directly; otherwise, if an active world
location matches the spec and has a present NPC to carry the hook, the case is
seeded ambient into the living world; else it falls back to the bureau
Case Board. buildSeasonCalendar replaces V5's authored weekly packs with a
generated drop calendar — dated drops a week apart, difficulty escalating across
the season, the cell rotating — and it never reads a clock, so a season is
reproducible from its id. The honest boundary is the wire: placeCase reads a
WorldState interface, but the live NPC-schedule injection and the in-engine
Case Board that consume its decision are the UE5 plugin — the external
remainder.
How a case fails to ship — refusals#
The layer is built to refuse rather than fabricate, each refusal specific and located:
- In-game solvability lost → a compile that drops a required edge, mis-binds
a node, or strips a herring's clearance makes G4 return
pass: false;decideReleaserefuses to publish (eval.test.ts:67). - G5 calibration absent or invalid → a passing heuristic/PCA aggregate cannot publish without exact-artifact, current, independently calibrated human-aligned judge evidence; the platform-suite parallels are low voice, low prose, or unsafe content.
- Under-determined skeleton → caught before any generation in the bundle
forge (
CaseNotSolvableError); in the suite it fails G2 solvability. - A non-green release gate at compile → a draft tolerates it; a publish does
not —
validateGeneratedManifestthen the Python gate reject the pack (compile.ts:100,:108). - Mint budget exhausted →
MintQueue.refillstops short withbudgetLimited: truerather than overrunning. - Honest absences → no
python3keeps a draft buildable while labeling it a draft; an absent media provider yields anot-configuredslot; a wired LLM judge that errors is propagated, not swallowed.
On any of these the case does not ship — nothing is published or cached — and the failing gate's reason is the signal a Clew repair pass or a human reviewer acts on.
Related#
- ./realization-and-living-suspects.md — the writers' room, asset fabric, and Ori suspects whose trees and manifest Daedalus folds into the V5 pack.
- ./cross-cutting-pipeline-and-localization.md — the budget, journal, determinism, provenance, and localization disciplines the Loom pipeline threads through every mint.
- ../architecture/daedalus-compiler-and-theseus-eval.md — the architecture companion: the deep compile target and Theseus eval path, gate by gate.
- ../architecture/oracle-director-cross-cutting-and-deployment.md — the Oracle, the cross-cutting spine, and the deployment shape in depth.
- Hub: ../V8_features.md · Architecture spec: ../V8_ARCHITECTURE.md.