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.
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), the goals domain (Arete — Goals, Habits, and Reflection), and the scholarly-study domain (Nisaba — Scholarly Study).
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 (bare
§N references point there); cross-domain build ordering lives in
../DEPENDENCIES.md (deps§N). The hub feature list is
../features.md. Companion runtime views are
Customer Domains and
Cross-Domain Support.
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.tsandlibs/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-integrationsandlibs/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
VerificationGateand 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 bygetAvailableDomains()(registry.ts:503). The 2026-06-23 triage confirms the shell drops Metis toplannedpost-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,checkBudgetCeilingsinlibs/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, andyemayaship a*-canonical-wiring.tsunderlibs/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, theVerificationGate) 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
metisPostgreSQL database.docker/docker-compose.dev.yml'sPOSTGRES_MULTIPLE_DATABASESlistsyemaya,lilith,isis,iris,sophia,hathor,bellona,calliope,tara,maat,nisaba,shakti,cybele,kalika,lakshmi,athena,oya—metisis absent. Metis's storage strategy (sharedoshun_devvs. 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:
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.mddomain-library enumeration is stale: it omitsgradebook,discovery, andverification, 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 atindex.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 carriesoversightContext(independent/minor-supervised/managed-program) andoversightRoles(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— adjudicatePOST {prefix}/metis/integrity/:verdictId/appeal— open an appealGET {prefix}/metis/integrity/:verdictId/audit— fetch the audit recordGET {prefix}/metis/integrity/appeals/:appealId— appeals workspace- a
POSTappeals 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 standarda/b/ctriple, with documented ranges (discrimination 0.5–2.5, difficulty −3.0 to 3.0, guessing 0.0–0.35).IRT_BOUNDSandMLE_DEFAULTSconstants, plusresolveIRTParametersForModelandisIRTRecalibrationDue.
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 discreteCATlibrary; 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.tsbacking.
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.runVerifiedGenerationandrunVerifierGuidedGeneration— the generate → verify → refine loop that re-prompts until the gate passes.PedagogicalJudgeVerifier/createPedagogicalJudgeVerifierwithPanelScore,ScorablePanel, andJudgeVerifierConfigtypes — 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.
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) areOSHUN_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.
- 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. - Bring-your-own-model safety harness —
libs/shared/inbound-integrations/src/byom-model.ts— the ~980-LOCByomModelFrameworkclass that sandboxes tenant-provided model endpoints.
Correcting
features.md: the doc says BYOM model calls run through@oshun/inbound-integrations/byom.tsin a per-tenant sandbox. That cites the wrong file —byom.tsis the material-ingestion connector; the model endpoint sandbox, quarantine, kill-switch, policy interlock, abuse monitor, and fail-closed behavior all live in the separatebyom-model.ts.
The model safety harness primitives#
byom-model.ts exposes concrete, testable primitives worth documenting:
ByomEndpointStatus— includingactive,quarantined,fail_closed_killed, andfail_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, andHIGH_RISK_TAGS— per-tenant abuse-pattern detection (anomalous rates, content categories, targeting). A flag flips the endpoint toquarantinedand routes to both tenant and platform operators.ByomTimeoutError— a hard per-call timeout; on timeout the call resolves tofail_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), memory and continuity (Iris Memory and Identity), generation control (Isis Generation Control), pedagogical tone (Lilith Persona Policy), real-time tutoring (Psyche Real-Time Runtime), grounding (Sophia Grounding), academic integrity (Themis), and rendering (Output Gallery, Lineage, Branch, and Replay). 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-memoriesandGET …/: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
and
Domain Templates and the Scene Score Editor
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 — the grounding gate every Metis educational claim passes through (the one cross-domain hook that is actually wired).
- Search, Discovery, Recommendations, and Knowledge Graph — platform view of the KG that Metis promotes to substrate.
- Isis Generation Control and Lilith Persona Policy — the governance and tone gates in the BYOM policy interlock.
- Persona, Avatar, and Voice Packs — avatar teacher and synthetic-teacher assets via the Aja wiring.
- Tenant, Institution, and Operator Toolkit and Review, Compliance, and Trust & Safety — the operator surfaces behind integrity adjudication and BYOM decisions.
- Customer Domains and Cross-Domain Support — runtime view.
../features.md— the hub feature list. Backlog: see§1.2,§1.3in../TODOS.md; ordering in../DEPENDENCIES.md.