Skip to content

OCR And MathType Owner-Scoped Source Contract

Status: non-default Gateway candidate proof. This is not default-route or production-browser promotion evidence.

Boundary

  1. Teacher frontend calls only Gateway /api/* with its Gateway session.
  2. POST /api/teacher/import-sources forwards multipart data to document-service. The service derives organization and actor from trusted headers, stores the binary, and returns an opaque sourceAssetId.
  3. OCR and MathType create calls pass that id to docx-import-service. The import service does not receive a browser storage key and does not read object storage directly.
  4. document-service allows GET /v1/internal/import-sources/{id}/content only when X-Internal-Service-Token, organization, actor, docx-import-source purpose, and the expected source kind all match.
  5. OCR detail, status, event log, review save, reprocess, and approval are scoped to the original job actor and persisted source_media_asset_id. A different actor cannot read recognized source text, alter review state, or nominate another user's source asset from the UI or direct Gateway call.
  6. MathType artifact download stays a Gateway-authenticated streaming route. OCR opens the existing import review screen after completion; it does not promise Word or Markdown download.

OCR Review Approval Contract

OCR completion stores an editor-oriented source-text review and intentionally has no ReviewedAt timestamp. POST /v1/import/docx/jobs/{jobId}/approve must reject that state before calling Question Bank. A teacher review save keeps the sourceText/sections[] editor payload but records ReviewedAt; the approval boundary then derives a canonical owner payload with questions[], teacher-edited stem/type/score rule, options, correct-answer labels, solution HTML, source-text spans, and sourceKind=ocr-document.

make test-import-pdf-ocr-workflow proves this HTTP owner contract with a Mistral-compatible fake: it asserts zero Question Bank calls before review and one canonical Question Bank ingest request after review. This is hermetic and does not prove billable Mistral recognition quality, browser behavior, or default Gateway promotion.

Candidate Tables

  • Compose: deploy/gateway/routes.import-ocr-mathtype-native-example.json
  • Localhost: deploy/gateway/routes.import-ocr-mathtype-native-localhost-example.json
  • Default: deploy/gateway/routes.json remains legacy_proxy for broad /api/exam-import traffic.

Verification

bash
GOTOOLCHAIN=go1.25.11 go test ./services/document-service/... ./services/docx-import-service/... -count=1
make test-import-ocr-mathtype-routes
OCR_BROWSER_SELF_TEST=1 make test-ocr-browser
OCR_REVIEW_BROWSER_LOCAL_POSTGRES_CONFIRM=local-postgres make test-ocr-review-browser-local-postgres
OCR_REVIEW_BROWSER_LOCAL_POSTGRES_CONFIRM=local-postgres make test-ocr-batch-review-browser-local-postgres
pnpm --filter @hoctapaz/ui test -- teacher-workspace.test.tsx
pnpm --filter @hoctapaz/ui typecheck

The focused service tests prove source owner/workflow rejection, no source object-key response fields, internal token enforcement, and reprocess reopening the persisted owner source. The UI test proves multipart source upload and job creation use Gateway authorization and organization headers only with ?teacherExamUtilityGateway=native; the default route makes no owner request. docs/qa/ocr-review-browser-local-postgres.md and docs/qa/ocr-batch-review-browser-local-postgres.md record isolated direct and opt-in batch OCR browser, PostgreSQL, local-provider, review save/reload, candidate approval, candidate Question Bank readback, and cross-actor proof.

Rollback

Set GATEWAY_ROUTE_TABLE=deploy/gateway/routes.json or remove the candidate table from the non-default rollout. This restores broad import traffic to legacy without changing legacy source or document-service's existing generic media endpoints.

Go-platform documentation is generated from repository Markdown.