V8 (Ariadne — the self-authoring detective universe) mints a mystery in two
halves: a symbolic skeleton that
Clew, Minos & Palimpsest prove is
uniquely solvable, and an experienced surface that
Anansesem, Loom & the Ori suspects
realize into prose, art, voice, and interrogation. Daedalus and Theseus
are the last mile: where those two halves become a thing the shipping game can
load, and where the pipeline earns the right to call a case shippable. Daedalus
is the compiler — it lowers a verified MysterySession plus its resolved
asset manifest into the exact V5 structs the existing cold-cases plugin reads,
then runs the same Python schema gate the human Case Author tool runs. Theseus
is the automated playtester and eval harness — an autonomous solver that
plays the compiled case against V5's real data model, an 8-dimension
LLM-as-judge quality panel, a difficulty calibrator, and a regression corpus,
composing into a single all-or-nothing release decision. Between them they
answer 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 rather than
attestations. This page is the deep companion to the section hub at
../V8_ARCHITECTURE.md, whose §4.7–§4.8 introduce
Daedalus and Theseus.
What ships, honestly#
The compile mapping is real and deterministic — Clues, clue logic, and
accusations lower into the FV5* structs (libs/yemaya/case-compiler/src) and
a v2 cold_cases_manifest.json that the authoritative Python validator
V5/tools/cold-cases/validate-cold-cases.py --generated must accept as a build
gate (compile.ts:108). Theseus is equally real: the solver reasons over the
compiled structs and is tested to reach the intended culprit decisively across
20 seeds (eval.test.ts:56); G4 in-game solvability is proven to fail when
a required edge is dropped (eval.test.ts:67); the PCA aggregation is a genuine
power-iteration eigenvector, not a mean (pca.ts:40); and a judge error
propagates rather than being swallowed (eval.test.ts:108). The seven-gate
platform suite (libs/v8/case-gates) and the C2PA-stamping bundle forge
(libs/v8/case-bundle) are real and spec-anchored too.
What is a seam, not a fabrication: the LLM judge is an injected JudgeFn
that refines the deterministic heuristic scores; absent, the heuristic still
grades from real case structure (judge.ts:152). The media providers are
injected CaseMediaGenerator boundaries — an absent provider yields a
not-configured slot, never a fabricated asset (case-bundle.ts:262).
Two honestly labeled divergences from the architecture prose, because the
doc and the code disagree. First, §4.7 names the app apps/v8/daedalus; the
real app is apps/v8/daedalus-compiler, a thin CLI wrapper — the compile
core was lifted into a library, @yemaya/case-compiler, so other libs and
apps can import it without a lib↔app dependency
(daedalus-compiler/src/index.ts:7). The "runtime-relay" the same comment
mentions is aspirational; the actual on-demand relay is the separate
apps/v8/loom-service (it owns the server.ts). Second, §3.4 says deduction
edges set Kind=Generated; the shipping V5 enum is only
'Authored' | 'Weak' (v5-target.generated.ts:15), so the compiler maps
confidence to those two real values — its comment says so: "the shipping enum
has no Generated value" (deductions.ts:9). The code is honest to the engine;
the doc over-specified.
Daedalus — compiling a verified skeleton into a V5 pack#
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
(compiled-case.ts:27). CompiledCase lives in @yemaya/case-contracts so the
compiler (an app) and Theseus (a lib) agree on the shape without depending on
each other.
The local pipeline: generate → verify → compile#
The CLI is the offline pipeline in one command
(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 suspect/clue
bands — standard ⇒ 4 suspects, 11 clues, cli.ts:38), calls
generateCaseSync (Clew), then verifyCase (Minos). It prints the Minos
verdict — g1 uniqueness, g2 completeness, g3 fair-play, plus balance — and
refuses to compile a case that failed verification, returning exit code 1
(cli.ts:85). Only on a green verdict does it compile, writing
<caseId>.compiled.json and .manifest.json (cli.ts:108).
The draft-vs-release distinction is load-bearing. A standalone compile is a
draft: Minos's G1–G3 are proven here, but G4–G8 (Theseus, calibrated judge
evidence, safety, canon, human-quality launch evidence) 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). A draft
produces the structs Theseus needs to play without pretending the case cleared
gates it has not been run through. In release mode the CLI runs G4, the
diagnostic judge, G6, and G7, loads exact-artifact calibrated G5 and
human-quality G8 evidence, calls decideRelease, and only then re-compiles
through the Python gate. Missing evidence blocks; no downstream gate is inferred
from --release.
The FV5 mapping#
compileCase (compile.ts:59) builds a shared context, then runs four
deterministic mappers:
- Evidence (
evidence.ts): oneFV5MindPalaceEvidenceNodeper clue. The fiction timestamp ist+NN%from the clue'sintroducedAt.percentage(what Theseus later reads to score pacing),bFalseLeadmirrorsisRedHerring, andImagebinds to the generated asset when the manifest has one. - Deductions (
deductions.ts): two pairing kinds form the Mind Palace graph. The culprit chain pairs the incrimination clues in the order they surface (means → opportunity → motive → broken alibi), with confidence climbing0.7 → 0.9as it converges on the alibi flaw — the0.95in theMath.min(0.95, …)clamp is a never-binding cap, since the formula's realized top is0.7 + 0.2·1 = 0.9(deductions.ts:69); each herring↔clearance pair links a refuted red herring to its suspect's clearance, at0.55.KindisdeductionKindFromConfidence—≥0.7 ⇒ Authored, elseWeak(v5-target.ts:31) — and a cross-cell pairing setsbCrossEra(deductions.ts:47). - Accusations (
accusations.ts): the culprit's outcome isRating: 'Brilliant',OutcomeBranch: 'TruthRevealed', carrying the culprit chain's edge ids asRequiredEdgeIds(accusations.ts:30) — the spine Theseus G4 walks. Each innocent gets a plausible-wrong outcome: one who kept a motive isDoubtful/PlausibleConviction("a wrongful conviction waiting to unravel," the hook Palimpsest'sfreed-vengefulwrite-back seizes), one cleared by alibi isWrong/Unproven(accusations.ts:53).
The manifest and the Python build gate#
compilePack (pack.ts) emits the FV5ColdCasePackDefinition header and the
v2 GeneratedColdCaseManifest. VO counts come from the asset manifest's real
voice-over summary (summariseVoiceOver), defaulting to zero when no audio was
generated rather than inventing line counts (pack.ts:43). The pack records a
full generation provenance block — seed, the C2PA root, the asset-manifest
id, the Minos verifier-report id, and the (seed, model-versions, canon-hash)
repro key (pack.ts:89) — alongside the releaseGates map (pack.ts:110).
Two gates then bite, in order. The in-process validateGeneratedManifest
(manifest.ts:72) mirrors the Python validator: ≥3 evidence nodes and ≥2
deduction pairs, no duplicate ids, sourceCells containing the lead cell and
MindPalace, a non-empty title/brief, a provenance block whose seed matches and
that cites a verifier report and C2PA root — and that every release gate is
green (manifest.ts:99). A draft tolerates not-yet-green release-gate
problems by filtering them out (compile.ts:100); a publish does not. Then, on
a publish only, runPythonBuildGate writes the manifest to a temp file and runs
validate-cold-cases.py --generated, throwing CompileError on a non-zero exit
(compile.ts:125). The CLI test proves the path end to end: a --release run
of seed 5 exits 0 and validateGeneratedManifest of the emitted manifest
returns [] (cli.test.ts:9). The schema is v2, backward-compatible — the
25 authored launch packs (v1) still validate; v2 only adds generation
provenance (manifest.ts:1). One more compile-time 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.
Theseus — playtesting the compiled case#
Theseus (libs/yemaya/case-eval, @yemaya/case-eval) is the architecture's
named eval lib (§4.8 — here the doc and code agree). 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 (solver.ts:1).
The autonomous solver#
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 (solver.ts:39). 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, not required to prove solvability.
G4 — in-game solvability#
checkInGameSolvable(compiled) (g4.ts:24) is the end-to-end proof in game
data. It finds the Brilliant outcome, then demands four things: the solver
accuses that culprit, the accusation is decisive, every RequiredEdgeIds
edge exists and is walkable (both endpoints resolve to real evidence nodes,
g4.ts:54), and the cited EvidenceChain nodes resolve. Any gap fails the gate
with a reason (g4.ts:75). The teeth: a test removes one required edge from a
verified case and asserts G4 flips to false (eval.test.ts:67) — the exact
compile-loss class this gate catches.
The judge-panel 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; difficulty-accuracy measures how closely the a-priori grade, the empirical
1 − solveRate, and the target align (judge.ts:116). An injected JudgeFn
may then refine any subset of scores, and a judge that throws propagates
(fail-loud, eval.test.ts:108). judgeCase aggregates equal-weight;
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), sign- and L1-normalized to
non-negative weights summing to 1 (pca.ts:58). The spec checks the eigenvector
of a diagonal [[5,0],[0,1]] favors axis 0 (eval.test.ts:123) — a stub mean
would fail it. The default pass threshold is 0.6 (judge.ts:164).
Those heuristic/PCA outputs are diagnostics, not release authority. G5 requires
independently calibrated human-aligned judge evidence bound to the exact
artifact, licensed gold, current approval, bias probes, held-out
champion/challenger evidence, and a clean contamination analysis
(calibratedG5EvidenceProblems, release.ts). Missing or invalid evidence
fails G5 even when the heuristic score passes.
Calibration and the regression corpus#
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, a case every weak solver cracks is
easier than its grade claims, and that signal feeds back to the Oracle's player
model. runRegressionCorpus (corpus.ts:26) anchors the suite: every corpus
case must be G4-solved by Theseus and judged above threshold (V5's 25
authored cases are the intended golden fixtures once cooked). Its test forges
six generated cases and asserts all six solve and pass (eval.test.ts:166).
The two gate contracts#
One thing to internalize before reading any gate code: V8 has a seven-gate
platform suite and a distinct eight-gate pipeline ReleaseDecision, both
real. Confusing them makes the code look contradictory when it is not.
| # | 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 (§11.4) | prose quality |
| G7 | canon consistency (§1.4) | content safety |
| G8 | preregistered human-quality launch evidence | — |
The ReleaseDecision framing (release.ts:40) is ordered by the pipeline
stage that produces each verdict — Minos owns G1–G3, Theseus and calibrated
judge evidence G4–G5, the safety and canon stages G6–G7, and preregistered
human-quality launch evidence G8 — and decideRelease publishes only when all
eight pass, attaching a specific blocking reason per failure; its test confirms
a single failing gate (G6) blocks publication (eval.test.ts:179). The
platform-suite framing (case-gates/src/index.ts:99) is ordered by kind of
check and registers seven GateDefinitions on the shared
@oshun/content-release-gates ReleaseGateService via the platform's
gateFromManifestCheck / gateFromEvalScore / createGroundingGate builders —
composed, not forked. evaluateV8Case returns cleared only when all seven
pass, and its spec asserts the exact gate-id list and that each fault blocks its
own gate (case-gates.spec.ts:30); like V9's lesson-gates suite it reads a
pre-stamped uniqueSolutionProven flag for G2 (index.ts:60) rather than
re-solving. There is even a third naming — Minos's internal
g1Uniqueness/g2Completeness/g3FairPlay the CLI prints (cli.ts:82), which
supplies the ReleaseDecision's G1–G3. The common thread: one false gate
blocks, and the manifest validator enforces the same rule in process — every
release gate green or no compile (manifest.ts:99).
The libs/v8/case-bundle forge is where the platform suite bites in the
libs/v8 vertical: 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
(stampAsset, :184), and runs the assembled case through evaluateV8Case — a
quality or fairness failure leaves blocked: true. Its spec proves no
prose/media is generated for an unsolvable skeleton and that tampering any
signed field flips verification to false (case-bundle.spec.ts:147,:169).
How a case fails eval — edge cases#
- In-game solvability lost. A compile that drops a required edge, mis-binds
a node, or strips a herring's clearance makes the solver miss or under-decide:
G4 returns
pass: falsewith the reason anddecideReleaserefuses to publish (g4.ts:75,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 (
calibratedG5EvidenceProblems,release.ts); the platform-suite parallels are low voice, low prose, or unsafe content (case-gates.spec.ts:106). - Under-determined skeleton. Caught before any generation in the bundle
forge (
CaseNotSolvableError); in the suite it fails G2 solvability (case-gates.spec.ts:65). - A solution clue withheld, invented, or mis-balanced misdirection. Fail
platform-suite G1 fairness (
case-gates.spec.ts:50), G3 clue-grounding (:71), or G5 misdirection — zero herrings or pastmaxRedHerrings(:79). - A non-green release gate at compile. A draft tolerates it; a publish does
not —
validateGeneratedManifestthen the Python gate reject the pack (manifest.ts:99,compile.ts:108). - Honest absences. No
python3⇒skipPythonGatekeeps a draft buildable while labeling it a draft; an absent media provider ⇒ anot-configuredslot, not a faked asset; a wired LLM judge that errors ⇒ 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 repair pass (Clew) or a human reviewer acts on.
Related#
- Clew, Minos & Palimpsest — the symbolic core — produces and proves the verified skeleton Daedalus compiles; Minos's IR-level uniqueness proof is what Theseus G4 re-confirms survived the compile.
- Anansesem, Loom & the Ori suspects — the writers' room and asset fabric whose trees and manifest Daedalus folds into the V5 pack; the Loom service is the runtime relay that mints and fetches cases.
- Oracle, cross-cutting concerns & deployment — the case director that consumes Theseus's calibration to grade and surface cases, plus the loom-service relay, provenance, budget, and HITL plumbing.
- Hub: ../V8_ARCHITECTURE.md.