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.
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.
Related#
- The section hub: ../V8_ARCHITECTURE.md, and the product framing in ../README.md
- ./canonical-data-contracts.md —
CaseSpec,CaseGroundTruth, and theMysterySessionIR that let independent subsystems work in parallel - ./clew-minos-palimpsest-symbolic-core.md — the symbolic core in depth: generation, the uniqueness/fair-play verifier, and the continuity graph
- ../../platform/oshun-domain-libraries.html — the shared platform libraries V8 composes (release gates, content signing, quality judge)