ISSUE-007 Test Report — Student/Cohort domain models

Scope

Implemented the ISSUE-007 operational data foundation:

ERD

erDiagram
  Course ||--o{ Cohort : "contains (courseId FK)"
  Student ||--o{ Enrollment : enrolls
  Cohort ||--o{ Enrollment : contains
  Cohort ||--o{ CohortLessonVisibility : controls

  Student {
    string id PK
    string email UK
    string name
    datetime createdAt
    datetime updatedAt
  }
  Course {
    string id PK
    string key UK
    datetime createdAt
  }
  Cohort {
    string id PK
    string courseId FK
    string key UK "(courseId, key)"
    datetime createdAt
    datetime updatedAt
  }
  Enrollment {
    string id PK
    string studentId FK
    string cohortId FK
    datetime createdAt
  }
  CohortLessonVisibility {
    string id PK
    string cohortId FK
    string lessonId
    boolean visible
    datetime createdAt
    datetime updatedAt
  }

Domain API

Function Behavior
enrollStudents(emails, cohortId) Lowercases/trims emails, creates missing students, enrolls valid non-duplicates, reports invalid and already-enrolled failures
unenroll(studentId, cohortId) Deletes matching enrollment and returns whether a row was removed
setLessonVisibility(cohortId, lessonId, visible) Fetches the cohort once, loads its manifest partition, validates lsn_... in that cohort only, upserts one visibility row per (cohortId, lessonId)
resolveCohortId(courseKey, cohortKey) Resolves [course]/[cohort] keys to a Cohort.id (course lookup + composite-unique), or throws DomainError
findCohortByKeys(courseKey, cohortKey) Repository op returning { id, courseKey, key } for a (course, cohort) key pair
normalizeEmail(email) Returns lowercase/trimmed email or throws DomainError("invalid_email")
normalizeLessonId(lessonId) Returns trimmed lsn_... lesson id or throws DomainError("invalid_lesson_id")
createCohortManifestLessonRegistry(manifest) Lesson registry scoped to one cohort manifest (ISSUE-005)
createFilesystemCohortLessonRegistry(courseKey, cohortKey) Loads lib/generated/content/<courseKey>/<cohortKey>.json and builds registry
syncFromContent(index, client) Idempotently upserts Course/Cohort rows from the manifest index by key; reports orphan DB rows
maskEmail(email) Masks local part before logging or CLI output

Verification Results

Command Result Evidence
pnpm typecheck Passed tsc --noEmit exited 0
pnpm lint Passed eslint . --max-warnings=0 exited 0
pnpm test Passed 13 unit test files, 41 tests passed
pnpm manifest:build Passed 3 lessons / 1 assignmentDoc across 2 cohorts, cohortMeta emitted
pnpm prisma generate Passed Prisma Client v6.19.3 generated (Course + Cohort.key)
prettier --check (changed files) Passed All changed source/test files use Prettier code style
prisma migrate dev (DB apply) + RUN_DB_TESTS=true integration Pending Requires migrate reset of the local dev DB (phantom prior migration diverged it); blocked on explicit consent

Known Limits