Ariadne · Architecture

Architectural Thesis & the Generation Pipeline

A focused page within the Ariadne Architecture documentation. The full map and every sibling page live in the Architecture hub.

5sections11 minread1diagram

On this page

V8 (codename Ariadne) is the version that turns V5's authored open-world detective game into a self-authoring one: a player or director asks for a case, and the system mints a fair, solvable, fully-realized mystery — ground truth, clue logic, prose, suspects, evidence, voice — with no human authoring per case. The single architectural decision that makes that safe is a hard separation between two layers, captured in one sentence the product repeats everywhere: the LLM proposes; a constraint solver disposes. A mystery has a symbolic skeleton (who did it, the means/motive/opportunity, the clue logic, and a machine-proved unique solution) and an experienced surface (the prose, dialogue, art, and voice an audience actually sees). V8 keeps them strictly apart. The skeleton is authoritative and machine-checked; the surface is generated from it, graded, and regenerated on failure. Nothing unsolvable, unfair, unsafe, or canon-breaking ever reaches a player, because the part that could hallucinate is never the part that decides whether the case is solvable.

That choice is what separates V8 from the freestyle-LLM failure mode — the rambling whodunit that contradicts itself, hides the murderer behind a fact it never showed you, or "solves" by authorial fiat. V8 is a small product by surface area, but the part that has to be provably correct is real code, not a prompt: a genuine finite-domain constraint solver proves uniqueness, the seven-gate platform suite and eight-gate pipeline release decision block failures in their respective tracks, and every generated asset is content-credentialed. This page is the orientation companion to the V8 architecture set — the thesis, and the multi-stage pipeline that realizes it. The section hub is ../V8_ARCHITECTURE.md.

What ships, honestly#

V8's V8_TODOS.md tracks the build at 87 of 90 tasks done (3 open, no partials), and the code backs a substantial, tested core. Because the monolith architecture doc (V8_ARCHITECTURE.md) describes an ambitious eleven-stage, nine-subsystem universe that reaches all the way into the running UE5 game, this section separates what is real today from what is planned or provider-gated. Honest "planned/gated" beats fake "shipped." There are, in fact, two real code tracks in the repo, both expressing the solve-first thesis at different scales.

