ADR-018 — The real student view and stateless preview¶
Status¶
Accepted (2026-09-22), consolidated through 2026-10-01. ADR-020 changes staff presence only; ADR-025 extends own-attempt reset to retakes; ADR-056 governs parameter instances. This consolidation changes no decision. The historical record retains the original decision numbers and seven UI amendments. Amended 2026-10-13: what a list's Participants count includes (Participants in the lists).
Context¶
A real rehearsal must exercise the student's production path without contaminating class results. A stateless preview answers a different question: whether the configured evaluation is right, before starting it or freezing its structure. These are separate modes, not separate implementations of the student player.
Decision¶
Real student view and return¶
The Teacher/Student switch belongs to the application frame, with account-menu
and command-palette access. It is available to teachers/admins, not students.
It is secondary chrome (no accent, one tier under the page's primary action), so
invariant 2 is untouched.
The mode and return path live in sessionStorage: reload preserves one tab's walk
without changing another tab's dashboard. Entering from an evaluation or its live
dashboard goes to that evaluation's /take/:id; an existing student route stays,
other pages go to the student home. Return restores the entry route.
The switch does not enroll anyone. A teacher obtains a staff seat explicitly with
Join as student on the classroom page. Without a seat, /take/:id answers 404
as it does to a stranger (invariant 6), and its screen explains that path to a
teacher. A teacher who is not staff of the classroom holds no seat and gets the
same 404; this record does not change that. The former evaluation-page button and its
automatic enrollment confirmation are gone.
The real attempt uses the student's lobby, player, content, grading and server
clock, including the normal deadline/410 rules and confined-exam requirements
(ADR-027). The attempt page
has no ordinary application frame, but a teacher in student view gets the return
banner and, inside the player, a "Back to teacher view" entry in the Ctrl+K
palette; returning leaves the attempt open. Students never see that banner.
Staff attempts¶
Staff attempts are visible and badged in the dashboard, grading and result tables. A staff seat without an attempt creates no row. One shared staff-attempt query identifies them. They count in no completion/success statistic, histogram, per-question distribution, released grade snapshot or CSV. The export omits the row completely rather than asking downstream consumers to honor a flag.
Presence is the deliberate exception (ADR-020): a staff member actually sitting the evaluation is a person in the room. Staff seats with attempts contribute to the presence denominator; dashboard-only connections do not create presence.
DELETE /evaluations/:id/attempt resets only the caller's own staff-seat attempts
(all their attempts when retakes exist), with dependent answers, attempt log and
gradings cascading. Staff access, staff seat and ownership are loaded predicates;
neither a student's nor a colleague's attempt is reachable. The student deadline
write gate does not prohibit deleting one's own rehearsal. Audit:
attempt.staff_reset; dashboards receive a refresh hint rather than a synthetic
live row-deletion protocol. Entry remains idempotent; reset is explicit.
Staff repositories¶
Accepted 2026-10-06 (product owner), ADR-077. A staff seat may accept an individual project to test it. Its repository is visible and badged on the staff page and counted nowhere: no count, no release, no gradebook, no notification. A group project is not testable from a staff seat (ADR-070 §2).
Participants in the lists¶
Amended 2026-10-13 (product owner). The Participants column of a classroom's
Activities tab counts people, not attempts or repositories: for an evaluation,
the distinct students and poll guests who have an attempt (a retake counts
once); for a project, the owners of its provisioned student repositories, or a
group repository's non-staff members (a seat not claimed yet included, and a
member on their way out of the group, whose access is not revoked yet). It
never counts a staff seat's rehearsal nor a staff test repository. The
evaluation's attemptCount, which locks the item list (F-EVAL-26), still counts
every attempt, the staff's included.
Stateless evaluation preview¶
The secondary Preview action opens a new full-screen tab in every evaluation state,
loaded through its staff predicate. No attempt, answer, attempt-log, grading or
audit row is written by preview start/run/simulate/grade. Answers and the countdown
live in memory in the browser. The student's PlayerView and reducer are reused,
without autosave or a live stream. A restart draws a new seed.
Start returns a seed, duration, student view and frozen version map. With a supplied
seed it rebuilds that walk. Question order, shuffles and parameter draws are
reconstructed from stored versions on the server; clients supply answers and seed,
never authoritative question content. All student content passes toStudent.
The preview countdown uses duration, or common-window length, and none for manual
timing; expiry hands in locally. It is intentionally not a test of the server clock.
Grade validates answers, applies the type's grading rule and evaluation defaults,
and runs all runner cases including hidden cases. It returns the correction outside
the student's feedback policy. Manual/proposed outcomes are not silently treated
as validated marks; an unavailable runner is an item status rather than failure
of the whole correction. The current preview does not call the LLM provider and
reports llm_unavailable for that path. Run/Simulate rebuild sources from stored
templates, expose only visible cases, and share the real interactive helpers.
Budgets are in memory per teacher: ten gradings/minute and the question's run
budget; compilation has the separate budget of ADR-024.
Preview does not exercise autosave races, the server clock/deadline gate, server-side navigation enforcement, pause, real lobby/presence, the attempt log or persisted grading. Use the real rehearsal for those properties.
Editing during preview and previewing the lobby¶
Edit question opens its draft in another tab only when the caller may edit it. Use the new version uses the ordinary item-update route only while the item list is editable, rebuilds with the same seed, replaces that question and drops only its answer. Other order/shuffles/answers remain. Frozen lists explain why no update is offered. Other item/version changes require Restart to avoid grading content the teacher did not answer. The countdown continues while editing elsewhere.
The preview uses a ModeBanner saying nothing is saved. Restart asks once answers exist and is disabled during grading; after correction it is the page's primary action. Edit and Show the points live with the player's question tools, not in an alert above the question. Version-change notices appear only when applicable.
The launch-step waiting-room preview renders the pure LobbyScreen, never its
connected Lobby container: no stream, clock request or presence registration.
It uses already loaded evaluation rules, zero presence and the roster denominator,
never question content. An evaluation that skips the lobby has no such preview.
Consequences and alternatives¶
A real staff rehearsal leaves ordinary data but never a student grade. A preview is cheap and available before launch but cannot certify the exam path. Dedicated simulation-attempt tables, implicit enrollment on a global toggle, cross-tab mode storage and trusting question content from the browser were rejected. Current inline title editing is independent of these modes: safe title changes remain allowed on a structurally frozen evaluation.
Implementation references¶
apps/web/src/studentView.ts,App.tsx,Shell.tsx: mode, routing and banners.apps/api/src/modules/evaluation/andmodules/guards.ts: staff attempts/reset.apps/api/src/modules/preview/routes.tsandservice.ts: access, seeds, budgets, grading and runner failures;packages/contracts/src/preview.ts: payloads.apps/web/src/preview/: player adapter, edit/version detection and correction.apps/web/src/student/Lobby.tsx: pure screen versus connected lobby.
Historical section references¶
Original numbered decisions and addenda are historical; apply the consolidated decision above. Their full text is the historical record. A citation in code or another record ("ADR-018 §3", "ADR-018, sixth addendum") lives here now:
| Old reference | Current section | Full text |
|---|---|---|
| §1 the walk; §2 where it was entered from; §7 the student path; first to third addenda | Real student view and return | first, second, third |
| §3 shown and badged; §4 counts in nothing; §5 CSV drops the row; §6 own reset | Staff attempts | §1–§7 |
| Fourth addendum (stateless preview) | Stateless evaluation preview | fourth |
| Fifth addendum (waiting room); sixth (fixing a question); seventh (preview is a mode) | Editing during preview and previewing the lobby | fifth, sixth, seventh |
Amended 2026-10-09: the list of compatibility anchors into the historical record was reduced to this table (the references that code and records cite) and bare compatibility anchors, so old links still land here; the full text stays in history/ADR-018.