# Metis — Education and Tutoring

> **Release: V1.2.** Metis is not part of V1.0. Everything on this page stays in
> the tree and stays worth building — the room has to be stocked and reviewed
> before it opens — but no V1.0 console may advertise, link to, count, or
> compose it. V1.0 opens Tara, Nyx, Arete, and Nisaba; see
> [`V1/BRAND.md`](../BRAND.md).

Metis is the educational substrate of Oshun V1 — the domain that turns approved
source material into grounded courses, runs an adaptive tutor loop, calibrates
assessments with real psychometrics, and emits grades and integrity verdicts to
institutional systems. It serves three audiences at once: the self-directed
learner who wants a structured path through hard ideas, the teacher or
institution that needs standards-conformant delivery and a defensible gradebook,
and the platform operator who has to keep a high-risk bring-your-own-model
surface safe. It sits in the same single Oshun shell as the contemplative domain
([Tara — Rituals and Contemplative Practice](./domain-tara.md)), the goals
domain ([Arete — Goals, Habits, and Reflection](./domain-arete.md)), and the
scholarly-study domain ([Nisaba — Scholarly Study](./domain-nisaba.md)).

Among the V1 domains, Metis is one of the **most heavily implemented at the
library level**: eleven canonical Zod contracts, real Item Response Theory, real
Bayesian Knowledge Tracing and FSRS-5, a full LTI 1.3 / SCORM / OneRoster / QTI3
/ Caliper / Open Badges integration layer, and a ~980-LOC tenant-model safety
harness all exist on disk. **Yet it is not a live launch surface.** The domain
registry marks Metis `availability: 'planned'`, which means
`getAvailableDomains()` filters it out of the shell. This page reads Metis as
product _and_ as code, and it is candid throughout about the gap between the
roadmap intent ("launch-blocking") and the current launch state ("planned").

The completion state of every item lives in [`../TODOS.md`](../TODOS.md) (bare
`§N` references point there); cross-domain build ordering lives in
[`../DEPENDENCIES.md`](../DEPENDENCIES.md) (`deps§N`). The hub feature list is
[`../features.md`](../features.md). Companion runtime views are
[Customer Domains](../architecture/customer-domains.md) and
[Cross-Domain Support](../architecture/cross-domain-support.md).

---

## What is real, what is planned

Because this domain's docs have historically overstated launch readiness, it is
worth front-loading the honest split before describing the parts.

**Implemented (verified by reading code):**

- All eleven canonical contracts are real Zod schemas in
  `libs/contracts/src/metis/index.ts`, re-exported as a namespace
  (`export * as MetisContracts from './metis'`,
  `libs/contracts/src/index.ts:103`).
- The six-band mastery model with per-band evidence vectors and half-life decay
  (`libs/metis/learning/src/mastery/`).
- The six-axis personalization manifold as a real schema
  (`LearnerPersonalizationStateSchema`,
  `libs/contracts/src/metis/personalization.ts`).
- A typed institutional gradebook with correction events and role-redacted views
  (`libs/contracts/src/metis/gradebook.ts` and
  `libs/metis/gradebook/src/emission.ts`).
- Real psychometrics: 1PL/2PL/3PL IRT with calibration and DIF monitoring
  (`libs/metis/assessment`); BKT, FSRS-5, and graph knowledge tracing
  (`libs/metis/adaptive`).
- The six-core-discipline taxonomy as typed data with anchor mappings
  (`libs/metis/learning/src/subject-taxonomy/`).
- Real standards plumbing — LTI 1.3 `id_token`/JWKS verification, SCORM-2004
  RTE, OneRoster dry-run, QTI3 export/import, Caliper, Open Badges
  (`libs/shared/inbound-integrations` and
  `libs/metis/integrations/src/standards/`).
- A full BYOM tenant-model safety harness with quarantine, kill-switch,
  fail-closed, and abuse monitoring
  (`libs/shared/inbound-integrations/src/byom-model.ts`).
- The grounded-generation `VerificationGate` and generate-verify-refine loop
  (`libs/metis/verification`).
- BFF routes for integrity adjudication/appeal/audit, tutor-session memory, and
  BYOM decisions (`apps/oshun/bff/src/routes/`).

**Aspirational / not yet:**

- **Metis is not a live shell surface.** `availability: 'planned'`
  (`libs/oshun/domain-registry/src/registry.ts:489`) is filtered by
  `getAvailableDomains()` (registry.ts:503). The 2026-06-23 triage confirms the
  shell drops Metis to `planned` post-hydration (shell domain count 5→4).
  "Launch-blocking V1 scope" is a roadmap _intent_, not the current state.
- The **P95 ≤ 600 ms adaptive-loop latency budget** is a spec assertion. There
  is a related budget-ceiling primitive in the verification lib
  (`MODE_CEILINGS`, `checkBudgetCeilings` in
  `libs/metis/verification/src/hardening/budget-ceiling.js`), but no runtime
  gate was found that enforces a 600 ms next-item ceiling on the live tutor
  loop.
