Metis · Features

Prometheus — the Solve-First Lesson Forge

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

10sections17 minread1diagram1table

On this page

Prometheus is the orchestrator that turns a single free-text wonder — "how old is the universe?", "why is the night sky dark?" — into a verified, gated, provenance-stamped V9LessonArtifact, generated on demand rather than pulled from a catalog. It is one async function, forgeLesson (libs/v9/prometheus/src/pipeline.ts:111), that composes the four wired V9 substrates (Atlas to resolve, the Nyx/Kalika kernels to compute, Hephaestus to build the explorable, Mnemosyne to schedule the retrieval) plus Aletheia and the seven contract gates, and refuses to deliver anything that fails one of them. The naming is the thesis: Prometheus stole fire — knowledge — and handed it down, but here the fire is checked at every seam before it reaches a learner. This page is the features-side deep dive the overview and the subsystem map both point at for "the forge stages, end to end"; the hub for the set is ../V9_features.md and the full mechanics live in ../V9_ARCHITECTURE.md.

The defining engineering decision is solve-first: the LLM never gets to freestyle the facts. Before a single word of prose is written, Prometheus assembles a verified skeleton — every factual claim bound to a vetted Sophia source pin, every STEM number recomputed from a real in-repo kernel rather than asserted — and the language model's only job is to "realize" that skeleton into Socratic prose, constrained so that every assertion traces back to a grounded claim by index. This is the V8 detective-engine discipline ("the LLM proposes, the verifier disposes") retargeted from fairness to truth. It is why V9 can promise a lesson that is interactive and memorable without promising a lesson that is confidently wrong: the surface is generative, but the substance is solved.

What ships, honestly#

The forge is real and tested. forgeLesson runs the whole "ask a wonder → grounded, gated, provenance-stamped lesson" path as a single function, and its spec (libs/v9/prometheus/src/pipeline.spec.ts, five cases) exercises the delivered-artifact path, byte-for-byte determinism, the profile-class cache hit, the blocked path (a denied safety gate yields no artifact and no cache entry), and the fail-loud path (no writer wired throws LessonWriterNotConfiguredError). The end-to-end case forges "how old is the universe?" against the real @kalika/cosmology Friedmann solver and asserts the delivered value lands in 13.6 < x < 14.0 Gyr — a number derived, not pasted.

