Skip to content

Settled specification questions

Historical answers retained with their original question numbers and rationale. Some rows include an original decision followed by an amendment: read the whole row and its current ADR before applying it. These are not open tasks. For unresolved and partly settled decisions, read open questions.

# Question Recorded answer
1 Project name, domain name, public or private repository Settled: HEIG Quiz, served at quiz.chevallier.io (staging quiz.dev.chevallier.io, ADR-028), from the public repository heig-tin-info/heig-quiz (deployment runbook, docs/development/deployment.md).
2 edu-ID attributes available to tell a teacher from a student. Is eduPersonAffiliation provided by the HES-SO federation? Otherwise teachers are promoted by the admin. Settled: affiliation available. edu-ID releases eduPersonAffiliation (not eduPersonPrimaryAffiliation); apps/api/src/auth/claims.ts (affiliationsOf) reads it and apps/api/src/roles.ts (roleForIdentity) makes a staff a teacher when it is scoped to one of STAFF_AFFILIATION_DOMAINS and no student of those same domains blocks it; an unscoped or foreign staff is not enough, a student elsewhere does not block. hes-so.ch is in the default because edu-ID releases HEIG-VD staff as staff@hes-so.ch, so staff of the other HES-SO schools also qualify (accepted). Fallbacks: a grant by the admin, or a seat on a course staff.
4 Rounding of the grade: to the nearest tenth, or to the half point like some HES grade scales? Settled: to the nearest tenth, half away from zero, with the method configurable per scale (nearest, up, down): roundToTenth and gradeFromPoints in @quiz/domain (packages/domain/src/round.ts, grade.ts), PLAN-MVP decision D13.
5 immediate feedback allowed in exam mode? Settled (F-EVAL-11, #78): immediate is refused for an evaluation sat in class, that is an exam, or an exercise with a waiting room (lobby auto or manual); it stays allowed for an exercise without a waiting room and for a poll. The rule is isInClass / isFeedbackAllowed in packages/domain/src/evaluationConfig.ts, enforced by FeedbackNotAllowed (422 feedback_not_allowed) in apps/api/src/modules/evaluation/service.ts. An exercise sat in class may still show its correction before the close by an explicit, irreversible act of the teacher, "Publish the correction" (F-EVAL-27, ADR-050, 2026-09-30); the policy is then applied as if released.
7 Runner languages in phase 1: C, C++, Python, JS, Rust. Rust compiles slowly, keep it? Settled: the runner builds all six images by default, c, cpp, python, js, spice (ngspice, for circuit, ADR-019) and rust (apps/runner/images/build.sh). Rust was first built on demand only, being the large image; since #234 it is built by default, by decision of the product owner: a code question may pick Rust, so production must be able to run it. Its cost: ~820 MB on disk, 2 GB free for the build.
8 Are the hidden tests of a code question revealed in the feedback? Settled (PLAN-MVP decision D15): during an attempt the student sees only the count and the points of the hidden cases; in the feedback, names and verdicts are shown and stdin and expected output never are, behind the per-evaluation option showHiddenCaseNames (packages/contracts/src/evaluation.ts, on by default). Amended by ADR-096 (2026-10-10): a hidden case's feedback is its verdict and a coarse failure category (timed out, out of memory, crashed, failed), never its exit code or time; the extra files and compileArgs are public program inputs, published by toStudent.
9 The public pool: who may publish to it at first? Settled (ADR-013): a public pool is READABLE by every teacher; it is written by its owner and by the members the owner named (contributor, owner). The admin remains the de facto owner everywhere — since ADR-054 (2026-09-30), only with Super Powers on.
10 Format of the off-VM backups: Hetzner object storage or other? Settled (ADR-009, amendment of decision 3, decided by the product owner on 2026-10-09, #235): a borg repository (repokey-blake2, deduplicated, zstd) on a Hetzner Storage Box, written every night by the application VM through a key the box forces into borg serve --append-only, for the dumps and assets of every service of the VM; prune and compact only from the operator's workstation. The passphrase is on the VM, which drops #235's "decryption key not on the VM" (why: the ADR-009 amendment). Object storage through rclone was the earlier assumption. Beside it, unchanged: the Hetzner provider backup of the whole VM and the dumps kept 30 days on the VM. The runbook is docs/development/deployment.md §6, The off-site copy; the offsite health check (ADR-055) watches it.
11 Drawing relies on embedded Excalidraw: accepted despite its own style? Settled (ADR-046, 2026-09-29): no Excalidraw. The drawing type is replaced by diagram (04 §4.14), a home-made structured editor on the grid of circuit, whose free kind (basic shapes and a freehand brush) covers free-form drawing.
12 An exercise evaluation with several attempts: best or last? Settled (ADR-025, #92): configurable per evaluation, best (ties to the latest) or last, with an optional maximum number of attempts. Each retake is a new blank attempt with a new seed; between attempts the student sees the score only.
13 Default LLM model for grading and for generation, and who pays: institutional key or the teacher's key? Settled (ADR-058, decided by the product owner on 2026-10-01): the institution pays, through ONE key entered by an administrator and encrypted at rest; one model for every purpose, Claude Sonnet by default, chosen in the administration screen (the schema keeps a model per purpose). No per-teacher key nor quota for now; a daily spending cap guards against a runaway bug.
14 Design system: start from a precise visual reference? The screenshot provided shows the expected dashboard. Settled: the design document is apps/web/DESIGN.md (tokens and components inherited from heig-classroom), enforced by .claude/skills/quiz-ui/SKILL.md.
15 Live poll: how to identify a participant without an account? Settled (ADR-014): a quiz_guest cookie (HttpOnly, SameSite=Lax, path /app/api/p, 12 h) of which the database only keeps sha256(token:evaluation), and one guest_participants row per (poll, browser). attempts.user_id becomes nullable, attempts.guest_id appears, and a CHECK constraint imposes exactly one owner. No fictitious account is created.
16 Live poll: does the end of a poll release results (running → released in the glossary)? Settled (ADR-014): no. "End poll" closes the poll (closed) and launches the deterministic grading, without release: releasing would write a frozen grade for the whole classroom, including the students who never saw the poll, and would make a 1.0 appear on their results page. The result of a poll is the projected distribution.
17 Code question: should the student's trial run in the browser (WASI) rather than in a container, and if so who grades? Settled (ADR-015): the browser runs, the server grades. runtime (backend by default, runno for C and Python) only chooses where the "Run" button executes; grade() always goes through the server's runner, because a result produced by a browser is not proof: WASI is not Linux (no fork, no signals, partial <sys/…>, the browser's clocks). The backend remains the fallback when the browser cannot (D14). The runtimes are hosted by the platform.
18 Poll: pseudonym for a participant without an account (F-AUTH-05)? Settled: no, a guest is anonymous, full stop; the pseudonym field of guest_participants stays null and no UI asks for it. A freely chosen pseudonym is either a real name, and the poll is no longer anonymous, or noise on the projection; the distribution needs no identity.
19 Does a poll appear in the evaluation list of its classroom? Settled: yes, with the "Poll" badge, since it is one (ADR-014); its row opens the projection and not the exam dashboard. Hiding it would make mode: "poll" a phantom evaluation, invisible where its classroom carries it.
20 Schematic question: how is a circuit graded, given that netlist comparison is out of scope (00 §0.6)? Settled (ADR-019): by SIMULATION of the output waveform, not by topology. The student's schematic and the teacher's reference are each rebuilt into a SPICE netlist server-side, run through ngspice (apps/runner, language spice) under every stimulus, and v(out) is compared by the rule of the stimulus's analysis: a transient passes when the normalised RMS distance is at or under tolerance times the reference's swing; an AC sweep (ADR-083) when its Bode plot stays inside an envelope around the reference's (grading.bode: gain within magDb above a floor floorDb under the reference's peak, phase within phaseDeg, one-sided below the floor). A circuit drawn differently that behaves the same is correct; an isomorphism check would need canonical forms for series/parallel merges and would still say no to it. The reference is simulated at grading time, never cached in the config.
24 A teacher acting as a student (impersonation): what may they do — see only, answer, submit — and how is it shown in the audit? ADR-027 shaped the session for it (actor_user_id, session kinds, per-kind route policy, launch tickets) and built nothing of it. Settled (ADR-034, 2026-09-28, #201): an ADMIN only in v1 (with Super Powers on, since ADR-054, 2026-09-30) (the session reads everything the student reads, beyond any staff seat), acting as a user of role student holding a student seat, else 404. Entry by a one-time link copied from the roster row and pasted into a private window (one cookie per origin: a new tab would replace the admin's session). A new impersonation session kind, one hour fixed, reaching the student's portal routes: read-only in production (one rule in the session hook, 403 impersonation_read_only on every write but sign-out), answer and submit in development (AUTH_DEV_LOGIN outside production, the test of invariant 3). Never counted present in the room; no .seb, so SEB exams are out of reach. Audit: impersonation.started/ended (sign-out or expiry), actor the admin, subject the student; tracer attributes any write to the admin. The student is told in the help, not notified.
26 Hiding a course a teacher no longer teaches (#155): a global archive of the course, a per-user hide, or both? And where does a hidden course still appear? Settled (ADR-032, 2026-09-27): per-user hide only, in user_course_prefs(user_id, course_id, hidden_at); no global archive, no course_staff column (an admin reaches every course without a seat — since ADR-054, only with Super Powers on). A hidden course leaves the caller's NAVIGATION only — the course list, both sections of the sidebar, the command palette — and stays in the pickers and in the MCP list_courses (otherwise an assistant would create a duplicate); everything stays readable. Hiding requires access to the course (staffAccess, else 404) and writes no audit event: it is personal display state. The same change makes archived classrooms reachable again, behind "Show archived" on their course.
28 The drill (ADR-041, #317): what the decisions of 2026-09-29 leave undecided. (a) Does deleting a classroom, an evaluation or a question delete the drill data it gave rise to? (b) When nothing is due, an "extra practice" on the weakest tags? (c) A shorter budget on a phone, or types kept for the computer? (d) Damping Easy on a question without variants, whose answer can be memorised? (e) Which evaluation's settings (negative marking, categorizePolicy) grade a review of a question met in several? (f) Opening a whole pool to drill for a classroom (F-DRILL-01)? (g) Does a card leave the session when its classroom is archived ("the courses of the current year")? (h) The feedback after a drill review: is the key shown, even for a question of an exam whose feedback policy hid it (showKey off)? (i) A new seed at each review, so that a question with random values asks the method, not the number (#317, §5)? (j) A card first met in classroom A and met again in B: whose teacher sees its reviews? (k) Does a student's opt-out hide their past drill activity from the teacher, or only stop new cards? (l) A minimum group size for the per-tag aggregates (the per-student view has none, ADR-041 §8)? Settled (ADR-041, decided by the product owner on 2026-09-29, second round of #317): (a) yes: deleting a classroom, an evaluation or a question deletes the drill data derived from it (N-DATA-03); otherwise the five-year retention governs it; (b) no extra practice in v1: an empty day says "nothing to review today" and gives the next due date (amended by ADR-115, product owner 2026-10-15, #897: extra practice exists as targeted revision by concept, on the student's own cards, outside FSRS and the level; the empty day is unchanged); (c) one budget of ten minutes, every v1 type on both device classes; (d) no damping of Easy in v1, and the choices of an mcq are shuffled at each review; (e) a review is graded with the settings of the evaluation where the card was met first (drill_cards.evaluation_id); (f) no whole-pool drill in v1; (g) a card leaves the session when its classroom is archived, and its data is kept for the retention period; (h) a drill review always shows the key (studentSolutionView), and the "Allow drill" setting says so next to its switch: students will see the key of these questions after each review; (i) a new seed at each review; (j) a card belongs to the classroom where it was met first, and only that classroom's staff see its reviews (note 2026-10-16, ADR-039 §6b, settled question 60: this covers a classroom's drill rows and every per-classroom read; the time of the first tries in targeted revision also enters, as an anonymous aggregate over every classroom from ten distinct students, the question's statistics in the pool, under (l)'s threshold); (k) an opt-out hides the activity from then on: what was recorded before stays visible to the teacher, and the opt-out confirmation tells the student so; (l) no minimum group size within a classroom, since the per-student view is visible anyway; the 10-student threshold stays for cross-classroom or multi-year statistics (N-DATA-06).
30 Merge (ADR-035), D26 of docs/merge/08-decisions.md: with Quiz's own GitHub App (D23), should projects too go live in production before the cutover, classroom by classroom, instead of waiting for the migration? Settled 2026-10-01 (product owner): projects open in Quiz together with the import of heig-classroom's data, never before it; Quiz then mirrors heig-classroom, and the teachers change nothing there until the final switch (F-PROJ-20). The cutover itself happens during the autumn semester, as soon as possible (D20). Amended 2026-10-02 (product owner, D26 addendum): every teacher may create projects in Quiz now, before the cutover, where Quiz's App is installed; the import still brings heig-classroom's projects (F-PROJ-20). The students see no project until the project's student view (merge task M3-09).
31 Merge (ADR-035), D09 of docs/merge/08-decisions.md: is the online workspace (heig-classroom's codespace) on the merge's critical path? Production has 3 online assignments, all in test classrooms with a roster of 1 (docs/merge/measures-2026-09-28.md). Settled 2026-10-01 (product owner): off the critical path. The test classrooms are not imported, so no online assignment and nothing of the codespace comes over; the online workspace is rebuilt in Quiz (M6) after the cutover, tested locally and by users, and its migration is looked at only once it is confirmed to work.
32 Merge (ADR-035), D10 of docs/merge/08-decisions.md: are heig-classroom's periodic tasks ported as scheduled_tasks (restart-safe, a status visible to admins, run-now, a period admins may edit)? Settled 2026-09-30 (product owner): yes. scheduled_tasks is ported (merge task M2-05), tasks seeded by code, the period editable by admins, run-now; the clock-bound live tasks stay on the ticker and are not configurable (05 §5.4, Clock; F-ADMIN-06).
33 Merge (ADR-035), D28 of docs/merge/08-decisions.md: what happens to a classroom's journal when the classroom is disconnected from its GitHub organization, or connected to another one (F-GH-04)? The journal is a repository of that organization (F-JRN-01). Settled 2026-09-30 (product owner): disconnecting or changing the organization is refused while the classroom has a journal (409) — amended by ADR-057: only a GitHub-mode journal blocks it; a Quiz-mode journal does not, and the Settings say to remove the journal first (F-JRN-04), which keeps the repository.
34 Does the drill serve an exercise's cards as soon as the correction is published (F-EVAL-27)? Settled (ADR-050, with the product owner on 2026-09-30): yes, by construction. The drill serves an exercise's card once results.keyShownTo says the key reaches that student (ADR-041 §13), and keyShownTo reads the same availability as the feedback page (feedbackGate in @quiz/domain), where a published correction counts as the release. So, under showKey, the cards are served to each student whose latest attempt is handed in, and held back again while a retake is being written; under none or without showKey, never. No drill rule was added.
35 Bonus questions (ADR-052): may the bonus flag of an item still change once an attempt exists (a teacher who realises after the exam that a question was too hard)? And does the threshold grade scale stay beside them? Settled 2026-09-30 (product owner): the flag is locked exactly like the points, once an attempt exists or the evaluation has been opened (assertItemListEditable); a teacher who needs to soften an exam afterwards corrects the points by hand. The threshold scale is removed: the scale is linear only, and migration 0040 turns the existing threshold rows (one draft in production) into linear with their rounding.
36 Kiosk stations (ADR-051): may an exam be sat on a school Chromebook attested by Chrome Verified Access, paired from the student's phone, beside Safe Exam Browser — and how does that meet D21, N-SEC-01 and N-SEC-10? Settled (ADR-051, with the product owner on 2026-09-30): yes, for exam only, as a second confined session kind kiosk beside seb, chosen per exam (settings.kiosk). D21 is settled for evaluations only (a SEB session checks its Config Key on every request, audit-only until proof B; a new confined session supersedes the previous one of the same student and exam, portal sessions untouched); the confinement to an activity stays open there. Confined cookies are SameSite=Strict. An unnamed station cannot be paired. A refused attestation suspends a kiosk sitting until the next accepted one; Google being unreachable suspends nothing, and the supervisor is alerted in both cases. The station polls for the approval (RFC 8628) instead of using the event stream. The extension admits the production and staging origins.
38 Parameterized questions (ADR-056): are the values drawn for an item recomputed from the attempt seed on every read (as permutations are, D19), or stored? And a regrade with version N? Settled 2026-10-01 (product owner): drawn for every parameterized item when the attempt is created and stored in attempts.instances (with the version they were drawn for); recomputed from the seed only where nothing is stored (the stateless student preview). A regrade with N keeps them when N declares the same variable names, and is refused for that item otherwise (ADR-056 §5).
39 Parameterized questions: where do the variables live, and what do the grading table (ADR-044) and the debrief (ADR-033) show when every answer has its own key? May a poll carry one? Settled 2026-10-01 (product owner): a header field of the version beside explanation; the table pins the template and shows each row's key in the side panel, rows and the debrief group by verdict, statistics are pooled across instances; a poll refuses it (ADR-056 §1, §9, §10).
44 Merge (ADR-035), D21 of docs/merge/08-decisions.md: the unified Safe Exam Browser design for projects — a seb session confined to an activity rather than to an exam, packages/seb, Browser Exam Keys per activity. Settled 2026-10-01 (product owner), on the suggestion, for M6: packages/seb, every .seb built by the platform, a seb session confined to one activity, the Config Key alone by default and Browser Exam Keys optional per activity, proof B before the first SEB project.
45 Merge (ADR-035), D20: does the import carry heig-classroom's GitHub account links (the GitHub id is the person's, docs/merge/03-github-projects.md §3.4), or does every student link their account again in Quiz? Settled 2026-10-01 (product owner): the import carries them. A link is an identity, not a grant: github_user_id and the login, no token (F-GH-05), so the App that recorded it does not matter, and Quiz's App invites by login with its own installation token. A link whose user is matched to a Quiz account is imported (unless that account or that GitHub id is already linked otherwise: reported, not merged); a student with no link in heig-classroom links from their settings.
46 Merge, D26 and D20: is heig-classroom frozen at the import, or does a window follow it in which both platforms run on the same repositories ("Quiz mirrors heig-classroom, the teachers change nothing there")? In such a window both Apps would lock, commit and restore on the same repositories. Settled 2026-10-01 (product owner): the import is the switch. One evening heig-classroom's web service is shut down, its database dumped and imported; from then on only Quiz acts on the repositories.
47 Merge, D20: the import makes no organization link, each teacher connects by hand. When? An imported project whose classroom is not connected has no App to act through: its pushes would get no receipt (and count as late), its deadline would not be applied. Settled 2026-10-01 (product owner): before the cutover. Each teacher installs Quiz's App and connects their Quiz classrooms; the import refuses a mapped classroom not connected to the organization its heig-classroom classroom used, and names it.
48 Gradebook (D06): what does a cell hold for a student who never took a released evaluation, never accepted a project, or for an evaluation released under the feedback policy none? Settled 2026-10-01 (product owner): a project never accepted leaves an empty cell that does not count. An absence has a mark of its own, as in the school's grade tool, where a1.0 means absent, hence 1.0: an evaluation released and not taken shows 1.0 marked as an absence (a sigil and a colour of its own, never colour alone, N-A11Y-03) and counts as 1.0. How a teacher marks an absence by hand, and how the mark travels in the CSV, is settled with the gradebook's screens (M5-04). Settled 2026-10-05 (product owner, ADR-074): an absence has two sources, both shown with the sigil — derived (a released exam not taken; an exercise not opened is an empty cell) and a stored staff mark absent, or score (the teacher's own points out of a maximum, which fills the cell of a project never accepted); a mark wins over the grade beneath it, replacing a real grade needs override: true; marks are staff-only until their column is released. How a mark travels in the CSV is M5-03b's.
49 A project's grading scale (D05): the default, the preset "the score is the grade" when the maximum is not 6, and a final score whose maximum differs from the frozen one's. Settled 2026-10-01 (product owner): Quiz's linear scale, the default; the preset "the score is the grade" only for a score out of 6, the linear scale otherwise, with a warning; every score converts with its own maximum.
50 F-EVAL-11: is immediate feedback shown after each question the student validates, or once the attempt is handed in? Settled 2026-10-02 (product owner, ADR-067): per hand-in. An exercise attempt is graded as soon as it is handed in, expires or is closed by the teacher, whatever its feedback policy, and immediate shows that feedback then; nothing is graded or shown per question while the attempt is open. An exam is graded at its close and shows nothing before it.
51 Course staff roles: does every member of a course's staff keep every right, or do some actions belong to an owner? Settled (ADR-068, product owner, 2026-10-02 and 2026-10-04): two roles, owner and assistant. An owner manages the staff and their roles, the course's name, code and deletion, its linked pools, its classrooms' creation and deletion, and the release, withdrawal and correction publication of its evaluations; an assistant does the rest (403 owner_required) and may leave the course on their own. A course keeps at least one owner (409 last_owner); every existing seat became an owner. An assistant may still set the feedback policy immediate, an accepted loophole. Amended 2026-10-10 (security audit M1/L1, ADR-068 §3): deleting an evaluation that is released, has its correction published or holds a student attempt (a poll: once released), and every grading write on a released evaluation, are an owner's too.
53 A teacher's test repository: may a staff seat accept an individual project? Settled 2026-10-06 (product owner, ADR-077): yes, an individual project only; the repository is visible and badged "Teacher" on the staff page and counted nowhere; no group projects for staff seats (409 no_group); no reset; a test with an organization owner's GitHub account does not reproduce the rulesets and protected files (documented, no refusal in code); removal from the course staff keeping the staff seat is a follow-up; imported staff repositories (M8-01) are counted in its dry run.
55 Item intro (ADR-084): (a) should a shuffled paper (shuffleItems) pin its intros to their positions instead of letting each travel with its item? (b) should passing an intro be recorded on the server, so that a "memorise this" text behind a milestone cannot be read again after a reload before its question is started? Settled 2026-10-08 (product owner, ADR-084): (a) no pinning; an intro travels with its item under shuffleItems, as the milestone flag does. (b) No server record; the passage is held by the player, and a reload before the question is started shows the text again.
58 The project page's table (F-PROJ-13): does a row show the current, frozen, review and teacher scores, as the requirement says, or the final score alone? Since before the dashboard (PR #775) the table shows one Score column, the final score in bold over its source (CI, review, teacher) as faint text; the four scores are in the row's sheet (TeacherScoreForm.tsx). Raised 2026-10-11 by the orchestrator. Settled (orchestrator, 2026-10-11, by delegation of the product owner): the repositories table shows the final score with its source (CI, review, teacher); the current, frozen, review and teacher scores stay in the row's sheet. F-PROJ-13 says so.
60 Targeted revision (ADR-115, #897 step E, the product owner's answer 7 of 2026-10-15): the time per question of a round (drill_revision_answers.time_ms) is to feed the question's mean answer time, but that statistic counts exam answers only (ADR-039 §6). Does it (a) join the exam series, or (b) form a separate series shown beside it? Until settled it was stored and fed to nothing; it never feeds the drill's rating reference times (ADR-115 §6, assumed). Settled (product owner, 2026-10-16, #897 E3): (b), a separate "Time in targeted revision" series beside the exam series, never merged into it nor summed into "Generate a quiz" (F-STAT-04): per question, one value per student, the time of their earliest answered first pass (any correctness, a zero left out), among the passes served since the question's last reset; shown from 10 distinct students (REVISION_TIME_MIN_STUDENTS), median with P25–P75, no mean; labelled in the question's statistics panel as a first try on a question already met whose key the student could see, not an exam time; the entry exists when either series qualifies. Rule and privacy reasoning: ADR-039 §6b, with F-STAT-01. Taken by assumption, the product owner may change them: the anonymous cross-classroom aggregate sits in the pool's panel (ADR-039 §6b, beside ADR-085 §8); and its residual differencing risk is accepted: with no mean there is no exact recovery that always works, but the median, compared before and after one student's round, can sometimes equal or bound that student's first-try time (ADR-039 §6b).