- Several cross-domain wirings the prose claims do **not** exist as files. Only
  `aja`, `iris`, `isis`, `lilith`, `psyche`, `sophia`, `themis`, and `yemaya`
  ship a `*-canonical-wiring.ts` under `libs/metis/integrations/src/`. There is
  **no** Tara, Nyx, Veritas, Nisaba, or Arete canonical wiring, despite the
  feature list naming them (`features.md`).
- The headline **BYOM ingest-to-course pipeline** is graded "partial/uncovered"
  in the 2026-06-22 completeness audit. To be precise about the split: the BYOM
  _contracts_ and gate primitives (`byom.ts`, `byom-model.ts`, the
  `VerificationGate`) are real on disk; what is partial is the **end-to-end
  ingest-to-course wiring** that would carry a member's uploaded material
  through validation into a live course.
- There is **no dedicated `metis` PostgreSQL database**.
  `docker/docker-compose.dev.yml`'s `POSTGRES_MULTIPLE_DATABASES` lists
  `yemaya,lilith,isis,iris,sophia,hathor,bellona,calliope,tara,maat,nisaba,shakti,cybele,kalika,lakshmi,athena,oya`
  — `metis` is absent. Metis's storage strategy (shared `oshun_dev` vs. domain
  tables) is undocumented and is a genuine gap.

---

## Where Metis lives in the product

### Consumer surfaces

The consumer hub is `/metis`, with presentational depth under
`apps/oshun/web/src/app/metis/`. The real route tree is **larger than the four
surfaces the feature list enumerates** (`features.md` lists only
`/metis/assessment`, `/metis/byom`, `/metis/lesson`, `/metis/tutor`). On disk
the directory tree is:

| Route                | Purpose                       |
| -------------------- | ----------------------------- |
| `/metis`             | Consumer hub landing          |
| `/metis/assessment`  | Assessment delivery surface   |
| `/metis/byom`        | Bring-your-own-material entry |
| `/metis/lesson`      | A single lesson               |
| `/metis/lessons`     | Lesson list                   |
| `/metis/tutor`       | Tutor runtime                 |
| `/metis/session`     | A tutoring session            |
| `/metis/courses/new` | Course creation               |
| `/metis/ingest`      | Source ingestion              |
| `/metis/upload`      | File upload                   |

The feature list's omission of `/metis/lessons`, `/metis/session`,
`/metis/ingest`, `/metis/upload`, and `/metis/courses/new` is under-listing, not
inaccuracy. The heavier study, mastery, and academic-integrity tools are mounted
inside this consumer hub rather than a separate power-user namespace.

### The `/domains/metis` vs `/metis/*` split

There is a real disagreement between the registry and the shipped web routes
that the feature list notes but does not reconcile. `features.md` states "Metis
does not yet ship a `/domains/metis/*` power-user namespace" — true at the
web-app level, since there is no `apps/oshun/web/src/app/domains/metis`
directory. **But** the domain registry declares `route: '/domains/metis'` and
`'bff-base-path': '/api/oshun/domains/metis'` with
`launch.defaultPath: '/courses'` (`registry.ts:425, 435, 448`). The registered
route family (`/domains/metis`) and the shipped consumer routes (`/metis/*`)
diverge; the `/domains/metis` route is declared metadata that the consumer shell
does not yet materialize. This is consistent with the domain still being
`planned`.

### Operator review surface

The shipped review surface is **`/operator/metis`**
(`apps/oshun/web/src/app/operator/metis/page.tsx`), not an `/admin/metis` route.
The feature list's reference to "Admin Metis dashboards" (`features.md`) maps to
two distinct things: (1) the consumer-shell review UI at `/operator/metis`, fed
by BFF routes prefixed `/metis/integrity` under operator scope, and (2) the
standalone `apps/metis/admin` application (62 `.ts`/`.tsx` files). There is no
`/admin/metis` route inside `apps/oshun/web`.

### Standalone Metis apps

All five `apps/metis/*` subdirectories exist — correcting an earlier
ARCHITECTURE snapshot that doubted `mobile`: `web` (93 ts/tsx files), `admin`
(62), `api-gateway` (29), `worker` (21), and `mobile` (6).

### Registry metadata

The Metis entry in `libs/oshun/domain-registry/src/registry.ts:422-490`:

| Field                    | Value                                                               |
| ------------------------ | ------------------------------------------------------------------- |
| `id`                     | `metis`                                                             |
| `route`                  | `/domains/metis`                                                    |
| `bff-base-path`          | `/api/oshun/domains/metis`                                          |
| `deep-link-prefix`       | `oshun://metis`                                                     |
| auth scopes              | `course:read`, `course:write`, `tutor:session`, `assessment:submit` |
| step-up actions          | `submit-assessment`, `publish-course-package`, `connect-lms`        |
| `launch.defaultPath`     | `/courses`                                                          |
| `launch.quickActionPath` | `/tutoring`                                                         |
| `accentColor`            | `#2563EB`                                                           |
| `icon`                   | `graduation-cap`                                                    |
| `availability`           | `planned`                                                           |

---

## Subject-matter focus: the six core disciplines as code

Metis's curriculum is deliberately weighted toward the **six disciplines that
converge on the human mind, meaning, belief, behavior, culture, and our place in
the cosmos** — philosophy, religion, psychology, neuroscience, anthropology, and
astronomy. STEM and other fields are first-class _supporting_ subjects, taught
where they illuminate the core six.