The focused symbolic core (real and tested today) — libs/v8/*. Three self-contained packages under @oshun/v8-* are the thesis in miniature. case-csp (~1,100 lines incl. tests) is a genuine CSP solver — backtracking search with node consistency, minimum-remaining-values ordering, and forward checking (solveCsp, libs/v8/case-csp/src/csp-solver.ts:212) — that enumerates solutions rather than returning a boolean, and a proveUniqueSolution (csp-solver.ts:356) that probes for a second model to decide unique | under-determined | unsatisfiable. Its spec anchors correctness against the canonical Zebra (Einstein) puzzle — "Norwegian drinks water, the Japanese owns the zebra" (csp-solver.spec.ts:168) — so the engine is verified against a known result, not just its own data. case-bundle's forgeCaseBundle (libs/v8/case-bundle/src/case-bundle.ts:236) proves solvability first, generates prose and media through injected boundaries, and C2PA-stamps every produced asset with the shared @oshun/content-signing Ed25519 signer. case-gates registers a seven-gate suite over the shared @oshun/content-release-gates service — composed, not forked (libs/v8/case-gates/src/index.ts:99). This track is internally coherent (bundle → csp + gates) and self-contained; notably, it is not wired into the runtime apps.

The eleven-stage pipeline (real, and end-to-end tested offline) — apps/v8/* over libs/yemaya/case-*. The runtime apps wire a separate, larger set of eleven subsystem libraries (~13k lines across case-contracts, case-engine, case-verifier, case-writers-room, case-assets, case-suspects, case-eval, case-pipeline, case-director, case-compiler, case-localization). The Loom service's runPipeline (apps/v8/loom-service/src/pipeline.ts:127) runs every stage from a single CaseSpec — and the §12.4 acceptance test (pipeline.test.ts:28) mints a case and publishes it offline, deterministically, with zero provider credentials and all eight ReleaseDecision gates green, then runs the real validate-cold-cases.py build gate. So "the pipeline" is not a slide: the offline mint→publish path is genuinely executable and regression-tested.

Provider-gated injected seams (fail-loud, not faked). The parts that need real models or money are typed boundaries the pipeline injects and runs degraded without: the LLM proposer/flavor (CreativeProposer) and prose enrichment (CompletionFn), live media providers (Stability/Flux/Hunyuan3D/Meshy/Suno/ ElevenLabs via Isis), ACE/Inworld runtime interrogation, and the clingo ASP binary. None of these fabricate when absent. A missing prose writer fails loud (CaseBundleNotConfiguredError, case-bundle.ts:115); an absent media provider yields an honest not-configured asset slot, never a fake asset (case-bundle.ts:260); the Minos sidecar reports whether clingo is present and falls back to the in-process DPLL solver for the same verdict (apps/v8/minos-asp-sidecar/src/server.ts:26); and the offline pipeline deps run "the deterministic Clew core, the grounded surface, a text-only degraded asset pack" with no keys at all (apps/v8/loom-service/src/deps.ts:44).

Spec-described / external-gated. The UE5 client plugin (V8/ue/Plugins/V8_Ariadne_CaseClient), live in-engine runtime interrogation, the on-demand runtime minting path, externally-authored case fixtures, and the full live Palimpsest canon store (Postgres+pgvector+Neo4j) are described in the monolith but are the remainder — they are not what the offline acceptance run exercises.

A real naming divergence worth knowing. V8 has two distinct gate contracts. The libs/v8/case-gates platform suite numbers seven checks G1 fairness, G2 solvability, G3 clue-grounding, G4 voice, G5 misdirection, G6 prose, G7 safety (libs/v8/case-gates/src/index.ts:1). The pipeline's authoritative ReleaseDecision numbers eight checks G1 formal uniqueness, G2 deductive completeness, G3 Knox/Van-Dine fair-play, G4 Theseus in-game solve, G5 human-calibrated judge evidence, G6 Sekhmet safety, G7 canon-consistency, G8 preregistered human-quality launch evidence (libs/yemaya/case-eval/src/release.ts:1). Both are real and fail closed, but they are not interchangeable. When this page says "the gates," it means the contract named by the surrounding code.

The solve-first thesis#

Skeleton vs. surface#

The skeleton is a MysterySkeleton (libs/v8/case-csp/src/mystery-skeleton.ts:69): a set of solution dimensions (culprit, weapon, location, motive, time…) each with a finite domain, an intended groundTruth assignment, and a list of clues — each clue marked presented or withheld and carrying a logical constraint over the dimensions. The skeleton is never shown to the player; the surface (prose, interrogation trees, art, VO) is realized from it afterward. This is what lets V8 gate a case once on its truth and re-skin the prose freely over the same proven logic — the same skeleton/surface split V9 encodes as skeletonHash vs. surfaceHash, here applied to mysteries instead of lessons. The canonical data contracts that make the split typed and parallelizable — CaseSpec, CaseGroundTruth, and the MysterySession IR — have their own page: ./canonical-data-contracts.md.

The solver that disposes#

The "disposes" half is the real engine. A clue's logical content compiles to a first-class CSP constraint — is/is-not/one-of/if-then/same, plus an allowed-tuples escape hatch for arbitrary fair deductions (compileConstraint, mystery-skeleton.ts:85). The solver's constraintViolated uses definite-violation semantics (csp-solver.ts:120): a constraint counts as violated only when no completion of the unassigned variables can satisfy it, which is exactly what keeps backtracking both sound and complete. Search seeds node consistency from the unary constraints, picks the most-constrained variable next (MRV), and forward-checks — pruning each unassigned neighbour's domain after every assignment and undoing the pruning on backtrack (forwardCheck, csp-solver.ts:278). The engine is domain-agnostic: the same code solves a murder, a logic grid, or the Zebra puzzle. The spec proves the small cases that matter to a mystery directly — four suspects [ada, ben, cara, dan], three eliminated, leaves exactly cara (unique); two eliminated leaves two survivors (under-determined); a suspect both required and forbidden is unsatisfiable (csp-solver.spec.ts:89).

Proving a case fair and solvable#

The gate the whole thesis stands on is proveCaseUniqueness (mystery-skeleton.ts:239). It compiles only the player-visible (presented) clues into a CSP (compileMysteryToCsp defaults to presented, mystery-skeleton.ts:136) and demands two things at once: the visible clues must admit exactly one solution, and that solution must equal the intended ground truth. An under-determined case (multiple suspects survive), an over-constrained one (no suspect survives), or a case whose visible clues prove a different culprit than the author intended are all rejected — never fabricated as solved. The spec exercises every one of those rejections, including the subtle one: "a case solvable only with withheld clues is under-determined for the player" (mystery-skeleton.spec.ts:178), which is precisely the cheat fair-play exists to forbid. Malformed skeletons fail loud before any "proof" (assertGroundTruthInDomain, mystery-skeleton.ts:156), and a separate groundTruthSatisfiesAllClues (:180) surfaces a generator bug where the case's own answer contradicts a clue it ships. The boolean uniqueSolutionProven (mystery-skeleton.ts:213) is the single flag the solvability gate consumes. The deeper symbolic-core walkthrough — Clew, Minos, and the Palimpsest continuity graph — is its own page: ./clew-minos-palimpsest-symbolic-core.md.

The generation pipeline#

The Loom service composes the stages end-to-end. The governing rule is solve-first: the symbolic skeleton is built and verified before any prose exists, and the surface stages are constrained to realize that skeleton. The stage names below mirror the Ariadne myth cycle (Clew the case engine, Minos the verifier, Anansesɛm the writers' room, Loom the asset fabric, Theseus the playtester, Daedalus the compiler); each maps to a libs/yemaya/case-* library the apps wire.

flowchart TD SPEC[CaseSpec + canon snapshot] --> GT[Ground truth + clue derivation<br/>Clew · case-engine] GT --> VERIFY{Verify G1-G3<br/>Minos · case-verifier} VERIFY -- fail --> REPAIR[Repair: regenerate<br/>only offending clues] REPAIR --> VERIFY VERIFY -- pass --> NARR[Narrative realize<br/>Anansesem · writers-room] NARR --> ASSETS[Asset realize<br/>Loom · injected Isis seam] ASSETS --> CIR[Compile-IR → CompiledCase] CIR --> EVAL[Eval G4<br/>Theseus solve + diagnostic judge] EVAL --> CAL[G5 calibrated human-aligned<br/>judge evidence] CAL --> SAFE[Safety G6<br/>Sekhmet seam · fail-loud] SAFE --> CANON[Canon-consistency G7] CANON --> HUMAN[Human-quality launch evidence G8] HUMAN --> DECIDE{Release decision<br/>all eight gates green?} DECIDE -- no --> BLOCK[BLOCKED · not published,<br/>reasons journalled] DECIDE -- yes --> COMPILE[Compile-game → FV5* pack<br/>validate-cold-cases.py gate] COMPILE --> PROV[Provenance + telemetry<br/>seed · model versions · canon hash]

runPipeline (pipeline.ts:127) walks this graph for one CaseSpec, threading a per-case token/asset budget, a StageJournal that records every stage in monotonic order (for audit and replay), and a telemetry aggregator. Clew generates the ground truth and clues; Minos verifies G1–G3 before anything downstream runs (verifyCase, pipeline.ts:145), running formal uniqueness via the ASP/DPLL runner, deductive completeness, and the existing Knox/Van-Dine fair-play checker. Anansesɛm realizes the briefing, scenes, and one interrogation tree per suspect; Loom either calls the injected asset realizer or emits a text-only degraded pack (emptyAssetManifest, pipeline.ts:91). Theseus supplies the G4 in-game solvability verdict and a heuristic/PCA quality diagnostic. G5 passes only with independently calibrated human-aligned judge evidence bound to the exact artifact; the diagnostic cannot satisfy it.

The eight gates and the release decision#

The pipeline's honesty is concentrated in two places. G6 safety is fail-loud by construction: requireSafetyClear throws on flagged or unscanned content, and the surrounding try/catch leaves g6 = false on any throw — so unscanned content cannot accidentally publish (pipeline.ts:199). The release decision then takes the conjunction of all eight gates (decideRelease, pipeline.ts:212); only when it returns publish: true does the pipeline re-compile the pack with every gate asserted green and run the non-skippable Python build gate (pipeline.ts:222). A blocked case journals its blocking reasons and produces no published pack. The §12.4 acceptance test asserts the positive path end-to-end — all eight decision.gates true, one interrogation tree per target suspect, and a pack whose manifest carries the eight green gates plus generation provenance (pipeline.test.ts:28).

The forge bundle and provenance#

The libs/v8 track expresses the same flow as a single function for the focused core. forgeCaseBundle (case-bundle.ts:236) proves uniqueness first and throws CaseNotSolvableError before any generation if the case is under-determined — the spec verifies it rejects an under-determined case with zero generator calls (case-bundle.spec.ts:169). Each produced asset is hashed and Ed25519-signed into a C2PA-style manifest (stampAsset, case-bundle.ts:184); tampering any signed field — digest, URI, kind — flips verifyCaseAssetManifest (case-bundle.ts:215) to false, which the spec proves with a deliberately mutated manifest (case-bundle.spec.ts:147). The assembled case is then gated through the same seven-gate suite via the shared ReleaseGateService (evaluateV8Case, case-gates/src/index.ts:183), so a quality or fairness miss leaves the bundle blocked. Provenance — seed, model versions, canon-snapshot hash, signer key — is recorded on every run, which is what makes a case reproducible from (seed, model-versions, canon-snapshot-hash).

Minos, the ASP sidecar, and compiling to V5#

Minos can offload the uniqueness proof to a clingo/ASP container via the sidecar (POST /solve, handleSolve, apps/v8/minos-asp-sidecar/src/index.ts:29), which emits the ASP program for audit and returns whether the clingo backend is available — falling back to the in-process DPLL solver for an identical verdict when no binary is present. Daedalus closes the loop: its CLI runs generate→verify→compile and, on a green Minos verdict, emits the case as V5's FV5* Mind-Palace structs plus a cold_cases_manifest.json so a generated case drops into the existing shipping game with no rewrite (runCli, apps/v8/daedalus-compiler/src/cli.ts:55). A standalone compile is honestly labelled a draft and skips the all-gates-green Python gate unless --release is passed.

Determinism, refusals, and where V8 sits#

A run is parameterized by a seed and a canon snapshot, and the journal records each stage so a case can be replayed and audited — determinism is both a provenance lever and a cost lever (a popular case is minted and gated once). The system is built to refuse rather than fabricate, and the refusals are specific: an under-determined or wrong-culprit case is rejected by proveCaseUniqueness; an absent prose writer throws CaseBundleNotConfiguredError; an absent media provider yields a not-configured slot; unscanned content keeps G6 red; any gate failure blocks publish and journals the reason. V8 is a domain product on the shared Oshun platform — it reuses the platform's content-release-gate service, content-signing, and quality-judge grounding gate rather than re-implementing them, which is why its net-new footprint is small; the platform substrate it builds on is described in ../../platform/oshun-domain-libraries.html.