---
status: reconciled-partial
coverage_depth: deep-for-shipped-independent-seams
last_walked: 2026-05-29
last_reconciled: 2026-07-20
specs:
  - apps/oshun/web/e2e/metis-lessons-session.spec.ts
  - apps/oshun/web/e2e/metis-lesson-completion.spec.ts
  - apps/oshun/web/e2e/metis-assessment-submit.spec.ts
  - apps/oshun/web/e2e/metis-tutor-session.spec.ts
---

# Journey: Metis lesson specimen, assessment integrity, and tutor handoff

The current customer flow joins navigation, not learner state. A BFF-backed
schoolroom can show owned course proposals and separately recorded tutor memory;
a dev/test-only backlog supplies the lessons index and today's session; all
course and lesson ids then land on one authored reader. Quiz and assessment
replay live in localStorage, the assessment can receive a durability-bound
Themis response, and the displayed tutor queues text only in the browser. No
shared authority records lesson completion or projects it into Home, the
schoolroom, the library, or another device.

## Personas

- **Returning learner** — enters from Home, the Metis schoolroom, the lessons
  index, or today's session.
- **First-run learner** — needs honest no-progress and no-assessment states.
- **Assessment learner** — clears the client rubric gate and sees integrity
  evidence with an appeal handoff when applicable.
- **Source-conscious learner** — follows authored tutor citations into Nisaba.

## Pre-conditions

- The customer web pages are opened through an authenticated shell.
- `/metis` can read `GET /v1/metis/room`; the route combines caller-owned course
  proposals, a curated catalog, honest zero progress, and any separately stored
  tutor-memory summaries.
- In development/test only, `GET /v1/metis/lessons` returns three fixed backlog
  rows. The production guard returns `503 not_configured`; the route has no
  account-scoped lesson source.
- `getMetisLesson()`, `getMetisAssessment()`, and `getMetisTutor()` return
  authored fixtures from `metis-depth.ts`.
- `POST /v1/metis/assessment-submissions` is reachable with a Metis-scoped
  bearer. Its verdict, appeal, gradebook consequence, and notification intent
  share one required, acknowledgement-bound operation snapshot in production.

## Steps

### 1. Enter from Home or the schoolroom

- Home's Metis continuation exposes a live/fallback state and **Browse
  courses**, opening `/domains/metis` with `origin=home` and a course-path hint.
- `/metis` reads `/v1/metis/room`. A learner without a real lesson cursor sees
  **Begin your first lesson**, zero lesson/assessment stats, and no open
  assessment rather than invented progress.
- Owned course proposals are prepended to three curated catalog cards. Every
  card links to the shared reader with a `course` query.
- The tutor nudge can quote a topic from a separately created tutor memory, but
  the card has no link or resume action.

### 2. Inspect lessons or today's session

- `/metis/lessons` groups the development/test backlog fixture by course and
  exposes course-level `courseId` links plus lesson-level `id` links.
- `/metis/session` selects the first row whose `assessmentReady` flag is true,
  otherwise the first row, and lists the next two fixture rows. It does not read
  dates, mastery, enrollment, due work, or a learner cursor.
- The lessons endpoint is shared fixture data without an auth pre-handler and
  fails closed in production. A failed server read is rendered as the same empty
  state used for an account with no lessons.

### 3. Open a course or lesson link

- Schoolroom cards preserve `?course=<code>`, course groups preserve
  `?courseId=<id>`, and individual rows preserve `?id=<lessonId>`.
- The URL retains the query, but `MetisLessonPage` does not read it. The page
  always calls `getMetisLessonFixture()` and renders the same PHL.102 Stoic
  ethics section.
- There is no per-course/per-lesson server lookup, authorization check, or
  mismatch response at the destination.

### 4. Read and answer the lesson quiz

- `/metis/lesson` renders an authored passage, five static source rows, and a
  four-option multi-select quiz.
- Answers are unmarked until submit. The client reveals the score and per-option
  results, supports **Try again**, and restores `{ picked, phase }` after reload
  from `oshun.metis.lesson-quiz.v1`.
- The key is not scoped by tenant, account, course, lesson, assessment version,
  or attempt. Storage errors are ignored.
- Previous/next section buttons have no target or handler and write no progress.

### 5. Compose an assessment answer

- `/metis/assessment` renders an authored prompt, fixed due copy, four fixture
  rubric bars, and a client editor.
