Skip to content

Merge progress

The single source of truth for where the merge stands. Update it in the PR of the task (claim in the first commit, close in the last), never in a separate commit on main. Protocol: README.md. A "card" cited below is in 09-tasks.md while its task is open, and in history/09-tasks-delivered.md once it is done or dropped.

Now

  • Phase: the journal (M4) and the projects (M3) are merged, the pilot's follow-ups M3-14a…n included except M3-14g, which waits for the product owner; M3-14f dropped the secret's check (2026-10-14). M4-10…13 are dropped. The gradebook (M5-03, M5-04), M6-01…06, M6-10, M7, M8-01…03 and the cutover runbook (M8-05, 10-cutover-runbook.md) are merged; M8-04 is dropped. The breadcrumb app-wide is merged (#576). The import runs from the production image (#655, the runbook's O6). The projects and the import go live together (D26) at the cutover (D20).
  • Next actions: the cutover is done (M8-07, Sunday 2026-10-11 07:07–07:50 UTC, rehearsed on staging the day before: M8-06): classroom redirects to Quiz, its data is imported, its App no longer acts. The observation period D (runbook §4) was clean: everything imported, the 19 MI-2026 roster lines in conflict resolved by hand. The product owner passed the point of no return on 2026-10-14, and E / M9-01 is done (2026-10-15): the redirect is a 308, the final copy of classroom's data is on the owner's workstation, and classroom's stack, CI credentials, GHCR package, SWITCH resource and App are gone (runbook §5, the M9-01 row below). M6-07's code is merged; proof B is done for evaluations (2026-10-10, Config Key enforced in production) and waits for the project flow (a real SEB, the owner, on staging); M6-08 and M6-09 are to do. Quiz's production App exists (registered by hand); staging's, heig-quiz-staging, exists since 2026-10-06 (M2-06). Teachers create their Quiz classrooms; the merge then writes the correspondence table (D22).
  • Classroom sync point — closed 2026-10-11, final since 2026-10-14: classroom's last commit in production was f572758 (images.txt, runbook §1.7), its CI was disabled and its data was imported at C3 from the dump of 07:08 UTC; nothing is forwarded any more, and since the point of no return (M9-01, 2026-10-14) nothing will be: there is no way back to classroom, whose repository is archived at the runbook's §5 step 10 and stays readable as evidence. The last sync point was a676c8c (classroom origin/main, 2026-10-06). A classroom commit after it touching a ported file had to be forwarded (see strategy §1.2, principle 6), checked with git -C ~/heig-classroom fetch && git -C ~/heig-classroom log --oneline a676c8c..origin/main. Moved from ab98cc0 with nothing to forward: f572758 (#48/#50, delete an assignment nobody accepted) — Quiz already deletes a project's rows in any state and nothing on GitHub (D19, F-PROJ-16); a676c8c (#46/#51, notification audiences and the per-classroom "Notify me about students" preference) — Quiz has no per-student-activity staff notification (F-NOTIF-11/13; student-activity notices are client-side on the open page, F-PROJ-21) and its course: SSE topics go to staff only (modules/realtime/routes.ts).
  • Quiz base of the analysis: a7dfa26.

Status values: todo · in progress · review (PR open, ready) · done · blocked (say on what) · dropped.

Plan

ID Task Status Branch PR Handoff
PLAN Merge plan: ADR-035 (proposed), docs/merge/ done plan/merge-classroom #268 Five read-only analyses (data, GitHub, journal+web, codespace+infra, spec fit) condensed into these files

M0 — Decisions and paper

ID Task Status Depends Branch PR Handoff
M0-01 Settle blocking decisions done — Every merge decision D01–D29 settled between 2026-09-28 and 2026-10-01 (D09 and D21 in #466), with spec 06 nos. 45–49.
M0-02 Measure production (read-only) done PO go plan/merge-classroom #268 measures-2026-09-28.md records production read-only: edu-ID subs differ pairwise, the workspace is unused by real classes, 3 classes merge into existing Quiz classrooms, 0 pending staff.
M0-03 ADRs (035 accepted, imports, amendments) done M0-01 merge/M0-03-adrs #365 ADR-035 accepted, the classroom ADRs imported as 011, 047, 048 and 049, and the affected Quiz ADRs amended.
M0-04 Spec amendments done M0-01 merge/M0-04-spec-journal (journal track), merge/M0-04-spec-projects #367, #461 The journal track (#367) and the projects track (#461) written into the specification.
M0-05 CLAUDE.md, AGENTS.md, reviewer prompts done M0-03 merge/M0-05-claude-md #369 CLAUDE.md invariants 4, 6, 11–12, 14 and 15 carry the merge's rules, and invariant-reviewer checks them.

M1 — Foundations

ID Task Status Depends Branch PR Handoff
M1-01 Pure domain into packages/domain done M0-03 merge/M1-01-domain #370 @quiz/domain gained the classroom's pure rules (ciScore, finalScore, repoName, groupRepo, reviewDispatch, studentIgnore, zone), imported rather than copied.
M1-02 GitHub adapters, config, image done M0-03 merge/M1-02-github-adapters #372 The GitHub App client lives in apps/api/src/github/, with token redaction, the config.ts refusals and tokens handed to git through the environment only.
M1-03 ActivityKind, ActivitySummary union done M0-03 merge/M1-03-activity-kind #373 ActivitySummary is a union on kind, and ActivityKind over KINDS (modules/activity/) is the point each activity kind fills (migration 0037).
M1-04 Missing primitives, long-form styles done M0-05 merge/M1-04-primitives #374 The primitives GithubIcon, OrgAvatar, Progress and Initials in ./ui, and the long-form md-doc style (DESIGN.md › Long-form reading).
M1-05 Web routes and mock skeleton done M1-03 merge/M1-05-web-routes #375 The classroom routes and their mocks, placed behind a route flag (CLASSROOM_PAGES, since removed) until the task that ships each screen.
M1-06 Import script skeleton, identity, login adoption done D04, D08 merge/M1-06-import-identity #464 apps/api/scripts/import-classroom.ts imports people, accounts, GitHub links and rosters into existing Quiz classrooms (migration 0052, login adoption ADR-061), and M8-01 extends it: card M1-06, "As delivered".

M2 — GitHub substrate

ID Task Status Depends Branch PR Handoff
M2-01 github schema and contracts done M1-02, D02, M0-04, M0-05 merge/M2-01-github-schema #402 The GitHub tables and contracts (migration 0048_github): card M2-01, "As delivered".
M2-02 Installations, org link, healing done M2-01 merge/M2-02-github-orgs #404 modules/github connects a classroom to an organization (/classrooms/:id/github), recordInstallation its one writer: card M2-02, "As delivered".
M2-03 GitHub account linking done M2-01 merge/M2-03-github-link #403 The account link to GitHub (auth/githubLink.ts, /app/api/me/github): card M2-03, "As delivered".
M2-04 Webhook intake, registry, deliveries done M2-02 merge/M2-04-webhooks #407 POST /webhooks/github verifies the HMAC, records the delivery and dispatches through onEvent/onReceipt, with a scheduled reconciliation and purge: card M2-04, "As delivered".
M2-05 Periodic tasks done D10 merge/M2-05-scheduled-tasks #392 scheduled_tasks (module system, migration 0042) and Admin › Scheduled tasks; a new periodic task adds its key to SCHEDULED_TASK_KEYS and the catalog.
M2-06 Quiz's Apps (production, staging), staging safety done M2-01, D23 merge/M2-06-github-apps, merge/M2-06-close #566 The App's settings in github/manifest.ts, pnpm github:app, the staging scrub and new-server.md; the staging App heig-quiz-staging exists since 2026-10-06 and is never installed where production holds real work: card M2-06, "As delivered".
M2-07 Web: classroom Settings tab, GitHub section, link card done M2-02, M2-03, M1-04, M1-05, D24 merge/M2-07-classroom-settings #408 The classroom Settings page and apps/web/src/github/ (connection sheet, account card): card M2-07, "As delivered".
M2-08 Student link from Settings, login on the roster done M2-03, M2-07 student-github-link #452 A claimed student of a connected classroom may link GitHub, and the roster shows the login: card M2-08, "As delivered".

M3 — Projects

ID Task Status Depends Branch PR Handoff
M3-01 project schema and contracts done M2-01, M1-01, D05 merge/M3-01-project-schema #468 The project tables (migration 0054_project), contracts and projectGrade: card M3-01, "As delivered".
M3-02 Project lifecycle done M3-01, M2-02, D19 merge/M3-02-project-lifecycle #471 modules/project/ (lifecycle, views, sources, routes; migration 0056, ADR-062): card M3-02, "As delivered".
M3-03 Acceptance and provisioning done M3-02, M2-03 merge/M3-03-project-accept #472 The student's Accept provisions an individual repository (modules/project/accept.ts): card M3-03, "As delivered".
M3-04 Ingestion and grading pipeline done M2-04, M3-03 merge/M3-04-project-ingest #477 The project webhooks, run ingestion, protection and restores (migration 0057_project_ingest): card M3-04, "As delivered".
M3-05a Deadline, freeze, reopen, per-repository deadlines done M3-04, D13 merge/M3-05a-project-deadline #481 Project deadlines, freezes and locks (deadline.ts, jobs.ts, migration 0059, ADR-064): card M3-05a, "As delivered".
M3-05b Final review dispatch, review checkpoints done M3-05a merge/M3-05b-project-review #487 The final review dispatch and the review checkpoints (review.ts, checkpoints.ts, migration 0060_project_review): card M3-05b, "As delivered".
M3-06 Reconciliation of grades and repos done M3-04, M2-05 merge/M3-06-reconciliation #515 The scheduled reconciliation of grades and repositories (reconcile.ts, migration 0070): card M3-06, "As delivered".
M3-06b The three restored-heads edges of protected files done M3-04 merge/M3-06b-restored-heads #519 The restored-heads edge cases (migration 0073, ADR-062 addendum 6): card M3-06, "M3-06b — As delivered".
M3-07 Sync of the source repository done M2-04, M3-02, D12 merge/M3-07-source-sync #517 The sync of the source repository, one pull request per branch (sync.ts, migration 0072, ADR-073), which needs the production App subscribed to pull_request: card M3-07, "As delivered".
M3-08a Teacher views: project page, runs, live state done M3-04, M3-05a merge/M3-08a-project-views #485 The staff project detail (GET /app/api/projects/:id, ProjectDetail) and run list: card M3-08a, "As delivered".
M3-08b Teacher score, release, invitation resend, protection re-enable done M3-08a merge/M3-08b-project-release #494 The staff writes on a project (score override, release, protection re-enabled, invitation resent; migration 0061): card M3-08b, "As delivered".
M3-09a Student side: the project's student view, the cards, the student's resend done M3-04, M3-08b, D18 merge/M3-09a-student-project-view #504 The project's student view, through the one exit modules/project/studentView.ts (N-SEC-20), and the student activity cards: card M3-09a, "As delivered".
M3-09b Notifications of projects done M3-09a, M3-05a, M3-05b, M3-08b merge/M3-09b-project-notifications #512 The seven project notification kinds of F-NOTIF-13 (modules/project/notify.ts, migration 0068): card M3-09b, "As delivered".
M3-09c Real-time notices of projects (F-PROJ-21) done M3-09a, M3-12a merge/M3-09c-project-notices #516 The client-side notices of the project pages (useNoticeToasts, F-PROJ-21): card M3-09c, "As delivered".
M3-10 Web: projects in Activities, New ▾ done M3-01, M1-05 merge/M3-10-web-projects #470 "New ▾" in the classroom (Evaluation, Project) and the projects listed under the evaluations: card M3-10, "As delivered".
M3-11 Web: new project form done M3-02, M2-07 merge/M3-11-project-form #473 The New project page (project/NewProjectPage.tsx): card M3-11, "As delivered".
M3-12a Web: project page (reads, lifecycle, deadline, checkpoints) done M3-08a merge/M3-12a-project-page #495 The staff project page (project/ProjectPage.tsx), which put projects live in production: card M3-12a, "As delivered".
M3-12b Web: per-repository writes, review state done M3-12a, M3-08b merge/M3-12bc-project-writes #506 The teacher's score form, Resend and Re-enable in a repository's sheet, and the final review's state: card M3-12b, "As delivered".
M3-12c Web: the release done M3-12a, M3-08b merge/M3-12bc-project-writes #506 Release scores as the project page's primary action: card M3-12c, "As delivered".
M3-13 Web: student ProjectRow and the student's project page done M3-09a, M2-07 merge/M3-13-student-project-row #508 The student's project row and project page (student/ProjectRow.tsx, student/StudentProjectPage.tsx): card M3-13, "As delivered".
M3-14 Pilot and load test done M3-01…13, M2-06 merge/M3-14-pilot-findings The product owner walks the pilot in production on the test organization heig-quiz-classroom (first walk 2026-10-06), its findings tracked as M3-14a…n, with no separate load test: card M3-14, "Findings as tasks".
M3-14a Pilot: projects table — repository links, time left; a draft shows no provisional date done M3-14 merge/M3-14a-projects-table #561 Findings 6 and 7, repository links and time left on the projects table: card M3-14.
M3-14b Pilot: the App's install as a same-tab round trip; the Education link of the Free-plan check done M3-14 merge/M3-14b-github-connect-flow #560 Findings 1 and 2, the App installed in a same-tab round trip, which needs the App's Setup URL https://<host>/setup/github/installed with "Redirect on update" ticked: card M3-14.
M3-14c Pilot: a staff seat accepts a project (the teacher's test repository) done M3-14, ADR-077 merge/M3-14c-staff-test-repo #562 Finding 8, a staff seat accepts an individual project as the teacher's test repository (ADR-077), with follow-ups M3-14g and the M8-01 count: card M3-14.
M3-14d Pilot: the project_published notification asks a student without a GitHub link to link it done M3-14 merge/M3-14d-publish-notice #565 Finding 4, the notification's text alone asks a student with no linked account to link it, no redirect nor banner: card M3-14.
M3-14e Pilot: New project in a sheet like New evaluation's dialog dropped — Finding 5, won't do (product owner, 2026-10-06): New project stays a page. DESIGN.md keeps a centered dialog to three fields and a scrolling dialog to reading; the project fixes its source, branches and strategy at Create and builds for seconds; M3-11 decided one page (2026-10-02): card M3-14
M3-14f Drop the ANTHROPIC_API_KEY organization-secret check done the final review moved to Quiz's own LLM drop-llm-secret-check #879 Finding 3; product owner, 2026-10-14: removed entirely, Quiz reviews with its own LLM access; the App's organization_secrets permission is to be removed on GitHub by its owner: card M3-14f, "As delivered".
M3-14g Leaving the course staff ends one's staff seats todo M3-14c ADR-077 Q7 (product owner, 2026-10-06: keep as is for now, a follow-up): removing a member from a course's staff (ADR-068) leaves their staff seats in its classrooms, and with M3-14c their test repositories' grants. To decide: remove the seats (and revoke) with the staff seat, or keep them: card M3-14
M3-14h Pilot: a project's two repositories as links on its row, no menu done M3-14a merge/M3-14h-pilot-cards #567 Finding 9, the source and distribution repository links on every list of projects: card M3-14.
M3-14i Pilot: the student's project card says the state of their work done M3-14 merge/M3-14h-pilot-cards #567 Finding 10, the student's card shows the short sha, date, commit count, CI status and indicative score (F-PROJ-04 amended, migration 0077): card M3-14.
M3-14j Pilot: the staff page with only the teacher's test repository done M3-14c merge/M3-14h-pilot-cards #567 Findings 11 and 12 were not bugs, and a regression test was added: card M3-14.
M3-14k Pilot: the protection ruleset applied later (a plan moved from Free to Team) done M3-14 merge/M3-14k-protection-retry #571 Finding 17, the daily reconcile.repos applies a missing protection ruleset before the effective deadline: card M3-14.
M3-14l Pilot: the student's activity card and project page redesigned done M3-14i merge/M3-14l-student-card-page #573 Findings 13 and 14, the student's card and project page redesigned with MetaItem, MetaLine, IconTip and Breadcrumb in ui/, the app-wide breadcrumb (finding 15) following in #576: card M3-14.
M3-14m Pilot: the staff page counts the student's commits done M3-14i merge/M3-14m-staff-commit-count #570 The staff row counts the student's commits through project/commits.ts, GitHub's total only in the tooltip.
M3-14n Pilot: a negative CI score counts 0, flagged to the staff done M3-14 merge/M3-14n-negative-score #572 Finding 18, a negative CI score counts 0 and is flagged to the staff (migration 0078, F-PROJ-10 amended): card M3-14.
M3-15a Groups: sets and a project's copy (API, database only) done M3-02 merge/M3-15a-group-sets #507 Classroom group sets replace groups per project (ADR-070, migration 0064_group_sets, modules/group/): card M3-15a, "As delivered".
M3-15b-1 Groups: group repositories at Accept, the invited accounts, synchronous revocations done M3-15a, M3-03 merge/M3-15b1-group-repos #510 A group project's Accept provisions one repository per group and invites its members, with access revoked on roster changes (migration 0067): card M3-15b-1, "As delivered".
M3-15b-2a Groups: per-group stop, the group.sync job, needs_confirmation, access to revoke done M3-15b-1 merge/M3-15b2a-group-sync #513 A group move that touches a repository is confirmed, then applied by the group.sync job (migration 0069_group_sync): card M3-15b-2a, "As delivered".
M3-15b-2b Groups: Resync with the set and the drift done M3-15b-2a merge/M3-15b2b-group-resync #521 A project's groups resync (POST /app/api/projects/:id/groups/resync, migration 0074): card M3-15b-2b, "As delivered".
M3-16a Groups (web): the Groups tab, a set's page, the project's set done M3-15a, M3-12 merge/M3-16a-groups-web #511 The staff Groups tab and group set page (group/): card M3-16a, "As delivered".
M3-16b Groups (web): rows per group, drift, Resync, confirmations done M3-15b-2b, M3-16a, M3-17 merge/M3-16b-groups-web #524 The consequences dialog of a group move and the project page's rows per group: card M3-16b, "As delivered".
M3-17 Groups formed by the students (ADR-070 lot 2) done M3-15a, M3-16, M3-09 merge/M3-17-student-groups #518 Students form their own groups while the staff keep a set open (F-PROJ-22): card M3-17, "As delivered".

M4 — Journal

ID Task Status Depends Branch PR Handoff
M4-01 packages/docrender, schema, contracts done M1-01, D03, D14, D15 merge/M4-01-docrender #371 @quiz/docrender (renderPage, navigation) and the journal tables and read contracts (migration 0038_journal).
M4-02 Read side and ingestion done M4-01, M2-02, M2-04 merge/M4-02-journal-read #414 modules/journal: the read routes on readableClassroom, the student exit studentView.ts and the ingestion: card M4-02, "As delivered".
M4-03 Writes done M4-02, M2-03 merge/M4-03-journal-writes #415 The journal's writes (modules/journal/writes.ts) and their nine journal.* audits: card M4-03, "As delivered".
M4-04 Web: reader done M4-02, M1-04, M1-05 merge/M4-04-journal-reader #378 The journal reader (apps/web/src/journal/, JournalReader).
M4-05 Web: Journal section of Settings, teacher tab done M4-03, M2-07, D24 merge/M4-05-journal-settings #416 The journal section of the classroom Settings and the teacher's Journal tab: card M4-05, "As delivered".
M4-06 Web: WYSIWYG editor done M4-05, D25 merge/M4-06-journal-editor #417 The journal editor, opened by Edit in the reader: card M4-06, "As delivered".
M4-07 API: journal modes, schema, GitHub mode read-only done M4-03, D29 journal-mode-schema #433 The journal's two modes, in Quiz or in a GitHub repository (migration 0050_journal_modes, ADR-057).
M4-08 API: the Quiz-mode backend done M4-07 journal-quiz-backend #438 The Quiz-mode journal backend: writes, revisions, restore and append-only assets (modules/journal/quiz.ts, rendering.ts).
M4-09 Web: mode choice, standard editor, GitHub mode read-only done M4-08, M4-06 journal-modes-web #441 The Quiz-mode journal on the web: the mode in Settings, the History and Deleted pages sheets, the standard editor.
M4-10 Rename, reorder, nest (Quiz mode) dropped M4-09 Not built (product owner, 2026-10-08): the journal as shipped by M4-07…09 is enough; implement on demand
M4-11 Move to GitHub dropped M4-10, M2-03 Not built (product owner, 2026-10-08): the journal as shipped by M4-07…09 is enough; implement on demand
M4-12 Bring back into Quiz dropped M4-08 Not built (product owner, 2026-10-08): the journal as shipped by M4-07…09 is enough; implement on demand
M4-13 Copy a journal from another classroom (later) dropped M4-08 Not built (product owner, 2026-10-08): the journal as shipped by M4-07…09 is enough; implement on demand

M5 — Student classroom page and gradebook

ID Task Status Depends Branch PR Handoff
M5-01 API: the student's classroom done M1-03 merge/M5-01-student-classroom-api #377 The student classroom API and readableClassroom in guards.ts (rule classroomPayload).
M5-02 Web: student Courses route and classroom page done M5-01, D07 merge/M5-02-student-classroom-page #380 The student's Courses route and classroom page (student/StudentClassroom.tsx, student/StudentCourses.tsx).
M5-03 Gradebook module (split: M5-03a domain + API, M5-03b CSV export) done M3-08a, M3-08b, D06 merge/M5-03a-gradebook (M5-03a), merge/M5-04-grades-web (M5-03b) #531 (M5-03a), #537 (M5-03b) The gradebook (migration 0075_gradebook, ADR-074) and its CSV export: card M5-03, "As delivered".
M5-04 Web: Grades tabs done M5-03 merge/M5-04-grades-web #537 The classroom's Grades tab for both roles and the student's global /grades page: card M5-04, "As delivered".

M6 — Online workspace and SEB

In the critical path only if D09 finds online assignments in production.

ID Task Status Depends Branch PR Handoff
M6-01 HS256, codespace contracts done D09 merge/M6-01-codespace-contracts #527 HS256 signing in packages/domain and the codespace contracts: card M6-01, "As delivered".
M6-02 packages/seb done D21 merge/M6-02-packages-seb #580 @quiz/seb holds the SEB configuration rules, and Quiz's SEB launch moved onto it: card M6-02, "As delivered".
M6-03 Import apps/codespace done M6-01 merge/M6-03-import-codespace #582 apps/codespace imported as @quiz/codespace from classroom a676c8c: card M6-03, "As delivered".
M6-04 Codespace CI/CD done M6-03 merge/M6-04-codespace-deploy #587 The codespace CI/CD (an image per sha, prod and staging instances on the engine VM), the VM switch applied on 2026-10-07 with DNS code-dev, the staging key, Quiz's env and the first deploys then pending: card M6-04, "As delivered".
M6-05 Engine VM capacity, hygiene, seccomp done D09 merge/M6-05-seccomp, merge/M6-05-slices-backup, merge/M6-05-host-nft #602 (part 1), #606 (part 2), #613 (part 3) Seccomp (#602), slices and backup A (#606) and the host nftables (#613), rolled out and accepted on 2026-10-09: card M6-05.
M6-06 Quiz codespace module done M6-03, M3-02 merge/M6-06-codespace-module #585 modules/codespace (work mode, grants, sync, start route; migration 0079): card M6-06, "As delivered".
M6-07 SEB for projects, proof B in progress M6-02, M6-06 merge/M6-07-seb-projects #590 Code merged; proof B (a real SEB, the owner, on staging) pending. Migrations 0080_seb_projects (sessions/launch_tickets.project_id) and the portal's 0002_platform_seb; Quiz builds every .seb (GET /app/api/projects/:id/seb, portal host + SEB_EXTRA_ALLOWED_HOSTS), a seb session confined to one activity (activities route config, PROJECT_SEB, sweep in seb.db.test.ts), launch token with seb.configKey, portal /launch checks it, BEKs optional on the portal, none sent by Quiz until proof B step 7, online_seb synced; portal seb/ on @quiz/seb; proof B pending (06 §6.3, the owner): card M6-07, "As delivered"
M6-08 Freeze and collect contract on the portal (ADR-075) todo M6-03, M6-05
M6-09 qt-workspace type and Quiz side (ADR-075) todo M6-06, M6-08 Kiosk use waits for proof B (M6-07)
M6-10 Git relay through Quiz-issued scoped tokens (ADR-078) done M6-04, M6-06 merge/M6-10-git-relay #594 The codespace git relay through installation tokens issued by Quiz (migration 0082, invariant 15 amended), its staging checks pending: card M6-10, "As delivered".

M7 — Finishing

ID Task Status Depends Branch PR Handoff
M7-01 Palette, help, tours done screens merge/M7-c-palette-tours #534 Palette entries and tours for projects, nudges and group or journal tours deferred.
M7-02 User guide done screens merge/M7-a-teacher-guide, merge/M7-b-student-guide #530, #528 The teacher (#530) and student (#528) guides for GitHub, projects, groups and the journal.

M8 — Migration and cutover

ID Task Status Depends Branch PR Handoff
M8-01 Import script complete done schema tasks, D11 merge/M8-01a-import-frame (a of a, b, c, d); merge/M8-01d-import-journals; merge/M8-01b-import-projects #535 (a), #538 (d), #539 (b), #550 (c) The classroom import (frame, journals, projects, groups), whose dry run on a production dump is M8-06's rehearsal: card M8-01, "As delivered (a)" to "(d)".
M8-02 Legacy URL resolver done M8-01, M3-12, M4-04 merge/M8-02-legacy-urls #547 GET /legacy/classroom/* resolves the classroom's old URLs: card M8-02, "As delivered".
M8-03 Caddy fragments done — merge/M8-03-caddy-fragments #598 infra/caddy/ maintenance and redirect fragments with their curl matrix: card M8-03, "As delivered".
M8-04 Codespace identity remap dropped M6 in scope Product owner, 2026-10-09: classroom's portal never served a real class, and it has been stopped and disabled since M6-04 (SQLite and volumes archived in /root/classroom-codespace on the engine VM); Quiz's portal started empty. Nothing to remap; runbook step C4
M8-05 Cutover runbook done M8-01…03 merge/M8-05-cutover-runbook #653 10-cutover-runbook.md replaces 06 §6.5 B–E and §6.7, and its finding O6 (the production image could not run the import) was fixed by #655: card M8-05, "As delivered".
M8-06 Rehearsal on staging done M8-05, D22, #655 deployed merge/M8-06-rehearsal Rehearsed 2026-10-10 by the product owner (srvstg) with the agent (srv): go. Findings folded into the runbook (§0 memory override and ROSTER, O8, §2 target times, §7 expectations): see the rehearsal log below
M8-07 Cutover done M8-06 go, D20, runbook O1–O5, O8 merge/M8-06-rehearsal Done 2026-10-11 (Sunday, short notice, W=12, O3 one import, O4 staff repositories imported, O8 explicit options). Times (UTC): §1.4 re-run 07:02 clean; C1 07:06 fragment, CI disabled, app stopped 07:07:48 (exit 137, no task left running); C2 07:08:09–07:08:16 (dumps 6.4 MB and 7.0 MB, scratch restored, runs 0); C3 07:18:01–07:18:19, exit 0, applied, pre-flight all ok, 0 red lines, 4 of 4 imported journals ok, runs 1; C5 07:19 health ok; C6 07:22:47 redirect fragment, 31 matrix rows ok, a real old link lands on Prog-A; C7 repos 07:25–07:28 (287 live repositories, 2 re-invited, 0 heads moved), grades 07:34–07:38 (0 runs to catch up), deliveries 07:39 (0 to replay); C8 07:50, all nine rows green (test push webhook processed in 1.5 s; hgc-protect has an empty bypass list on the imported repositories, classroom's App was not in it either, nothing to add). Freeze C1→C8 43 min. Known: 19 MI-2026 roster lines flagged for the teacher (O8); off-site backup stale (last 2026-10-09); classroom's postgres and backup containers stay up until E. Production deploys unfrozen 07:55 (image af62dde5, #751); "done" message sent by the owner. Next: D (runbook §4), then E / M9-01 from T0 + 7 days

M9 — Decommission

ID Task Status Depends Branch PR Handoff
M9-01 Point of no return, decommission, close #143 done M8-07 + observation merge/M9-01-decommission, merge/M9-01-done #876 Done 2026-10-15 (point of no return 2026-10-14, product owner: D clean, everything imported, the 19 MI-2026 conflict lines resolved by hand). #876: the resolver redirect is a 308 (legacyRule's own 302s stay), the docs describe classroom's stack as gone, push.sh no longer lists /srv/heig-classroom/backups. Step 2 deviated (product owner): the final copy is classroom's last nightly dump hgc-2026-10-14.dump (08:33 UTC, the app stopped since C1), copied by scp to the owner's workstation, sha256 fde6b3a3217f59d2f0ddf0c880ba9120f6d245b422eb98c5429ab79b5bcd7242; the off-site borg archives keep classroom's dumps for their retention (~3 months). As run by the owner (runbook §5): 2026-10-15 the fragment installed and check-classroom-redirects.sh green (308 rows); hgc_cutover dropped and /srv/quiz/merge deleted after a local copy; h down -v, /srv/heig-classroom removed, its deploy.sh key line removed from srv's authorized_keys, its image removed; the GHCR package deleted; the repository was already archived, so its DEPLOY_SSH_KEY secret and DEPLOY_USER variable stay, inert (no workflow runs, the key opens nothing); SWITCH: deletion of the separate resource « HEIG Classroom » (hes-so_oidc_client_95037) requested, Quiz's two resources and the shared JWK kept; engine VM: /root/classroom-codespace deleted, no /etc/codespace/github-app.pem left; hgc-prod deleted. #143 commented.

L — After the merge

Project grading by criteria on the platform (ADR-106); the pilot (L-02g) comes before the student table (L-02f).

ID Task Status Depends Branch PR Handoff
L-02a Criteria snapshot: parser, totals, project_criteria, opt-in criteria mode done ADR-106 project-criteria-mode #793 Parser packages/domain/src/criteriaParse.ts, snapshot and mode switch (modules/project/criteria.ts, migration 0109); the checkpoint-name check at creation and the testsCriterion pre-fill rule go to L-02d/L-02c.
L-02b Runner project action, lab-c image, project.evidence done L-02a project-evidence-run #797 (runner), #799 (API) Runner: #797. API: modules/project/evidence.ts (runEvidence, migration 0110); the evidence job writes the auto rows through writeCriterionGrades (criterionGrades.ts), which L-02c's review job reuses for the llm rows (ADR-106 §4 amended); nothing enqueues the job yet, the milestone path is L-02d's.
L-02c Final pass, proposals, regrade done L-02a, L-02b project-llm-pass #806, #820 (identity criterion) Purpose project (exempt from the user share), project.review (modules/project/reviewPass.ts, masked by projectMaskTerms), the final pass claimed in grade_dispatches at the freeze (jobs.ts), Regrade and the staff's criteria table (regrade.ts), criteriaTable in @quiz/domain; no migration. Follow-up (the card's commit-authors check): the project setting identityCriterion, graded by the evidence job from the handed-out branch's commits read through the App (project_evidence.commits, migration 0114; bots and the handed-out commit excluded) by commitIdentityPoints, never sent to the model, its rationale masking the e-mail; the settings' select on the web.
L-02d Milestone locks done L-02c, L-02e project-milestone-locks #814 modules/project/milestone.ts: the ticker claims a criteria checkpoint's pass in grade_dispatches and enqueues project.evidence (no grade-milestone dispatch), the pass grades the tagged criteria at the last push before the date, rows written with locked_by_checkpoint_id/locked_at (migration 0113, FK deferred by hand); heldCriteria holds locked rows, a superseding row inherits the lock, a deadline moved later supersedes the unlocked machine rows and their validations (before the release); checkpoint_untagged at creation, a fired milestone undeletable (checkpoint_dispatched, the deferred FK behind it); locked in criteriaTable, lock icon on the grading screen. The Labo-Intersection CI checkpoint is an auto project: not converted.
L-02e Teacher grading screen, release gate done L-02c project-grading-screen #811 modules/project/criteriaGrading.ts (GET …/grading, a teacher's points as a manual row still proposed, Validate per repository and in bulk through writeCriterionGrades, 409 criteria_incomplete), the release refused 409 not_validated (grades.ts), the criteria final-score source (resolveFinalScore, criteriaScore, repoValidation in @quiz/domain), the primary action grade; web /projects/:id/grading (project/grading/), mock ?pjcriteria=1; no migration.
L-02f Student criteria table done L-02c, L-02g student-criteria-table #815 studentView.ts (the one exit): criteria (StudentCriteriaRow[]: the student audience of criteriaTable over the seat's own repository; final once every row is validated), null off the criteria mode; N-SEC-20 search test extended (second student, superseded and milestone rationales, reason, source, pass and checkpoint ids, another mode); web student/ProjectCriteria.tsx under the score (row cards on a phone), one RationaleFold shared with the grading table, mock ?projects=1&pjcriteria=1; no migration. Ahead of L-02g by the orchestrator's order.
L-02g Labo 00 pilot todo L-02c, L-02e

Rehearsal log

Date Dump date Duration Parity report Go / no-go Notes
2026-10-10 both dumps 2026-10-10 17:37 UTC (classroom live, 6.5 MB; Quiz 7 MB) C2 (refresh, scratch database, restore) 17 s; dry run 18 s; C3 --apply --final --window-hours 12 --assistants staff --missing-students enroll 17 s, exit 3 after the commit; idempotence nothing to do; resolver and C8 rows 1, 4, 7 walked with Super Powers, done 19:10 UTC. C1→C8 wall clock 1 h 33, of which the import steps under 1 min and the rest the two findings below identity 86 by swiss_edu_id, 3 by address, 38 new, 0 ambiguous; parity equal on every table (528 repositories across 34 projects, 170 frozen grades, 902 push receipts, 7 groups, 12 members, 153 enrollments); red lines: the two journals (Prog-C, VisIndus) refused forbidden by staging's App, expected (§7); the two journals Quiz already had kept and ok go (1) compose run inherits staging's 256 MB cap: first import attempt exit 139, heap out of memory; fixed with the §0 override. (2) Staging's edu-ID client has its own sector, so the owner's login created a second account without seats: resolver 404 and empty course list until Super Powers; fix requested from SWITCH (same sector_identifier_uri). Same-day production dry run (T-1): clean under the same options, deadlines ok with W=12. Personal-data copies deleted the same day.