Skip to content

Design Gaps

github-actions[bot] edited this page Oct 14, 2026 · 1 revision

Design gaps — requests to the design team

The deck in docs/design/deck/ is the single source of truth for the UI. This register lists what the deck does not draw, what it draws in two incompatible ways, and where a decision overrides it: DG-01 to DG-11 were taken with Thuong on 2026-09-26, DG-12 to DG-19 on 2026-10-03 with the second import, under his delegation; DG-117 on 2026-10-04, likewise. Each entry says what we build until the design team answers ("Meanwhile") and which release needs the answer (docs/plan/70-redesign-overview.md).

DG-108 to DG-116 were opened on 2026-10-04 with the third import, which redrew the Test builder's editor pane and the import review's "Question" field. Their "Meanwhile" is the default the plan builds (docs/plan/74-r4.md), not a decision: each stays Open until Thuong or the design team answers. That import fully answers no earlier entry; DG-35, DG-36 and DG-60 are partly answered and say so, and DG-63, DG-69, DG-80, DG-83 and DG-90 carry a note of what it added.

DG-118 and DG-119 were opened on 2026-10-04 with R3's documents (docs/plan/73-r3.md, T-R3.13 and T-R3.14). Their "Meanwhile" is what R3 built. DG-80 holds the engine's frames for sign-off as one list.

DG-122 was opened on 2026-10-04 with R4's plan (docs/plan/74-r4.md, T-R4.51). It is the decision DG-117 and DG-119 record, taken for the Teacher deck under the same delegation.

DG-182 to DG-195 were opened on 2026-10-12 with the fourth import (T-D4.1 of docs/plan/74d-d4-deck-update.md): the design team's export of 2026-10-04, 17:31, which rebuilt the Student take-test screen and the Teacher builder's shared content, and which the v2 export carries byte for byte in every file it did not touch. Their "Meanwhile" is the default the plan builds, not a decision: each stays Open until Thuong or the design team answers. DG-182 moves to the decisions above only if Thuong confirms the default (Q3 of that plan). The import also leaves notes on DG-36, DG-60, DG-63, DG-68, DG-69, DG-80, DG-111, DG-113, DG-115 and DG-116. T-D4.12 (2026-10-13) made the "Meanwhile" of DG-182 to DG-194 say what D4 built; each still stays Open until answered. A reference "S n" or "T n" is a line of the pretty form of the fourth export's Student or Teacher page (docs/plan/74d-d4-deck-update.md, "Reading the references").

DG-196 to DG-202 were opened the same day with the v2 export of 2026-10-10, 10:44, which draws the AI assistant. Their "Meanwhile" is likewise the plan's default (D4, sections F and G). That export answers DG-01 and leaves notes on DG-22, DG-36, DG-63, DG-71, DG-100 and DG-106. T-D4.40 added a "Built in D4" note to DG-196, DG-197 and DG-199 to DG-202 saying what the server built (T-D4.31 to T-D4.33); the web tasks T-D4.34 to T-D4.39 add what they draw. DG-198 is R8's, not the assistant's.

DG-210 to DG-212 were opened on 2026-10-13 by T-D4.12's comparison of the built screens with the deck. Their "Meanwhile" is what D4 built; each stays Open until Thuong or the design team answers.

DG-213 to DG-216 were opened on 2026-10-14 by T-E1.5's comparison of the builder with the deck after E1 (docs/plan/74e-e1-group-move.md) let a question be dragged into and out of a shared-context group. The deck has no group inside a section, so each row is a part of that drag the deck cannot have drawn. Their "Meanwhile" is what E1 built (v0.11.6); each stays Open until Thuong or the design team answers. E1 also reversed DG-186's Q8 default and changed DG-211.

DG-205 and DG-206 were decided on 2026-10-12: the owner asked for one page width, and the design team's page-width design (deck/page-width-proposal/, imported from c1472f4c) is the approved answer.

When a new export answers an entry, mark it Answered with the export date, and delete the "Meanwhile" rule once the product matches the drawing.

Status: Open — needs the design team. Decided — Thuong decided; the deck should be redrawn to match. Answered — resolved by a later export.

Decisions that override the current drawings

