- Walked: 2026-05-29 at
9455bc53ad. The retained result named an ephemeral/tmp/claude-oshun-lt-2-walkthrough/walk.mjsscript but preserved no script, trace, request log, storage snapshot, or completion record. - Reconciled: 2026-07-20 against the current schoolroom, lesson backlog and session pages, shared lesson reader, quiz and assessment storage, integrity and gradebook stores, tutor specimen and queue, separate tutor-memory route, production fixture guard, and all four named Playwright files. This was source review, not a fresh application run.
- Verdict: partial / deep for the shipped independent seams — 36 Playwright cases combining browser and API evidence deeply cover the dev/test lesson backlog, schoolroom entry, authored reader and tutor anatomy, local quiz and assessment replay, a real durability-bound integrity response, Nisaba citation navigation, and a separately created durable tutor memory appearing in the schoolroom. They do not prove that a selected lesson is resolved, completed, persisted for an account, projected into Home or the schoolroom, or saved to a learner library.
- Current authority:
WALKTHROUGH/journeys/metis-lesson-completion.mdnow defines the same independent seams and partial outcome.
Result at a glance#
| Interaction | Proof · limit |
|---|---|
| Home and schoolroom entry | Proof: the lesson-completion suite opens Home's Metis continuation, retains its domain/provenance parameters, then verifies the signed-in /metis room's first-run lesson action, curated courses, honest no-assessment branch, and disclosed tutor card. Limit: Home opens /domains/metis, not this lesson chain; /v1/metis/room has no lesson-play cursor, always reports zero lesson/assessment progress, and combines learner-owned draft proposals with a curated catalog. |
| Lessons index and today's session | Proof: four cases read the real dev/test BFF endpoint, render three rows grouped into two courses, select the first assessment-ready item, expose a two-row queue, verify 44 px links, and keep both pages free of horizontal overflow at 390 px standalone. Limit: /v1/metis/lessons is an unauthenticated, production-guarded fixture: it returns the same three rows in development/test and 503 not_configured in production. Both pages silently turn a failed read into an empty state. |
| Course and lesson identity | Proof: schoolroom, index, and session links retain course, courseId, or id in the destination URL. Limit: MetisLessonPage accepts no search parameters and getMetisLesson() returns getMetisLessonFixture() directly. Every id opens the same hard-coded PHL.102 section; the page title, passage, sources, and next/previous labels do not come from the selected row. |
| Lesson quiz | Proof: Playwright chooses an answer, submits it, sees deterministic per-option grading, retries, and reloads a submitted score. Limit: the only record is { picked, phase } under the single browser key oshun.metis.lesson-quiz.v1; it has no learner, tenant, course, lesson, attempt, timestamp, server acknowledgment, or completion event. Previous and next controls are inert buttons. |
| Assessment editor | Proof: four cases verify the 180–220 word and citation gates, post a clear or suspicious answer, render the returned Themis evidence, reopen a draft, replay the submitted view after reload, and follow an appealable verdict to its audit page. Limit: prompt and rubric are fixtures, the client hard-codes courseId: phl-102, and reload replays the BFF response from localStorage rather than reading a submission from the server. The browser test replaces the request with a test-authored Metis bearer before forwarding it to the real BFF. |
| Integrity and gradebook response | Proof: POST /v1/metis/assessment-submissions authenticates Metis scope, deterministically detects signals, and appends an ordered operation whose Themis verdict and gradebook consequence publish only after the shared snapshot commits. Production hydration, restart tests, the evidence_pack export, subject erasure/fencing, compliance retention, and notification reconciliation are present. Limit: the editor still replays local JSON after reload and never performs server read-back. |
| Tutor specimen and composer | Proof: 19 cases pin six fixture turns, three disclosed assistant turns, two Nisaba citation links, four context rows, the end note, composer input, modifier shortcut, local queued acknowledgement, and the absent voice control. Limit: the displayed session number, “11 turns,” transcript, grounding claim, and “saved to library” note are authored copy. Send appends to a browser-local queue and has no consumer, tutor POST, stream, generated reply, transcript mutation, end-session handler, or library write. |
| Separate tutor memory | Proof: one browser case posts a real tutor-session-memory record and verifies that /v1/metis/room reflects its topic and session count. The route awaits candidate persistence; production requires and hydrates the snapshot, while export, erasure fencing, and scheduled retention cover memory plus mastery state. Limit: the fixture tutor page never calls that route, and the named browser case proves only same-process read-back rather than a deployed restart. |
| Learner completion | Proof: none in these four files. Limit: no action writes lesson completion, section position, quiz attempt, assessment completion, tutor transcript, library state, or Home continuation to one account-scoped authority. The schoolroom remains at zero lessons and assessments after the local/browser interactions. |
Evidence map#
The map is deliberately vertical so the four authority planes remain readable on a narrow Docs Center rail. Solid edges are exercised seams; dashed edges name the joins that the current runtime does not make.
Proven observations#
The historical pass is not reproducible evidence of completion#
- The old record established that visible Metis routes rendered at the walked
commit. Its walker lived under
/tmp; there is no repository artifact that can reproduce its zero-error or zero-failure claims. - The current four Playwright files contain 36 cases: four lesson-index and session cases, nine schoolroom/reader/quiz cases, four assessment cases, and 19 tutor cases. That is deep interaction evidence, but it is evidence for several independent surfaces rather than the lifecycle promised by the old result title.
- The former 2026-07-02 reconciliation called the lesson “query-param driven,” assessment reload “durable,” and the whole journey a pass. Current source contradicts each unqualified claim: ids are ignored by the reader, reload is localStorage replay, and no completion mutation exists.
The schoolroom has an honest empty progress model#
/metiscallsgetMetis(), which readsGET /v1/metis/roomand falls back to an explicit unavailable model rather than an embedded successful fixture. The route prepends caller-owned course proposals to three curated catalog entries when a member is resolved.buildMetisRoomintentionally returns a zero resume cursor, zero lessons, zero assessments, zero streak, and no open assessment. That is accurate: there is no learner lesson-play store to read.- A separately created tutor memory is the one live learner signal the room consumes. It changes the tutor nudge and session count, not lesson progress. The tutor card itself remains display-only, so the nudge cannot open that memory or its resume URL.
- The Home continuation test proves a domain-shell handoff with provenance. It does not prove that local quiz or assessment activity updates Home, because neither component publishes a continuation record.
The new index and session pages are production-guarded specimens#
/metis/lessonsand/metis/sessionboth server-read/v1/metis/lessons. In development/test, that endpoint returns the same three authored rows, spanning PHL.102 and AST.110 with exactly oneassessmentReadyflag.- The index groups rows by course and links each course and lesson. The session page chooses the first assessment-ready row, then the first two remaining rows, yielding a deterministic 58-minute specimen. “Today's” is therefore a selection over fixture order, not recency, due date, mastery, or a learner cursor.
guardedFixtureRouteblocks this endpoint in a production runtime with503 not_configured; it is not an account-scoped backlog. The endpoint also has no auth pre-handler in development/test. The signed-in shell tested by Playwright does not change the response's authority.- Both pages replace a null/non-2xx BFF read with
lessons: []. A production fixture refusal is rendered as “No active lessons,” which is visually honest about absence but does not distinguish an empty account from unavailable infrastructure.
Id-bearing navigation terminates at one fixture reader#
- The schoolroom emits
?course=, the lessons index emits?courseId=and?id=, and today's session emits?id=. The current browser suites prove these exact hrefs and one clicked schoolroom destination. MetisLessonPagedeclares nosearchParamsinput. It callsgetMetisLesson(), which immediately returnsgetMetisLessonFixture(). Consequently the selected id never reaches a repository, adapter, or BFF.- The rendered heading, section number, four passage paragraphs, five sources, four quiz rows, generated-content disclosure, and previous/next section labels are static component or fixture values. Even the AST lesson row opens the Stoic ethics text.
- Previous and next are
LBtncontrols without an href or handler. The tested presence of those buttons is not section navigation, completion, or progress.
Quiz reload is one unscoped local record#
MetisLessonQuizhides correctness before submit, permits multi-selection, computes exact row parity on the client, exposes per-option results, and supports a clean retry. The nine-case journey suite exercises the meaningful grading loop rather than only checking that controls exist.- Every instance defaults to
oshun.metis.lesson-quiz.v1. Onlypickedandphaseare stored. There is no schema version beyond the key suffix, result timestamp, score record, server call, or storage error surfaced to the user. - Because the lesson page ignores identity and the storage key is global, all course/id URLs in one browser profile share the same quiz. Another signed-in user reusing that profile can also inherit it.
- “Auto-saved · 14:08” beside the footer is fixed display copy. It is not derived from the localStorage write, and ignored quota/private-mode failures leave the claim visible.
Assessment submission reaches a real durability-bound integrity engine#
- The assessment prompt, due label, rubric percentages, provisional originality, tutor-turn count, and citation count are authored specimen data. The real client island counts words and citation-like syntax, stores the draft, and refuses submit outside 180–220 words or without one citation.
- On submit the editor posts
assessmentId, a hard-codedphl-102course id, the answer, and a timestamp. The BFF requiresdomain:metis, constructs a submission/verdict id, derives deterministic signals, adjudicates throughMetisThemisCanonicalBridge, and emits a gradebook value before returning201. - The assessment browser suite intercepts this request and forwards it with a dev token authored inside the test. This joins the genuine UI payload to the genuine BFF route, but does not prove that the unmodified browser session supplies production Metis authorization end to end.
- The editor reduces the response to a local
SubmittedAssessmentResultand writes it beside the answer underoshun.metis.assessment.draft.v1.<assessmentId>. Reload reads that object; it does not call the audit, submission, or gradebook read route. - A suspicious answer proves the browser handoff in one running BFF: after the custom forwarder also authenticates integrity reads, the browser opens the canonical appeal page and reads the signal rationale and excerpt. Separate durability tests, not this browser case, prove the same authority can rehydrate.
Integrity, appeals, gradebook consequences, and privacy share one ledger#
AcademicIntegrityAppealStoreis now an ordered operation authority. Every adjudication, appeal open/resolution/decision, gradebook consequence, and notification intent is replayed into a candidate runtime, persisted undermetis-academic-records, and published only after the sink acknowledges.- Production calls
requireDurableMetisAcademicRecords, hydrates the ledger before traffic, and reconciles its idempotent notification outbox afterward. The externally referenced gradebook singleton is a projection replaced from the persisted ledger, not an independent restart authority. - Unit tests cover exact verdict/appeal/gradebook/outbox restoration and failed- write non-publication. A live PostgreSQL integration proves restart read-back, deletion, and compliance purge. Those tests strengthen the server boundary; they do not make the editor reload from it.
- The default
evidence_packcollector exports the learner's verdicts, audits, appeals, gradebook history, and only that subject's authored actions. Exact subject deletion removes owned evidence, pseudonymizes roles in retained adjacent cases, fences recreation, and registers the two-year evidence-pack retention/purge path.
The displayed tutor and durable tutor memory are different seams#
/metis/tutorcallsgetMetisTutor(), which returns six fixture messages. The component adds fixed session/turn/save labels, four fixed context rows, a disclosure, and a fixed end note. The named suite accurately pins the anatomy and both real Nisaba link navigations.- Transcript and End session have no handler. The shared Report action is live and covered by the separate user-flag journey, but it reports static Metis target ids; it does not make the transcript a stored tutor session.
MetisTutorComposerstores the draft underoshun.metis.tutor.draft.v1.defaultand the last 50 submitted texts under the adjacent.queuekey. Send waits 200 ms, clears the draft, and says the tutor will pick it up. No code reads that queue for synchronization or response.- The separate
POST /v1/metis/tutor-session-memoriesroute accepts a modeled understanding turn, updates mastery, and gives/v1/metis/rooma real nudge. Its store serializes mutations, persists the memory and mastery candidate before publication, and maps an unavailable sink to a service error. - Production requires and hydrates this snapshot before traffic. The
continuity_stateexport includes the subject's memory, mastery states, and diffs; deletion removes that partition behind a hashed recreation fence; and startup plus a scheduled task purge expired sessions under the canonical continuity rule. The fixture browser tutor still never calls the route.
Boundaries and gaps#
- A signed-in page is not an account-scoped backlog. The lessons endpoint is a shared dev/test fixture without an auth pre-handler and fails closed in production.
- A fixture row is not a learner assignment. Its week, readiness, and duration are authored values with no enrollment or progress source.
- A “today” selection is not scheduling. It chooses fixture order and one boolean; it reads no date, due time, mastery, or learner cursor.
- An id-bearing href is not identity resolution. The shared reader ignores
course,courseId, andid. - A shared reader is not a course. Every selected backlog row produces the same PHL.102 section and quiz.
- A scored quiz is not an attempt record. Its one localStorage value lacks account, lesson, attempt, timestamp, and server authority.
- Same-browser reload is not cross-device durability. Quiz and assessment restoration replay browser-local JSON.
- “Auto-saved” is not acknowledged persistence. localStorage failures are swallowed while fixed save copy remains visible.
- A fixture rubric is not an instructor grade. The percentages are static, and the returned gradebook score is based on integrity class rather than the four displayed rubric dimensions.
- A test-authored bearer is not production browser authorization. The assessment suite rewrites the browser request before it reaches the BFF.
- A durable Themis response is not assessment read-back. The server authority survives restart, but the editor reloads its reduced localStorage copy and never verifies the submission, verdict, or latest gradebook projection.
- A local submitted card is not server read-back. Reload never asks the BFF whether the submission or verdict still exists.
- A citation link is not dynamic grounding proof. The two tutor citations and grounding disclosure come from the authored fixture.
- A local queue is not tutor delivery. It has no consumer, retry worker, receipt, generated turn, or transcript append.
- “Saved to library” is not a library write. It is component copy with no save action or read-back.
- A separately posted tutor memory is not browser tutor integration. The test creates it through the API outside the fixture composer.
- A durable tutor-memory API is not browser tutor integration. Its awaited commit, export, deletion fence, and retention path remain disconnected from the fixture transcript and local composer queue.
- Composed academic privacy is not lesson privacy. Integrity/gradebook and tutor-memory records now participate in export and deletion; the quiz, assessment draft, and submitted-card replay remain browser-local and unscoped.
- Thirty-six deep cases are not lesson completion. No named case asserts a completion write, restart-safe progress, cross-device read, or exact Home/schoolroom update for the lesson it opened.
Re-run evidence#
The 2026-07-20 work was source reconciliation and Docs Center verification; it
did not execute these application suites. A fresh journey run should use the
repository's real web/BFF harness and retain reports instead of another /tmp
walker:
pnpm --dir apps/oshun/web exec playwright test -c playwright.config.ts e2e/metis-lessons-session.spec.ts --project=chromium --workers=1
pnpm --dir apps/oshun/web exec playwright test -c playwright.config.ts e2e/metis-lesson-completion.spec.ts --project=chromium --workers=1
pnpm --dir apps/oshun/web exec playwright test -c playwright.config.ts e2e/metis-assessment-submit.spec.ts --project=chromium --workers=1
pnpm --dir apps/oshun/web exec playwright test -c playwright.config.ts e2e/metis-tutor-session.spec.ts --project=chromium --workers=1
Retain the commit and environment mode, web/BFF reports, authenticated subject and tenant, selected course/lesson ids, pre/post browser storage, assessment request/response, verdict and gradebook ids, snapshot backing tier, and a process-restart read-back. A completion-grade follow-up must also retain an account-scoped attempt/completion id, server commit receipt, exact lesson read-back, and the resulting schoolroom, Home, library, and second-device projections.
Source trail#
- Current journey contract
- Schoolroom page data read
- Schoolroom room model
- Schoolroom and depth components
- Lessons index
- Today's session page
- Production-guarded lessons fixture
- Shared lesson route
- Authored depth fixtures
- Lesson quiz state
- Assessment editor state
- Integrity and gradebook routes
- Durable academic operation ledger
- Gradebook projection
- Tutor composer queue
- Separate tutor-memory route
- Tutor-memory snapshot store
- Lessons/session browser evidence
- Schoolroom/lesson/quiz browser evidence
- Assessment browser evidence
- Tutor browser evidence
Cross-references#
- Metis BYOM result — independent ingest, decision, and proposal seams that do not feed this lesson reader.
- Themis assessment appeal result — the wider appeal lifecycle behind the assessment handoff.
- Lessons view, session view, lesson view, assessment view, and tutor view — per-route interaction records.
- User flag result — separate coverage for the lesson and tutor Report actions.
- Results convention — status vocabulary and evidence rules.
Open questions#
- What authenticated course, enrollment, lesson, and assignment contracts will replace the production-guarded backlog fixture?
- Which route will resolve every course/lesson id and refuse mismatched or unauthorized identity rather than silently rendering one fixture?
- What attempt schema will scope quiz state by tenant, learner, course, lesson, assessment, version, and retry while retaining timestamps and scoring input?
- Which write defines “lesson complete,” and how is its commit projected into the schoolroom, Home continuation, library, notifications, and other devices?
- Which authenticated submission GET will let the editor replace browser replay with the durable verdict and latest gradebook projection after reload?
- What cross-instance concurrency protection governs the whole-snapshot academic and tutor-memory stores beyond their in-process mutation queues?
- Will the browser tutor create/resume the existing tutor-memory model, stream generated turns, append citations, and prove the same transcript after a restart?
- Which labels should be hidden or qualified until they are true: “today,” “auto-saved,” “saved to library,” “grounded in four sources,” and “the tutor will pick this up”?