Context. surface customer · domain metis · route /metis · auth signed-in · source apps/oshun/web/src/app/metis/page.tsx
Last walked. 2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data (2xx), console/page-errors, expected content, screenshot verified; live screen-reader, touch, offline, and telemetry-delivery checks pending a manual AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; content re-verified 2026-06-03 against current source; course-card links, first-run no-assessment state, and hub CTAs reconciled 2026-06-27 by metis-lesson-completion.spec.ts
Purpose#
The Metis domain hub. The schoolroom: active courses, this week's progress stats, the open assessment, and a tutor grounded in the sources. The recommended next action resumes a specific course at a specific section when the BFF returns an in-progress cursor; the live first-run state instead says "Begin your first lesson" and keeps the same lesson CTA route.
Entry points#
- Home domain card grid — see
../02-home-discovery/home.md - Domain switcher —
/switcher(see../02-home-discovery/switcher.md) - Library / Explore — learning-reentry collection and curated routes link here
- Direct URL / bookmark — yes (auth required via shell middleware)
- Server fetch —
getMetis()runs on the server before render
Layout regions#
page.tsx is a thin server component: await getMetis() →
<MetisSchoolroom data={data} />.
Inside MetisSchoolroom (metis.tsx, line 65):
- Web shell top —
LCustomerNav active="library" - Header row (
gridTemplateColumns: '1fr auto'):- Left — Resume / first-run headline — Metis glyph
(
LDomainMark domain="metis"), eyebrow "Metis · the schoolroom",LDisplay"Resume at §." when resume.weekTotal > 0; otherwise "Begin your first lesson." The meta line is either<courseLabel> · week <n> of <total> · <minutes> minutes todayor "No lesson in progress yet — open a course below to start." - Right —
LBtn kind="primary" href="/metis/lesson"— "Continue lesson →" or first-run "Start a lesson →"
- Left — Resume / first-run headline — Metis glyph
(
- Two-column body (
gridTemplateColumns: '1.4fr 1fr'):- Left — Open courses · N — list of
Link-wrappedLCards perdata.courses, each with code, week/weekTotal, title, teacher, progress bar, andhref="/metis/lesson?course=<code>"; theherecourse gets a 3 px accent left border and bg colour - Right — sidebar:
- This week —
LCardwithLFieldrows for Lessons read, Assessments, Tutor minutes, Streak (fromdata.weekStats) - Open assessment —
LCard(accent border). Whendata.openAssessment.openis true it shows code, title, kind, word count, due label, "Begin" primary button to/metis/assessment, and "Rubric" ghost button. When false it shows "No assessment is open." plus the honest explanatory eyebrow and hides Begin/Rubric. - Tutor · ✻ —
LCard(dotted border) with a paragraph fromdata.tutorNudgeand eyebrow "AI tutor · grounded in 4 sources · disclosed"
- This week —
- Left — Open courses · N — list of
States#
- Loaded —
getMetis()resolves before render; covered bymetis-lesson-completion.spec.ts. - Resume present / first-run —
data.resume.sectionNumberpopulates the resume headline whenweekTotal > 0; the live first-run BFF state renders "Begin your first lesson." instead. - Open courses populated — one linked card per
data.courses; the E2E count and click-through are covered. - Active course (
here === true) — highlighted with accent border in source. - Week stats populated —
data.weekStatsfield rows (lessons read, assessments, tutor minutes, streak) - Open assessment present —
data.openAssessment.open === truepopulates the sidebar card and exposes Begin/Rubric. - No open assessment — live first-run BFF state shows "No assessment is
open." and hides Begin/Rubric; covered in
metis-lesson-completion.spec.ts. - Tutor nudge present —
data.tutorNudgeitalic paragraph and visible "AI tutor · grounded in 4 sources · disclosed" eyebrow. - Reduced motion — composes static Lilith primitives; no route-level animation on this hub.
- Auth gate — shell middleware only.
Interactions#
Header#
- Continue lesson → / Start a lesson → (
LBtn kind="primary")- Function: navigates to
/metis/lesson - Disabled when: no in-source disabled branch — always rendered
- Covered by:
metis-lesson-completion.spec.ts
- Function: navigates to
Open courses lane#
- Course card (
LinkwrappingLCard) — navigates to/metis/lesson?course=<code>; covered by browser click-through. - Progress bar — non-interactive.
Sidebar#
-
LFieldrows — non-interactive (Lessons read, Assessments, Tutor minutes, Streak) - Begin (
LBtn kind="primary" href="/metis/assessment")- Function: navigates to
/metis/assessment
- Function: navigates to
- Rubric (
LBtn kind="ghost")- Function: display-only in V1; no destination or modal handler is wired.
- Tutor card — non-interactive paragraph + eyebrow; no
hrefwired.
Data & contracts#
- Reads:
getMetis()from@/lib/lilith-data/metis— fetches the live BFF routeGET /v1/metis/roomviabffGet(metis.ts~14-19) and returnsMetisDatawithresume,courses[],weekStats,openAssessment,tutorNudge. On an unreachable feed it returns an honestmetisUnavailable()room (no embedded fixture). - Writes: None — read-only hub.
- Realtime: None.
- Caching: server fetch; SW caches the rendered HTML for offline reload
- Auth/role check: shell middleware
- Route metadata: title "Metis · the schoolroom", canonical
/metis
Cross-references#
- Shell:
shell/01-app-shell.md - Sibling Metis routes:
metis-assessment.md— short-answer assessmentmetis-byom.md— bring your own materialsmetis-lesson.md— course readermetis-tutor.md— chat tutor with cited sources
- Cross-domain partners:
- Nisaba (
../07-nisaba/) — source-grounded study moments
- Nisaba (
- Component sources:
apps/oshun/web/src/components/lilith/metis.tsx(MetisSchoolroomline 65)apps/oshun/web/src/lib/lilith-data/metis.ts
- Feature spec:
V1/features.md#metis
Open questions / known gaps#
- Course cards are real
Links to/metis/lesson?course=<code>; no separate per-course detail page is mounted. - The Rubric ghost button is display-only in V1; the rubric preview itself
lives on
/metis/assessment. -
MetisDatais served live fromGET /v1/metis/room; the browser spec asserts the live first-run/no-assessment shape instead of page-routing a fake server component payload. - Tutor nudge card integration is confirmed absent in V1; direct URL
/metis/tutoris the reachable tutor entry.