ID Where What changes Status Needed by
DG-01 Teacher › Class detail, join code card Codes are stored encrypted and always shown in full to their teacher and to admins. Answered, 2026-10-10 (v2 export): the card shows the full code, the link, the QR and Copy code / Copy link / Download QR, and the New-code dialog says "Share the code, the link or the QR with your students."; no sentence about showing the code once remains. Built by T-D4.23 (the card, the projector dialog and the New join code dialog). Members' "Joined via" still shows "Code ••{hint}": the deck's full code there needs a field the contract does not carry, which T-D4.23 left for a decision. Left out of D4 (T-D4.12): showing the code in full there is a contract change to what a member row says about a join code, under spec §6 (join codes, a high-risk area), so it waits for a task of its own; D4 keeps the hint. Answered R4, D4
DG-02 Sign in › Join, Student › Join dialog, Landing The public preview never shows a student count ("{n} students" goes); schedule and room may stay. Sample codes must use the §6 alphabet (ABCDEFGHJKLMNPQRSTUVWXYZ23456789, which has no 0, O, 1 or I): ABCD-1234 becomes e.g. K7QM-2PXA. Draw the invalid-format state (the Landing input silently does nothing today). Decided R1, R8
DG-03 Admin › Roles & permissions Add the row "Create student accounts" (Admin and Teacher on). The Teacher Students page has "Add student", but "Add and disable users" is Admin-only. Decided R2
DG-04 Admin › Users, Roles Assistants are attached per class (class staff). Draw where a teacher or admin adds an assistant to a class, and what an assistant's sidebar shows. Until then Assistant is hidden from role pickers. Decided R5
DG-05 Admin › Users import, password resets Emails carry a one-time set-password link, never a temporary password. Draw the set-password page (signed out, from the link) and reword "Email sign-in details". Decided R5
DG-06 Landing › Consultation Add an explicit consent checkbox and a linked privacy notice page; leads are kept 12 months. Decided R11
DG-07 Admin › System settings › Data & privacy Retention choices drive a nightly sweep. "Delete disabled accounts after" anonymises the account (results stay, identity is removed) rather than deleting rows; please reword the hint. Decided R5
DG-08 Teacher › Messages Direct messages are readable by their participants only; admins never open them. Nothing to redraw unless an admin surface is added. Decided R7
DG-09 Teacher › Media A published test version never changes. "Replace file" reaches drafts and bank questions only, and a file used by a published version cannot be deleted. The Replace and Delete copy says otherwise; please redraw both, including the "used in published versions" case. Decided R4
DG-10 Admin › API reference The API has no /v1 prefix. The base URL reads https://api.quizzivy.com. The "Try it runs as you and is recorded" note is false: the docs session holds no bearer token. Decided R5
DG-11 Admin › Audit log The diff shows join codes by their last four characters only, never in full. Decided R5
DG-12 Teacher › Imports › Paste a test Every paste is plain text. The box is a plain textarea, and the prototype keeps only a label of where the last paste came from, never the formatting. The product stores and processes the text alone, whatever the clipboard held. The kind pill has one state, "Plain text · mark answers with * or “Answer:”", and shows whenever the box has text, typed or pasted (the prototype shows a pill only after a paste event, a clipboard read or the sample, never for typed text); the pills "From Word or Google Docs · bold, underline and colour kept" and "Rich text · basic formatting kept" and the "Formatting kept from …" lines do not ship. Recognition never takes an answer from a mark, so no answer is lost. Redraw the pill with its plain state only. Decided R4
DG-13 Teacher › Imports › Paste a test, "Found so far" The quick count follows the server's recognition rules for pasted text, not the prototype's WI_detect, so the page cannot contradict the review; one fixture, api/testdata/pasted-text-counts.json, holds both sides to the same numbers. The server learns the conventions the page teaches (T-R4.56). What still differs from the prototype: "Question 1" counts without punctuation after the number (tip 2 promises it, and the prototype misses it), and "Q1" and "Cau 1" are questions too; a bare number is a question only in sequence (the next number, 1, the first of a part, or a jump forward of at most 20), so a repeated or out-of-order bare number is not counted, where the prototype counts every numbered line, and the duplicate note still names it; "0.25 points each" is not question 0; "Part A", "Exercise 2", "Bài tập 1" and a bare "II." are parts; options may share a line and run past D; a * counts only before or after an option, never inside a stem; an answer at the end of a question or option line counts, and so does a key heading alone on its line with its entries beneath; the limit is 100,000 code points after NFC normalisation, where the prototype counts UTF-16 units. Nothing to redraw. Decided R4
DG-14 Teacher › Imports history, pasted rows; Imports › processing, the Ready card The To review chips and the Ready card's pills read "{n} need action" and "{n} to confirm" for every import. The deck's "{n} needs an answer" / "{n} need an answer", on a pasted row and as the first pill of a pasted import's Ready card, does not ship: the count covers every blocking finding, not only a missing answer. The Ready card's success pill "Every question has an answer" ships, shown when nothing blocks and no answer is missing (T-R4.37). The search does not match the "Pasted text" label, as the prototype's does: the label is localized and the stored filename is hidden, so a pasted import is found by its title only (T-R4.55). Decided R4
DG-15 Teacher › Imports › Paste a test "Use a sample" in the paste box is prototype chrome and does not ship, like the same button in the file slots. "Paste from clipboard", with its two failure messages, and the "Copy example" button ship as drawn. The example it shows and copies does not: the deck's (WI_PZ_EXAMPLE) ends "Answer key: 3-since 4-for" but holds only questions 1 and 2, so the page uses a case of api/testdata/pasted-text-counts.json with nothing missing (T-R4.57). Please redraw the example so its key names its own questions, and mark the sample buttons as prototype-only. Decided R4
DG-16 Teacher › Imports › Paste a test, footer hint "Processing takes a few seconds." ships only if T-R4.51 measures 10 s or less from Start to ready, on a cold worker, for the deck's sample. Otherwise the footer uses the file flow's sentence, "Processing takes about a minute. You can leave this page.", and this entry records the measurement. Measured 2026-10-12 (T-R4.51, docs/team/verification-r4-51.md): 2.33 to 2.42 s in ten runs, from the click on Start processing to the visible "Ready for review" card, with the deck's sample (912 characters, ten questions), an idle local worker woken by the API, and nothing else running. The run itself takes 67 to 96 ms; the rest is the page's 2 s poll. So the footer takes the deck's sentence, in both languages (QA-51-8). Not measured: a stopped Fly machine booting before it hears the wake. Decided R4
DG-17 Teacher › Imports history; Teacher › Imports › new import (Source); Admin › Audit log Status filters are a group of toggle buttons, and their counts follow the search. The deck marks the segmented status filter role="tablist" with role="tab" options; the product's Segmented stays a role="group" of aria-pressed buttons, because a filter has no tab panel to control. The Source switch on the import page ("Upload a file Paste text"), which the deck also marks role="tablist", is the same Segmented with the same semantics, for its own reason: it swaps one card and the heading above itself while the title, "How to read the content", the privacy callout and the footer stay, and the mode is a URL parameter (?source=paste), so no single panel belongs to a tab. On the Imports history each count is the number of imports under the current search (T-R4.21's facets); the prototype counts the whole list and ignores the search box. The look, the order, the count badge on every option and the track that scrolls sideways are built as drawn. The Audit log's counts are DG-19. Nothing to redraw. Decided
DG-18 Teacher › Imports history The list switches layout by a container query on itself: the six-column grid from 960px of its own width, stacked cards below, no sideways scroll at any width. The prototype computes that width from the viewport: width − sidebar (248, or 60 collapsed) − 56, or width − 28 under 768. The column tracks are the deck's, apart from DG-21. Nothing to redraw. Decided R4
DG-19 Admin › Audit log The tab counts are real and follow the search and the date range, ignoring the selected tab (facets on listAuditLog, T-R5.12). All also counts the entries only the All tab lists, so it can exceed the sum of the six families. The deck's counts are static (All is a literal 1,248 beside families that sum to 132), and its search box and date control do nothing, so it does not say what the counts follow. Decided R5
DG-117 Sign in › every page, the heading; Sign in › the small logo under 900px The heading keeps a 1.25 line-height and the small logo keeps a 28px margin. The Sign in deck's five h1s set no line-height and inherit the page root's line-height:1.5 (a 36px box at 24px); the System pages h1 and eight of the Student deck's eleven set line-height:1.25, which is the product's --text-h1--line-height. The product keeps 1.25 everywhere, so the content under a sign-in heading sits 6px higher than drawn, 12px under a two-line heading. From the top of the small logo to the heading the deck measures 62px and the product 56px: the extra 6px is the line box under the prototype's inline <img>. Please set line-height:1.25 on the Sign in h1s and make the logo a block (#170). Decided R1
DG-122 Teacher › sixteen page headings The heading keeps a 1.25 line-height. These h1s set no line-height and inherit 1.5; the product keeps 1.25, as DG-117 and DG-119 do for the Sign in and Student decks. Decided R4
DG-140 Teacher › Tests, the cards A test card can be selected, and duplicates beside its menu, as the approved list change request of 2026-09-22 asks (spec §8: explicit multi-selection with confirmed bulk removal; duplication beside the row menu and inside it). The deck's cards draw neither. A checkbox leads the card's head row, before the status pill; selecting shows the deck's inverted bulk bar (Archive selected, Delete permanently) above the grid. Once a card is ticked the bar also offers "Select all on this page" until every card shown is selected; the selection holds across pages, tabs and searches, and while some selected tests are not shown the count reads "2 selected · 1 not shown" (F-36, QA-29-2 and QA-29-3). The footer ends with a 26px Duplicate button and the "…" menu, in the place and the size of the deck's Share button, which comes with sharing in R7. Please draw the selection and the two buttons. (T-R4.29) Decided R4
DG-142 Teacher › Imports › Paste a test, "How to lay out pasted text" The tips switch to two columns by the card's own width, not the viewport. A container query at 594px, the card's inner width at a 900px viewport with the sidebar expanded, matches the deck there exactly (measured at 899 and 900). Where the card is wider than the deck's viewport rule expects, two columns arrive early: with the sidebar as a drawer from 624 to 767px, and with it collapsed from 768 to 899px, where the deck still stacks the tips below the example (T-R4.57). Nothing to redraw. Decided R4
DG-143 Teacher › Tests › Builder, "Student preview" The Student preview scrolls the paper, with Previous and Next moving between questions, so a group's passage stays in view; the deck pages one question at a time. The preview draws the draft through the engine's readers, which put a shared group's passage above that group's first question only, so a one-question page would lose it for every later question of the group. Previous and Next scroll each question into view and say "Question {n} of {total}"; the dialog opens on the question being edited (T-R4.31b). D4's full-window preview (T-D4.2c) replaces this dialog. Please draw the scrolling preview. Decided R4
DG-144 Teacher › Tests › Builder, "Publish test?" Publish keeps its full weight while a check fails, and pressing it shows "Fix the items above before publishing" instead of sending; the deck greys it. The deck greys Publish through its form's validate, while the checks are an info field, which the shared FormDialog leaves out of validation and which no other dialog needs to fail. The failing rows already say what to fix and carry "Fix it", and the alert says why nothing was sent. The third check, "All groups have instructions or a title", is built: it shows whenever the test holds a group, and it always passes, because the contract requires a group's title (T-R4.31b). Decided R4
DG-145 Teacher › Test detail The preview is the student's paper, not the deck's sketch of it. The deck draws five questions with two-column options and "Showing 5 of {n} questions"; the detail renders the chosen version through StudentPreview, the engine's own question sheets, every question, with "{n} questions. Answers are hidden from students." under them. The phone frame is the deck's 390px with a 24px radius. "Changes from version {n}" lists Removed rows too, with a danger chip the deck does not draw, because the diff reports questions the newer version dropped (DG-66). Assign is off for an archived test as well as for one with no version, since the wizard cannot assign it. Restore as draft and Delete stay focusable when they are off (aria-disabled with the deck's title as their description), so a keyboard user hears why; Make default is plainly disabled, as the archived note says why. The publish confirm carries an optional change note of up to 200 characters (DG-66). Share waits for sharing in R7 (DG-90). (T-R4.30) Decided R4
DG-146 Teacher › Question bank › Question editor, "Delete question" A question that a draft test still uses cannot be deleted; the deck deletes it and says "It is used in {n} tests. Those tests keep their own copy." A draft outline references the bank question rather than holding a copy, so the server refuses the delete (QUESTION_REFERENCED) while any draft uses it; only a published version keeps its own copy. For such a question Delete opens "This question cannot be deleted yet", which links each draft test, and sends nothing; a question no test uses asks "Delete this question?" with "No test uses it. Published tests keep their own copy." A refusal from the server shows the same list (T-R4.33). Decided R4
DG-147 Teacher › Imports › Review The review is the deck's card with the product's rules inside it. The title in the top bar stays an input, styled as the deck's text, because the title is part of the saved draft. "Page view" shows in the source pane's view switch but is off, described by "Page view is not available yet.", until a page renderer exists (DG-67); a pasted import offers "As pasted" only, as drawn. A shared passage is a dashed panel holding its member questions' cards, with each gap a button that opens its question, not one cloze card, because the draft keeps a group's questions as questions (DG-68). Findings on a section or a group sit under its heading, and findings on no question in the Whole test card, which opens first when the first open finding is one of them. Picking a candidate radio card applies its value at once, as every other edit in the review does, and the provenance chip of a teacher's edit reads "Edited by you". A phone is read-only, as today, so its dismissible note says "On a phone you can look through the review; make changes on a larger screen." rather than the deck's "fix small items here". The question menu holds Exclude or Restore only (DG-67). "Preview & finish" and the "Everything is resolved" band open today's summary dialog until T-R4.39 builds the preview. Please draw the group panel and the read-only phone. (T-R4.38) Decided R4
DG-148 Teacher › Imports › Preview and create The preview shows every included question through the student's paper, not the deck's sample. The deck draws seven of 34 questions in its own sketch with two-column options; the page draws the saved draft through StudentPreview, the engine's question sheets, as the test detail does (DG-145), and reads "{n} questions. Answers and your notes are hidden from students.", or "Showing {k} of {n} questions…" while a question has a type the paper cannot draw. "Audio and images" reads "None" with "Images and audio are not imported. Add them in the test builder.", not the deck's "None needed": an import never carries media, so whether any is needed is the teacher's call. The summary's first row reads "Questions included", since it counts questions, where the deck says "Answers included". The deck's "Your latest change is not saved" hint is not built: the review saves before it opens this page, and its leave dialog keeps the teacher there when it cannot. Danger ink means the row blocks the draft. The deck reds every value that carries a link, including "Points: Not confirmed"; here only "Answers set" while a blocking answer finding is open and "Still to resolve" while anything is open are red. A gap that does not block (a short answer with no sample answer, default points) reads in normal ink and links to where it can be set: the question's own card (/review?question=) or the filter that lists it, never an empty filter (QA-39-2). Please redraw the preview as the student's paper, the media row and the two inks. (T-R4.39) Decided R4
DG-149 Teacher and student › the bell On a phone the list opens in the shared sheet, not the decks' popover, which leaves 12px either side of a 336px card under the bar; the sheet takes the whole width with room for long Vietnamese sentences and a close button. The student's panel has "Mark all read" (DG-82), and both panels have "Load more", "You're all caught up.", a loading state and an error line with Retry, which neither deck draws. The time under a row is the reader's language ("2 hours ago", "yesterday", the date from a week back) rather than the decks' samples. Please draw the phone sheet and the four states. (T-R4.45b) Decided R4
DG-150 Teacher › Assignment › Students, the attempt sheet's "Attempt timeline" "Answers autosaved" reads "while answering", not "every 10 s", and shows only when nothing else was recorded. The engine saves an answer 1.5 s after it changes, not on a ten-second clock, and the events payload holds no save events, so the row is a fixed line between the start and the submission, where the deck draws it for an attempt with nothing else to show. Leaving the test (another tab, another window, fullscreen, and the submission that leaving forced) is a danger dot with how long it lasted ("Left fullscreen · 14 s", "Switched to another tab · 2 min"); a lost connection, audio, pastes and every other kind keep a neutral dot, so a dropped network never reads as a focus loss. Times read to the second, as the full timeline does; "Submitted" closes the list only once the attempt is handed in (T-R4.46). Please draw a timeline that holds a lost connection and a paste. Decided R4
DG-151 Teacher › Assignments › New assignment, the Rules step's Integrity group The Rules step adds a closed disclosure with spec §10.5's full text under the deck's sentence. The deck draws only "A browser cannot prevent cheating. These rules record what happened so you can decide." Spec §10.5 asks for its limits in the help text wherever rules are set, and the wizard is now that place. Under the sentence, "What it can and cannot see" opens to say that the app detects only this tab losing focus, that it cannot see a second device, a phone beside the laptop, a person in the room or a printed sheet, and that the signals are evidence for a conversation, not proof (T-R4.46). Please draw it. Decided R4
DG-152 Teacher › Attempt review (/teacher/attempts/{id}) Extend, reset and void stay in the roster's row menu; the review page does not repeat them. The deck draws no attempt review page (DG-68). Its attempt sheet (Teacher.dc.html lines 2085 to 2116) holds the score, the time, the timeline, the private note, "Open full attempt" and "Grade answers", with no action on the attempt. The only extend it draws is the assignment's "Extend deadline" (lines 3190 and 3287). The page restyled to the deck's primitives keeps the operations it had: grading, Finish grading, the flag and the note (T-R4.47). Please draw the full attempt page, and say whether it carries the interventions. Decided R4
DG-153 Teacher › Assignments, "Close early" and the bulk "Close now" Closing now keeps the time of a student mid-test; the deck says "Attempts in progress are submitted as they are." closeNow stops new starts and leaves every attempt in progress with its own deadline, as the assignment detail already says ("Students mid-test still get their full {n} minutes"). The row's "Close early" opens the detail's confirmation, with its one tick; the bulk "Close now" reads "Students who have not started can no longer get in. Students mid-test keep their time." and reports each selected assignment that is not live instead of closing it (T-R4.24). Decided R4
DG-154 Teacher › Assignments, "Extend deadline" and "Duplicate" Extend is for everyone and notifies in the app; Duplicate asks only for the classes. The deck's Extend offers "For: Everyone | Chosen students" and promises an email; extendAssignment moves the close for everyone and its notification is in the app, while one student's extra time is the detail's student override. Extend is disabled on a closed assignment as well as on a draft, since a closed one is reopened from the detail (ASSIGNMENT_CLOSED). The deck's Duplicate has a Title field, but an assignment takes its test's title, so the dialog asks for the classes alone, the original's to start with (T-R4.24). Decided R4
DG-155 Teacher › Assignments, undrawn What the list does that the deck does not draw. A draft's row menu ends with Delete, where a live row has Close early: a draft with no attempts can be deleted, and the old list offered it. On the Drafts tab the window column shows the planned opening rather than "—". "Export results" downloads one CSV for up to 50 assignments (the endpoint's limit) and says so above that; a refusal such as the export's rate limit is shown, not swallowed. Each row action and each bulk action shows only with the permission it needs: changing assignments for Edit settings, Extend, Duplicate, Close and Delete, grading for Export (T-R4.24). Decided R4
DG-156 Teacher › Assignments, the status pills The assignments list draws the deck's status pills; the shared assignment badge does not change yet. The list's pills are the deck's: Live in success, Scheduled in info, Closed muted with muted text and Draft bare, each with the 6px dot. STATUS_BADGES.assignment is also read by the class page's Assignments card and by the admin dashboard, which is not rebuilt; restyling the shared map would change a screen that has not reached its own task, so the list scopes its pills (AssignmentStatusPill) and the other screens take them when they are rebuilt (T-R4.24, VER-24). Decided R4
DG-157 Teacher › Settings, the frame and Sign-in & security Settings shows only what has shipped, and the Password card changes the password. The sections are the deck's five, Profile, Sign-in & security, Notifications, Assignment defaults and Appearance (the last two since T-R4.44), except that Assignment defaults is listed only for who may assign (teaching.assignments.write); a section that has not shipped is never drawn as a placeholder, as the deck's "Coming next" screen never ships. API reference is a section of its own for holders of system.api_reference until R5. The deck's Password card draws two fields and no button; it keeps a "Change password" button, the rule under the new password and the server's refusals, and drops "Last changed 3 months ago", which the account does not record. The Google account card, which the deck does not draw, sits between Password and Signed-in devices as it did. A Google-only account has no Password card. The old frame's Sign out button is gone: signing out stays in the account menu, as drawn. Please draw the Password card's button and the Google card. (T-R4.43, T-R4.44) Decided R4
DG-158 Teacher › Settings › Profile Language and Time zone are fields of the form, applied once saved; the photo saves on its own. An edit to any of the six fields raises the DirtyBar, and Save changes sends only the changed fields in one PATCH /auth/me; the interface switches language, and stores it for the next load, when the server keeps it. Change photo opens a dialog with the file box ("Square PNG or JPG, at least 200 × 200") and saves with "Save photo"; a file that is not a PNG or a JPEG, or is over 2 MiB, is refused before it is sent, and the server's own message shows for anything it refuses. Remove shows only while there is a photo, and asks first. The initials follow DG-22. Email is read-only. Time zone offers a curated list of 18 zones, Ho Chi Minh City first, each "(GMT+7) City" at today's offset; an account zone outside the list is added under its own id. (T-R4.43) Decided R4
DG-159 Teacher › Assignment › Students, the roster The flag marker also shows in the student cell from 560 to 700, where the deck drops the Focus lost column; colour alone never marks a flagged row. The deck's roster (Teacher.dc.html line 4198: rStatus: tw >= 560, rFocus: tw >= 700) shows Status but neither the Focus lost column nor its inline "· {n}× focus lost" in that band, which leaves only the row's tint. Under the student's name the band shows the compact flag and "{n}×" in danger ink, named "Flagged · {n} times focus lost", as the phone row already does. A flagged row also keeps its danger tint on hover (T-R4.46, QA-46-1). Please draw the marker in that band. Decided R4
DG-160 Teacher › Assignment, "Extend deadline" for chosen students, "Reopen for a student" and the reopen for everyone Each carries a required "Reason" (up to 500 characters) that the deck does not draw. Their operations require one (setStudentOverrides, reopenAssignment, T-R4.12) and the audit log keeps it with the teacher's name. Extending for everyone needs none, so that form has none. The field is the last one before the buttons, with "The reason is recorded with your name." under it (T-R4.26). Please draw the Reason field in these three dialogs. Decided R4
DG-161 Teacher › Assignment › More › "Close early" The confirmation keeps the true copy, that students mid-test keep their time, under the deck's title and button. The deck says "Attempts in progress are submitted as they are", but an early close leaves an attempt's deadline where it was set at the start (the start caps it at the planned close, not at an early one). The dialog says "Close {title} now?", "Closes at {now} today instead of {planned}. Students who have not started can no longer get in.", "Students mid-test still get their full {n} minutes.", how many students with their own extension keep it (none draws no sentence), and asks for the tick before "Close now" (T-R4.26). Please redraw the body with the true sentence. Decided R4
DG-162 Teacher › Assignment › Settings, the four Edit dialogs Each Edit opens the wizard's own controls for its group, not the deck's shorter fields. The deck's Test & timing dialog offers 30/45/60/90 min and 1, 2 or 3 attempts, which cannot show a stored 50 minutes or 5 attempts; the wizard's presets with a custom value and its 1–99 stepper can. Window takes the wizard's two date-and-time fields in the app's zone and the class chips (students assigned by name stay). Integrity takes the whole of the wizard's group: fullscreen, copy and paste, leaving the test with its allowance, the action when it is passed, the short absences ignored, and the honest limits with their disclosure (DG-151). Results takes the score, correct answers, explanations (which wait for correct answers), when results show (DG-65) and the class average. Question order sits with Test & timing, so it locks with it while the assignment is open. The note to students is a fifth card (DG-71). An unchanged window is sent as stored (T-R4.26). Please draw the dialogs with these controls. Decided R4
DG-163 Teacher › Assignment › More › "Reopen for a student" Reopening adds one more attempt only for a student who has none left, and the dialog says which case applies. The deck says "Gives one student a new attempt with its own time limit." A student whose latest attempt is handed in and was their last (attemptNo ≥ the attempts allowed) gets extraAttempts: 1, and the dialog says "{name} has used their attempts, so they get one more."; any other student gets the later close and the time limit only, and it says "{name} still has attempts left, so they can continue without one more." (T-R4.26). Please draw the two descriptions. Decided R4
DG-164 Teacher › Settings › Signed-in devices A row says only what the server sent. The name is device, or "Unknown device" when the server could not name it, and the icon follows deviceKind; the line under it is "{location} · {when}", with the location as given and left out when there is none, and "now" on this device's row. A row other than this device's signs out at once, as drawn; "Sign out other devices" asks first, and says "No other device was signed in." when there was none to end. While any sign-out is in flight every Sign out is off, because each one moves the account's session epoch. (T-R4.43) Decided R4
DG-165 Teacher › Settings, Notifications and Assignment defaults Notifications draws In app and the teacher's three updates; each section saves on its own. The deck's Notifications has an Email column and five rows; Email, New message and Weekly summary arrive with R7, so the card has Update and In app and the rows A student submits, An attempt is flagged and An assignment is about to close. Saving sends all five switches, the student's two as they were read. The deck draws one unsaved-changes bar for the whole page; each section that has a form (Profile, Notifications, Assignment defaults) has its own DirtyBar, which saves and discards that section alone, and the bar of a section not shown is hidden while its edits are kept. Assignment defaults saves all five values in preferences.assignmentDefaults, which the new assignment wizard starts from. (T-R4.44) Decided R4
DG-166 Teacher › Students, the list The list says what the product knows, and keeps an Admin's account controls. The deck's search reads "Search by name or username"; students have no username, so it reads "Search by name or email" and searches both. Status offers Active, Password reset and Suspended: a suspended account would otherwise vanish from every list with no way back to it, and the deck's Status options draw no sign-in state the server records before R5. Last active is the last test taken ("taking a test" while one is live) until R5 records sign-ins. A role holding people.users.manage (an Admin) also gets "Disable selected accounts" and "Delete permanently" in the bulk bar, and Suspend, Restore and Delete in the record, which the Teacher deck does not draw because a teacher holds none of them (T-R4.40). Remove from class and Move to class act on every class in the student's row, which for an Admin is every class in the system, not only the ones they teach; so the confirmation names the classes a Remove or a Move leaves ("{name} will leave: {classes}."), and the bulk Remove counts the memberships it ends and names their classes. The Classes column keeps a row 56px high whatever the count: the deck wraps every chip, which a student in many classes (an Admin sees all of them) pushes over Average and Last active, so the cell shows the first two chips, each truncating with its name as a title, then "+N" naming the rest in its title and to a screen reader (QA-40-2). Please draw the Suspended status, the Admin's two bulk actions, the named classes and a student in many classes, or confirm. Decided R4
DG-167 Teacher › Students, a temporary password (Add student, Reset password, the bulk reset) A temporary password is shown in a dialog that only Done or its X closes, never in a toast. The deck's Reset password toasts "Temporary password: {pw}", and its bulk reset toasts a count. A toast can vanish before the teacher reads it, and the password cannot be shown again. Each of the three opens one dialog: the warning that it is shown once, a row per student with the name, the email, the password and Copy, the reminder to send it privately, and Print for the sheet alone. Escape and a click outside do nothing; Done forgets the passwords. A bulk reset lists the students it could not reset with the reason (not found among your students, they hold permissions you do not, another teacher also teaches them so an admin must reset it, or an error), and refuses more than 40 at once, which is the operation's limit (T-R4.40). Please draw the dialog. Decided R4
DG-170 Teacher and student › the bell, an account that both teaches and takes tests Each bell counts, lists and clears only its own console's kinds. Each deck draws one console's bell for one kind of reader, so neither draws an Admin with "Take tests" on, who can get kinds of both. The reach is narrow: the due-time kinds go only to student-like roles, so the one student kind that can reach an Admin is "Result ready", written when a paper the Admin handed in is graded. Decided: the teacher's bell asks for audience=teacher and the student's for audience=student on the unread count (getTeacherSummary, getMySummary), the list (listNotifications) and the marking (markNotificationsRead, by ids and for all), so a "Result ready" no longer lights the teacher dot, the teacher kinds no longer light the student dot, and marking all read in one bell leaves the other's rows unread. A caller that sends no audience gets every kind, as before. Built (server in #495, spec v0.80; web in #499): both bells send their audience on the count, the list and every marking, and "Mark all read" is active while a listed row is unread. Please draw an account that holds both consoles, or confirm. R4
DG-174 Teacher › Assignment, "Extend" on a closed assignment Extend reopens a closed assignment from now, with a reason, and replaces the old "Reopen for everyone" menu. The deck draws Extend in the header whatever the status and its dialog only for a live one. On a closed assignment the 15 min, 30 min, 1 hour and 1 day count from now, since the close has passed, and the description reads "{title} · closed {when}. Opens again until {moment}." For everyone it goes through reopenAssignment, which requires a reason (DG-160) and sends no notification, so Notify students is not shown; for chosen students it writes each one's override with closesAt and the reason, and Notify stays. On a closed assignment only, a fifth step, "Pick a time…", shows DG-175's date and time pair, which must be ahead of now; a live assignment keeps the deck's four steps. For chosen students, a student whose own close is already later than that moment is left out of the list, so no override is shortened. The detail's earlier "Reopen for everyone" menu (until 21:00 today, one day, three days, a chosen moment) and its dialog are retired; the picked moment covers the longer reopenings (T-R4.26). Please draw the closed state of the dialog with the fifth step. Decided R4
DG-175 Teacher › Assignment › More › "Reopen for a student", "Open until" "Open until" is a date and a closing time, both required. The deck draws one optional date. The override stores an instant (closesAt), which must be ahead; a date alone would leave the hour to a guess, and without one a student reopened after the close could not get in. The dialog offers tomorrow at 21:00 to start with, in the app's zone, and says so when the moment has passed (T-R4.26). Please draw the time beside the date and drop "(optional)". Decided R4
DG-178 Teacher › Classes, undrawn What the class cards do that the deck does not draw. An Active | Archived control with counts sits under the header, as Admin › Classes draws it (the Teacher page draws none). An archived card's footer says Archived with Restore, and its menu is Restore and Delete class, which the old list offered for an archived class nothing uses. A code past its expiry or its uses shows "Expired" or "Used up" after it. A code that cannot be read (a pre-v0.8.0 code, or one whose key is gone) shows "••••-{hint}" with New code, and a class without a code offers Create code. The menu's New join code and Create code issue a code for 30 days and 40 uses (O-06) after a confirm, and the toast names it. The QR dialog adds a row that downloads quizzivy-{code}.png "for slides or Zalo". The cards page 24 or 48 at a time on the deck's pager. A reader without teaching.classes.write sees the cards with the code masked and no menu or New class. (T-R4.41) Decided R4
DG-179 Teacher › Class detail, members and Add students, undrawn What the class's members and its picker do that the deck does not draw. The members page 20 or 50 at a time on the deck's pager once a class has more than 20, and the search asks the server. The picker searches the students the teacher reaches on the server, and lists a student already in the class, marked "already a member" and not choosable, where the deck leaves them out; adding runs one student at a time and names any it could not add. A reader without teaching.classes.write sees no checkboxes, no Add student, no Remove from class, the Class card's fields read-only and the join code masked with the switch inactive; Assign to class needs teaching.assignments.write and is not offered on an archived class. A class that does not exist, or that the teacher does not teach, says "Class not found" with the way back to Classes. View results opens the student's results sheet until R9's Gradebook, and there is no Send message until R7, as the plan says. (T-R4.42) Decided R4
DG-180 Teacher › Class detail, join code card states The join code card's states the deck does not draw. A code past its expiry shows "· expired" in danger ink after its date, where the deck draws only "· in {n} days"; one expiring today says "· today". A code with no use limit reads "Uses {u} / unlimited". A code that cannot be read back (a pre-v0.8.0 code, or one whose key is gone) shows "••••-{hint}" and "This code cannot be read back. Make a new one to share with students.", without Copy link, Copy code, QR or Download, and New code replaces it. A class with no code says "No active code. Students can only be added by you." with Create code, and leaves out the footer the deck draws whatever the state, "A new code makes the old code, link and QR stop working." (since T-D4.23; the v2 deck draws the "Joining paused" chip only beside a code). A code that cannot be read back keeps the chip while joining is paused. An archived class offers neither New code nor Create code, since nobody can join it, and says "This class is archived, so nobody can join it. Restore it from Classes to make a code."; Stop stays. The server refuses one too, with 409 CLASS_ARCHIVED (#510, F-64); a page that has not yet seen the class archived elsewhere shows that refusal's own message in the New code dialog and reads the class again. (T-R4.42, QA-42-4, QA-42-5) Decided R4
DG-181 Teacher › Imports › new import, "Where your content goes." and the retention line The privacy note says only what the server reports. The deck writes "Files and pasted text are processed on Quizzivy's own servers. Your centre's settings do not send exam content to outside AI services. The original stays private and students never see it." The product cannot back the first two claims from the page: where processing runs and whether a provider is used are deployment settings the client does not see. So the note reads "Files and pasted text belong only to your import, not to learner media." followed by what getWordImportCapabilities reports ("This server enables intake and document processing.", or that it is still checking), and the page adds the retention line from the same answer ("Original files and the review are kept for {n} days after the test is created…"), which the deck does not draw (T-R4.36). Please redraw the note to name only what the server can state, and draw the retention line. Decided R4
DG-205 Teacher › every page, the page width One page frame, up to 1600px, at every width. The v2 deck drew a width per screen, each centred inside mainPad: 1320px on most screens, 1080 on New assignment and Settings, 860 on the import's Upload and setup, 720 on Processing, so a title jumped sideways between a list and its subpage (from a 1624px window with the sidebar open, New assignment's title started 120px right of Assignments'). The owner asked (2026-10-12) for one width on every page at every size and for wide screens to be used; the design team's page-width design (deck/page-width-proposal/Page Width Proposal.dc.html, c1472f4c, approved by the owner the same day) answers it, and the product builds it: (1) every Teacher page renders in one frame, --page-max 1600px, which fills the space beside the sidebar and centres beyond it, at every width, 2560px included (no wider step, owner, 2026-10-12); (2) title, toolbar and content start at the frame's left edge on every page, loading, empty, error and not-found states included; (3) cards, lists, tables and steppers fill the frame, and only text is capped: a field at --field-max 480px, prose at --prose-max 72ch; there are no form columns, so New assignment's stepper, list and cards fill with the summary docked on the right (300px), and Settings' fields flow into at most three columns of at least 260px, each field at most 480px (the design's text; its markup's auto-fit alone would allow more); (4) gutters --page-gutter 14px below 768, 28px from 768 and 40px from 1920, top padding 16 / 24px; (5) the one named exception is the import review, full-bleed with the sidebar collapsed (width: "full"). The lists follow the design's sketch by content width: Assignments shows Assigned to from 1240px, Submitted from 760, To grade (a column of its own) from 900, the window column always, and keeps the v2 deck's Status from 760; the Imports history is a grid from 960 and adds Source (Word, PDF or Pasted text, from the exam source's format) from 1240. Reflows inside a page follow the content width (the shell's bands, a container query), never a new viewport breakpoint. The workspace pager is every list's (DG-203); below 768 it drops rows per page, first and last, and its arrows are 44px. The merged import workspace the design draws for Upload and Processing is DG-207. Measured against v2 (T-D4.12): a sticky side column is capped at calc(100vh - 112px) against the deck's 88px, because the frame's 24px of top padding sits above the 16px offset, so the deck's cap ended a stuck column 8px past the window and 112px ends it 16px above, as the deck's geometry intends (T-D4.20 As built). At 1440 the frame, not the deck's per-screen width, sizes the content (spec §12): Settings' content is 40px wider than the deck's, and with the sidebar collapsed Class detail's content is 1324px against the deck's 1320, so its side column, and the join-code card in it, is 1.3px wider. The Settings navigation column is 204px against 200: the sticky column takes 2px of padding on each side for focus rings and shadows and gives them back as a negative margin, so its links sit where the deck draws them. Decided R4
DG-207 Teacher › Imports › the import workspace (approved page-width design, c1472f4c, "Import workspace" and its viewer's import states) One page per import, two panes. Upload and setup and Processing are one page: the Sources pane beside the status pane, --pane-split (two equal columns) from 960px of the page's content width, stacked below it. The design team left gaps; the Tech Lead decided them (owner's delegation, 2026-10-12), and the product builds: (1) the address is /teacher/imports/new for the draft; starting it replaces the history entry with /teacher/imports/:id, which then stays the same through every state; the review stays its own full-bleed screen, and a committing or committed import is shown by its confirm page (the address redirects there). (2) States by status: awaiting sources is the draft (the file and paste modes keep the mode switch in the head); queued shows every stage waiting, the Queued pill and Cancel, and the existing processing-off notice when the server is not processing; processing shows the stages, the elapsed time, Cancel and "You can leave this page…", and a run waiting to retry shows its attempt as today; needs review shows the stages done, the success note, its counts, Start review (primary) and Later; failed marks the stage it stopped at, and a failure that needs another file shows under the exam's file with "Replace exam file" (any other failure shows in the status pane with its code and "Process again"); files removed and a stale read show their existing notices in the status pane. (3) Sources after the start are file cards: name, kind · size, a state pill (Waiting, Reading, Read, Failed) and Download original; a failed file import keeps its slots and Replace. (4) Paste mode reads the text as you type in the status pane, "{n} questions recognised · {m} need checking", listing only what needs checking (each unanswered question, each number used twice in a part, eight at most); the server stays the authority in review. (5) Phone order: the draft shows Sources first, any started import the status pane first. (6) Not built, and why: a cancelled import offers "Start over" (a new import), not "Process again", and its files have no Replace, because the server accepts neither sources nor a run on a cancelled import (domain.AcceptsSources); "Earlier runs" is not built, because the API returns only the latest run (it needs the import's runs in getWordImport); "Use a sample" and "From media library" are not product features (DG-15); the "Read with AI" row waits for D4 (T-D4.33), and its place is the Sources pane, between the sources and the privacy note. A failure that needs another file is shown under the exam's file, since the run's error code does not name which source failed. Built in D4 (T-D4.39): the "Read with AI" card (V-11) sits in a new file import's Sources pane after the files and before the privacy note, only while the assistant is available and the server takes PDFs; it starts from the teacher's "Read imports with AI" preference, changes this import alone, switches the accepts line, and adds the AI sentence to the privacy note while it is on. Paste mode does not offer it. The deck's "About 400 credits per page" is not drawn (a placeholder; the product shows no figure it has not metered, §12), and the proposal's "Uses 1 AI credit" footer is not built. Decided R4

Open — needed before or during the release named

Language and copy

ID Gap Meanwhile Needed by
DG-20 Only Landing and Splash carry Vietnamese; Admin, Teacher, Student, Sign in and System pages are English only, and Settings › Language defaults to English. We write vi first from the existing glossary, en from the deck, and Vietnamese is the default. Please review the glossary: workspace, admin console, roles & permissions, audit log, shared with me, can use / can edit, gradebook, attendance, flashcards. Built in R1: vi is the default locale and the fallback, and every R1 string was written vi first. The glossary review goes to the design team with R1's new and changed keys (listed in the T-R1.18 PR). R1
DG-21 Fixed-width labels clip longer Vietnamese strings: navigator text (min-width 92px), change-kind chips (70px), a 160px status column on the Imports history (170px until the 2026-10-03 export), 110/100px access and date columns, and the two 168px Source tabs on the import page (new in that export). Columns and tabs size to content with a minimum. R3, R4
DG-22 Avatar initials differ: lists, sharing and Landing use given + family name (Hoàng Thương → TH), the sidebar avatars use HT / TQ. Note, 2026-10-10 (v2 export): the deck's teacher is now "Giàu Bùi", with no honorific; the rule does not change. Given + family (TH) everywhere. Built in R1: Avatar (components/ui/avatar.tsx) takes given + family everywhere, so Nguyễn Văn An is AN. R1

Foundations and accessibility

ID Gap Meanwhile Needed by
DG-30 No focus states: inputs only change border colour and buttons have none. The light --ring (#9aa3a5) is about 2.6:1 on white, under the 3:1 a focus indicator needs. A 2px :focus-visible ring from a darker ring token. Built in R1: --focus and a 2px :focus-visible ring on every control. tokens.test.ts holds --focus at 3:1 or more on --bg, --card, --sidebar and --muted, in both themes. R1
DG-31 --border #e4e7e8 on white is about 1.25:1, so input outlines fall below 3:1 non-text contrast. White text on --danger is about 4.47:1. Inputs use a darker border token; danger buttons use a darker fill. The token test measures both. Built in R1: --input for input borders (3:1 or more on --bg and --card), and --danger-solid / --danger-solid-fg for danger buttons (4.5:1 or more), both held by tokens.test.ts in both themes. R1
DG-32 Toasts always show a green success check, even for "Pick a score first". Error, warning and info tones with their own icons. Built in R1: the Toaster (components/ui/sonner.tsx) has error, warning and info tones, each with its own icon. R1
DG-33 Continuous motion (infinite marquee titles, the pulsing live dot) conflicts with WCAG 2.2.2. Marquee only on overflow, paused on hover and focus; both static under reduced motion. Built in R1: MarqueeText (components/shared/) moves only when its text overflows and pauses on hover and focus; MarqueeText and LiveDot both hold still under prefers-reduced-motion. R1
DG-34 Hard-coded colours: switch knob #fff, danger button text, badge text #1b2123, QR tile, the white "paper" of the import page view, theme preview swatches, the serif used for quotes (Georgia/Times). The "Match device" swatch is a gradient. Tokens for each, including a --font-serif; the swatch is split, not a gradient. Built in R1: --switch-thumb, --danger-solid-fg, --accent-fg, --qr-bg / --qr-fg, --paper / --paper-fg and --font-serif; no-raw-colours.test.ts refuses a literal colour (hex, rgb()/rgba(), oklch()) or a Tailwind palette class in the .ts/.tsx files under src/, except GoogleMark.tsx. R1
DG-35 Dark mode is not drawn for content surfaces: transparent question images, the import page view, rich-text tables, the Landing product mocks. Partly answered, 2026-10-04: the content editor draws its tables with tokens (--border cells, a --muted header row), so a table in the teacher's editor follows the theme. An inline image sits on --muted, and the Student page is not redrawn. Content keeps a light "paper" surface in dark mode, except a table inside the teacher's content editor, which is built with the tokens as drawn (T-R4.63). Built in R1: the --paper / --paper-fg tokens. The surfaces that use them arrive with their rebuilds, and the Landing product mocks with the Landing (R11); the old consoles stay light until then. R1
DG-36 Keyboard: the share dialog has no Esc or focus trap, the palette has no arrow keys or no-results state, menus lack roving focus, the toast has no live region. Partly answered, 2026-10-04: Esc closes the content editor's menus and its two dialogs; they have no focus trap, no focus return and no arrow keys (DG-116). Also, 2026-10-10 (v2 export): the AI panel has no Esc, no focus trap and no focus return, and the fourth import's Shared content dialog and preview overlay have none of the three either (DG-187, DG-188, DG-201). Built to the WAI-ARIA patterns. R4
DG-37 "Compact tables" has no drawn effect. Each table's drawn row loses 16px: a fixed height (54 → 38, 56 → 40) or a minimum (60 → 44, 56 → 40); a padded row's vertical padding is halved (10px → 5px). The header row stays 40px. No drawn body row is 40px, so "32px instead of 40px" described no table. R4
DG-116 The content editor's semantics (2026-10-04 export). "Rich text | Markdown" and the Media dialog's "All | Images | Audio" are role="tablist" with no panel. "Write | Preview" swaps a panel and is two plain buttons, with no role and no selected state. role="toolbar" and role="menu" have no arrow keys. The editable area and the inputs set outline: 0, and the toolbar buttons have no focus style (DG-30). The two dialogs close on Esc and have no focus trap or return (DG-36). The selection is kept on mousedown, so touch is not handled. The tick and the switch knob are #fff (DG-34), and error toasts use the success toast (DG-32). Also, 2026-10-12 (fourth import): the Shared content dialog and the preview overlay are dialogs with no accessible name, no Esc and no focus trap (DG-187, DG-188). "Rich text | Markdown" and the Media dialog's kind filter are the Segmented, a group of aria-pressed buttons (DG-17); "Write | Preview" is a tab pair with its panel. A toolbar is one tab stop with arrow keys, a menu has roving focus, a dialog traps focus and returns it. Every control has the :focus-visible ring, and the editor box keeps the drawn focus halo. Tokens and toast tones are R1's. (T-R4.63, T-R4.65) R4
DG-123 Teacher › sidebar, the workspace tile: the mark is drawn 18px high in a 32px tile, under the brand kit's 24px floor for the mark (B-05). Built as drawn. R4
DG-128 Teacher › Assignments and Students, the "⊕ Class" and "⊕ Status" filters: the button looks the same with and without a filter chosen. The button shows the number chosen in the count pill the segmented control uses, and says it in its accessible name. R4
DG-138 The Markdown textarea's accessible name (2026-10-04 export). The deck names it "Prompt (Markdown)" and "Explanation (Markdown)" with aria-label, so the field's visible label does not name it. The textarea is named by the field's label, through <label for>, as the rich editor is; the pressed "Markdown" in the header says the mode. (T-R4.64b, T-17) R4
DG-134 Two notes set no align-items: "Where your content goes." on the upload page (line 1690) and "You can leave this page." while an import is processing (line 1708). Their icon is an icon-font glyph that stretches with the note, so it lands at the middle of the note when the text wraps, and 1px low on one line. The deck's other notes with the same 2px nudge on the icon say flex-start (lines 754, 777, 838, 1906, 2046). Callout puts the icon on the first line of the text, 2px down, in every size and tone. A screen that wants it centred passes items-center. (T-R4.3b) R4
DG-136 Teacher › Grading: the deck draws no assignment or student filter, though ?assignment= and ?student= narrow the queue (a link from an assignment or a student lands there). A narrowed queue shows its filter as a removable chip in the header's sub line, after the count, named by the assignment's title or the student's name; removing it widens the queue. The deck draws no filter, so there is no permanent filter row. (T-R4.28) R4
DG-141 Characters Be Vietnam Pro does not draw, and where the deck uses a monospace face. The font has no arrows (U+2190–21FF), no ⌘, ⏎ or ✕. Its shipped subsets (fontsource, the same as Google Fonts) also drop ≤, ≥ and the combining marks U+0302, U+0306 and U+031B that decomposed Vietnamese uses. Any of these renders in a system fallback font. Yet the deck writes ⌘ and ↵ in its key caps, "↑ ↓ to move" under the tag list, and "→" in content. Every <kbd> in the deck is font-family:inherit (the brand font), while the Markdown mode's Write textarea (lines 752, 836 and 1904 of the Teacher deck), join codes, the 404 path, error ids and the Word paste box are ui-monospace. A key symbol the font lacks is the matching lucide icon (KeyGlyph: command, corner-down-left, arrow-up, arrow-down), named for screen readers, inside the key cap or the sentence. Running text names a modifier as "Cmd" or "Ctrl" ("Cmd+Shift+V"). A range reads with the en dash, as the deck's calendar does ("09:00, 10/10/2026 – 09:00, 13/10/2026"), and "≥3s" becomes "3s+" / "từ 3 giây". Text is composed to NFC where content is rendered and where an editor writes it. Italic faces are loaded for every upright weight. The Markdown Write textarea stays monospace, as drawn, with its Preview in the brand font. A key cap is the brand font, as drawn, inside data-scale="deck", in the teacher top bar and in the command palette; AdminLayout's cap keeps font-mono until its screens are rebuilt. font-coverage.test.ts refuses a UI string with a character the loaded faces do not draw. (FONT-1) R4
DG-195 github.md, the sync behind the fourth export. It read two migrations; the contract (api/openapi.yaml: QuestionGroup, StudentGroup, AudioPolicy), the take-test engine and the group editor were not read. Please read api/openapi.yaml, web/src/features/take-test/** and web/src/features/question-groups/** at the next sync, and add them to the Screen map. Please also read server/internal/modules/ai/ and web/src/features/ai/ once D4 builds them. Next sync
DG-210 Shared primitives, measured against the v2 deck by T-D4.12 (2026-10-13). The deck draws the Switch 34×20 (ours 36×20), a segmented control's icon 14px (13px), outline buttons with no shadow (ours carry 0 1px 2px at 5%), 12px labels on an 18px line (16.8px), header icons at 18px (17px), a dialog title at 15px with no rule above its footer and 14px of padding on its Save (FormDialog: 16px, a rule, 16px), a disabled control at 40% (45%), small buttons at 8px radius and 13px text (10px, 13.5px), and its labels at weight 500 where Field uses 400 in the Shared content dialog. Line boxes differ by 0.7 to 3.5px where the deck sets a line-height the tokens do not carry. A tooltip at the edge of a 360px screen ends at 359.8px, with no side gutter. The primitives stay as R1 and data-scale="deck" built them: each is shared by every screen, so changing one for a screen D4 redrew would move the screens it did not. T-R5.30 makes the deck's geometry the default and takes these with it; the tooltip's collision padding goes with them. R5

Front door and system

ID Gap Meanwhile Needed by
DG-40 Auth states not drawn: Google callback and its errors, 429 rate-limit copy, disabled account, a signed-in user opening /join/:code, enrolment failing after sign-in. Deck primitives on the auth layout, listed for sign-off. Built in R1: the Google callback's loading and error states, the server's 429 message, the disabled-account message, the non-student note on /join/:code and the enrolment-failure variant of Joined, all on AuthLayout. R1
DG-41 Forgot password shows the front-desk phone and hours, but Admin › Organization has no field for them (nor contact email and address the Landing shows). Fields added to Organization settings. R1, R5
DG-42 Maintenance: no Admin control to schedule a window, no "all systems normal" status page, no rule for how long tests closing during maintenance are extended. Windows are scheduled from the command line; in-progress attempts and closing tests extend by the window length. Built in R1: cmd/maintenance's window-schedule, window-list, window-cancel and window-end (T-R1.12); in-progress attempts and tests closing inside a window move by its length, audited as System; the API answers 503 during it and refuses a start that would run into it (T-R1.13). R1
DG-43 Home targets on system pages all go to the Student app; teachers and admins need their own, and signed-out visitors go to sign in. Home = the caller's console. Built in R1: "Home" on the system pages is homePathFor(user), or /login signed out. R1

Roles, users and the Admin console

ID Gap Meanwhile Needed by
DG-50 The matrix has no rows for imports, courses, vocabulary, messages, schedule, gradebook, reports, data export, API reference or leads. Each maps to an existing row or to "any teacher permission" (listed in 70-redesign-overview.md). R2
DG-51 Admin's "Take tests and view own results" cell is editable while every other Admin cell is locked. Kept: admins may take tests if an admin turns it on. The built-in Student role cannot lose it. R2
DG-52 Custom roles have no delete action; what happens to their members? No delete in v1. R5
DG-53 A plain teacher (no Admin console) and custom roles: which nav items and workspace switcher entries show. Nav items and the switcher follow permissions. R4
DG-54 Users: status precedence (disabled / must change password / never signed in / active), what the sidebar badge "4" counts, and what "active" means for Last active and the daily chart. Disabled > must change > never signed in > active; the badge counts must-change; active = an authenticated request that day. R5
DG-55 Plan & usage shows a plan, seats (400) and a teacher limit (15). Billing is a non-goal. Values are configuration, shown but not enforced. "Attempts kept 18,420 · 46%" needs a denominator. R5
DG-56 No ownership transfer when a teacher leaves, and no view of a disabled teacher's content. An Admin "Transfer content" action in the user sheet. R5
DG-57 No leads inbox, no field for who is notified of new leads, and no maintenance or term management in the Admin console. Terms in Admin settings (T-R8.13); the leads list and its recipients field under Admin, built from deck parts (T-R11.9); maintenance windows from the command line (DG-42). R8, R11
DG-58 "Signed-in devices" shows "MacBook Air" and a city. A user agent does not give the device model. "Mac · Chrome · Ho Chi Minh City". R4
DG-59 The Admin console has no language control, so a user whose only workspace is the console cannot change language or profile. An interim "Language" item in the Admin account menu writing the user's locale preference. R5
DG-196 Admin › AI credits, the pool's rules (v2). The deck offers "When the centre pool runs out: Pause AI for everyone | Allow 10% extra", and says the extra and added credits are "billed on your next invoice". D21 (the pool is never overspent without an Admin's approval) and the spec's non-goal on payments: the rule has one value, "Pause AI for everyone"; "Add credits" is the approval and records the approver; the dialog reads "Added to the centre pool right away. The extra is paid for outside Quizzivy." Please redraw the rule and the two sentences. Built in D4 (T-D4.31): ai_settings.on_teacher_limit is the rule for a teacher who runs out, pause or request. The pool has no rule column: a pool that runs out refuses every call with 402 AI_CREDITS_EXHAUSTED and details.scope pool. addAiCredits is the approval and records the approver in its audit row. Nothing in the API or the operator's guide says anything is billed (docs/setup/operations.md: the extra is paid for outside Quizzivy). The dialog's wording is R5's. D4 (T-D4.31), R5 (T-R5.35)
DG-199 Admin › Roles & permissions (v2). The matrix draws no row for the AI, while the product adds two grantable keys. "Use AI features" in Content (Admin and Teacher on) and "Manage AI credits" in System (Admin on), drawn in the matrix's own style. Please draw the two rows. Built in D4 (T-D4.32): migration 00124 inserts ai.use (Content) and ai.credits.manage (System), both in the matrix, and grants ai.use to the built-in Teacher role; the Admin's wildcard holds both. permissions.golden changed once, in that pull request. The matrix rows are R5's (T-R5.24). D4 (T-D4.32), R5 (T-R5.24)

Teaching

ID Gap Meanwhile Needed by
DG-60 Question types differ by screen: the builder has Matching, the editor has True/False and Short answer, the bank lists Open answer and "Audio · labelling", grading has Essay with a 0–9 band, import has True/False/Not given and Cloze group, the student engine has "Choose two" and word-limited answers. Partly answered, 2026-10-04: the builder draws the authoring side of six types: single choice, multiple choice, true / false with an "Include “Not given”" switch, fill in the blank, short answer and matching (DG-113). The sets still differ: the builder has six, the bank's Question editor five (no Matching), the import review seven. Essay, cloze group, "Choose two" and the word limit are still undrawn. Note, 2026-10-12 (fourth import): the Student page now draws True / False / Not given, matching, a two-pick multiple choice and the word limit on the take-test screen (DG-194); essay is still undrawn. One canonical set: single, multiple (optional exact count), true/false/not given, fill in the blank, short answer (optional word limit), essay (band), matching, cloze group. Please draw the authoring side of each. R4's type menu offers the five types the product stores (T-R4.31b). R6
DG-61 Band scores and rubric tiles (Task achievement, Coherence, Vocabulary, Grammar) have no model. Rubric criteria defined per question; the band is their mean, rounded to 0.5. R6
DG-62 Levels and skills: forms offer A1–C1, fixtures use Pre-A1 and ranges, filters group A1–A2. Pre-A1…C2 per question; skills: grammar, vocabulary, reading, listening, writing, speaking. R4
DG-63 Option limits: the builder allows 6 options (A–F), the editor 8 (A–H). Media limits: upload 50 MB for every type, Replace limits images to 10 MB. The 2026-10-04 export keeps "Up to 6 options" in the builder and adds a third audio limit and two formats: "Audio: MP3, M4A or WAV up to 25 MB" on the builder's question media, and "JPG, PNG, WebP or GIF" for an image in the text. The Media screen and the bank's "Add media" dialog still say 50 MB. Note, 2026-10-12 (fourth import): "MP3, M4A or WAV up to 25 MB" appears a third time, in the Shared content dialog (DG-187). Note, 2026-10-10 (v2 export): the question editor's AI panel says "up to 6 options"; the cap stays 8. 8 options; audio 50 MB, images 10 MB. Audio is MP3 or M4A and an image JPG, PNG or WebP on every screen; WAV and GIF are not taken (74-r4.md, open items). Please redraw the builder's two lines. R4
DG-64 Grading: does "Save & next" follow the grouping or global order? Does grading the last item release scores, or is there a release action? Follows the grouping; scores release when the last answer is graded, as today. R4
DG-65 Assignment settings: which groups stay editable while live; results visibility disagrees (wizard: after submitting, live Results group: after the window closes); what "Save draft" persists. Only Test & timing locks; release follows the stored rule; drafts persist every wizard field. R4
DG-66 Test detail draws a per-version diff and change notes with no model. Diff = questions added, removed and changed between versions; the note is free text at publish. R4
DG-67 Imports: current behaviours not drawn (elapsed time, retries, stale reload, "Use the new result", the committed banner, the leave guard, the no-imports empty state); the audio slot, saved profiles, source conventions, template download, Move / Split / Merge, the processing history, "Create another test from this file", "Delete import" and "Process again" have no backend. R4 keeps current behaviour with deck styling and gates the controls without a backend; their backend and UI are built in R6 beside T-R6.13. Entering review no longer collapses the sidebar permanently. "Paste a test" (2026-10-03 export) is not one of the gated controls: R4 builds it (T-R4.55 to T-R4.57), with its departures in DG-12 to DG-16. Its "How to read the content" card is the file flow's, so the same controls stay gated there. R4, R6
DG-68 The existing question-group (passage/cloze) bank screens and the full attempt review page are not in the deck. Note, 2026-10-12 (fourth import): the builder now draws a group's passage and recording (DG-186); the bank's group screens are still undrawn. Restyled with deck primitives. R4
DG-69 Media card "Play limit" against the per-question "Plays allowed": which wins? The 2026-10-04 builder draws the per-question setting a second way, "Plays: Once | Twice | Unlimited" with Twice as the default, beside the bank editor's select (DG-111). Note, 2026-10-12 (fourth import): a third drawing of "Plays", a select with "3 plays", in the Shared content dialog (DG-187). The question's setting wins; the card's value is the default for new questions. R4
DG-70 Dashboard and Reports range selectors are cosmetic. They drive the data. The Dashboard offers 7, 14 and 30 days, as drawn. R4, R9
DG-129 Teacher and Student › the bell's fixtures read “6 answers … need grading”, “left fullscreen 3 times” and “graded: 8 / 10”. The product counts papers with an answer waiting, counts every time a student left the test, and never puts a score in a notification: “6 papers in … need grading”, “… left the test 3 times”, “Your result for … is ready”. Five undrawn variants (plain hand-in, assignment closing, replaced join codes, assignment opened/extended) reuse the decks' icons for those things. R4
DG-71 The Student deck's Test intro draws a note from the teacher ("Note from Ms Thương"); the Teacher deck has no field to write it. Note, 2026-10-10 (v2 export): the deck's teacher is now "Giàu Bùi", with no honorific; the rule does not change. assignments.student_note (≤500 characters) with a plain "Note to students (optional)" field in the wizard's Rules step and the Settings tab. R4
DG-72 The Question bank's Import dialog (CSV / XLSX) is drawn, but no import of bank questions exists. Built in R6 after T-R6.3. R6
DG-73 A pasted import (2026-10-03 export) keeps the file flow's wording on screens the deck did not adapt: the processing header keeps the file tile, the failed screen reads "Stopped at “Check the files”" and offers "Replace exam file", the cancel and delete copy says "uploaded files", and the review note names a .docx; the Imports history sub still reads "Word and PDF files you are turning into tests", and today's no-imports empty state speaks only of uploading. The processing header shows the clipboard tile, as the import's history row does. The history sub reads "Word and PDF files and pasted text you are turning into tests. Each import keeps its original content, its progress and your review, so you can come back at any time.", and the empty state's hint names both ways in and offers both header actions. A failed pasted import offers "Start a new import", which opens the paste mode; the detail page has no paste field. The other lines name the pasted text in place of the files. R4
DG-108 One editor, two drawings. The product renders the builder's editor pane and the bank's Question editor with one component, and the 2026-10-04 export redrew it in the builder only. There, "Prompt" and "Explanation" are the rich content editor; a fill-in-the-blank has gap chips in the prompt, one row of accepted answers per gap and the line "Capital letters and extra spaces are ignored."; media is the "Question media" block. The bank's Question editor screen keeps plain textareas, [1] blanks with "Match case", and the "Add media" dialog. The explanation's hint reads "· shown after grading" in the builder and "students see it after results are released" in the bank. Default: one QuestionEditor. The builder's drawing of the prompt, the explanation, the answer areas, the grading note and the question media is built on both pages. Each page keeps its own frame: the builder's header with the type menu and "More options"; the bank's type control, save area and SETTINGS column. "Match case" stays on every gap row, because the model has it and the bank draws it, and "Capital letters and extra spaces are ignored." shows only while no gap matches case. A prompt still stored as Markdown keeps its {{n}} placeholders. The explanation's hint states the rule on both pages: students see it with their result when the assignment shows explanations. The placeholder drops "Students see this after grading." for the same reason. Please redraw the bank's Question editor. (T-R4.66, T-R4.31b, T-R4.33) R4
DG-109 Media inside a prompt or an explanation (2026-10-04 export). The editor draws "Image" and "Audio" in the toolbar, each with "Upload from device" and "Choose from Media"; an image pasted or dropped into the text ("Uploading to Media…", then the toast "Saved to Media · {name}"); figures with their own alt text; and ![](media:{file name}) in Markdown. The contract's QuestionContent holds no media, and nothing draws the student side. Inline audio is a tile that says "plays in the test": no play limit, no length or size check, no rule for the integrity record. Markdown names a file by its name, which is not an identity. GIF is offered; the server takes PNG, JPEG and WebP. Default: not built in R4. The toolbar has no "Image" and no "Audio"; a pasted or dropped file is refused with a notice, which points to "Question media" where the screen has it; the paste preview's "{n} images in the copied content were left out." ships without its second sentence. Audio or an image is attached as question media. The contract, the publish snapshot, the student payload, the engine and the two buttons are R6 work, planned when Thuong confirms; the alternative is to build them in R4 as their own backend and engine tasks. Please draw the student side and say what limits inline audio. (T-R4.63) R4, R6
DG-110 The Markdown mode has no stated model (2026-10-04 export). The prototype opens every question in "Rich text" and converts a field left in "Markdown" when the question changes, without asking. "Switch to Markdown" says gaps "have no Markdown form and are removed", while the prototype writes a gap as ___ and reads it back without its label. Default: the mode is the form the field is stored in. "Rich text" is stored content, "Markdown" the stored Markdown string; a field opens in its own form and a new field is rich text. Nothing converts without "Switch to Markdown" or "Apply conversion". While a fill-in-the-blank prompt holds gaps, "Markdown" is disabled, because the gaps bind the accepted answers. Markdown gains tables and strikethrough for the teacher and for the student. (T-R4.64) R4
DG-111 Question media (2026-10-04 export). "Students can pause" has no model: AudioPolicy is maxPlays, allowSeek and showTranscriptAfterSubmit. The block draws neither "Allow skipping ahead" nor "Show transcript after submitting", which the bank's Question editor draws. "Plays" is "Once | Twice | Unlimited" here and "Unlimited / 1 / 2 / 3" in the bank (DG-69). "Alt text" has no field in the model. The hint says the media is "shown above the prompt" while the block sits under the answers. "Replace" swaps the question's attachment; the Media screen's "Replace file" replaces the file (DG-09). No upload progress, failure, rejected length or expired link is drawn. Default: "Students can pause" is not built; "Allow skipping ahead" and "Show transcript after submitting" stay, under "Plays". "Plays" has the three drawn options, and a stored value outside them shows as a fourth option while it is the value. Alt text is stored on the question and frozen at publish (T-R4.62). The block sits where it is drawn and keeps its hint, which says where students see the media. "Replace" is built as drawn, with an accessible name that says it changes this question's media. Upload states follow DG-83, with today's rejection messages. (T-R4.65) Reopened, 2026-10-12: the fourth import draws "Students can pause" on a group's recording too, and D4 builds it as one boolean, allowPause, on by default (DG-183; T-D4.13, T-D4.9, T-D4.15). Built: the contract, the four columns and the stored rule (T-D4.13); the engine's inert button (T-D4.9); and the switch, under "Plays" in AudioPolicyPanel, on a question's audio, a group's recording and the Shared content dialog (T-D4.15). R4, D4
DG-112 "Choose from Media" (2026-10-04 export). Its sub reads "Files you uploaded and files other teachers shared with you." and a fixture row reads "Shared by Phan Minh Đức", but media is not a shared kind (DG-90) and the Media screen shows no shared file. The usage line mixes "Used in {n} questions" with "Used in 1 test". A file is an icon, not a thumbnail. The counts on "All | Images | Audio" ignore the search. No loading, error, empty-library or paging state is drawn; the list is eight files. The bank's Question editor still draws the older "Add media" dialog ("From": Media library | Upload). Default: the dialog lists the caller's own files and its sub reads "Files you uploaded."; the usage line is "Used in {n} questions" or "Not used yet"; an image shows its thumbnail; the counts follow the search (DG-17); the list pages, with the states of DG-83. Both pages open this dialog (DG-108). Shared files wait until R7's sharing covers media and the deck draws it. (T-R4.65) R4, R7
DG-113 Matching and "Not given" are drawn in the builder (2026-10-04 export), against R6's plan. "Include “Not given”" is a switch on True / False, while the import review lists "True / False / Not given" as its own type and the bank's editor has neither. Matching draws lettered items, options numbered i to x with the tag "Extra", and the toasts "Up to 10 items" and "Up to 10 options"; R6 planned 2–12 options, 2–20 items and a switch that lets an option be used twice, which is not drawn. No rule is drawn for an item left unset at publish, for a minimum, or for reordering. Default: neither ships in R4 (DG-60). In R6 "True / False / Not given" stays its own stored type, and the switch chooses between the two types; matching takes the drawing's layout and keeps R6's bounds, 12 options and 20 items, with toasts that name them; the reuse switch is extrapolated and listed for sign-off; an unset item blocks publishing. Please confirm the limits and draw the reuse rule. (T-R6.9a, T-R6.9b) Note, 2026-10-12 (fourth import): the Student page draws matching too, and it differs from R6's plan: chips per row, three key styles and the nouns "pick the {pick} for each {what}" (DG-194; T-R6.10). R6
DG-114 Review workspace, the "Question" editor (2026-10-04 export). No read-only state is drawn, and an excluded question keeps a live editor. The toolbar has no "Insert gap", though the product binds gaps in an imported fill-in-the-blank, and "Accepted answers" stays one list, not a row per gap as in the builder. A "Markdown" mode is offered for content that was never Markdown. "Image" and "Audio" insert into an item's prompt while the paste preview says images are "left out". The prototype saves plain text only. The cloze group's "Shared passage" keeps its plain text (DG-68). A finding on the prompt has no link to the editor. Default: the product's behaviour in the deck's frame. The open card's "Question" field is the editor, and it stores content, as today. A fill-in-the-blank item keeps "Insert gap", up to 20 gaps. There is no "Markdown" switch, no "Image" and no "Audio" (DG-109). Where the review is read-only (a phone, a stale session, a committed import) and for an excluded question, the field is the read view. Options keep today's rich option editing. (T-R4.38) R4
DG-115 The builder's editor pane, undrawn or contradictory (2026-10-04 export). No loading state for the editor and no failed save. No character limit beside "{n} words"; the product allows 100,000 characters in a document. "Insert gap" shows in the Explanation toolbar of a fill-in-the-blank question, and an explanation never holds a gap. The type menu's toast "Remove the gaps from the prompt before changing the type" cannot fire, because a disabled item ignores the click. Validation is drawn for multiple choice, gaps and matching only: nothing for an empty prompt, an empty option, fewer than two options or a single choice with no correct answer. "Points" is a static "1". The Student preview dialog was not redrawn: it shows four demo options for every type and no rich content, gap or media. Answered, 2026-10-12 (fourth import): the three previews now embed the take-test screen in a frame (DG-188). The prototype's paste cleaner unwraps any tag it does not know and drops images; the product's converter refuses the whole paste on an unknown tag, a del, an h4 or an http: link. Default: the editor keeps today's loading skeleton, and its "content limit" and "unsupported structure" messages show in the notice band; a failed save is the title bar's status. The explanation's toolbar never has "Insert gap". A locked type shows "Remove gaps first" and no toast. The other validation messages are the bank editor's, in the drawn inline style. "Points" is an input. The Student preview renders through the engine's readers. The converter stays strict, except that it leaves images out and counts them (T-R4.63). (T-R4.31b, T-R4.63, T-R4.66) R4
DG-135 Teacher › Test builder. The builder calls a section a "group": "Add group", "Remove group" and its confirm button, a new section named "Group 3", "Students see this above the group’s first question". The product's outline also holds question groups (shared-context groups), so one word would name two things. Also undrawn or unmatched on the same screen: the footer's "Add shared-context group"; the Back, Question settings and Versions controls; a state for an edit waiting to be saved; the save label's cloud icon, which the deck's pinned icon font (lucide-static 0.469.0) lacks, so "Saved" renders bare; on a phone, row actions that only appear on hover. en says "section" for a section and vi says "phần": "Add section" / "Thêm phần", "Remove section" / "Gỡ phần", the confirm "Remove “{title}”?" with the deck's body and a "Remove section" button, a new section named "Section 3" / "Phần 3" and opened for renaming. The rest of the builder's copy follows the deck. The undrawn controls: "Add shared-context group" is a fourth footer button, outlined like "Add question", above "From question bank"; Back, Question settings and Versions are icon buttons with their name as a tooltip, so the title bar keeps one row wherever the deck does; an edit waiting out the 1.5s debounce reads "Not saved" / "Chưa lưu" with no icon; "Saved" keeps the cloud-check icon the markup names. Below 768px the selected row shows Move up, Move down and Remove at 44px in place of its points, and other rows show none, so titles keep their width. (T-R4.31a) Kept (T-D4.12): at 768 with the sidebar expanded the title bar does not keep the deck's one row: it wraps, and Publish goes to a third row, because the product keeps R4's Versions control beside Preview and Publish, which the deck does not draw. Every action stays reachable and in the same order, so the wrap is kept rather than dropping a control. R4
DG-139 True / False. The deck draws the two answers as "True" and "False" in the builder's cards and the student's options, and says nothing about what is stored. The editor stores a true/false question's options as the plain texts "True" and "False", and the Word import as the same texts with one paragraph of plain content each (recognised in build.go, committed by plan.go, kept by preserveOptionContent through later edits). The engine and both reviews showed the stored text, so a Vietnamese student read English. Where a true/false option is shown (the engine, the student's result, the teacher's attempt review and grading), an option whose text is exactly "True" or "False", stored plain or as one paragraph of unmarked text equal to it (isPlainOptionContent), reads in the reader's language, "Đúng" / "Sai" in vi (trueFalseLabelKey, used by OptionText). So editor-made and Word-imported questions both read in the reader's language. The label follows the stored text, never the position, because options can be shuffled. Any other text (a legacy question whose teacher renamed the two options) and any content with marks, gaps or media shows as stored. Storage, the payloads, dealing and grading are unchanged; the new editor's True / False field always writes the canonical texts (T-R4.66a). Not yet canonical: the import review's type change writes the teacher's language (imports.review.trueOption / falseOption, "Đúng" / "Sai"), which then shows as stored; making changeType write "True" / "False" is a logged follow-up. Three key pairs name the same two words and must not drift: trueFalse.true / .false, result.true / .false and imports.review.trueOption / .falseOption. R4
DG-186 Teacher › Test builder, the group (fourth import). The deck's group now carries shared content. Built in D4 (T-D4.2a, T-D4.14): the deck's group is the product's section, which keeps Rename, Instructions, Move and Remove. Shared content belongs to a shared-context group inside it, whose row carries the shared-content line ("Passage · {title} · {n} gaps", "Audio · {file} · {plays}", or "{n} materials · {m} recordings") and a "…" menu (Rename, Shared content, Move up, Move down, Remove group); the line and Shared content open the dialog. A bank question could not be dragged into a shared group (Q8). Reversed 2026-10-14 (owner): a bank question can be dragged into a shared group and a member out, built in v0.11.6 (docs/plan/74e-e1-group-move.md; DG-213 to DG-216 record what it draws beyond the deck). D4
DG-187 Teacher › Test builder, the Shared content dialog against the product's group (fourth import): a plain textarea, one passage or one recording, "[gap n]" appended at the end, any question as a target, one question on two gaps, unbound gaps saved, "MP3, M4A or WAV up to 25 MB", no "Show transcript after submitting" and no "Allow skipping ahead", no title for a recording. Built in D4 (T-D4.2b, T-D4.14, T-D4.15): the dialog edits a group with at most one passage or one recording. The passage is the content editor (T-R4.63's document profile), whose toolbar holds the dialog's only "Insert gap" (the deck's separate 30px button is not built), a gap at the caret, each bound in a gap row (the "gap {n}" chip, a select whose first entry, "Choose a question…", unbinds it, and "Remove gap"); targets are the product's (choice questions and blanks, each once) and a gap left unbound blocks Save. The recording takes DG-63's limits and keeps "Allow skipping ahead" and "Show transcript after submitting" ("Optional. Students see it after they submit." while it is on); it is saved as one material named after the file without its extension, a name the student never sees. A group holding more than the dialog shows stays in the full pane, which says so. The deck's sentence "Students see it on the left while they answer." (T 7029) reads in English "Students see it beside the questions while they answer.", because a phone shows a drawer, not a left pane. D4
DG-188 Teacher › the three previews (fourth import). They embed the take-test screen, answerable, with a running 45:00 timer, and keep the live save line ("Saving…", "All answers saved") after every pick (S 961-963, 1617), a slip: nothing in a preview is saved. T-D4.2c built the bar and the frame; T-D4.16 puts the engine in the frame (EnginePreview), answerable, with what is chosen kept only while the preview is open, and no saving, no integrity record and no play counting. A test has no time limit and no integrity policy: both belong to the assignment (AssignmentInput.durationMinutes, IntegrityPolicy), and previewTest, the builder draft and the review draft carry neither. So, against the deck: the timer pill is a placeholder of the same size reading "––:––", named "The time limit is set when the test is assigned", and no clock runs; the save line reads "Answers here are not saved." with the eye, where the deck says "All answers saved"; pasting is allowed and nothing is counted; the content is the teacher's own paper, not the deck's fixture. Inside a frame narrower than 1024px the engine's engine-lg: sizes and its 44px floor follow the frame, not the window, so the phone frame draws a phone's 44px controls where the deck's prototype has no floor. The question group's preview dialog and Assignment detail keep R4's read-only paper (InlineStudentPreview). D4
DG-197 Teacher › "Make a variant" and "Clean up the question bank" (v2). The deck saves a variant "as a draft version" of the test, and merges two bank questions so that "tests that used either question now share one copy". A test has one draft, so a variant is a new draft test named "{title} · Variant", owned by the teacher, with "Open the variant" where the deck says "Review it in Version history"; a near-duplicate card offers "Open" for each question and "Keep both", and nothing merges (a published version holds frozen copies; a merge would need an operation of its own). Tag suggestions apply through the bulk tag write. Built in D4 (T-D4.32): makeTestVariant answers the changes (questionId, number, kind, before, after, payload) and writes nothing; the new draft test is made by the caller with duplicateTest, and the kept changes go to its questions through updateQuestion (T-D4.34). cleanUpQuestionBank answers duplicate pairs, each with the draft outlines that use each question, and tag suggestions, and there is no merge operation. One call reads the caller's own questions only, at most 2,000 and 300,000 characters, finds at most 20 pairs and suggests tags for the first 60 that have none; truncated says to apply them and run it again. A chunked pass is a follow-up (74d). Drawn in D4 (T-D4.34b): "Make a variant" saves a new draft test "{title} · Variant", toasting "Variant saved as a draft." with "Open the variant"; because a copied draft names the same bank questions, each changed question is duplicated and the change written to the duplicate, so the test and its questions are untouched. A near-duplicate card offers "Open one", "Open other" and "Keep both"; kept tags go through the bulk tag write. D4
DG-200 Teacher › Settings › AI assistant (v2). The Admin page lists teachers' requests for more credits ("{name} asked for {n} more credits"), and the teacher side draws no way to ask. "Ask for more credits" under the usage card (amount and reason, as the Admin card shows them), shown while the rule allows requests. Please draw it. Built in D4 (T-D4.31, T-D4.32): requestAiCredits takes 1,000 to 100,000 credits and a reason of at most 500 characters, one waiting request per teacher and month, five an hour; AI_REQUESTS_OFF while the rule is pause. getAiUsage says whether the centre takes requests and carries the teacher's waiting one. Every ai.credits.manage holder gets ai.credit_request, and a decision tells the teacher with ai.credit_request.decided. The form is T-D4.38's. Built in D4 (T-D4.38): a row under the usage card's five rows, "Need more credits this month?" and "Ask for more credits", opens the form in place (amount and reason, Cancel, "Send request"); the waiting request replaces it until decided, and nothing is drawn while the rule is to pause. Left out (T-D4.39, follow-up 10, #588): the preference "Read imports with AI" ends its hint after the first sentence, without the deck's "About 400 credits per page", following spec §12's rule that no figure is shown which the product has not metered, as the import card does; the usage card shows what was really spent. D4
DG-201 Teacher › the AI panel's states (v2). Not drawn: the panel with the provider off (the entry points are hidden; the Settings section says "AI is not turned on for this school"), a teacher who is paused or out of credits (the deck says "AI buttons stay visible but can’t be used": a disabled button with the reason as its tooltip, and the sentence "Your allowance is used up. Ask for more in Settings." in the panel's footer), a refusal or a timeout (the warning callout, with "Try again", never sample content), a suggestion that fails validation, and Esc, a focus trap and focus return (DG-36). Those states, from deck parts. Built in D4 (T-D4.32): the server answers each state the deck lacks, in vi and en: 501 AI_OFF, 403 AI_PAUSED, 403 AI_READ_OFF, 402 AI_CREDITS_EXHAUSTED with details.scope teacher or pool, and 503 AI_UNAVAILABLE with Retry-After: 30 for an outage, a refusal, an answer no decoder can use or a rejected request. Nothing is written on any of them and no sample content exists. The panel's drawing, with Esc, the focus trap and the return, is T-D4.34's. Drawn in D4 (T-D4.34a): the panel is the Sheet, so it closes on Esc, traps focus and returns it to the button that opened it. An outage, a refusal or an answer that fails the schema is the warning callout "AI didn't respond. Try again in a minute." with "Try again" over the fields as they were; 402 (by scope) and 403 AI_PAUSED are the footer's sentence with Run disabled; an entry point is disabled with that sentence as its tooltip while the usage read says paused or out of credits, and hidden while PublicStatus.ai is false or the caller lacks ai.use. No sample output is drawn, and the footer shows only metered credits. Drawn in D4 (T-D4.36): the grading card's box has the same states: the callout with "Try again" on an outage, the block sentence with "Suggest a score" disabled, and the credit note where the deck draws "Sample output. AI didn’t respond."; 403 AI_READ_OFF turns it into the line that suggestions are off. Drawn in D4 (T-D4.35): the question editor's two inline panels (V-10) draw the same states from deck parts: an outage, a refusal or an answer with no suggestion is a line in the panel, with the button as the retry; 402 and 403 AI_PAUSED are the block sentence there and on the buttons' tooltips; each panel that answered ends with the credit note. Intended (T-D4.12): with the AI off for the school, Settings keeps its AI assistant link and the section reads "AI is not turned on for this school" ("AI chưa được bật cho trung tâm này." in vi): that sentence is the Settings note for every teacher who holds ai.use, so the place to look stays where it will be once the AI is on. A teacher without ai.use has no AI assistant section and no link (TeacherSettingsPage). The grading card's block sentence sits in a row, as the inline panels' does; in the card's column it had taken a 180px band. D4
DG-202 Teacher › "Suggest a score", "Check this test" and "Generate questions" against R6 (v2). The deck scores against the four IELTS criteria, offers "True / False / Not given", and fixes "Change to Not given", "Add word limit" and a matching heading. D4 suggests a score in the grading card's own set (0 to max in 0.5 steps); the band form, the TFNG type and the word-limit fix join in R6 (T-R6.10, T-R6.11). Built in D4 (T-D4.32): suggestAiScore moves the model's score to the nearest multiple of 0.5 up to the question's points, for a short answer waiting for a mark by hand; generation offers the five stored types; a check's fix is option_text, accepted_answer, explanation or none, so a fix whose write does not exist is advice. The band form, TFNG and the word-limit fix wait for R6. Drawn in D4 (T-D4.34a): Generate offers the five stored types as chips; a finding whose fix is none offers "Open question" and "Dismiss" only. Drawn in D4 (T-D4.36): "Suggest a score" is offered on a short answer, with the short-answer sentence and the card's own score set; the band sentence and form wait for R6. D4, R6
DG-203 Teacher › Imports history, the pager. The deck draws two pagers: every other list's footer is the workspace pager ("1–8 of 8 assignments", "Rows per page", "Page 1 of 1", first, previous, next and last), while the history's is a reduced one ("9 of 9 imports", whose first figure counts the rows the filter leaves, a static "Page 1 of 1", previous and next) that pages nothing. The history's footer is the workspace pager (data/Pager, frame="card") inside the card, under the last row, with the border, padding, size and colours of the deck's footer, because the API pages the history (DG-67) 20, 30 or 50 at a time (QA-F1-2). A page past the end, with no rows, draws the pager alone. Please draw the history's footer as the other lists draw theirs. (QA-51-11) R4
DG-204 Teacher › Imports › new import, the Files card's formats line and the note under it. The deck always names three formats ("DOCX, DOC or PDF · up to 25 MB each", "Accepts .docx, .doc and .pdf files…"); the server accepts .doc only with the converter and IMPORT_LEGACY_DOC, which is off by default. Both lines name only the formats the server's limits list, in the deck's order and wording: "DOCX, DOC or PDF" and ".docx, .doc and .pdf" with .doc on, "DOCX or PDF" and ".docx and .pdf" without it (Vietnamese "DOCX, DOC hoặc PDF", ".docx, .doc và .pdf"). The refusal of a file of another type lists the same formats with "or". Please draw the card with the formats the server reports, as DG-181 asks for the privacy note. (QA-51-13) R4
DG-206 Teacher › Media, the Replace and Delete dialogs, the toast after them and the Storage card, after F-68 (the owner's decision of 2026-10-12: a replaced or deleted file is kept while a published test uses it and deleted for good seven days after none does). The deck's dialogs say nothing of what becomes of the old file and offer no copy of it, and its Storage card draws one total, with no held or pending files. Both dialogs carry an info note (Callout, tone info, with an outline small "Download" button on the row's URL) above the file field or the buttons. Replace: "2 published tests still use this file. It is kept for them and deleted 7 days after no test uses it. Download it now if you want a copy." (each test counted once however many versions hold the file), or, with no published test, "No published test uses this file yet, so the old file is deleted 7 days after the replacement and cannot be restored. …". Delete: "The file is deleted for good 7 days after you delete it and cannot be restored. …"; a file a published version uses is still refused, as DG-09 says. The toast names the date ("File replaced. The old file is deleted for good on 19 Oct 2026."), or that the file is kept for the tests that hold it. The Storage card counts held bytes in the used figure, draws them as a third bar segment, and lists "Kept for published tests · 30 MB" and "Pending deletion · 12 MB · from 19 Oct 2026" (the earliest day, since the files go on different days) under the bar while they are not zero. A replacement refused for room while a published test holds the file says the library needs room for both files, and a 429 says how long to wait. There is no bell and no restore. Please draw the notes, the two lines and the toast. R4
DG-208 Teacher › Grading › Ready to finish, the row's "Flagged" pill and the check's flag line (page-width-proposal/Grading Finish States.dc.html, 2026-10-13). The page draws them in the warning tones. Decided (Tech Lead, 2026-10-13; spec §10.4 wins over the drawing): they read the danger tones of features/integrity/tones.ts, as every other "Flagged" in the teacher workspace does (D8). A paper flagged by hand with no focus loss reads checkFlagged_zero rather than "left the test 0 times". Built in T-D4.21b. The design team is asked to redraw the two in danger at the next deck update. D4
DG-209 Teacher › Assignment › Students, the roster's select and search (v2). The deck filters the roster only through the progress card's legend (T 607-631, rosterF) and draws no filter select and no search box above it. The product keeps both beside the legend (T-D4.22). The select's five filters (Tất cả, Đã nộp, Chờ chấm, Cần xem lại, Chưa nộp) gain "Đang làm", and the select and the legend read and write one value (?roster=), so "Chờ chấm" (awaiting grading), which the legend has no entry for, stays reachable; the search ("Tìm học viên") narrows the rows and never the legend's counts. Please draw the select and the search, or say where "awaiting grading" goes. D4
DG-211 Teacher › builder, AI panels and sticky columns, measured by T-D4.12 (2026-10-13). A group's member rows draw a drag grip (ours had none; their 33px pitch matched since T-D4.12c). Built in v0.11.6 (E1): the member grip is 20×24 at a 33px pitch, as the deck's; its icon is 14px at .40 against the deck's 13px at .45, as on our standalone rows. The Shared content dialog keeps Save enabled on a recording with no file; ours disables it until a file is chosen. The bank's Generate draws source chips and "Start empty", and keeps Generate enabled with an empty source; ours draws neither and disables Generate at 50% with the sentence that says why. Grading's "Suggest a score" is a native disabled button with its reason as text beside it, where every other AI entry is aria-disabled with a tooltip. Import's "About 400 credits per page" and Settings' credit hint are not drawn: the contract meters no such figure (§12; 74d-d4-deck-update.md, T-D4.38 and T-D4.39). The eight sticky columns cap at calc(100vh - 112px) and the question editor and Settings nav scroll inside it, where the deck caps at 100vh - 88px and does not scroll, because our <main> adds 24px above the offset and the deck's cap would end a column 8px below the window (T-D4.20); they stick at 41px against 40 (the editor's aside at 41 against 58). The test detail and import pages are 4px wider at 1440 with the sidebar collapsed (DG-205). What is built, as listed. The request to draw a member row without a grip is withdrawn: the owner decided on 2026-10-14 that members are dragged (DG-186). Please draw the recording dialog's Save before a file is chosen, the bank's Generate setup without a source, and the sticky columns' cap at our page's geometry. R5
DG-213 Teacher › Test builder, a shared-context group's header as a drop target (E1, 2026-10-14). The deck has no group inside a section, so it tints only a section's header with --accent-soft while a question is dragged over it, and draws the 2px --primary line before or after the question row under the pointer. The group's header, the row with its grip, disclosure, title and "…" menu, is a drop target of its own and takes the same --accent-soft tint while a question is over it. A drop there lands as the group's first member and opens a closed group, and a screen reader hears "Thả vào nhóm" / "Drop into the group". Member rows draw the same 2px --primary line, before or after the row under the pointer, as a question row does. Please draw the group header as a drop target. R5
DG-214 Teacher › Test builder, a member row's actions (E1). The deck's question rows show ↑ ↓ × on hover and draw no "…" menu on a row; it has no member of a group. A member row has a "…" menu with four moves: Move up, Move down, Move out of group and Move to group…. It shows on hover or focus from 768px, in the place of the points, and at 44px on the selected member below 768 (DG-135). Move up is off for the first member and Move down for the last, and Move to group… is off while the test has no other group. The row draws no ↑ ↓ ×. A standalone question's outline row keeps the deck's ↑ ↓ ×; its "Move into group…" is in the "…" menu of the question's editor, beside Duplicate and Move to section…. Please draw the member row's menu. R5
DG-215 Teacher › Test builder, a member that a material gap is bound to (E1). The deck draws no bound state. The member's grip is faded (the icon at .20 against .40), aria-disabled, not a drag source, and its tooltip and description say "Đang gắn với chỗ trống trong nội dung dùng chung" / "Bound to a gap in the shared content". In the member's menu, Move out of group and Move to group… are off and the reason is printed under them; Move up and Move down stay on. The server's refusal (group_gap_bound) is the backstop, and shows as a toast naming Shared content. Please draw a bound member. R5
DG-216 Teacher › Test builder, "Chuyển vào nhóm…" / "Move into group…" on a standalone question and "Chuyển sang nhóm…" / "Move to group…" on a member (E1). Neither the picker nor the toast is in the deck. One picker dialog serves both entries: a "Nhóm" / "Group" select whose entries read "{group} · {section}", every group of the test but the member's own, titled "Chuyển câu {n} vào nhóm" / "Move question {n} into a group", with the dialog's "Chuyển" / "Move" button. The question lands at the end of the chosen group. After a question is copied into a group, a toast says "Đã sao chép câu hỏi vào nhóm. Bản gốc vẫn ở ngân hàng câu hỏi." / "The question was copied into the group. The original stays in the question bank." Please draw the picker and the toast. R5

Take test and student

ID Gap Meanwhile Needed by
DG-80 Since the fourth import the deck draws a passage, a cloze passage and a recording as shared content, the sections navigator (a rail and a sheet), fill in the blank, an image above the prompt and the phone drawer. Still missing: the recorded-extra-plays note (DG-182), timer at zero, the focus dialog for the warn and auto_submit policies, fullscreen enter/return, offline, session takeover, session expiry. Since the 2026-10-04 export the teacher side draws a prompt with a table and a link, and with an inline image and inline audio (DG-109); the Student page draws none of them. Built (T-R3.9a to T-R3.9d) from deck primitives. The frames for sign-off, in one list. Header and save state: the save line's two troubled states, "Could not save. Trying again…" and "You are offline. Saving when you reconnect.", in the danger ink; on a phone, the strip under the header, which carries the save line only for a failed or offline save and the strike count where the assignment sets a limit; the strike count itself ("2 times away left", "No times away left", "Your teacher has been told"), which the deck does not draw; the timer with each digit in a cell one zero wide, so the pill keeps one width where the deck's changes with its digits: it is wider than drawn by what the digits fall short of a zero (4px at the deck's own 38:12 and 16px at "11:11", and 4px narrower at "44:44", as T-R3.13 measured them in the browser) and by one more cell under ten minutes, reading "04:59" and "1:30:00" where the deck writes "4:59", and 00:00 in the danger tones at zero. Leave dialog: "will be saved before you leave" while an answer is unsaved, the save in flight, and "Your answers have not been saved" with Stay and "Try saving again". Question pane: question audio's extra-plays line; a question's image; rich blanks in a table and the case-rule line; the part eyebrow and a part's instructions; the worth line under the answer; the answer field as a textarea that grows, 16px below 1024; the unknown-type block; a locked paper's disabled rows, fields and flag; a material or image that did not load, with its retry. Passage pane: tables and lists in the material; a shared recording's scope and sync lines under its card; a group with several recordings, each card under its node's label; a material that mixes text and audio. Footer: a sealed paper's footer, with no Finish; the F key, which flags (the deck binds a–e and the arrows). Dialogs: the focus dialog under warn, with no absence allowed, under auto_submit (inside the allowance and at its last absence) and with no limit; the Submit dialog with under a minute left, after time is up, while a submission is out and after one fails, and its chips scrolling in a box of their own. Bars and end states: under the header, the return-to-fullscreen bar in the warning tone, one muted sentence on a browser with no fullscreen, and the lock's bar with an icon each for taken over, time is up and ended; the submitted screen, on a success tile for the student's own submit, the timer's for a timeout and the focus dialog's for an auto-submit, with "Back to home" and "View submitted paper"; the notice "Your test is being submitted". Offline is the save line and the Submit dialog's failure line; session expiry is R1's overlay over the mounted engine. Every control has the focus ring (DG-30). T-R3.13 walked the release on the real API and found no frame beyond this list. What D4 dropped from this list, each once its task shipped: T-D4.4 the footer and sheet frames the fourth import draws, all but a sealed paper's footer and the F key; T-D4.8 the place of a shared recording, the listening group with no passage and question audio's plays left, which the recording card now draws (its scope and sync lines, a group with several recordings and a material that mixes text and audio stay listed); T-D4.6 "a fill-in with its blanks", which the deck's field now draws; and T-D4.10a "gaps that lead to their question", which the cloze's gap chip now draws. T-D4.12 removed the last two. R3, D4
DG-81 Student routes have no URLs. /app, /app/classes, /app/assignments/:id, /app/attempts/:id(/result), /app/settings/:section, /app/messages/:id, /app/week, /app/grades, /app/learn/…. R3
DG-82 What the Home badge "3" counts; the bell's red dot is always on; no "Mark all read" or full list for student notifications; student notification switches have one channel while teachers have In app / Email. Badge = due within 7 days; dot only when unread; mark all read in the popover; student switches control both channels. R3, R4
DG-83 Missing empty, loading and error states on most new screens (Messages, Calendar, Attendance, Gradebook, Reports, Courses, Vocabulary, Shared with me, Admin Users, Roles, Audit, Overview). Since 2026-10-04 also the content editor, its uploads and its two dialogs, which draw only "No files match." (DG-112, DG-115). One sentence + one action, from deck primitives. Each release
DG-84 The result page draws a "Comment" callout from the teacher with no model behind it. Built (T-R3.10): no callout in the summary. A grader's comment on one answer shows under that answer, in a lime box, as the deck's callout without the avatar. A comment on the whole attempt has no model: it would need a column and a control where the teacher grades, and attempts.teacher_note is the teacher's private note, which never reaches a student. Please say whether the callout belongs to the attempt or to the one hand-graded answer; R6 builds the second for a paper whose only hand-graded answer has a comment (T-R6.12). R3, R6
DG-85 Result variant 2 draws topic tiles (Present perfect 4/5, Past simple 4/5) for a one-part, one-skill paper; nothing models topics. Not built: a one-part, one-skill paper shows no tiles. R6
DG-86 Essay grading draws scores 3–8 in nine values; bands run 3–9 in half steps. 3–9 in half steps; please redraw the score row. R6
DG-87 The Student deck centres its toast at the bottom, 20px from the edge and 84px while the tab bar shows; the Teacher and Admin decks put it at the bottom right, 16px from both edges. One toaster for all three consoles, at the bottom right and 16px, lifted to 84px while the student tab bar shows (T-R3.5). Please draw one position. R3
DG-88 Every console header writes "Quizzivy" in the interface typeface beside the mark; the brand kit says the wordmark is never re-set in that typeface (docs/design/README.md, "The brand"). Built as the decks draw it: the mark with the name as text, 16px bold in the student header (T-R3.5). Listed so the design team decides between the kit's rule and the decks. R3
DG-89 The phone tab bar's "Me" opens Settings, which is a detail screen: it hides the tab bar, so "Me" is never shown as the current tab. Built as drawn. Five tabs are drawn; the product shows a tab only when its module has shipped, so v0.9.0 has Home, Classes and Me. R3
DG-102 Home draws one moment and no rules. Not drawn: a greeting for any other time of day; the line under it when nothing is in progress but something closes today, or nothing is coming; a paper closing today (only "Due tomorrow"); a second attempt in progress; "Opens" beyond the next week or later today; a result whose score is hidden ("Submitted"); how long "Just now" lasts; results when a paper has a retake left. Built from the deck's parts (T-R3.6): three greetings by the app's clock (05:00, 12:00, 18:00); "You have n tests due today." and "Nothing due today."; "Due today" beside "Due tomorrow", by the calendar day within 24 hours; an "In progress" row in the info tone; "Opens 19:00", "Opens Mon", "Opens 5 Sep"; "Submitted" as plain muted text; "Just now" for one minute; a paper with a retake left shows both as still to do and as a result. Home lists every result, not three, until Grades exists (R9): nothing else links to an older one. Please confirm or redraw. R3
DG-103 The Join dialog is drawn centred at every width, with no state but found, not found and already a member. Not drawn: a lookup or a join on its way, a join that fails, the rate-limited answer, a character no code uses, an account that is not a student. Already a member is drawn as an error. Built (T-R3.7): centred from 768 and 12% from the top below it, because the field takes focus on open and a centred panel puts the class and the buttons under the phone keyboard. A spinner on "Join class" while joining; "Could not join the class" under the field; the server's sentence and "Try again in n seconds" for a 429 (with DG-40); "Codes never use 0, O, 1 or I" at once; "Joining a class is for student accounts" under the found class. Already a member as drawn. Please confirm the phone position and draw the states. R3
DG-104 Classes draws two fixture cards and no rule or state. Not drawn: how "Next" is chosen and worded beyond two samples, a class with no teacher, loading, no classes, an error. The card has no place for the class description, which is where a student reads when the class meets until the timetable ships. Built (T-R3.7): "Next" is Home's first paper for that class, in five shapes ("{title} · in progress", "{title} closes today at 21:00", "{title} · due Thu 25 Sep", "{title} · opens today at 19:00", "{title} · opens Mon 29 Sep") or "Nothing assigned yet"; a class with no teacher has no teacher row; two card shapes while loading, one sentence for no classes, the error card with retry. The description takes the timetable's line under the name until R8. Please confirm or redraw. R3
DG-105 The Test intro draws five fixed sentences under "Before you start" and no policy: only the date line is computed, and the leaving line always reads "2 times". The Teacher deck's "What students will read" generates different sentences for the same switches ("You have 45 minutes once you press Start…", "your teacher will be told", "Your teacher will share results later."). Not drawn on the intro: an attempt in progress ("Continue test" exists only on Home); a closed test; no attempts left (the "1 of 1" fixture still offers Start); loading, an error, a test that is not the student's; a start the server refuses; a test that closes before its time limit runs out; fullscreen on a browser that has none; audio plays. The upcoming variant promises "We will notify you when it opens." and its date line has no times. Built (T-R3.8): one generator for both screens, in the Student deck's words where it has them and the Teacher deck's for the cases it lacks. Leaving reads "Leaving the test is recorded." with no limit (the Teacher deck's line; the server records every absence), "Leaving the test is not allowed. …" for none, and "You can leave the test n times. After that, …" with "your teacher is told", "you will get a warning" or "your test is submitted". The score line has four forms and is absent when the score is hidden: nothing shares results later yet. With the score hidden the correct-answers and explanations switches go unannounced too, although the result page shows what they release; please say whether the intro should name them. The date line carries times ("Opens Mon 29 Sep, 08:00 – Wed 1 Oct, 21:00."). "Continue test" is the Start button with "This attempt ends at 17:38." and no question; closed and used-up tests are one sentence in the inert button's muted box; "Opens Monday" is aria-disabled with "You can start once it opens." until notifications ship (R4). "Start now?" says "The test closes at 21:00, so you have 20 minutes." when less than the time limit is left. A refused start closes the dialog and says why above the button. Please confirm the sentences, draw the missing states, and make the two decks agree. R3
DG-106 The Result draws three fixture papers and no review policy. Its just-submitted paper shows a total ("3 of 6 so far") while every auto-marked answer stays a neutral dash, and its lock lines need facts the product does not have yet ("Correct answers appear after the test closes today at 21:00.", "Answers appear once grading is finished.", "Your teacher graded this by hand."). Its pending paper lists no answers. Not drawn: a score the teacher withholds; an answer that earned part of its points; a paper with one part and no topics; a filter with nothing in it; a retake ("attempt 1 of 2"); shared material, a question's recording and its transcript; a per-answer comment; loading, an error, a result that is not the student's. The summary names the teacher ("Ms Thương") and promises a notification. Note, 2026-10-10 (v2 export): the deck's teacher is now "Giàu Bùi", with no honorific; the rule does not change. Built (T-R3.10): an answer shows its own mark whenever scores are shown (check, cross and "1 / 1"), because the server sends each mark with the total and the Wrong filter needs it; the dash is for a hidden score. An answer with part of its points gets a lime circle with a percent sign and "0.5 / 1", is listed under Wrong and is not struck through. A withheld score draws a lock in the ring, no tiles and "You answered 7 of 8 questions. Your teacher has not released the score." The lock line names what the policy hides ("Your teacher is not showing correct answers or explanations for this test.", seven forms). The pending paper keeps its answers on screen, each "Waiting", and says "Your score appears here when grading is finished." until notifications ship (R4). The teacher is "Your teacher". "Correct answer" is left out for an answer already marked correct. The filter has no "Wrong" when scores are hidden, no "Waiting" when nothing waits, and is absent when "All" would stand alone; an empty "Wrong" reads "There are no incorrect answers in this paper." with "View all questions". The line above the title adds "attempt 1 of 2" when the paper allows a retake. Shared material keeps the teacher console's card above its first question; a recording, its transcript and the grader's comment (a lime box, as the deck's callout without the avatar) sit under the answer. A one-part paper has no tiles (topic tiles: R6). Please confirm the per-answer marks and the partly-right state, and draw the withheld score and the missing states. R3
DG-107 Student Settings draws a name field and no way to save it, and no state but the settled one. Not drawn: an unsaved, a saving and a failed name; a name the rules refuse; a password the rules or the server refuse; an account that signs in with Google only; a deployment without Google sign-in; a control that shows the typed password. "Linked · {email}" shows the Google address, which the contract does not carry: the account's own email can be a different one. The strength hint tells every password, a strong one too, to "Add a number or symbol". Built (T-R3.11): the Teacher deck's bar ("You have unsaved changes." / Discard / Save changes) under the Profile card while the name differs, the rule in place of the hint under the field, and the server's reason in the bar. The Google row reads "Linked", with no address. A Google-only account has no password row and keeps Unlink switched off beside "Google is currently the only way into this account. Set a password before unlinking." Both password fields keep the show and hide button. The hint reads "At least 8 characters.", then the strength alone, with the deck's advice only while the password has no number or symbol; a password the server would refuse never reads better than "Okay", and the deck's "Weak" is never shown, because a password long enough to be named already scores two bars. The toast after a change reads "Password updated. Other devices have been signed out." Notifications is absent until its module ships. Please confirm or redraw. R3
DG-118 Two places where the deck draws something it does not mean (found by T-R3.13's browser run). Splash › skeleton, student destination, at 360: one placeholder line is 320px wide in a 304px column and overhangs it. Student › Test intro on a phone: the rules list is visible through the 28px (48px from 768) of page padding under the sticky action, so a rule shows below the button while the list scrolls. Built (R1, T-R3.13): the skeleton's line stops at its column, and the intro's action covers the padding under it in the page background. Neither defect is copied. Please correct both in the deck. R3
DG-119 Student › Classes and Settings, the heading. These two h1s set no line-height and inherit the page root's line-height:1.5; the deck's other student headings set line-height:1.25 (Home, Test intro and the screens of later releases). Built (T-R3.7, T-R3.11): the heading keeps the product's 1.25 on every student page, as DG-117 keeps it on Sign in. What is under the heading sits 6.5px higher than drawn from 768, and 5.5px higher on a phone on Classes; below 768 Settings draws no heading. Please set line-height:1.25 on both. R3
DG-137 The Student deck's result draws no class average, and the Teacher deck's Results group has no switch for one. The product adds the choice (review.showClassAverage, off by default, T-R4.11) and so needs a place on the result. One muted line, "Class average: {n}%.", under the summary sentence in the result's summary card, at most one decimal. It is the mean of each target student's best graded attempt, and it shows only when all four hold: the teacher turned it on, this result is released (an after_close result is withheld until the close), the assignment has closed, and at least 3 students qualify. Voided, ungraded and unstarted work counts for nothing. No tile, ring or chart. Exposure: in a group of exactly three, a reader who knows their own score can derive the other two's combined score. The floor of 3 is the default of the approach and is listed for Thuong's sign-off (options: 3, 5, or no average for a reader in a group of exactly three); a different choice is a follow-up. Please draw it. (T-R4.11) R4
DG-182 Student › Take test, a recording at its play limit (fourth import). The deck locks it: "No plays left", a lock icon, "You have used all {N} plays", and the button does nothing. Built in D4 (T-D4.8), the default: spec §11.4 stands and the button stays live at the limit. Past the last allowed play the counter reads "Played {n}/{N} times" and the status "You have used all {N} plays." with the product's "You can keep listening. Additional plays are recorded for your teacher to review."; the canary case "still plays when the hint says none are left" is unchanged. Please redraw the state, or Thuong changes §11.4 (Q3). D4 (Q3)
DG-183 "Students can pause" (Teacher: question media and Shared content; Student: the inert button and two status lines), fourth import. Built in D4 (T-D4.13, T-D4.9, T-D4.15): one boolean, allowPause, default on, on a question's audio and on a group's recording; a save that does not send it keeps the stored value. "Students can pause" sits between "Plays" and "Allow skipping ahead" in the question media block, the group pane's recording and the Shared content dialog. Off, the card's button is inert while the recording plays (aria-disabled, 45% opacity) and the status reads "Playing · this recording can’t be paused" ("Press play when you are ready. It can’t be paused once it starts." before the first play); a pause from elsewhere (a headset button, another recording, leaving the group, a lock) still reads "Paused" and resumes for no play. The intro fixture's "you can pause once" is read as a note, not a count. Measured (T-D4.12): the media row's "Students can pause" switch is 36px wide, the shared Switch primitive's small size, against the deck's 34px; the Shared content dialog's "Plays" control and its label weight are not the deck's drawing either, because "Plays" is one control everywhere (Q25, T-D4.15). D4
DG-184 Student › Take test, a cloze (fourth import). It is one item with n gaps on the Student page and one single-choice question per gap in the builder. The deck of record's import preview drew the product's model on a student-eye surface (a passage with gap chips and a member "23.1 Choose the word for gap 23.1." with its own options); this export removed it (T 4975-4980) and left its data in the script (T 7428). Decided by the design team (Q6, 2026-10-13, #581; page-width-proposal/Cloze Decision.dc.html): one question per gap, each with its own number, square, flag, points and result row, shown as one screen. Built in the engine (T-D4.10a): two or more consecutive single-choice members bound to gaps of one material, none with an image or audio, are one stop. It prints the members' shared plain prompt once, or each member's own prompt in the gap card; the hint names the cloze's gaps that have screens of their own; a chip per gap; the open gap's card ends with its own worth; a choice opens the next gap with no answer, going round. The squares stay one per question, tied within a row ("One screen" in the legend) and ringed while the run is open, the open gap's in lime with aria-current. A member with media, or a gap left alone, is a question of its own whose line says "Cloze · 1 of m gaps"; on a cloze stop the flag names its question. In the passage a gap is the deck's chip with the chosen word. On the result (T-D4.10b), a run whose gaps share one prompt prints it once on a run line over one-line rows, and the passage shows each gap's word in its mark's colour, struck through when wrong, "—" when unanswered, neutral when the policy hides marks. D4
DG-185 Student › Take test, numbers and counts (fourth import). "Question 23 of 31" against 35; a matching numbered "1–5" counts five, another numbered "31" counts one. Every question has one number and counts once (Q6 answered, #581; Q7's default). Built (T-D4.10a): a run's line reads "Questions 23–27 of 34 · Cloze · 5 gaps", "… · 3 of 5 gaps" for part of a cloze, and a gap on its own "Question 26 of 34 · Cloze · 1 of 5 gaps" ("· 1 gap" for a cloze of one); the total is the paper's question count, 34 on the fixture paper T-D4.3 builds (s9 without its matching) and 35 once R6 adds the matching. The footer, the squares and the Submit dialog count gaps one each. D4
DG-189 Student › Take test, frames keyed by fixture ids with no model (fourth import): the sign card, the 60px word tiles, the image caption, the per-question hint, paragraph letters. Not built in D4 (Q18's default): a notice is prompt content or an image, an underline is option content; the 60px tiles, the caption, the per-question hint and paragraph letters have no field. Not built
DG-190 Student › Take test, the phone drawer (fourth import). It draws no Esc, no focus move, no inert, no reduced-motion form and no rule for how long the tip is remembered; on a phone the recording is out of sight while the student answers. The closed drawer is aria-hidden (S 1041, 1700), which hides it from a screen reader and leaves its gap buttons in the Tab order. Built in D4 (T-D4.7): opening moves focus to the close button and closing returns it to the handle; Esc and the backdrop close it; the closed drawer is inert, in place of the deck's aria-hidden, and stays mounted, so the passage's place and a playing recording survive; under reduced motion there is no nudge, no tip animation and no slide; the nudge and the tip show until a group's drawer is opened once in the attempt (sessionStorage['quizzivy.stimulus-seen.<attemptId>']). A recording plays on behind the closed drawer, and the handle's 7px dot is the only sign of it on the question (Q13). D4
DG-191 Student › Take test, navigation (fourth import). The rail comes and goes between questions from 900 to 1179; the key hint names "A–D" on every question and omits E and F; the sheet has no title; the sheet's 42px squares, the rail's 34px, the 30px handle and the 38px blank are under the 44px floor below 1024; the rail prints the part of a section title after " · "; the arrow keys bypass go(), so in the deck they do not close the drawer or the sheet and do not pause a recording, and Esc does not close the sheet. Built in D4 (T-D4.4): the rail as drawn, from 900px with no shared content and from 1180px with it, so it comes and goes from 900 to 1179 (Q12), printing a section's whole title; the hint as drawn ("A–D"), "to move" alone on a question with no options, while A to E and F keep working (Q20); the sheet's name ("Questions") and its total for a screen reader only; a blank and the sheet's squares 44px below 1024 (the squares 42px from it); the rail's 34px squares, the 30px handle and the 34px close button as drawn (Q21). Every move, by key or by click, goes through one function, so the arrows close the drawer and the sheet and pause a recording as a click does, and Esc closes the sheet. D4
DG-192 Student › Take test, section instructions (fourth import). They show above every question on the Student page while the builder says "above the group’s first question"; a group's own instructions are not drawn. Built in D4 (T-D4.5): the section's title over its instructions above every question, left out on a paper of one section with no instructions; the builder's Instructions dialog says "Students see this above every question in the section."; a group's own instructions stay under the stimulus heading, or under the kicker when there is none. D4
DG-193 Student › Take test, what spends a play (fourth import), and unlimited plays ("Play 1 of 99"). Built in D4 (T-D4.8): a start with no play in progress spends one and a resume none; a play in progress and its place are remembered in memory while the tab lives, and a reload forgets them; a start whose place cannot be put back counts as a play; leaving a group pauses its recording however the student left; unlimited reads "Play {n}". A card that comes back after a reload in the middle of a play reads "Finished" (74d, follow-up 3, asked of the design team). D4
DG-194 Student › Take test, matching (fourth import): chips per row, three key styles, the nouns "pick the {pick} for each {what}", 38px chips. Not built in D4: R6 (T-R6.10 as corrected by T-D4.19). R6
DG-212 Student › Take test, measured by T-D4.12 (2026-10-13). The deck styles scrollbars at 10px with a rounded --border thumb; ours are the platform's, so with classic scrollbars (Windows, Linux, macOS set to always show) a scrolling passage, question column or drawer is 5px narrower and its text rewraps. The drawer's backdrop is rgba(15, 20, 22, .45) in both themes; ours is --overlay (.4 in light, black at .6 in dark), the backdrop of every dialog. The Submit dialog says "Unanswered questions score zero." where the deck says "Unanswered gaps, matches and questions score zero" (76-r6.md). A blank's text is 16px below 1024, where the deck draws 18px, as every product field is below 1024 (74d-d4-deck-update.md, T-D4.6; DG-191 covers its 44px height). A recording that comes back after a reload in the middle of a play has a count and no place to resume, so it reads "Finished" ("Finished · {n} plays left") with the button "Play again", though the student may not have heard the end (74d-d4-deck-update.md, follow-up 3). What is built, as listed. Please say whether the student app should style its scrollbars, whether a drawer's backdrop is its own colour or the overlay token, and whether that recording should read "Played". R6

Collaboration, schedule, insights, learn

ID Gap Meanwhile Needed by
DG-90 Sharing entry points are drawn for tests only; Shared with me lists four kinds. Draw sharing for question sets, word lists and courses, and what a "question set" is in the bank. Also: what a Can-use view allows, who is shown as author when a Can-edit recipient publishes, and where the share message appears. The 2026-10-04 "Choose from Media" dialog also speaks of files "other teachers shared with you"; media is not one of the four kinds (DG-112). Question set = a named selection made from the bank's bulk bar; Can use = read-only + make a copy; the owner stays the author, the publisher is recorded; the message appears in-app and by email. R7
DG-91 Messages: is the attempt-event card in a DM teacher-only? Class-thread attachments render as a "me" bubble. No teacher-to-teacher messaging. Teacher-only; attachment bubbles follow the sender; no staff DMs. R7
DG-96 Data & privacy has no row for how long messages are kept; no screen shows an address that bounced or complained. Messages are kept; anonymising an account deletes its direct messages. A suppressed address shows in the Admin user sheet from deck parts. R7
DG-97 Student Grades draws one "Grammar & vocab" tile; skills are tagged separately. The command palette omits Reports. Skills shown separately; the palette follows the deck. R9
DG-92 Schedule: are sessions generated from the class schedule, from "Repeat every week", or both? Is an Excused or Unmarked attendance status needed? Per-date exceptions on the teacher side. Sessions come from a weekly series; statuses present / late / absent, plus unmarked. R8
DG-93 Gradebook: no place to set an assignment's category and weight, "homework" is undefined, terms have no management screen. Category and weight in the wizard's Schedule step; terms managed in Admin settings. R8, R9
DG-94 Courses: no lesson editor for reading, video or listening; video source undefined; reorder grips have no behaviour; unit "On a date" prints a raw ISO date. Lessons edited with the existing rich editor; video by upload; reorder by drag; dates formatted per locale. R10
DG-95 Vocabulary: the source of "Play pronunciation" / "Listen" audio. Uploaded audio per word, falling back to the browser's speech synthesis. R10
DG-198 Teacher › Class detail › Attendance (v2, R8). The footer says "Students see their own attendance." and the save dialog "They count as absent until you mark them." R8's decisions stand (T-R8.6: no student operation in R8; DG-92: unmarked is a status outside the rate); the two sentences are not taken until R8 decides. R8

Landing

ID Gap Meanwhile Needed by
DG-100 Below 960px the section links disappear with no menu; testimonials need consent from real people; the footer "Status" link has no target; SEO / Open Graph content; the page defaults to English. Note, 2026-10-10 (v2 export): the testimonials now name the owner as "Centre manager"; they are still placeholders until the people consent. A menu button below 960px; placeholder testimonials until consent; Status → the status page; vi default. R11
DG-101 The consultation form has no submitting, server-error or rate-limited states. Deck primitives, listed for sign-off. R11

Generated from docs/design/gaps.md. Edit that file in the repository; changes made on this page are overwritten.

Home

Start here

Product

Implementation plan

Redesign (Phase R)

Setup and operations

Design

Team

Code READMEs

Clone this wiki locally