What the prose does not say is that **this taxonomy is codified typed data**,
not just editorial intent. In
`libs/metis/learning/src/subject-taxonomy/subject-taxonomy.ts`:

```ts
type CoreMetisDiscipline =
  | 'philosophy'
  | 'religion'
  | 'psychology'
  | 'neuroscience'
  | 'anthropology'
  | 'astronomy';

type MetisSubjectRole = 'core_headline' | 'supporting_scaffold';
```

`SUPPORTING_METIS_SUBJECTS` enumerates the scaffolding fields (mathematics,
physics, biology, chemistry, computing, history, arts, languages,
social_studies). Each `LearningSubjectDefinition` carries a `headlineAllowed`
flag and a `scaffoldingOnlyByDefault` flag, so the "supporting, not headline"
policy is enforceable rather than advisory. A `SUPPORTING_TO_CORE_ANCHOR` map
records the convergence rule literally — e.g. `cosmology → astronomy`,
`culture → anthropology` — and there are typed structures for per-discipline
`CurriculumSeedPack` (subfield ontology, prerequisite graph, canonical reading
list, misconception bank, worked-example library), `DisciplineSafetyPolicy`
(stance, required labels, prohibited patterns such as `'astrology as science'`,
abstention rules), `ReviewerPoolRequirement` (quorum and credential rules), and
`ReleaseGateCoverageRequirement` (per-discipline gold-set counts).

---

## Canonical contracts

The eleven named contracts are not interface sketches — they are
runtime-validating Zod schemas in `libs/contracts/src/metis/index.ts`, each with
`superRefine` cross-field invariants, exported through the `MetisContracts`
namespace.

| Contract                     | Schema symbol                      | Line |
| ---------------------------- | ---------------------------------- | ---- |
| Learning source bundle       | `LearningSourceBundleSchema`       | 251  |
| Grounding pack               | `GroundingPackSchema`              | 461  |
| Course build                 | `CourseBuildSchema`                | 643  |
| Lesson asset bundle          | `LessonAssetBundleSchema`          | 978  |
| Publication package          | `PublicationPackageSchema`         | 1226 |
| Tutor persona profile        | `TutorPersonaProfileSchema`        | 1425 |
| Tutor session memory         | `TutorSessionMemorySchema`         | 1605 |
| Learning objective map       | `LearningObjectiveMapSchema`       | 1706 |
| Assessment evidence pack     | `AssessmentEvidencePackSchema`     | 1845 |
| Learning telemetry statement | `LearningTelemetryStatementSchema` | 2020 |
| Academic integrity verdict   | `AcademicIntegrityVerdictSchema`   | 2151 |

These contracts span the whole pipeline: **source → grounding → course → lesson
asset → publication** for the authoring path, **tutor persona → session memory**
for the runtime, and **objective map → evidence pack → telemetry → integrity
verdict** for the assessment and oversight path. The invariants are real — for
example, the telemetry statement (`LearningTelemetryStatementSchema`) rejects a
statement whose `stored` timestamp precedes its `timestamp`, and rejects an
LRS-exportable statement with a null `authority`.

---

## The library landscape

The `@metis/*` libraries are substantial. Approximate non-test LOC:

| Library                  | Path                         | ~LOC  | Role                                    |
| ------------------------ | ---------------------------- | ----- | --------------------------------------- |
| `@metis/agents`          | `libs/metis/agents`          | 23.3K | Agent runtime, orchestration, verifiers |
| `@metis/knowledge-graph` | `libs/metis/knowledge-graph` | 19.2K | KG construction and GraphRAG retrieval  |
| `@metis/integrations`    | `libs/metis/integrations`    | 18.5K | Standards and cross-domain wirings      |
| `@metis/assessment`      | `libs/metis/assessment`      | 12.4K | IRT, DIF, adaptive item selection       |
| `@metis/adaptive`        | `libs/metis/adaptive`        | 8.5K  | BKT / FSRS-5 / graph knowledge tracing  |
| `@metis/core`            | `libs/metis/core`            | 6.1K  | Core domain types                       |
| `@metis/learning`        | `libs/metis/learning`        | 5.5K  | Mastery bands, decay, subject taxonomy  |
| `@metis/tutoring`        | `libs/metis/tutoring`        | 4.3K  | Hint ladder, tutor modes                |
| `@metis/course`          | `libs/metis/course`          | 4.2K  | Course build                            |
| `@metis/verification`    | `libs/metis/verification`    | 4.1K  | Grounded-generation gate                |
| `@metis/discovery`       | `libs/metis/discovery`       | 1.5K  | Browse / recommend backing              |
| `@metis/gradebook`       | `libs/metis/gradebook`       | 0.85K | Gradebook emission                      |

> The `ARCHITECTURE.md` domain-library enumeration is stale: it omits
> `gradebook`, `discovery`, and `verification`, all of which exist on disk.

### The thin domain facade

