Skip to content

Attempt Public Surfaces 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: attempt-service.

Goal:

Prepare public attempt list/detail/start/save/submit/result surfaces without weakening exam assignment/access policy.

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/teacher attempt callers under /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/web.

Writable files:

  • services/attempt-service/**
  • contracts/openapi/services/attempt-service.yaml
  • docs/api/attempt-service.md
  • docs/agents/service-tasks/attempt-public-surfaces.md

Orchestrator-owned files:

  • Gateway route tables, exam runtime cross-service contracts, frontend/browser smoke artifacts, and default route promotion.

Tasks:

  • Keep student attempt list parity green: GET /v1/student/attempts backs non-default GET /api/student/attempts route rehearsal with lightweight summaries, newest-first ordering, student scoping, and score redaction.
  • Done at usecase layer: access-policy tests cover own-student, other-student denial, parent denial until a relationship adapter exists, teacher/admin internal reads, event reads, result reads, student-owner-only event writes, and unauthenticated denial.
  • Done at HTTP layer: attempt detail denies missing actor headers, other students, and parents while allowing owner-student and internal teacher/admin reads. Attempt event writes deny missing actor headers, other students, parents, teachers, and admins.
  • Done at usecase layer: result visibility tests cover hidden scores, submitted IMMEDIATE, hidden/released MANUAL, hidden/opened/released AFTER_CLOSE, and in-progress nil hidden reason.
  • Done at usecase layer: timeout result visibility is covered with a retake workflow. A first TIMEOUT attempt under MANUAL stays score-redacted for the student while teacher reads remain visible; a second retake attempt after resultsReleasedAt exposes the timeout score to the student.
  • Done at service layer: teacher detail/events/result reads now require copied exam creator or managed-classroom teacher scope from the trusted start snapshot.
  • Done at orchestrator layer: named attempt route coverage plus opt-in live and browser smoke targets now exist. make test-attempt-routes keeps the default table legacy and validates the non-default exam_start_adapter route table. make test-attempt-live can exercise /v1/routes, GET /api/student/attempts, POST /api/exams/:examId/start, GET /api/attempts/:attemptId, GET /api/attempts/:attemptId/events, and GET /api/attempts/:attemptId/result against a running gateway with disposable fixtures; answer/event/submit writes require explicit request body or submit confirmation. make test-attempt-browser runs the same gateway header checks from a Playwright browser page context and writes artifacts under output/playwright/attempt-browser-smoke-*.
  • Remaining: run live gateway and browser proof with real disposable fixtures before default promotion.
  • Integrate only after exam-runtime-access.md is complete.
  • For start promotion, the public adapter must call exam-service POST /v1/exams/{id}/runtime-access and forward data.startInput to attempt-service. Do not route POST /api/exams/:examId/start directly to attempt-service.

Acceptance:

  • Start requires hydrated exam runtime snapshot/access decision.
  • Attempt snapshots remain independent of later question edits.
  • Result reads preserve legacy redaction rules.
  • Public list/detail/start/save/submit/result promotion requires named route tests, browser/runtime proof for the changed student/teacher path, and rollback evidence. Start promotion must use exam-start-adapter.md.

Verification:

  • GOTOOLCHAIN=go1.25.11 go test ./services/attempt-service/...
  • make test-attempt-routes
  • ATTEMPT_LIVE_SELF_TEST=1 bash scripts/test/attempt-live-smoke.sh
  • ATTEMPT_LIVE_CONFIRM=attempt-native ATTEMPT_EXAM_ID=<published-exam-id> ATTEMPT_AUTHORIZATION='Bearer <student-token>' ATTEMPT_ORGANIZATION_ID=<org-id> make test-attempt-live
  • ATTEMPT_BROWSER_SELF_TEST=1 bash scripts/test/attempt-browser-smoke.sh
  • ATTEMPT_BROWSER_CONFIRM=attempt-native ATTEMPT_BROWSER_EXAM_ID=<published-exam-id> ATTEMPT_BROWSER_AUTHORIZATION='Bearer <student-token>' ATTEMPT_BROWSER_ORGANIZATION_ID=<org-id> make test-attempt-browser

Go-platform documentation is generated from repository Markdown.