Repository navigation
Classroom follow-on: Instructor-run live class, roster, and dynamic team management #312
Description
Goal
Turn the current capability-oriented Classroom foundation into the Instructor-led classroom experience expected during a live KT exercise.
The intended model is:
- Instructor chooses Start a class and names the class/exercise.
- The product gives the Instructor a simple human-facing Student join code/link.
- Students join the class with that class code and a display name. They should not need to understand or type an assignment/workspace capability.
- Newly joined Students appear in an Instructor waiting/unassigned roster even after the exercise has started.
- The Instructor creates individual/team workspaces and assigns or reassigns Students during the live class.
- Moving a Student changes which collaboration workspace their Student experience synchronizes with. The Student does not need to manually leave/rejoin with another secret.
- The Instructor can rapidly see each team/individual workspace, activity, coaching status, and progress, then open the existing read-only observer + coaching UI.
- Case Study/resource assignment can later be scoped per class/team without weakening the protected-resource authorization boundary.
Why this is a follow-on
The current backend already supports:
- class creation with separate Instructor and Student-join capabilities;
- individual/group classroom workspaces;
- Instructor-scoped workspace enumeration;
- Student membership-bound editable workspace capabilities;
- Instructor read-only observation and coaching.
However, the current Student admission flow requires both a class join capability and an assignment capability up front. The current Instructor UI also starts from an existing Instructor access capability instead of owning the complete Start Class / roster / grouping lifecycle.
That is secure as a lower-level capability foundation, but it is not the desired classroom UX.
Product requirements
Instructor start
- Add a clear Start a class flow from Instructor experience.
- Instructor enters at minimum a class title; optional exercise label/retention may follow.
- Preserve the raw Instructor capability for same-device resume, but do not ask the Instructor to invent or type it during normal class creation.
- Present a human-friendly Student join code and copy/share link/QR affordance.
- Distinguish the human join code from internal bearer capabilities.
Student join / waiting roster
- Student enters one class join code plus display name.
- Joining should create/admit a class participant without exposing class/workspace enumeration.
- A Student may initially be unassigned/waiting.
- Late joiners must appear in the live Instructor roster without restarting the class.
Team/workspace management
- Instructor can create/rename teams and individual workspaces.
- Instructor can assign unassigned Students to a team.
- Instructor can move Students between teams after work has started.
- Drag-and-drop is preferred when accessible, with keyboard/button alternatives as the canonical accessible path.
- Reassignment must be server-authoritative; client UI alone cannot redirect a Student to another workspace.
- Student clients should learn that their assignment changed and reconnect to the newly authorized workspace automatically.
- Old Student workspace authorization should be revoked or otherwise prevented from continuing to edit after a move, subject to a documented migration/transition policy.
State when moving a Student
Moving a Student between teams needs an explicit content policy. Preferred default:
- the Student begins synchronizing with the destination team's existing Intake;
- the destination team's state wins as the team artifact;
- the old team's Intake remains with the old team;
- coaching records remain keyed to the workspace they reviewed rather than being silently copied.
Do not merge two independent Intake snapshots automatically during reassignment.
Instructor operating dashboard
The live Instructor dashboard should make it easy to:
- see unassigned/late Students;
- see teams and membership;
- see online/editing/activity state;
- see coaching status / needs-improvement counts / changed-since-review signals;
- switch immediately into the existing read-only observer;
- provide field-level feedback;
- identify teams that have not started or may need help.
Resources
- Instructor can see teaching Case Studies/resources after class start.
- Design toward assigning resources at class or team/workspace scope.
- Preserve Classroom 7/8: Server-gated Case Study catalog and payload delivery #295: protected Case Study metadata/payloads remain server-gated and absent from public browser assets.
Security/invariants
- Students must still never enumerate classmates/workspaces through Student credentials.
- Human-friendly join codes must map server-side to authorization and must not become editable workspace capabilities.
- Instructor may administer only the represented class.
- Student reassignment must not grant simultaneous edit authority to old and new teams indefinitely.
- Instructor observation remains read-only with respect to Student Intake snapshots.
- Classroom credentials remain outside exported Intake state.
- Standalone remains backend-optional and unchanged.
Architecture direction
Likely requires an additive distinction between:
- class participant/admission identity,
- current workspace assignment/membership,
- per-participant editable workspace authorization.
The existing assignment capability can remain an internal/admin primitive if useful, but should not be part of the normal Student join UX once Instructor-managed assignment exists.
Consider a Student assignment-status/read endpoint or long-poll/poll response so an already connected Student can detect server-side reassignment and rotate to a newly issued workspace capability without exposing other workspaces.
Browser acceptance journeys
- Instructor starts a class and receives one Student-facing join code.
- Student joins and appears unassigned.
- Instructor creates Team A and Team B and assigns Students.
- Two Students assigned to Team A synchronize the same Intake; Team B is isolated.
- Late Student joins after work has started and can be assigned without restart.
- Instructor moves a Student A -> B; Student reconnects to B, sees B's Intake, and can no longer edit A.
- Instructor observer/coaching remains usable across all teams.
- Accessible non-drag alternative exists for every grouping action.
- Unauthorized Student workspace enumeration still fails.
Relationship to current work
- Parent program: Classroom experience program: Standalone, Student, and Instructor #288.
- Builds on Classroom 3/8: Class domain model, credentials, and workspace membership APIs #291, Classroom 4/8: Student class join, assignment, and resume experience #292, Classroom 5/8: Instructor class dashboard and read-only live workspace observer #293, Classroom 6/8: Field-level coaching feedback channel and student feedback UI #294, and Classroom 7/8: Server-gated Case Study catalog and payload delivery #295.
- Classroom 8/8: Browser E2E, accessibility, and CI protection for role/classroom journeys #296 / Add critical-path Playwright and accessibility regression suite #279 should finish the current browser-quality layer without encoding the current two-secret admission UI as the permanent product contract.
- Implement this follow-on in its own PR after the current Add Classroom browser E2E and accessibility coverage #308 browser-E2E slice is stable/merged.
Active implementation
- Draft PR: Add Instructor-run live classroom management #314 on
feature/classroom-live-management. - Base: Add Classroom browser E2E and accessibility coverage #308 merge
6c58336ac1677764641c09eadb201abcad8eeac1. - Architecture checkpoint:
0c6bf97d1939437bd63e7f3107995b811cf3a7cd. - Canonical contract:
docs/classroom-live-management.md.
Decided security/lifecycle model
- Human join code is admission-only, not workspace authority.
- Admission creates a high-entropy Student class-session capability.
- Student may remain waiting/unassigned.
- Workspace edit token is assignment-specific.
- Reassignment revokes the old edit token before destination access is issued.
- Never remap one live edit token across workspaces; this prevents an in-flight old-team PUT from being interpreted as a destination-team write.
- Destination team's current Intake wins; no automatic snapshot merge.
- Legacy two-code admission remains available during the additive migration.
Completed persistence/repository tranche
- implementation head:
df3633d008bb7e352509e15c1964b7d27ebf441f; - documentation checkpoint:
8eed407c19f9f0034b518fead649bc6dbbf8f917; - human join-code normalization + additive
student_join_code; - additive
classroom_participantswaiting/unassigned model; - independent Student class-session and assignment-specific workspace-access hashes;
- Instructor-scoped participant listing + Student-session lookup primitives;
- re-admission rotates the class session without forcing assignment;
- legacy two-code Student path remains intact;
- validation: repository quality 241 tests / 1 intentional skip, required Browser E2E 22 passed / 6 intentional skips / 0 failed, CodeQL/Dependency Review/Template Manifest Guard green.
Completed HTTP admission/status/access tranche
- implementation checkpoint:
04f95f24dd63d2ce75260034d75c9c514d07e84e; - documentation checkpoint:
6e1a023fb2e9e2a504f85b4d236856d25efc4722; - Start Class human join-code return;
- one-code Student admission into waiting/unassigned state;
- Instructor-only participant roster;
- Student own-status only;
- assignment-specific workspace access only after assignment;
- prior workspace access rotates/revokes safely;
- Student class-session capability is not collaboration edit authority;
- live workspace token works with existing Student coaching/protected-resource scope;
- validation: 244 tests / 243 pass / 0 fail / 1 intentional skip, required Browser E2E 22 passed / 6 intentional skips / 0 failed, remaining repository gates green.
Completed assign/reassign/unassign authority tranche
- implementation checkpoint:
7bfd662e2dcbe5511a4065b7b19222129485d08a; - documentation checkpoint:
27e9df7af70c21a1f02553d8241077821409c5e0; - Instructor-only assignment transitions;
- assignment revision increments only on real changes;
- old workspace edit authority is revoked before assignment mutation;
- stale presence is removed from the old workspace after revocation;
- cross-class destination assignment is rejected;
- individual workspace occupancy is enforced;
- move/unassign clears current workspace-access hash;
- stale old-team tokens cannot read/write or read coaching after reassignment;
- no Intake snapshot copy/merge occurs;
- live Student coaching/protected-resource context now requires the stored access hash to map to an active, unrevoked collaboration alias;
- validation: 246 tests / 245 pass / 0 fail / 1 intentional skip, required Browser E2E 22 passed / 6 intentional skips / 0 failed, all remaining repository gates green.
Completed Instructor live-management client tranche
- implementation checkpoint:
d3e2a397cd76fc75e62516ed63ad76231bb4812c; - documentation checkpoint:
d88a763293df3e5484c22a151fb64d9dd737a5c3; - primary Start Class flow with human Student join code;
- same-device Instructor resume;
- live Waiting/assigned Student roster;
- Team/Individual workspace creation;
- accessible assign/reassign/unassign selectors;
- live participant counts in workspace cards;
- observer/coaching navigation preserved;
- Instructor client ignores legacy assignment tokens;
- deterministic fixture + real-browser Start Class -> Waiting -> create Team -> assign -> observe -> reload/resume journey;
- validation: 248 tests / 247 pass / 0 fail / 1 intentional skip, required Browser E2E 23 passed / 7 intentional skips / 0 failed, all remaining repository gates green.
Completed Student live-class client tranche
- implementation checkpoint:
0c8692c7486ecb50c730d0757c41426b81830250; - documentation checkpoint:
738712799d46dd1c710d121c49e6be24cfb1aa6e; - normal Student path is one human class code + display name;
- legacy two-code access remains under an explicit recovery disclosure;
- stable class-session resume with assignment-specific workspace tokens kept memory-only;
- Waiting without collaboration authority;
- own-status polling only;
- safe automatic assignment, A -> B reassignment, and unassign;
- destination snapshot wins; no automatic Intake merge;
- stale old-team workspace tokens fail after move/unassign;
- desktop/mobile real-browser lifecycle coverage;
- validation: 252 tests / 251 pass / 0 fail / 1 intentional skip, required Browser E2E 25 passed / 7 intentional skips / 0 failed, all remaining repository gates green.
Completed integrated live-class acceptance tranche
- implementation checkpoint:
9315210dd15ed583cfbd3201302699d025ded3a1; - documentation checkpoint:
01c20b731c1002a54c62f28de00a82a785b9f575; - one Instructor and three live Students share one deterministic class instance using the join code actually displayed by the Instructor UI;
- late Waiting arrival, Team Alpha/Team Beta creation and assignment, same-team sync, cross-team isolation, observer/coaching, A -> B reassignment, stale-A cutoff, unassign, and stale-B cutoff are all covered in one browser journey;
- integrated fixture state is capability-isolated from existing browser specs to preserve parallel determinism;
- validation: 252 tests / 251 pass / 0 fail / 1 intentional skip, required Browser E2E 26 passed / 8 intentional skips / 0 failed, all remaining repository gates green.
Final #312 readiness review complete
- final head:
d6a2f27b95639340ad46f6e596368f064671a08f; - complete branch comparison: 79 commits ahead / 0 behind;
- no unresolved PR review/comment state;
- API, architecture, README, Security, roadmap, API agent rules, and AI onboarding now describe the implemented one-code live lifecycle rather than the legacy two-code path;
- additive rollback/compatibility remains explicit: legacy
/api/classes/join,classroom_memberships, and Standalone collaboration are retained; - final validation: 252 tests / 251 pass / 0 fail / 1 intentional skip, required Browser E2E 26 passed / 8 intentional skips / 0 failed, CI/CodeQL/Dependency Review/Template Manifest Guard all green.
Exact next action
Merge #314, close #312, then start #313 from the resulting main merge commit. The first #313 tranche is architecture/server contract only: exercise lifecycle, stage/release authorization, protected staged-content model, checkpoint/debrief semantics, late-join/reassignment rules, and server-enforced edit-freeze direction before UI work.
Activity
Add Instructor-run live classroom management (#314)
Refresh Classroom production handoff and roadmap (#323)
Close out #312 compatibility migration in live-class docs
Pre-production compatibility reset (#332)