messages.mdmetis-assessment.mdoperator-metis.md04-auth-session.md05-notifications.mdJourney flow#
Generated from the authored steps below — click a node to jump to that section.
This journey is a real browser-to-BFF chain: a Metis assessment submission runs
detection and canonical Themis adjudication, an eligible learner files an
appeal, an operator decides it in /operator/metis, the gradebook receives a
terminal correction, and the learner receives an in-app message. The chain is
deep but process-local: verdicts, disputes, appeal ids, and the gradebook
adapter are memory stores with no restart hydration in these modules.
| Stage | Source of record in this implementation |
|---|---|
| Detection and verdict | MetisThemisCanonicalBridge |
| Appeal workspace | In-memory AcademicIntegrityAppealStore |
| Operator decision | POST /v1/metis/integrity/appeals/:id/decision |
| Grade correction | In-memory MetisGradebookStore |
| Learner notice | Customer message-center in-app incident |
| External delivery | Not implemented for this decision |
Personas#
- Learner — submits the assessment, reads only their own verdict/audit record, and may file an allowed appeal.
- Metis operator / teacher — holds an admin Metis scope, reads the full appeal queue, selects an outcome, and supplies the resolution note.
- Themis canonical bridge — detects/classifies the record, owns the verdict, dispute, due-process profile, timeline, and audit model.
- Assigned adjudicator — optional bridge participant selected from the registered shortlist.
- Customer message center — receives the learner-facing decision notice after the workspace closes.
Pre-conditions#
- The learner is signed in with Metis scope and opens
/metis/assessment. - The submitted answer satisfies the assessment editor's rubric gate.
- The BFF has a default academic-integrity policy binding and the canonical bridge is available.
- A non-clear verdict is required for an appeal; clear verdicts carry
appealAllowed: false. - The operator has the admin scope required by
hasOperatorScope. - Browser continuity assumes the same BFF process because the appeal and gradebook stores are not durable.
Steps#
1. Learner submits and receives a canonical verdict#
-
MetisAssessmentEditorposts assessment id, course id, answer, and timestamp toPOST /v1/metis/assessment-submissions. - The route derives a submission/verdict id, runs
detectAcademicIntegritySignals, and passes detection signals, excerpts, classifier outputs, and model versions into the bridge. - The bridge returns a verdict, classification, enforcement outcome, and
audit record with
sourceOfRecord: themis. - Appealable non-clear verdicts emit a gradebook entry with
integrityVerdict: pending. - The assessment editor locks the submitted answer and renders compact verdict class, severity, signal count, source, recommended action, and appeal link.
- The compact panel is not the full evidence record; the learner-safe audit detail is on the appeal page.
2. Learner opens the appeal workspace#
- The verdict-provided route
/integrity/:verdictId/appealloadsGET /v1/metis/integrity/:verdictId/audit. - Ownership is fail-closed: a learner may read only a verdict whose learner id matches their authenticated user id. A mismatch returns the same 404 as an unknown record.
- The page renders rationale, policy binding, signal/evidence counts, learner-safe excerpts, and classifier provenance.
- A clear/teacher-cleared verdict renders an
appeal-not-allowedstate without a form; a direct POST returns 409.
3. Learner files the appeal#
- The form collects narrative, requested relief, and an optional preferred adjudicator id.
-
POST /v1/metis/integrity/:verdictId/appealchecks verdict ownership and opens the canonical dispute. - The bridge reuses the verdict's evidence excerpts as dispute evidence, shortlists adjudicators, assigns one when available, and returns dispute, evidence, timeline, deadlines, events, and due-process summary.
- Filed confirmation renders status plus optional case and adjudicator fields.
- There is no learner evidence-upload field; only the canonical excerpts travel into the dispute.
4. Operator reviews the live queue#
-
/operator/metisreadsGET /v1/metis/integrity/appealswith operator scope. - Each row renders dispute parties, evidence count, deadline stages, and due-process summary.
- The decision form blocks a blank resolution note.
- Outcome controls expose Uphold, Revise (
inconclusive), Dismiss (clear), and Escalate (severe). - This queue is process-local; an appeal disappears on BFF restart.
5. Operator decides and closes the case#
- The UI posts
outcome,resolutionNote, andcloseCasetoPOST /v1/metis/integrity/appeals/:appealId/decision. -
upholdretains the prior verdict class; the other controls map directly toviolation | inconclusive | clear | severe. - The route constructs a server-side teacher override, re-adjudicates the canonical verdict, then closes the dispute and records the resolution timeline note.
- A changed class becomes
overturned; an unchanged class becomesupheld. - A second decision against an already closed appeal returns 409.
- The sibling
/resolveendpoint can close a workspace without selecting a new verdict class. The browser decision flow uses/decisionand should not be described as the same transition.
6. Gradebook and in-app message reflect the decision#
- The decision route emits a terminal gradebook version with trigger
integrity_verdict_changeandcascadeFrom: appeal. - The correction preserves the prior version and exposes the corrected
version through
GET /v1/metis/gradebook/:assessmentId/latest. - Severe results receive an evidence-pack reference when one was not already present.
- The message center receives a high-priority in-app incident named Academic integrity appeal decided with the appeal-record deep link.
- Following the link records a clicked receipt without implicitly marking the row read; mark-read is separate.
- No push, email, or institution webhook adapter is invoked.
7. Learner and operator inspect the resulting record#
- Learner and operator can re-read the canonical audit record; unrelated learners receive 404.
- The updated decision rationale includes the teacher-override line.
- The appeal workspace reads closed, and the gradebook correction is available to the permitted role.
- The learner sees the message in
/messagesand can return to the appeal record. - These records are not a durable institutional audit ledger; they live in the singleton bridge and memory gradebook store.
Post-conditions#
- The appeal dispute is closed with a resolution note and terminal verdict status.
- A terminal gradebook version corrects the pending version when the assessment had an appealable verdict.
- The learner has an in-app decision message and explicit delivery/read/click receipts.
- Learner ownership checks remain enforced on verdict, audit, and workspace reads.
- Restart durability, external notification, and LMS grade export are not implied by the completed browser flow.
Failure modes#
- Unknown or another learner's verdict — an unknown record and another learner's record both return 404.
- Appeal disabled — clear verdicts show no form and POST returns
academic_integrity_appeal_not_allowed. - No adjudicator registered — the appeal can remain triaged with no assignment.
- Blank decision note — client and route validation block it.
- Parallel operator decisions — the first close wins at the HTTP guard, but the underlying bridge maps have no general optimistic concurrency version.
- BFF restart — verdict, appeal, gradebook, and their indexes are lost.
- Notification duplicate or suppression — the decision remains closed; notification status reports the delivery outcome.
- External delivery expected — no push/email path exists for this event.
- Learner evidence needed — the current appeal accepts narrative and relief, not an uploaded evidence bundle.
- Bias review needed — the enum admits
paused_bias_review, but this route does not drive that transition.
E2E coverage#
apps/oshun/web/e2e/metis-assessment-submit.spec.tsdrives browser submission, clear and suspicious verdicts, read-only post-submit state, audit detail, and the appeal link.apps/oshun/web/e2e/integrity-appeal.spec.tsdrives ownership-safe audit reads, form anatomy, filing, disabled appeal, direct operator resolve, teacher override/uphold branches, and error cases over the real BFF.apps/oshun/web/e2e/operator-metis-themis-review.spec.tsdrives the operator queue and decision controls, terminal gradebook read-back, learner message, followed deep link, clicked receipt, and mark-read.
Coverage is deep for one-process behavior. It does not prove persistence across restart, external delivery, learner evidence upload, or bias-pause routing.
Per-view files touched by this journey#
customer/08-metis/metis-assessment.md— submit, compact verdict, and appeal link.operator/operator-metis.md— live appeal queue and decision form.customer/02-home-discovery/messages.md— in-app decision notification and receipts.shell/04-auth-session.md— learner/operator scope boundary.shell/05-notifications.md— in-app delivery versus absent external channel.
Cross-references#
metis-lesson-completion.md— upstream learning path.tenant-audit-log-investigation.md— a different persistent/admin audit surface.apps/oshun/bff/src/routes/metis-integrity.ts— HTTP ownership, decision, notification, and gradebook orchestration.apps/oshun/bff/src/metis/academic-integrity-appeal-store.ts— process-local canonical bridge holder.apps/oshun/bff/src/metis/gradebook-store.ts— in-memory gradebook emitter and correction index.libs/metis/integrations/src/themis-canonical-wiring.ts— adjudication, disputes, due process, and audit model.
Open questions#
- Which durable store owns verdicts, disputes, audit records, and gradebook corrections in production?
- What concurrency token prevents two teacher decisions from racing before the closed-state check?
- How can a learner attach and safely disclose supporting evidence?
- Which external channels, if any, deliver academic-integrity decisions?
- How does a terminal grade correction leave this memory adapter for the tenant LMS?
- What policy and UI drive
paused_bias_review? - Should the generic
/resolveendpoint remain distinct from the verdict-selecting/decisionpath?