- The editor requires 180–220 words and at least one citation-like token before
  enabling submit. **Insert citation** appends a placeholder; **Save draft** and
  every change write to `oshun.metis.assessment.draft.v1.<assessmentId>`.
- The request body uses the page's assessment id and hard-codes
  `courseId: phl-102`; it does not derive identity from a selected lesson.

### 6. Submit for integrity review

- A valid answer posts to `POST /v1/metis/assessment-submissions` with Metis
  scope. The BFF derives deterministic integrity signals, adjudicates them with
  the canonical Themis bridge, persists the operation and gradebook consequence
  before publication, and returns the verdict evidence.
- The browser locks the editor and shows verdict class, severity, signal count,
  recommended action, source of record, and appeal availability.
- The browser stores that reduced response in localStorage. Reloading the
  submitted card is browser replay, not a submission/audit/gradebook GET.
- The browser suite forwards assessment and integrity requests with a
  test-authored bearer, so it proves the UI and route seams but not untouched
  production browser authorization.

### 7. Follow an appealable verdict

- A suspicious answer can return a violation with a canonical
  `/integrity/:verdictId/appeal` link.
- In the browser run's same BFF process, the appeal page reads the verdict's
  signal count, rationale, and excerpt and exposes the appeal form.
- Production hydrates the `metis-academic-records` ledger before traffic. Unit
  and PostgreSQL integration tests cover restart restoration, failure rollback,
  export, erasure fencing, and retention; this four-case browser suite does not
  itself restart the service.

### 8. Inspect the tutor specimen

- `/metis/tutor` renders six fixture messages, three authored assistant turns,
  two citation chips, four fixed context rows, a disclosure, and an authored
  end-of-session note.
- Citation chips genuinely navigate to
  `/nisaba?passage=<src>&from=metis-tutor&ref=<label>`.
- **Transcript** and **End session** are display-only. **Report** delegates to
  the shared Trust & Safety flag flow, covered by a separate journey.
- “session 14,” “11 turns,” “grounded in four sources,” and “saved to library”
  are component/fixture copy, not reads from the tutor-memory store or library.

### 9. Send a tutor question

- The composer persists its draft under `oshun.metis.tutor.draft.v1.default`.
- Submit by button or modifier+Enter appends the text and timestamp to the last
  50 entries under the adjacent `.queue` key, clears the draft, waits 200 ms,
  and displays **Queued · the tutor will pick this up**.
- No BFF tutor POST, SSE, WebSocket, model response, transcript append, retry
  worker, or library write consumes this queue.

### 10. Compare the separate tutor-memory seam

- `POST /v1/metis/tutor-session-memories` is a different API. It authenticates
  Metis scope, folds an understanding turn into mastery state, and lets the
  schoolroom reflect its topic and session count.
- Production requires and hydrates tutor memory plus mastery state. The route
  awaits its ordered candidate snapshot before `201`; export, exact-subject
  deletion with a recreation fence, and scheduled retention are composed.
- Creating that record directly and reading it from `/metis` proves a real
  independent seam; it does not make the displayed fixture transcript or local
  composer durable.

## Post-conditions

- The user can navigate Home or Metis into id-bearing course/lesson URLs.
- In development/test, the lessons index and session expose a deterministic
  three-row backlog and responsive 390 px layout.
- Every selected id renders the same authored lesson.
- Quiz state and the assessment response can replay in the same browser profile.
- A valid assessment can receive a durability-bound Themis verdict, and an
  appealable verdict can open its audit evidence in the running browser harness.
- Tutor citations can open Nisaba; submitted tutor text remains only in a local
  queue.
- No learner completion, server quiz attempt, browser-to-server assessment
  read-back, tutor transcript, library save, or Home/schoolroom progress update
  is produced by this chain.

## Failure modes

- **Production backlog requested** — `/v1/metis/lessons` returns
  `503 not_configured`; index/session pages flatten that failure into empty.
- **Course or lesson id implies unique content** — the destination ignores it
  and renders the PHL.102 fixture.
- **Quiz state leaks across ids or users in one browser profile** — the single
  key has no account or lesson partition.
- **Browser storage rejects a write** — the component swallows the error while
  save-oriented copy remains visible.
- **Assessment is below/above bounds or lacks a citation** — submit remains
  disabled.
- **Integrity request fails** — the answer remains editable and error copy is
  visible.
- **Browser reloads or changes device after a verdict** — the durable server
  record remains, but this editor has no submission GET and replays only its
  local card.