The V1 adapter-consolidation target tracked by TODOS §1.3 (per
`ARCHITECTURE.md`) **already exists**, so the "target / tracked" framing reads
as not-yet-done when the facade is in fact present.
`libs/oshun/domain-metis/src/index.ts` is one line (`export * from './adapter'`)
and `adapter.ts` is six lines that re-export `@metis/api-client` and alias
`createMetisAdapter → createMetisDomainAdapter` and
`createMetisReadAdapterRegistry → createMetisDomainReadAdapterRegistry`. The
substantive adapter is `libs/metis/api-client/src/adapter.ts` (1,111 LOC).

---

## Tutor runtime modes

The tutor supports Socratic, direct-explanation, scaffolded-hints,
worked-example, practice, and review modes, plus a switching policy
(learner-initiated, teacher-policy-initiated, or performance-triggered —
struggle escalates scaffolding; mastery advances to the next skill — with every
switch logged in tutor session memory).

### The hint ladder is concrete

The feature list says "per-hint cost tracked" but omits the actual ladder. In
`libs/metis/tutoring/src/hints/hints.ts` the levels are an ordered enum with
fixed reveal percentages:

| `HintLevel`      | Value | Reveal % | Description                                     |
| ---------------- | ----- | -------- | ----------------------------------------------- |
| `SUBTLE`         | 1     | 0.1      | A gentle nudge in the right direction           |
| `DIRECT`         | 2     | 0.3      | Specific guidance about the concept or approach |
| `WORKED_EXAMPLE` | 3     | 0.7      | A similar problem solved step-by-step           |
| `ANSWER_REVEAL`  | 4     | 1.0      | The complete solution with explanation          |

`HINT_REVEAL_PERCENTAGES` quantifies how much of the answer each rung exposes,
so the "cost against assessment evidence" the prose mentions has a real numeric
basis: a learner who needs `ANSWER_REVEAL` consumed a full reveal, which is what
the evidence pack records. There is also a `HintCategory` axis (`CONCEPTUAL`,
`PROCEDURAL`, `STRATEGIC`, `FACTUAL`, `METACOGNITIVE`).

### Two distinct integrity-mode vocabularies

The feature list presents a single five-mode integrity vocabulary, but the code
actually has **two** that coexist and must not be conflated:

- The **assessment-mode** vocabulary (`GradebookAssessmentMode`,
  `gradebook.ts:25-31`, mirrored at `index.ts:2145`): `assessed`, `formative`,
  `practice`, `exam`, `collaborative`. These describe an _assignment's_ help
  policy.
- The **tutor-session integrity mode**
  (`TutorSessionMemoryGovernanceStateSchema`, `index.ts:1557`): `teach`, `hint`,
  `practice`, `do-not-complete-for-me`. These describe what the _tutor_ is
  allowed to do in a session. The session governance state also carries
  `oversightContext` (`independent` / `minor-supervised` / `managed-program`)
  and `oversightRoles` (teacher / guardian / institution).

The feature list shows only the five-mode set; both vocabularies are real.

---

## Academic integrity: the Themis adjudicator

Integrity adjudication routes through Themis via the `AcademicIntegrityVerdict`
contract. The detection-signal taxonomy in the code is **exactly** the ten
signals the prose lists (`index.ts:2073-2082`):

`paste_external`, `offplatform_search`, `response_pattern_anomaly`,
`generated_text_classifier`, `tutor_output_in_submission`, `pace_anomaly`,
`device_fingerprint_change`, `proctor_observation`, `peer_collaboration_breach`,
`teacher_flag`.

Each `AcademicIntegrityDetectionSignal` carries a `confidence ∈ [0,1]`, an
`observedAt` timestamp, a `summary`, and `evidenceExcerptIds`. A separate
`AcademicIntegrityClassifierOutput` records a `modelVersion`, a `label`
(`human_likely` / `ai_likely` / `mixed` / `copied` / `unknown`), a `score`, a
`threshold`, and a `calibratedAt` timestamp.

### Verdict classes — correcting the feature list

The feature list (`features.md, 1490`) names verdict classes `policy_violation`
and `severe_violation`. **The shipped enum literals are different.**
`AcademicIntegrityVerdictClassSchema` (`index.ts:2062-2066`) is:

```
clear | inconclusive | violation | severe
```

The gradebook's `GradebookIntegrityVerdictSchema` (`gradebook.ts:44-50`) adds a
fifth value for in-flight rows:

```
clear | inconclusive | violation | severe | pending
```

The doc's `_violation` long forms do not match either enum. Verdict decisions
map to a recommended action drawn from `none`, `educator_review`,
`learner_warning`, `score_hold`, `submission_reject`, `institution_escalation`
(`AcademicIntegrityDecisionSchema`), each carrying an
`AcademicIntegrityAppealPath` (`appealAllowed`, `appealBy`, `appealRoute`,
`institutionalPolicyUrl`). Evidence excerpts carry a `redactionState` of `none`
/ `learner_safe` / `operator_only`.

### Integrity BFF routes

The operator-scoped adjudication surface is wired
(`apps/oshun/bff/src/routes/metis-integrity.ts`):

- `POST {prefix}/metis/integrity` — adjudicate
- `POST {prefix}/metis/integrity/:verdictId/appeal` — open an appeal
- `GET {prefix}/metis/integrity/:verdictId/audit` — fetch the audit record
- `GET {prefix}/metis/integrity/appeals/:appealId` — appeals workspace
- a `POST` appeals workspace handler

