Appearance
Exam Runtime Access Task
Agent workflow: follow README.md for Audit -> Investigate -> Code -> Test -> Fix; keep this pack's writable scope and verification commands authoritative.
Dispatch type: orchestrator
Owner: exam-service.
Goal:
Expose a native exam runtime snapshot/access-decision contract that attempt-service can consume before any public attempt-start cutover.
Legacy source evidence:
/Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/exams/**/Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/prisma/schema.prisma- student exam-start callers under
/Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/web.
Writable files:
services/exam-service/**contracts/openapi/services/exam-service.yamldocs/api/exam-service.mddocs/agents/service-tasks/exam-runtime-access.md
Orchestrator-owned files:
- Attempt-service consumer integration, gateway route tables, route promotion, and frontend/browser smoke artifacts.
Tasks:
- Done locally: add
POST /v1/exams/{id}/runtime-accessfor published exams with question snapshots by value and astartInputpayload compatible withattempt-service. - Done locally: add access-decision fields for assignment, link/password, open/closed window, login/guest policy, attempt limit, and organization scope.
- Done locally: add
exam_assignmentsread-model migration plus a verifier interface for classroom/org membership checks without cross-DB reads. - Done locally: add tests covering assigned student via verifier, link access, password failure, closed exam, body
studentIdrejection, and missing snapshots. - Done locally: block assigned-exam starts when the classroom/IAM verifier is missing, returning
ASSIGNMENT_DECISION_UNAVAILABLEwithclassroomMembershipinpendingPolicyChecks. - Done locally: add runtime-access tests for open/close window boundaries, missing access links, unassigned exams, and overdue assignments.
- Done locally: runtime-access now treats an access link with
expiresAt == evaluatedAtas inactive, matching legacyexpiresAt <= nowbehavior before any attempt-service call. - Done locally: wire production verifier clients behind
IAM_SERVICE_URL/IAM_SERVICE_BASE_URLandCLASSROOM_SERVICE_URL/CLASSROOM_SERVICE_BASE_URL. The verifier checks IAM active organization membership through the internal single-account check endpoint and checks assigned classroom membership with a student-scoped classroom-service read, without cross-service DB joins. - Done locally: attempt-service consumer hardening now enforces retake/open-attempt/access-link counts after the trusted exam-service decision, requires the trusted decision marker plus idempotency/correlation context, persists start replay keys per exam/student, and guards concurrent duplicate
IN_PROGRESSrows. - Keep public
/api/exams/:id/startlegacy until attempt-service and gateway integration tests prove the full flow.
Acceptance:
- Attempt-service receives all access policy inputs without reading exam DB.
- Question payloads are snapshots, not live question-service rows.
- Gateway route rehearsal does not bypass exam-service access decisions.
- Runtime resolver returns
data.startInput; gateway/BFF must pass only that payload to attempt-service. - Public start promotion also requires
exam-start-adapter.mdroute proof, browser/runtime smoke, and rollback evidence; service tests alone are not enough.
Verification:
GOTOOLCHAIN=go1.25.11 go test ./services/exam-service/... ./services/attempt-service/...GOTOOLCHAIN=go1.25.11 go test ./services/iam-service/... ./services/exam-service/... -count=1make test-attempt-routes- Use
docs/agents/service-tasks/exam-start-adapter.mdto add/run the adapter-specific route test before/api/exams/:examId/startpromotion.