- **Tutor nudge is treated as a resume action** — the card has no link.
- **Tutor queued acknowledgement is treated as delivery** — no runtime reads the
  local queue.
- **“Saved to library” is read literally** — no library write or read-back
  occurs.
- **Footer navigation is treated as progress** — the controls neither route nor
  persist.

## E2E coverage

- [`apps/oshun/web/e2e/metis-lessons-session.spec.ts`](../../apps/oshun/web/e2e/metis-lessons-session.spec.ts)
  contains four cases covering the dev/test BFF fixture, grouped lessons,
  session selection and queue, link/tap-target contracts, and 390 px standalone
  overflow.
- [`apps/oshun/web/e2e/metis-lesson-completion.spec.ts`](../../apps/oshun/web/e2e/metis-lesson-completion.spec.ts)
  contains nine cases covering Home handoff, schoolroom branches, course-card
  URL, reader anatomy, quiz choose/submit/retry/reload, and inert footer
  controls.
- [`apps/oshun/web/e2e/metis-assessment-submit.spec.ts`](../../apps/oshun/web/e2e/metis-assessment-submit.spec.ts)
  contains four cases covering rubric gating, test-forwarded real BFF
  submission, local submitted replay, clear and suspicious verdicts, and appeal
  navigation/read-back.
- [`apps/oshun/web/e2e/metis-tutor-session.spec.ts`](../../apps/oshun/web/e2e/metis-tutor-session.spec.ts)
  contains 19 cases covering fixture transcript anatomy, disclosure, citation
  links/Nisaba navigation, local composer acknowledgement, absent live voice,
  and a separately created tutor-memory record read by the schoolroom.

## Per-view files touched

- [`customer/02-home-discovery/home.md`](../customer/02-home-discovery/home.md)
  — domain continuation entry.
- [`customer/08-metis/metis.md`](../customer/08-metis/metis.md) — room, curated
  courses, proposals, zero progress, and tutor-memory nudge.
- [`customer/08-metis/metis-lessons.md`](../customer/08-metis/metis-lessons.md)
  — production-guarded backlog fixture and id-bearing links.
- [`customer/08-metis/metis-session.md`](../customer/08-metis/metis-session.md)
  — fixture selection and queue.
- [`customer/08-metis/metis-lesson.md`](../customer/08-metis/metis-lesson.md) —
  shared fixture reader and local quiz.
- [`customer/08-metis/metis-assessment.md`](../customer/08-metis/metis-assessment.md)
  — authored prompt, local replay, and durability-bound integrity submit.
- [`customer/08-metis/metis-tutor.md`](../customer/08-metis/metis-tutor.md) —
  authored transcript and local composer queue.
- [`customer/07-nisaba/nisaba.md`](../customer/07-nisaba/nisaba.md) — citation
  destination.

## Cross-references

- `apps/oshun/web/src/lib/lilith-data/metis-depth.ts` — authored lesson,
  assessment, and tutor fixtures.
- `apps/oshun/bff/src/routes/domain-stubs.ts` — production-guarded lesson
  backlog and schoolroom route.
- `apps/oshun/bff/src/routes/metis-integrity.ts` — assessment, adjudication,
  appeal, and gradebook routes backed by the durable operation ledger.
- `apps/oshun/bff/src/routes/metis-tutor-memory.ts` — separate tutor-memory
  route.
- [`metis-byom-ingest-to-course.md`](./metis-byom-ingest-to-course.md) —
  independent ingest, decision, and proposal seams.
- [`themis-assessment-appeal.md`](./themis-assessment-appeal.md) — wider appeal
  lifecycle.

## Open questions

- [ ] Replace the guarded backlog fixture with an authenticated enrollment and
      assignment read, including explicit unavailable and empty states.
- [ ] Resolve `course`, `courseId`, and `id` into authorized records; reject
      unknown or mismatched identity.
- [ ] Persist lesson attempts and completion by tenant, learner, lesson,
      version, and retry, then project them into Metis, Home, and Library.
- [ ] Add account-scoped assessment/verdict/gradebook read-back to replace the
      editor's browser-local submitted replay.
- [ ] Connect the browser tutor to the existing tutor-memory model with an
      generated-turn stream, transcript read-back, and real resume action; the
      memory commit itself is already acknowledgement-bound.
- [ ] Replace or qualify “today,” “auto-saved,” “saved to library,” “grounded,”
      and queued-delivery copy until each has the corresponding authority.