Three honesty notes a careful reader needs, all grounded in the tree rather than the design doc:

  • The forge spans nine architectural stages (0–8) and runs eight of them. V9_ARCHITECTURE.md §3 actually lists ten stages (0–9), but the last — 9 Deliver — is the L6 experience layer (buildLessonPlayer), not the forge; Prometheus owns stages 0–8, which is why the sibling pages call it the nine-stage forge: 0 Resolve, 1 Ground, 2 Plan, 3 Write, 4 Realize media, 5 Build explorable, 6 Assess, 7 Gate, 8 Compile. The code comment at the top of pipeline.ts lists 0 → 1 → 2 → 3 → 5 → 6 → 7 → 8 and skips stage 4. That is deliberate: stage 4 is the Isis/Euterpe/Psyche asset realization (visuals, score, the Chiron face/voice), and those are provider-gated generators V9 does not run. The forge therefore treats media as an injected pass-through (input.media ?? { visuals: [] }, pipeline.ts:213) — a caller supplies asset refs, the forge folds them into the surfaceHash, and nothing is fabricated. So the "nine stages" the sibling docs name are the forge's architectural slots 0–8; the runnable forge is eight.
  • The writer is a fail-loud seam, not a wired model. V9 owns no agent loop (the repo's "no new agent loops" rule), so Stage 3 generation is the injected Iris boundary LessonWriter. With none wired, realizeNarrative throws LessonWriterNotConfiguredError (write.ts:78) — refusing to fake a lesson is the opposite of a stub. The same is true of the optional MisconceptionAnticipator, WonderEmbedder, QualityJudge, and the G6 policy/age seams.
  • Two evaluators are deliberately scoped. The G2 kernel registry computes six cosmology / physical-constant refs today (libs/v9/aletheia/src/kernel-evaluators.ts), extensible via an injected KernelEvaluator; and the default defaultQualityJudge (G5) is an honest deterministic structural proxy for the injected LLM-judge panel, not a fake LLM. Both are overridable through ForgeLessonInput.

Two artifacts in one: the verified skeleton and the regenerable surface#

The whole trust model rests on a split baked into the contract (libs/contracts/src/v9/lesson.ts). A V9LessonArtifact carries a groundTruth — the verified skeleton, authoritative and immutable post-gate — and a narrative/media pair — the regenerable surface that can be re-skinned over the same gated truth. groundTruth holds V9GroundedClaims (each: text, 1–16 Sophia pins, an epistemicStatus, and an Aletheia truth verdict where only 'true' clears G1) and V9KernelResults (a computed scalar plus its tolerance and a contentHash). The narrative holds beats, socraticTurns, and anticipated misconceptions, and — crucially — every Socratic turn and misconception references its grounding claim by index (claimRefs). The artifact's own top-level superRefine (lesson.ts:218) rejects any claimRef that does not point at a real claim, so the teacher's words cannot drift off the skeleton even at the schema layer.

That split is fingerprinted as two separate hashes: skeletonHash over groundTruth, surfaceHash over narrative + media (compile.ts:39, compile.ts:43). The payoff is both trust and cost: a different Chiron persona, voice, or visual treatment changes only the surfaceHash; the gated truth — and its skeletonHash — is untouched, so a re-skin does not require re-verification.

The forge, stage by stage#

forgeLesson is a linear composition; each stage hands a typed value to the next, and a failure anywhere upstream of the gate throws rather than degrading.

Stage 0 — resolve (Atlas)#

resolveWonder(input.wonder, input.atlas, …) (pipeline.ts:113) turns the free-text question into a target concept and a prerequisite-first conceptSet, scoped to the learner's mastery. Sophia BM25 picks lexical candidates, an optional Nous WonderEmbedder reranks densely, and Mnemosyne's gap analysis plus a topological sort return the minimal teaching set. An unresolvable wonder throws rather than inventing a concept. The mechanics live in ./atlas-wonder-resolution.md.

Stage 1 — ground / solve-first (the heart)#

buildGroundTruth (ground-truth.ts:43) walks the resolved concept set and assembles the verified skeleton from the real grounded Atlas nodes — nothing here is generated:

  • A grounded fact node contributes a V9GroundedClaim carrying its Sophia pins (sliced to the contract max of 16, ground-truth.ts:57), its epistemicStatus, and truth: 'true'. The claim sentence defaults to the node label but can be overridden per concept via claimTextByConcept.
  • Every STEM kernelRef on a node is computed, not asserted: the default KernelEvaluator runs the real in-repo computation (e.g. kalika:cosmology#ageTodayGyrageTodayGyr(PLANCK_2018_COSMOLOGY)), and the result is recorded as a V9KernelResult with a tolerance of 1e-6 and a contentHash = sha256([ref, params, value]) (ground-truth.ts:67). Each computed value also emits a GroundTruthNumericClaim — the asserted-vs-computed pair the G2 accuracy gate later re-checks.

If the concept set yields no grounded fact node, buildGroundTruth throws ("refusing to forge an ungrounded lesson", ground-truth.ts:86). A lesson with nothing to ground is refused, not faked. This is the function that makes "solve-first" literal: by the end of Stage 1 the lesson's entire factual and numeric substance already exists, verified, before any model is invoked.

Stage 2 — plan (deterministic HTN)#

planLesson (plan.ts:35) decomposes the skeleton into a LessonPlan: the beat outline (Hook → Establish[i] for each claim → Why it matters → The next question), which concept binds the explorable (the forge passes the resolved target concept — explorableConceptId: target.id, pipeline.ts:132; when no override is supplied, planLesson's own fallback is the last concept in the set, plan.ts:52), the Chiron personaRef (default chiron:warm-generalist), a one-line Euterpe scoreBrief, and the assessmentClaimRef — the index of the most-established claim, chosen by max(pin.credibility) (plan.ts:47), so the retrieval checkpoint probes the lesson's highest-confidence fact. The plan is deterministic: the same skeleton + seed always plans the same lesson, which is one half of the determinism lever Stage 8 cashes in.

Stage 3 — write (constrained realization + misconception pass)#

realizeNarrative (write.ts:77) is where the LLM finally enters — and where it is fenced in. It calls the injected LessonWriter to produce a draft (beats + Socratic turns + optional misconceptions), then enforces the grounding constraint: every turn's claimRefs must index a real claim, or the writer's output is rejected with claimRef … outside [0, nClaims) (write.ts:87); a draft with zero beats is rejected too (write.ts:94). A misconception pass merges the writer's anticipated misconceptions with the default anticipator (defaultMisconceptionAnticipator, write.ts:49), which flags every non-established claim (contested / one-tradition / frontier) as misread-prone and pairs it with a grounded correction, deduping by text. With no writer wired, the whole stage fails loud. The output is a contract V9Narrative.

Stage 4 — realize media (the pass-through seam)#

The architecture's Stage 4 (Isis visuals, Euterpe score, Psyche face/voice) is not run in-repo — those are provider-gated generators. The forge instead accepts a media value on its input and defaults it to { visuals: [] } (pipeline.ts:213). The media is real input, folded into the surfaceHash; it is simply not generated here. See ./chiron-and-hephaestus.md and ./governance-and-boundaries.md for the embodiment and provider-gating story.

Stage 5 — explorable (Hephaestus)#

input.explorableBuilder(plan.explorableConceptId) (pipeline.ts:147) binds the chosen concept to a manipulable surface — typically a computed-kernel explorable like the Kalika orbit sim or the Nyx "time-travel" sky. The DoD V9 enforces is that every P1 lesson ships ≥1 computed-kernel explorable whose success state was demonstrably reached (successState.reachable === true), proven by the kernel output, never asserted blind. That DoD becomes the G4 gate. See ./chiron-and-hephaestus.md.

Stage 6 — assess & schedule (Mnemosyne)#

applyRetrievalCheckpoint (pipeline.ts:151) turns the target concept into an FSRS card and schedules the next retrieval at the forgetting frontier — when recall is hardest-but-possible (the testing effect). The forge assembles a V9MnemosyneSchedule (checkpointRef, intervalDays, nextReviewAtIso) and a V9Assessment whose active-recall prompt is built from the most-established claim (Recall: …, pipeline.ts:164). If flowHistory is supplied, tuneDifficultyToFlow reuses the Mnemosyne IRT ability MLE to place the next item in Csíkszentmihályi's flow band (success probability in [0.6, 0.85]), and the resulting FlowChannel feeds G3. The FSRS mechanics are detailed in ./threads-and-mastery-loop.md.

Stage 7 — gate (G1–G7)#

This is where the seven contract gates are computed and composed. Aletheia owns the three truth-shaped gates and runs them in parallel under Promise.all (runAletheia): G1 grounding (every claim has a credible Sophia pin), G2 accuracy (every STEM number recomputed within tolerance), G6 safety (epistemic-status label on every claim + Metis/Sekhmet policy, fail-loud on a high-stakes discipline). Prometheus composes the other four in composeGates (gates.ts:132): G3 pedagogy (evaluatePedagogy — prerequisite coverage, ≥1 misconception, in-flow difficulty), G4 completeness (the Hephaestus explorable DoD), G5 quality (evaluateQuality against a 0.7 threshold), and G7 provenance (evaluateProvenance — the C2PA hashes are well-formed 64-hex and the ledger id is present). The full per-gate mechanics, the two different seven-gate numberings, and the fail actions are the subject of ./subsystem-map-and-gates.md; this page focuses on how the gate verdict steers the forge. At a glance — the seven runtime gates, the function that computes each, what it verifies, and what a failure does:

Gate Owner (function) What it verifies On failure
G1 grounding Aletheia evaluateGrounding every claim binds ≥1 Sophia pin at ≥0.5 credibility (plus Sophia entailment when a CitationVerifier is wired); an unsupported evidence-bundle verdict blocks reground
G2 accuracy Aletheia evaluateAccuracy every STEM number recomputes within tolerance via the real Nyx/Kalika kernel; an unknown ref blocks regenerate-with-corrected-ground-truth
G3 pedagogy Prometheus evaluatePedagogy prerequisite coverage (minus already-mastered prereqs), ≥1 anticipated misconception, in-flow difficulty block → re-plan
G4 completeness Hephaestus evaluateExplorableDoD ≥1 computed-kernel explorable demonstrably reached its success state block
G5 quality Prometheus evaluateQuality narrative quality score ≥ 0.7 (injected judge panel, or the deterministic structural default) block → revise
G6 safety Aletheia evaluateSafety an epistemic-status label on every claim + the Metis/Sekhmet policy; high-stakes disciplines (religion, psychology, neuroscience) additionally require a human-review checkpoint block-or-escalate
G7 provenance Prometheus evaluateProvenance skeletonHash/surfaceHash/cacheKey are well-formed 64-hex and ledgerEntryId is present block

Only G1/G2/G6 — the Aletheia-owned gates — carry a named directed-regeneration action (the AletheiaFailAction union below); G3/G4/G5/G7 simply block the artifact and route the fix back to the offending stage.

Two forge-level details worth pinning down. First, the safety scan runs over the realized prose, not just the claims: content is [...narrative.beats, ...groundTruth.claims.map(c => c.text)].join('\n') (pipeline.ts:180). Second, G3's prerequisite check excludes already-mastered prerequisites — the forge derives masteredConcepts from the learner's learnerMastery map (levels advanced/expert/master, pipeline.ts:198) so a learner is not re-taught what they already hold.

The forge then computes blockedGateIds = ALL_GATE_IDS.filter(id => !gates[id].pass) (pipeline.ts:232). If anything is blocked, it returns without an artifact (next section). G7 is evaluated on a previewProvenanceBundle (pipeline.ts:214) — a deterministic, content-addressed bundle identical to the one Stage 8 will compile — so the provenance verdict computed before compile is valid for the compiled artifact.

Stage 8 — compile & cache#

Only a fully-passing lesson reaches compileLesson (compile.ts:152). It:

  1. computes the (conceptSet, profileClass, seed) cache key (cacheKeyFor, order-independent in concepts, compile.ts:31) and returns a cache hit immediately if one exists (servedFromCache: true);
  2. re-derives the C2PA previewProvenanceBundle (the same skeletonHash, surfaceHash, deterministic ledgerEntryId = ledger:<cacheKey[:32]>);
  3. parses the assembled V9LessonArtifact through V9LessonArtifactSchema.parse (compile.ts:169) — so the artifact is contract-valid by construction;
  4. appends an immutable generation-ledger entry (InMemoryGenerationLedger.append never overwrites an existing id, compile.ts:67) and caches by the profile-class key.

Back in forgeLesson, a final defensive check runs: if isV9LessonPublishable(compiled.artifact) disagrees with the gate sum, it throws rather than ship (pipeline.ts:257). The contract's own publishability and the pipeline's gate accounting must agree, or the build fails loudly.

sequenceDiagram participant L as Learner (wonder) participant P as forgeLesson participant A as Atlas participant K as Kernels (Nyx/Kalika) participant W as Iris writer (seam) participant H as Hephaestus participant M as Mnemosyne participant Al as Aletheia + gates participant C as compile + cache L->>P: wonder, seed, profileClass P->>A: resolveWonder (S0) A-->>P: target + conceptSet P->>K: buildGroundTruth (S1, solve-first) K-->>P: claims + computed values (verified skeleton) P->>P: planLesson (S2, deterministic HTN) P->>W: realizeNarrative (S3, constrained) W-->>P: beats + Socratic turns (or fail loud) P->>H: explorableBuilder (S5) H-->>P: computed-kernel explorable P->>M: applyRetrievalCheckpoint (S6) M-->>P: schedule + assessment + flow channel P->>Al: runAletheia + composeGates (S7) alt any gate fails Al-->>L: BLOCKED — no artifact, blockedGateIds else all seven pass Al-->>P: G1..G7 pass P->>C: compileLesson (S8) C-->>L: V9LessonArtifact (cached, C2PA-stamped) end

A worked forge: "how old is the universe?"#

The end-to-end spec traces a real run. Stage 0 resolves the wonder (aliased on the Atlas node) to the kalika:age-of-the-universe target with a cosmos:cosmology-basics prerequisite. Stage 1 grounds it: the fact node yields a claim pinned to src:planck-2018 (credibility 0.98), and its kernelRef computes ageTodayGyr(PLANCK_2018_COSMOLOGY) ≈ 13.8 Gyr from the Friedmann integral — the number is solved, with a contentHash over the computation. Stage 2 plans the beats and picks the Planck-pinned claim as the retrieval target. Stage 3's deterministic test writer realizes the skeleton into a hook, an "establish" beat, a Socratic turn citing claimRef 0, and one misconception ("the universe is infinitely old" → "it has a finite, measurable age"). Stage 5 builds a Kalika orbit explorable whose success state is reached by the integrator. Stage 6 schedules the FSRS retrieval; the [correct, correct, incorrect] flow history tunes the next item into the flow band. Stage 7 runs all seven gates green — G2 matches the asserted 13.8 against the recomputed value within tolerance. Stage 8 compiles a V9LessonArtifact, stamps a 64-hex skeletonHash, writes the ledger entry, and caches it. The spec then forges the same inputs again and asserts an identical skeletonHash, surfaceHash, and id — and that a second forge sharing the cache returns servedFromCache: true.

Blocked lessons and regenerate-with-direction#

Gates block; they do not warn. When any gate fails, forgeLesson returns { blocked: true, blockedGateIds, gates, aletheia, conceptSet } with no artifact (pipeline.ts:235), and because compile never runs, a failing lesson is never cached (the spec asserts cache.get(cacheKey) is undefined). The intelligence in the retry comes from the AletheiaFailAction union, which makes the regeneration directed rather than a blind re-roll: reground (G1 — re-ground or drop the claim), regenerate-with-corrected-ground-truth (G2 — the kernel value is authoritative, the prose is wrong), and block-or-escalate (G6 — a safety failure routes to editorial, it does not silently regenerate). runAletheia de-duplicates the distinct actions across the failed gates so an orchestrator applies each correction once. In the spec's blocked case, a Sekhmet seam that denies (allowed: false) fails G6, and the run returns blocked with G6 in blockedGateIds and no artifact.

Determinism: a provenance guarantee and a cost lever#

Determinism is not incidental — it is engineered, because it pays twice. The plan, the hashes, and the ledger id are all derived from content ((conceptSet, profileClass, seed) and the skeleton/surface), so the same inputs always produce the same artifact. As a provenance guarantee, that means a lesson's skeletonHash is a stable fingerprint of its verified truth. As a cost lever, it means a popular lesson is gated once and then served from the profile-class cache many times — note the cache key is the learner profileClass, not the learner id, so two "curious-adult" learners asking the same wonder share one gated artifact. The cross-cutting verifier proves it: verifyForgeDeterminism runs a forge twice and assertDeterministic (libs/v9/cross-cutting/src/determinism.ts:44) blocks promotion on any field mismatch across id, seed, skeletonHash, surfaceHash, cacheKey, or groundTruth.

Edge cases and failure modes#

The forge's correctness story is mostly about what it refuses to do:

  • No grounded fact ⇒ no lesson. buildGroundTruth throws rather than forge an ungrounded lesson (ground-truth.ts:86).
  • A writer that drifts off-skeleton is rejected. An out-of-range claimRef or a zero-beat draft throws inside realizeNarrative (write.ts:87, write.ts:94), and the contract superRefine is a second, schema-level guard.
  • A lesson of only established facts can be blocked by G3. evaluatePedagogy requires ≥1 anticipated misconception (gates.ts:54); since the default anticipator only flags non-established claims, a lesson built entirely from settled facts whose writer anticipates nothing has no misconception and fails G3 — a deliberate pedagogical floor.
  • Out-of-flow difficulty blocks G3. If a flowHistory tunes the next item to boredom or anxiety rather than flow, G3 blocks (gates.ts:60).
  • An unreproducible number blocks G2. An unknown kernel ref or a relative error beyond tolerance fails the accuracy gate — "you cannot ship a number you cannot reproduce."
  • Unwired seams fail loud. The Iris writer (and, transitively, the whole forge) throws LessonWriterNotConfiguredError rather than fabricate.
  • The contract and the pipeline must agree. If isV9LessonPublishable contradicts the gate sum post-compile, the forge throws (pipeline.ts:257).

Configuration — the injected dependencies#

Almost all of Prometheus's behaviour is the shape of ForgeLessonInput (pipeline.ts:53). The required surface is small — wonder, atlas, learnerProfileClass, seed, a caller-supplied nowUnixMs (no fabricated clock), signedAtIso, an opaque runId, the explorableBuilder, and the retrievalScore. Everything else is an optional injected boundary: writer and misconceptionAnticipator (Iris), embedder (Nous dense rerank), claimTextByConcept (per-concept claim sentences), learnerMastery (drives both wonder-scoping and the G3 prerequisite exclusion), flowHistory (G3 flow tuning), qualityJudge and safetyOptions (the G5/G6 evaluators), humanReviewed and nextWonders, and the media, cache, and ledger for Stage 8. Swapping the KernelEvaluator (on buildGroundTruth) or the QualityJudge is how the two deliberately-scoped defaults are extended without touching the forge.

How Prometheus connects to its neighbours#

Prometheus is the spine the other subsystems hang off, but it owns very little itself — by design, V9 adds no new agent loop and no new providers. It resolves through Atlas (./atlas-wonder-resolution.md), grounds and gates through Aletheia and the kernel registry, builds through Hephaestus and delivers through Chiron (./chiron-and-hephaestus.md), schedules through Mnemosyne (./threads-and-mastery-loop.md), and opens the next wonder through Theia's threads (./braid-commons-and-films.md). Its output, the gated V9LessonArtifact, is consumed downstream by the experience layer: buildLessonPlayer (libs/v9/experience/src/lesson-player.ts) projects it into the player screen — the grounded explanation, the "show your sources" transparency panel (every claim with its pins and epistemic label), the explorable canvas, and the active-recall checkpoint — and refuses to build a player for an ungated lesson (UngatedLessonError). The cost, determinism, entitlement, and anti-metric guardrails that bracket every forge live in ./governance-and-boundaries.md. For the gate mechanics this page deliberately summarizes, read ./subsystem-map-and-gates.md.