---

## Mastery model and item calibration

Mastery is a **banded** state per `(learner, objective)` pair, not a single
scalar. The bands are codified verbatim in
`libs/metis/learning/src/mastery/evidence-requirements.ts` and mirrored as
`GradebookMasteryBandSchema` (`gradebook.ts:34-41`):

```
unintroduced → introduced → developing → approaching → mastered → maintaining
```

### Per-band evidence requirements

`PLATFORM_BAND_REQUIREMENTS` declares, for each band, a minimum evidence vector
— the transition fires only when **all** components are met; otherwise the
learner stays at the lower band rather than silently advancing:

| Band           | min items | min hard items | min distinct contexts | max recency (days) | prerequisite floor |
| -------------- | --------- | -------------- | --------------------- | ------------------ | ------------------ |
| `unintroduced` | 0         | 0              | 0                     | 365                | `unintroduced`     |
| `introduced`   | 1         | 0              | 1                     | 60                 | `unintroduced`     |
| `developing`   | 3         | 0              | 2                     | 30                 | `introduced`       |
| `approaching`  | 6         | 1              | 3                     | 21                 | `developing`       |
| `mastered`     | 10        | 3              | 4                     | 14                 | `approaching`      |
| `maintaining`  | 14        | 4              | 5                     | 30                 | `mastered`         |

`evaluateEvidence()` returns a list of explicit `failures`
(`item-count-below-floor`, `hard-items-below-floor`,
`distinct-contexts-below-floor`, `recency-window-too-wide`,
`prerequisite-band-floor-not-met`) so an unmet transition is auditable.

### Decay

Demotion is allowed and half-life-based. `decay.ts` exposes an
`ObjectiveHalfLife` metadata shape (`masteryHalfLifeDays`,
`maintainingHalfLifeMultiplier`) and an `evaluateDecay()` function that demotes
`mastered` to `approaching` when the half-life elapses; entering `maintaining` —
which is only reached after a stable re-check — multiplies the half-life by
`maintainingHalfLifeMultiplier` to slow decay further. Per-tenant overrides can
tighten band thresholds but never loosen below the published platform minimum.

### IRT is real

Item calibration uses genuine Item Response Theory in
`libs/metis/assessment/src/irt-models/irt-models.ts`:

- `IRTModelFamily` = `1PL` / `2PL` / `3PL`.
- `IRTParameters` = `{ discrimination, difficulty, guessing }` — the standard
  `a` / `b` / `c` triple, with documented ranges (discrimination 0.5–2.5,
  difficulty −3.0 to 3.0, guessing 0.0–0.35).
- `IRT_BOUNDS` and `MLE_DEFAULTS` constants, plus `resolveIRTParametersForModel`
  and `isIRTRecalibrationDue`.

Differential Item Functioning is monitored by
`monitorDifferentialItemFunctioning`
(`assessment/src/analytics/analytics.ts:263`), and next-item selection lives in
`assessment/src/generation/adaptive-selector.ts`.

> **On "CAT-aligned assessment" (`features.md`):** the adaptive selector is
> **IRT-information-gain based**, not a separately-named Computerized Adaptive
> Testing module. There is no discrete `CAT` library; cite the IRT selector, not
> a CAT feature class.

### Knowledge tracing

`libs/metis/adaptive/src/path/` ships three real tracers plus a unifier:

- `bkt.ts` — Bayesian Knowledge Tracing with Baum-Welch EM parameter learning.
- `fsrs.ts` — the FSRS-5 difficulty/stability/retrievability spaced-repetition
  model.
- `graph-knowledge-tracing.ts` — a Nakagawa-style graph tracer.
- `adaptive-knowledge-engine.ts` — a unified engine combining BKT, GKT, and
  FSRS.

---

## The personalization manifold

Adaptation is multi-dimensional, and the manifold is a real schema —
`LearnerPersonalizationStateSchema` in
`libs/contracts/src/metis/personalization.ts` — keyed per `(learner, course)`
with a semantic `version` (regex `/^\d+\.\d+\.\d+$/`) and a `previousVersion`
for rollback. It has **exactly six axes**, each with a
`PersonalizationAxisControl` (`pinned`, `loosened`, `reset`, `lastChangedAt`,
`rationale`) that backs the learner-profile "how we're teaching you" surface:

| Axis               | Shape                                                                                   |
| ------------------ | --------------------------------------------------------------------------------------- |
| `pace`             | `itemsPerSession` (1–60), `targetSecondsPerItem` (10–1200), `breakIntervalItems` (1–20) |
| `modality`         | `read-first` / `watch-first` / `practice-first` / `dialogue-first`                      |
| `prerequisitePath` | `intensity` (`minimal` / `scenic`) and `recap` boolean                                  |
| `scaffoldDensity`  | `hintLadderDepth` (0–8), `workedExamplesPerArc` (0–20)                                  |
| `framingRegister`  | `socratic` / `direct` / `narrative` / `formal-proof`                                    |
| `culturalFrame`    | `declaredFrames` (≤8 labels) and `pedagogicallyPermissive` boolean                      |

