Skip to content

Handoff: SVC-009-exam-attempt-public-proof

Scope

  • Dispatch ID: SVC-009
  • Service: exam-service
  • Task pack: docs/agents/service-tasks/exam-service.md
  • Next task: SVC-009-exam-attempt-public-proof
  • Goal: prove exam authoring/start contracts with attempt-service plus live/browser evidence before public route promotion.
  • Status: accepted bounded contract slice, not service completion.

Docs Read

  • docs/agents/service-agent-next-slice-queue.json
  • docs/agents/service-agent-next-slice-closeout-ledger.json
  • docs/agents/service-tasks/exam-service.md
  • docs/agents/handoff-phase-7-exam-snapshots.md
  • docs/qa/exam-authoring-route-rehearsals.md
  • docs/qa/exam-attempt-public-proof.md
  • docs/api/exam-service.md

Legacy Evidence Read

  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/exams/exam-core.service.ts
  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/exams/exams.controller.ts
  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/exams/exams.controller.spec.ts
  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/exams/exam-core.service.spec.ts
  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/prisma/schema.prisma

Legacy source was read-only evidence. No file under /Users/velikho/Desktop/WORKING/HOCTAPAZ/ was changed.

Files Changed

  • services/attempt-service/internal/usecase/attempt.go
  • services/attempt-service/internal/usecase/event_result.go
  • services/attempt-service/internal/http/server_test.go
  • docs/qa/exam-attempt-public-proof.md
  • docs/agents/handoffs/SVC-009-exam-attempt-public-proof.md
  • docs/agents/service-tasks/exam-service.md

Behavior Implemented

  • Verified a real in-memory exam-service published snapshot through runtime-access, then through Gateway exam_start_adapter into a real in-memory attempt-service.
  • The temporary IAM/classroom verifier fixture required the real X-Internal-Service, X-Internal-Token, actor, role, and organization headers before returning an active organization-membership decision.
  • Fixed a public response leak found during the proof: Start and idempotent start replay now return the same student projection as attempt reads. It removes option isCorrect, non-empty answer keys, scoring rules, source snapshots, and explanations until a result is visible.
  • Attempt creation, answers, grading, and results remain attempt-service owned; the default Gateway table remains unchanged.

Required Evidence

  • exam-attempt contract proof: a direct runtime-access call on the seeded published snapshot returned an allowed exam-service decision with verified password, one question, and no access-link code or password hash in output/qa/exam-attempt-public-proof-20260713/authoring/.
  • authorization regression proof: focused runtime-access tests still cover the fail-closed verifier behavior; the local fixture proves the configured verifier contract only, not a deployed IAM/classroom stack.
  • live/browser proof: Gateway list/start/detail/save/event/submit/result and post-grade idempotency replay passed against real local services. Chromium read smoke passed from a same-origin /healthz shell, not from the student UI.
  • rollback notes: the unchanged default deploy/gateway/routes.json returned 502 with exams/legacy_proxy and attempts/legacy_proxy against a deliberately unavailable legacy target.

Tests And Verification

  • GOTOOLCHAIN=go1.25.11 go test ./services/exam-service/... -count=1
  • GOTOOLCHAIN=go1.25.11 go test ./services/exam-service/internal/usecase ./services/exam-service/internal/http -run 'TestExamRuntimeAccess|TestRuntimeAccessRouteReturnsAttemptStartInput' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/attempt-service/internal/http -run TestStartAttemptHTTP -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/attempt-service/internal/usecase -count=1
  • make test-exam-authoring-routes
  • make test-attempt-routes

All commands passed. The local browser smoke proves authenticated browser fetch and route headers, but not the student-facing application workflow.

Route State

  • Route/default state: exam authoring/start promotion requires exam-attempt contract proof plus live/browser and rollback proof.
  • Default exam, attempt, and fallback routes remain legacy-proxied.
  • The candidate table was only deploy/gateway/routes.attempt-native-localhost-example.json at 127.0.0.1:18085; it was stopped after proof.

Data Notes

  • Exam-service owns exam snapshots, access-link policy, assignments, and access decisions.
  • Attempt-service owns attempts, answers, grading, and results.
  • Question snapshots are copied by value; no cross-service question DB reads.

Risks / Blockers

  • The proof uses memory stores and a local IAM/classroom verifier fixture, not persistence or deployed downstream services.
  • The Chromium run executes same-origin API fetches from /healthz; real student UI navigation, rendering, and authenticated session behavior remain open.
  • Full legacy share-link CRUD and guest-registration parity remain future work.

Rollback Notes

These are the rollback notes for the accepted bounded slice and were exercised:

  • Set GATEWAY_ROUTE_TABLE=deploy/gateway/routes.json.
  • Disable any non-default exam/attempt rehearsal caller.
  • Rerun make test-exam-authoring-routes and make test-attempt-routes.

Next Step

Before any default-route promotion, run a deployed IAM/classroom-backed proof and an actual student application browser workflow; retain the legacy route table until both are captured.

Go-platform documentation is generated from repository Markdown.