Team R4 Readiness - SekiroKenjii/Quizzivy GitHub Wiki
The onboarding surveys of the tasks that were ready on 2026-10-07, against
work/redesign-r4 at bb4d4000. This is a dated snapshot that informs the delegation
briefs. It is not the plan: docs/plan/74-r4.md stays the authority, and a task's own
"As built" supersedes its entry here. Delete this file when R4 closes.
Read-only survey, no tests run. References are docs/plan/74-r4.md line numbers and paths
under server/. The next migration number on work/redesign-r4 is 00092.
- All seven tasks edit
api/openapi.yaml, the generated code andpermissions.golden, and bump pinned literals, so their PRs conflict textually and merge serially, each regenerating after it brings in the integration branch:-
permissions_test.go:85(operation count) and:424(Assistant refusals; 12 adds three, 20 adds one). -
group_authoring_test.go:63(body budgets; 8 adds one). -
credential_limits_test.go:109(20, and 18). -
resource_contract_test.go:13withopenapi.yaml:63(resource kinds; 12 addsoverride). -
isolation_world_test.go:354snapshotOf(12's table).
-
- The
ErrorCodeenum (openapi.yaml:479) gainsASSIGNMENT_LOCKED(11),ASSIGNMENT_CLOSED(12),IMAGE_DIMENSIONS(8), and an unnamed code for 9's 409. - The isolation runner requires a missing id to fail (
isolation_runner_test.go:306) or anexcuse./auth/*is outside the suite. A new/me/*operation needs a row even without a uuid. - Where a plan "Touches" list omits a file, the task below names it (ledger F-1).
-
Operations.
-
publishTesttakes an optional{changeNote}and returnstestUpdatedAt. -
getTestgainsunpublishedChanges. -
TestVersiongainsassignmentCountandchangeNote. - List rows gain
assignments{live,scheduled,closed}. - New
GET /teacher/tests/{id}/versions/{version}/diff?against=(workspace.teacher,x-resourceid=test).
-
-
Migration.
test_versions.change_note, nullable, at most 200. -
Reuse.
loadQuestions(publish_load.go:68),readGroupMaterials/Recordings(group_read.go:13-28),versionColumns(versions.go:13). -
A new lock-free draft loader.
loadDrafttakesFOR SHARE(publish_groups.go:13-36), and PostgreSQL refusesFOR SHAREin a read-only transaction. The diff needs its ownREPEATABLE READ READ ONLYtransaction, set withSET TRANSACTION, becausedb.Connhas onlyBegin(platform/db/context.go:19). -
Tests. Diff units per kind and for a reorder; endpoint and bank-edit integration;
publish_snapshot_test.gountouched; an isolation row likedeleteTestVersion's. -
Open questions:
- Where
testUpdatedAtlives. - How a change is counted.
- Whether
assignmentCountcounts drafts, and whose assignments. - What
against=previousmeans for version 1.
- Where
-
Operations.
createAssignment/updateAssignmentgainreview.release,review.showClassAverage,studentNoteand a 409ASSIGNMENT_LOCKED.getAssignment,getMyAssignmentandgetAttemptResult(classAverage) change.maxAttemptsgets a maximum of 99. -
Migrations.
add_assignment_review_options(constant defaults) andadd_assignments_student_note(nullable, 1 to 500 after trim). -
Files.
-
assignments:domain/commands.go;repositories/write.go:155-170,assignments.go:30,student.go:44. -
attempts/repositories/result.go:115(resultRules).
-
- Tests. The release rule, the three-student floor, the lock, the note, the leak walk, and the canaries at the branch point and the head. About fourteen MSW fixtures are swept in a mechanical commit. The web half (results page, intro) belongs to a frontend owner.
-
Questions for the Principal:
- A full-replace PATCH with optional fields must preserve an omitted field (the
json.RawMessageprecedent of T-R4.7), or an old tab resets them. -
after_closemust also gate the student card'sscore(student.go:44), and "answers" needs a definition. - How the client learns the release time.
- The type of
classAverage, and who counts toward the three. - The lock's precedence over
VERSION_LOCKED. - One shared "effective close" helper that 12 extends (R9 reuses it,
79-r9.md:291).
- A full-replace PATCH with optional fields must preserve an omitted field (the
-
Operations.
-
POST /teacher/assignments/{id}/extend(teaching.assignments.write). -
GET/PUT /teacher/assignments/{id}/student-overridesandDELETE …/{studentId}(teaching.attempts.intervene,x-resource-listoverride, kinds student and override).
-
-
Migration.
create_assignment_student_overrides: composite key,ON DELETE CASCADE, anupdated_attrigger and CHECKs. It is added to the isolation world. -
Files.
-
assignments:schedule.go,student.go,for_student.go. -
attempts:rulesQuery(store.go:34),CanStart/Deadline(support/service.go:109,domain/attempt.go:113),monitor.go. -
core/maintenance/windows.go:50,107, andjoin_and_take_flow_test.go.
-
-
Tests.
- Effective-window units.
- A start under an override.
- The deadline recomputed under attempt row locks, with the audit in a data-modifying
CTE (
attempts/repositories/admin.go:20). - A non-target student, isolation, the maintenance extension, reopen for one student.
-
events_test.goandpublish_snapshot_test.gountouched.
-
Questions for the Principal:
- Does PUT merge or replace?
- What is
extendBy's unit and base? - The effective close is
max(assignment, override), so an earlier override never restricts. - How does an override interact with an early close?
- How does extend behave on a draft or a scheduled assignment?
- The teacher must reach the student, which the suite does not catch.
- What is the contract field for "Extended to…" on
MonitorRow? -
notifyhas no consumer until 10b. - What 422 code does a non-target student get?
-
Operations.
-
POST /teacher/assignments/{id}/duplicate(teaching.assignments.write;classIds). -
GET …/{id}/item-analysis(teaching.grading). -
GET /teacher/assignments/results.csv?ids=(teaching.grading; streamed, BOM). -
listAssignmentsgainsq,classId[]andquestionCount.
-
- No migration.
-
Files.
-
assignments: duplicate,narrow(),selectAssignment. -
attempts: item analysis, results export,analysis.go. - A new
platform/tabular, and a zone port wired like the dashboard's (adapters/zone.go).
-
-
Questions:
- A foreign or missing id in
idsshould 404 the whole request. - Which attempt per student, and which class per row.
- What status does a request over 20,000 rows get?
- What is item analysis's denominator?
- Duplicate copies
review_releaseandstudent_note, so it follows 11. - What do
classId[]semantics mean against T-R4.54?
- A foreign or missing id in
-
Operations.
PUT /me/avatar(multipart,x-max-body-bytes2 MiB,perActor10 an hour) andDELETE /me/avatar, each with an isolation row.IMAGE_DIMENSIONSis a 415. -
No migration:
avatar_keyexists since 00085, but nothing reads or writes it. -
Files beyond the plan.
-
domain.Userand its projection,toCurrentUser(five call sites), and wiring. - The storage client is built only in
wiring/media.go, after identity, so it has to be shared. - A new
platform/imagesafeand an identity object-store port. No new dependency.
-
-
Questions. EXIF orientation is dropped, not applied. The
avatars/{userId}/key in student payloads (T-R4.18'steacherAvatarUrl) needs a leak review.
-
Operations.
GET /auth/sessions,DELETE /auth/sessions/{familyId}andPOST /auth/sessions/revoke-others. They are outside the isolation suite, so they need their own 404 test. -
Migration.
refresh_tokens.geo_label, nullable, at most 80. -
Files.
identity'ssession.goandrefresh_store.go(issueSuccessorcopies the label), a newplatform/uaparse, and a location-header middleware besideWithRefreshCookie(router.go:88-89). -
Session effects. Each revoke bumps the caller's epoch and calls
Forget. The caller's own tab then recovers through the single-flight refresh, soclient.refresh.test.tsstays untouched. -
Questions.
- The 409's error code is unnamed.
- The geo label is trusted only behind
CF-Connecting-IP. - The location shown is where the user first signed in, because rotation copies the label.
-
Operations.
-
POST /teacher/students/reset-passwords(people.students.reset_password; 2 a minute and 10 an hour per actor; joinstheCredentialMinters). -
listStudentsgainsclassId[]andmustChangePassword.
-
-
Reuse.
ResetPasswordand the unshared rule (students_write.go:171,216), andhashSlots. -
Tests.
-
STUDENT_SHAREDlands infailed, and a foreign id answersNOT_FOUND. - The reset token dies, and the rate limit holds.
- The isolation row needs an
excuse(the missing-id case answers 200).
-
-
Questions.
- Is
classId[]OR or AND? - If the client drops mid-request, committed resets lose their one-time passwords: decide whether the work detaches from the request context.
- Is
-
11, 12 and 13 share
assignments/repositories/{assignments,student,write}.go, the HTTP handlers, the domain and theAssignmentschemas: serialize them. 13's attempts half is file-disjoint from 11, 12 and 16. - 16 stands alone; 62 follows it.
-
8, 9 and 20 share
identity/application/app.go,ratelimits.goandcredential_limits_test.go. They can be built in parallel worktrees but merge one at a time, and each later one regenerates after bringing in the integration branch. - Parallel worktrees are safe for 16, 11, 20 and 9. The contract, generated code and pinned tests always merge serially.
-
Inputs to the schedule (the one schedule is the ledger's): 11 introduces
EffectiveClose, which 12 and 10b extend; 16 unblocks 62, 29, 30 and 31b; 13's attempts half is file-disjoint and can fill a gap.
Read-only survey; only git fetch and diffs were run. References are paths under web/
and deck line numbers in Quizzivy Teacher.dc.html.
-
layouts/TeacherShell.tsxrendersTeacherLayout(inside the deck scale) when the leaf route has a teacher handle, andAdminLayoutotherwise.AdminLayoutstill forces light (AdminLayout.tsx:88). - Rebuilt to the deck: the Dashboard, the imports list, new import and import run, and the assignment detail. Still old: tests, test detail, builder, import review, bank, groups, question editor, media, assignments list, new and edit, attempts, grading, students, classes and settings.
-
Composites available:
-
components/shared/data/(DataTable,Pager,FacetFilter),CardGrid,BulkActions. -
form/(FormDialog,DialogShell,ChipInput,TagCombobox,NumberStepper,RadioCard,FileDrop, fields). -
Sheet,CopyField,DirtyBar,SettingsLayout,ConfirmDialog. -
stats/(KpiTile,StatStrip,ProgressBar,Meter),charts/BarChart,IconTile,Callout,LockNotice,EventList,SplitPane,Waveform. - The hooks
useIdlePolling,useFileDrop,usePage;layouts/shell/(PageHead,useCrumbs,useContentWidthAtLeast,handle);ui/segmented,RowMenu. - Test support:
tests/units/shell/support.tsx.
-
- Content widths (sidebar 248 expanded or 60 collapsed, side padding 28): 464 or 652 at 768, 720 or 908 at 1024, 976 or 1164 at 1280, 1136 or 1320 at 1440, and 332 in the drawer at 360.
-
Outcome.
ContentEditorgets the deck's box, toolbar, link popover, table row, notice band, word count andreadOnly. Pasted images are left out and counted. - References. Deck 742-760 and 813, script 3955-4030; DG-30, 35, 36, 109, 110, 115, 116.
-
Files.
-
components/shared/content/editor/(ContentEditor,ContentToolbar,PastePreview). - New
TableToolbar,LinkPopover,NoticeBand. -
clipboardHTML.ts,useContentPaste.ts,extensions.ts,content.css. - The content unit tests, and
e2e/rich-question-content.spec.ts.
-
-
API. None. i18n under
contentEditor. -
Open points.
- "Touches" omits the six hosts. The recommendation is that 63 ships the new props with defaults and edits only the group and option hosts.
- Every host is still an old, forced-light screen behind
VITE_RICH_QUESTION_EDITOR, so the dark and five-width check needs a deck-harness case (cases/r4-63.tsx). - DG-115 is an unconfirmed default.
- Accessibility. The toolbar becomes one tab stop with roving arrow keys. The link popover traps focus and returns it on Esc. A selection survives a touch press.
-
Canaries.
router-chunksstays untouched.
-
Outcome. Paste mode replaces the deferred placeholder in
NewImportPage.tsx:66-70. - References. Deck 1595-1701; DG-12, 14, 15, 17, 21.
-
API. Everything exists. The 46-case count fixture is already in CI's web set.
TEXT_MARKS_UNAVAILABLEalready has copy in both languages. -
Size.
paste.tsports part of a roughly 1,460-line Go grammar, and each rule is mutation-tested, so this is L. -
Open points.
- The crumb can come from
PageHead, which avoids editingrouter.tsxandteacher-routes.test.tsand so the collision with 27a. - "Tips beside the example from 900px" should be a container query.
-
[&_button]:min-w-[168px](NewImportPage.tsx:62) contradicts DG-21.
- The crumb can come from
- Accessibility. Ctrl or ⌘+Enter never fires during IME composition, and leaving asks first.
-
Outcome. The deck's Media page, the Upload, Replace and Rename dialogs, and
useMediaUpload. - References. Deck 1168-1202, script 3383-3388 and 3484; DG-09, 63, 69, 83.
-
Files.
-
MediaLibraryPagebecomesMediaPage(router.tsx:148,teacher-routes.test.ts:40). - New
MediaCard,UploadDialog,ReplaceDialog,useMediaUpload.ts;UploadPanelis retired. - The upload call in
QuestionMediaFieldandMaterialAssetDialog. -
limits.ts,probe.ts, andmedia/api.ts, which lacksq,unused,replaceMediaandupdateMedia.
-
-
Contract gap. "Download":
LibraryAsset.urlis a cross-origin signed URL, so<a download>cannot name the file. Either it opens in a tab, or the backend adds a disposition. -
Canaries. No
router-chunksedit is needed:ADMINalready covers all offeatures/media/. Do not export the hook fromfeatures/media/index.ts, whichResultPageimports.audio-player.test.tsxstays untouched, and the media card's play button needs its own same-tick test. -
Open points.
- The two former
UploadPanelhosts need their own progress and error UI. - The image pre-checks are new client logic.
- DG-63 and DG-09 override the deck's copy.
- The two former
- References. Deck 477-549, script 4197-4296.
-
Files.
QuestionBankPage.tsx(648 lines), a handle inrouter.tsx:117, andtests/units/question-bank/. -
Contract gaps.
- No count for "Audio", although the plan asks for server counts.
- No per-tag counts, which the deck's popover shows.
- No operation to remove a tag from a row:
tagQuestionsonly adds.
- Decision left to this task by T-R4.1a. The column thresholds: content width (the deck's, which overflows by up to 62px at 1024 expanded beside the 220px aside) or the table's own width.
- Level groups. The deck groups "A1–A2"; the plan wants Pre-A1 to C2.
- References. Deck 854-940; DG-65.
-
Files.
- New
AssignmentWizardPageandWizardStepper, replacing the 925-lineAssignmentFormPage. -
router.tsx:157,177andteacher-routes.test.ts:42,50. - The four
?testId/?classIdlink sites. -
e2e/support/live.ts:123-145andadmin-change-requests.live.spec.ts:125-155.
- New
-
Main open point. 27a ships steps 1 and 2, while Schedule, Rules and the final
Assign are 27b, which waits for T-R4.11. Between them the integration branch would lose
scheduling, rules, the §10.5 honest-limits text and the Assign that
assignToClassdrives. Proposal: 27a mounts today's schedule and rules groups as interim steps 3 and 4, keeps a final Assign, and keeps/:id/editworking for published assignments.
-
Mostly built already. The Dashboard's Flagged tile, the roster's flag tone, and
KIND_LOOKflagged.FocusLossCellis dead code. -
What remains.
- Consolidate the tones in
integrity/tones.ts. - Colour the compact timeline's dots (
Timeline.tsx:99,108). - There is no "submitted" event (it comes from the attempt as a prop), and no autosave event behind the deck's "Answers autosaved".
- Consolidate the tones in
- For the Principal. Danger dots against spec §10.4 ("neutral text"); AGENTS.md D8 appears to settle it.
-
#414 shares
router.tsx, thebuilderlocale namespace,MarqueeText.tsx,index.cssand separate hunks ofadmin-change-requests.live.spec.ts. #416 sharesrouter.tsx:192andteacher-routes.test.ts:52, one line from 27a's and 35's rows. -
Inputs to the schedule (the one schedule is the ledger's). With one frontend
engineer the order is 63 (the critical path), then 35, 46, 32, 57 and 27a. If a second
implementer joins, 63, 46 and 35 are file-disjoint and can run in separate worktrees.
27a goes after 35, whose rows sit beside its own in
router.tsxandteacher-routes.test.ts, and after the interim-steps question is settled. -
Serialize anything editing
router.tsxorteacher-routes.test.ts. Locale namespaces merge one at a time.
For the Principal (approach) or the user (product), before the task that needs them:
- T-R4.11 and 12: omitted-field preservation on PATCH, one
EffectiveClose, how an override meets an early close, the PUT semantics. - T-R4.16: the change count,
assignmentCount,against=previousfor version 1. - T-R4.27a: the interim steps 3 and 4.
- T-R4.32: the three contract gaps and the column thresholds.
- T-R4.35: Download.
- T-R4.46: danger tones on the compact timeline.
- DG-115 and DG-110 (user).
Generated from docs/team/r4-readiness.md. Edit that file in the repository; changes made on this page are overwritten.