The `superRefine` enforces that `previousVersion` never equals `version`, so a
rollback always points at a distinct prior state. The
`scaffoldDensity.hintLadderDepth` bound (0–8) ties directly to the four-rung
hint ladder above — depth controls how far the tutor is allowed to climb before
stopping.

---

## The adaptive loop

The tutor runs a tight cycle every item: present → collect response and
telemetry → build an `AssessmentEvidencePack` → update mastery (writing a
`MasteryTransition` if the band changes) → update per-item personalization axes
→ run an integrity scan over the turn → select the next item from the item bank,
knowledge graph, and manifold → emit telemetry to xAPI / cmi5 / Caliper. Failure
of any step is logged but does not block the next item; failure rates feed
operator drift dashboards.

- **Latency budget — spec, not enforced gate.** The doc asserts P95 ≤ 600 ms
  from response to next item, degrading to a "loading next item" UX under
  backpressure. The verification lib has a generic budget-ceiling primitive
  (`MODE_CEILINGS` / `checkBudgetCeilings`), but no runtime gate enforcing the
  600 ms next-item ceiling on the live loop was found. Treat the 600 ms figure
  as a design target.
- **Replayability.** Any item turn is reconstructible from the persisted
  evidence pack, the prior mastery state, and the personalization vector at the
  time of the turn.
- **Cross-domain hooks — partly wired.** The prose cites Tara recovery rituals
  on frustration signals, Arete plan re-scope on drift, and Sophia grounding for
  any educational claim. Of these, only **Sophia** has a canonical wiring file
  (`sophia-canonical-wiring.ts`); the Tara and Arete hooks are described as
  intent, with no `*-canonical-wiring.ts` backing.

---

## The grounded-generation gate (`@metis/verification`)

This library is the concrete enforcement the docs only gesture at abstractly
when they say generation is "grounded." `libs/metis/verification/src/index.ts`
exports:

- `VerificationGate` / `createVerificationGate` — the gate runtime.
- `composeP0Gate(cfg)` — assembles a P0 generation gate from a retriever, an
  entailment judge, a pedagogical judge panel, and a step verifier.
- `runVerifiedGeneration` and `runVerifierGuidedGeneration` — the generate →
  verify → refine loop that re-prompts until the gate passes.
- `PedagogicalJudgeVerifier` / `createPedagogicalJudgeVerifier` with
  `PanelScore`, `ScorablePanel`, and `JudgeVerifierConfig` types — the
  judge-panel scorer.
- Hardening (`MODE_CEILINGS`, `checkBudgetCeilings`), provenance
  (`EvidenceRecord`), and an eval harness (`scoreVerifier`, `cohenKappa`,
  `parseGoldSet`, `loadGoldSet`).

This is the machinery behind the feature list's "synthetic/fabricated research
blocking, claim extraction, verifier orchestration, adjudication."

---

## The knowledge graph (`@metis/knowledge-graph`)

The KG promotion is far richer than the one bullet in the feature list. The
library is ~19.2K LOC across 75 files and ships construction (an
entity-relation-extractor with cycle and orphan detection), a
`GraphRagRetriever` with a `defaultCommunitySummarizer`, multi-hop expansion, a
pgvector seed step, and a governance filter, plus GNN and temporal modules and a
`GraphRagBenchmarkSuite` for GraphRAG-style benchmarking. Retrieval integration,
governance, and persistence end-to-end specs exist alongside the
implementations. For the platform-wide view of how this connects to search and
recommendations, see
[Search, Discovery, Recommendations, and Knowledge Graph](./search-discovery-recommendations.md).

The lighter `@metis/discovery` library backs the browse/recommend surfaces the
feature list mentions but never attributes to a lib: it ships a
`SearchableObjectCatalog`, a `SignalStore` with typed `SignalCategory` /
`SignalType` definitions, an `EvidenceGroundingState`, and recommendation
candidate sourcing — the data layer behind course browse and "why this is
recommended."

---

## Standards, rostering, and institutional delivery

The standards layer is real, not a wrapper.
`libs/metis/integrations/src/standards/institutional-delivery.ts` defines
`LmsStandard` (`xapi`, `cmi5`, … `qti_3`, `caliper`, `clr`, `open_badges`) and
exports working functions: `exchangeLtiLaunchToken`,
`createLtiDeepLinkResource`, `dryRunOneRosterImport`,
`mapLearnerActivityToXapi`, `createScormFallbackManifest`, `exportQti3Item`,
`importQti3Item`, `mapLearnerActivityToCaliper`, `issueOpenBadgeCredential`,
plus `requiredMetisV1Standards()` and `validateInteropMatrix()` for the per-LMS
interop matrix.

The lower-level protocol verification lives in
`libs/shared/inbound-integrations`:

| Capability     | File                  | Symbols                                                                                                                       |
| -------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| LTI 1.3        | `lti-verification.ts` | `VerifyLtiIdTokenInput`, `LtiJwks`, `buildLtiAuthenticationRequestUrl`, `generateLtiLoginState`, `InMemoryLtiLoginStateStore` |
| SCORM 2004 RTE | `scorm-2004-rte.ts`   | `Scorm2004RuntimeApi`, `SCORM2004_ERROR`                                                                                      |
| OneRoster      | `oneroster.ts`        | `ONEROSTER_RESOURCE_TYPES`, dry-run / sync                                                                                    |
| Identity       | `identity.ts`         | SAML 2.0 / OIDC / SCIM 2.0 provisioning                                                                                       |

> **On the feature list's identity bullet:** SCIM 2.0 / SAML 2.0 / OIDC plumbing
> is real in `identity.ts`. The Metis V1 launch locales (which gate multilingual
> content) are `OSHUN_LAUNCH_LOCALES` (`libs/oshun/i18n/src/index.ts:26`):
> `en-US`, `es-US`, `fr-FR`, `de-DE`, `ar`, `he`, `ja-JP`, `pt-BR` (eight,
> including two RTL).

---

## The institutional gradebook contract

Grades, mastery, completion, and integrity verdicts flow back to institutional
gradebooks through `GradebookEntrySchema` (`gradebook.ts:121`), keyed per
`(learner, assignment, attempt)`:

| Field                                              | Type / values                                                                                    |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `id`, `version`                                    | stable idempotent ID and positive integer version                                                |
| `learnerId`, `assignmentId`, `attempt`, `courseId` | identity                                                                                         |
| `score`, `scoreScale`                              | numeric and `{minimum, maximum, scaleKind}`                                                      |
| `scoreBasis`                                       | `rubric` / `irt_derived` / `completion` / `attempt_count` / `mixed`                              |
| `masteryBandAtEmission`                            | one of the six bands                                                                             |
| `assessmentMode`                                   | `assessed` / `formative` / `practice` / `exam` / `collaborative`                                 |
| `integrityVerdict`                                 | `clear` / `inconclusive` / `violation` / `severe` / `pending`                                    |
| `emissionTrigger`                                  | `assignment_completion` / `mastery_transition` / `integrity_verdict_change` / `manual_recompute` |
| `correctsVersion`, `correctionReason`              | back-link for revisions                                                                          |
| `visibility`, `tenantBinding`                      | per-role rules and tenant/policy binding                                                         |

The `superRefine` invariants are meaningful: a `completion`-basis entry must use
a `pass_fail` scale; a `correctsVersion` must point at a strictly earlier
version and carry a `correctionReason`; a `severe` integrity verdict must
include an `evidencePackRef`. Late revisions (e.g. a post-appeal correction)
emit a `gradebook.correction` event (`GradebookCorrectionEventSchema`,
`type: 'gradebook.correction'`) carrying the prior version reference, while the
LMS only ever receives the latest version.

### Rights and visibility — a worked example

The "rights and visibility" bullet is concretely implemented. `gradebook.ts`
ships `DEFAULT_VISIBILITY_RULES` for `learner` / `teacher` / `guardian` /
`institutional_admin` and a `viewGradebookEntryForRole()` function
(`gradebook.ts:276`) that redacts a row per role — each
`GradebookVisibilityRule` declares `canSeeScore`, `canSeeIntegrityVerdict`, and
`canFollowEvidencePack`. `emission.ts` defaults a new entry's `visibility` to
`DEFAULT_VISIBILITY_RULES` when none is supplied, so an evidence pack is
followable only by an operator with the right scope.

---

## BYOM: two different things, and the safety harness

The feature list conflates two separate frameworks under "BYOM." They are
different files with different purposes.

1. **Bring-your-own-_material_ ingestion** —
   `libs/shared/inbound-integrations/src/byom.ts` — the connector framework for
   file / URL / feed / LMS-import source bundles. This is the "ingest-to-course"
   path.
2. **Bring-your-own-_model_ safety harness** —
   `libs/shared/inbound-integrations/src/byom-model.ts` — the ~980-LOC
   `ByomModelFramework` class that sandboxes tenant-provided model _endpoints_.

> **Correcting `features.md`:** the doc says BYOM model calls run through
> `@oshun/inbound-integrations/byom.ts` in a per-tenant sandbox. That cites the
> **wrong file** — `byom.ts` is the material-ingestion connector; the model
> endpoint sandbox, quarantine, kill-switch, policy interlock, abuse monitor,
> and fail-closed behavior all live in the separate `byom-model.ts`.

### The model safety harness primitives

`byom-model.ts` exposes concrete, testable primitives worth documenting:

- `ByomEndpointStatus` — including `active`, `quarantined`,
  `fail_closed_killed`, and `fail_closed_quarantined`.
- `ByomKillSwitchSource` — `platform_operator` | `tenant_operator`. Platform
  operators can disable any endpoint on safety/compliance/billing grounds;
  tenant operators can disable their own. Disabled endpoints **fail closed** (no
  fallback to a default model unless tenant policy explicitly opts in).
- `ByomPolicyInterlock` — every call still passes through the Lilith tone, Isis
  governance, and Sophia grounding gates; tenant policy can only tighten beyond
  the platform minimum, never bypass it.
- `ByomAbuseMonitor`, `DEFAULT_BYOM_ABUSE_THRESHOLDS`, and `HIGH_RISK_TAGS` —
  per-tenant abuse-pattern detection (anomalous rates, content categories,
  targeting). A flag flips the endpoint to `quarantined` and routes to both
  tenant and platform operators.
- `ByomTimeoutError` — a hard per-call timeout; on timeout the call resolves to
  `fail_closed_killed`.
- `MemoryByomAuditStream` — a tenant-scoped audit stream; cross-tenant
  aggregation is impossible by design.

The admin decision lifecycle is wired at
`apps/oshun/bff/src/routes/admin-metis-byom-decision.ts`: an admin-scoped route
accepts a decision of `approve` / `request_changes` / `reject`, recording the
canonical action as an `admin.metis_byom.decision.<decision>` audit event.

---

## Cross-domain wirings — claimed vs. present

The feature list (`features.md`) names cross-domain Metis flows from Tara,
Arete, Veritas, Nyx, Nisaba, Aja, Sophia, Isis, Lilith, Iris, Psyche, Yemaya,
and Themis. On disk, `libs/metis/integrations/src/` ships exactly eight
`*-canonical-wiring.ts` files:

| Wiring present                                                          | Wiring claimed but absent                   |
| ----------------------------------------------------------------------- | ------------------------------------------- |
| `aja`, `iris`, `isis`, `lilith`, `psyche`, `sophia`, `themis`, `yemaya` | `tara`, `nyx`, `veritas`, `nisaba`, `arete` |

The present wirings connect Metis to embodied instruction
([Persona, Avatar, and Voice Packs](./persona-avatar-voice-packs.md)), memory
and continuity ([Iris Memory and Identity](./iris-memory-identity.md)),
generation control ([Isis Generation Control](./isis-generation-control.md)),
pedagogical tone ([Lilith Persona Policy](./lilith-persona-policy.md)),
real-time tutoring ([Psyche Real-Time Runtime](./psyche-realtime-runtime.md)),
grounding ([Sophia Grounding](./sophia-grounding.md)), academic integrity
(Themis), and rendering
([Output Gallery, Lineage, Branch, and Replay](./output-gallery-lineage.md)).
The five named-but-absent wirings are aspirational.

### Additional Metis BFF routes

Beyond integrity and gradebook, the BFF (`apps/oshun/bff/src/routes/`) ships:

- `metis-tutor-memory.ts` — `POST`/`GET {prefix}/metis/tutor-session-memories`
  and `GET …/:sessionId` (record a turn, list memories, fetch one session).
- `metis-search-seeds.ts` — discovery seed surface.
- `assistant-metis-handoff.ts` — the assistant → Metis handoff.
- `metis.ts` — the base domain route.

---

## Living Scenes integration

Metis ships Lesson Visualizer Living Scenes bound to a lesson's knowledge-graph
anchor set. The "what if X?" branch is constrained to what-ifs the KG supports,
with graceful fallback when a cue exits the manifold. Themis academic-integrity
gates block visualizations on active assessments. Tenant standards bindings
(Common Core, IB, NGSS) are honored where wired. Student-generated lesson
visualizers default to `tenant_internal_only` share scope under tenant policy.
See [Living Scenes — Concept and Customer Promise](./living-scenes-overview.md)
and
[Domain Templates and the Scene Score Editor](./domain-templates-and-editor.md)
for the full template.

---

## Tests

The intended coverage (from `features.md`) spans: mastery-transition determinism
(same evidence vector → same band; decay against synthetic timelines);
personalization-axis update cadence (per-item / per-session / per-arc signals
apply at the right cadence without bleeding); adaptive-loop latency (P95
next-item ≤ 600 ms with backpressure UX — a target, see the latency note above);
the Themis severity → action map round-tripping every (mode, severity-band,
tenant-policy) tuple including appeals; BYOM sandbox isolation (no cross-tenant
leakage, kill-switch ≤ 5 s, quarantined endpoints fail closed); and gradebook
emission (per-LMS interop fixtures, correction cascade, idempotency, late-grade
replay). The verification, gradebook, assessment, and adaptive libraries carry
real `.spec.ts` suites against these behaviors; end-to-end interop and latency
gates remain partly aspirational.

---

## Related

- [Sophia Grounding](./sophia-grounding.md) — the grounding gate every Metis
  educational claim passes through (the one cross-domain hook that is actually
  wired).
- [Search, Discovery, Recommendations, and Knowledge Graph](./search-discovery-recommendations.md)
  — platform view of the KG that Metis promotes to substrate.
- [Isis Generation Control](./isis-generation-control.md) and
  [Lilith Persona Policy](./lilith-persona-policy.md) — the governance and tone
  gates in the BYOM policy interlock.
- [Persona, Avatar, and Voice Packs](./persona-avatar-voice-packs.md) — avatar
  teacher and synthetic-teacher assets via the Aja wiring.
- [Tenant, Institution, and Operator Toolkit](./tenant-toolkit.md) and
  [Review, Compliance, and Trust & Safety](./review-trust-safety.md) — the
  operator surfaces behind integrity adjudication and BYOM decisions.
- [Customer Domains](../architecture/customer-domains.md) and
  [Cross-Domain Support](../architecture/cross-domain-support.md) — runtime
  view.
- [`../features.md`](../features.md) — the hub feature list. Backlog: see
  `§1.2`, `§1.3` in [`../TODOS.md`](../TODOS.md); ordering in
  [`../DEPENDENCIES.md`](../DEPENDENCIES.md).
