Appearance
OCR And MathType Owner-Scoped Source Contract
Status: non-default Gateway candidate proof. This is not default-route or production-browser promotion evidence.
Boundary
- Teacher frontend calls only Gateway
/api/*with its Gateway session. POST /api/teacher/import-sourcesforwards multipart data to document-service. The service derives organization and actor from trusted headers, stores the binary, and returns an opaquesourceAssetId.- 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.
- document-service allows
GET /v1/internal/import-sources/{id}/contentonly whenX-Internal-Service-Token, organization, actor,docx-import-sourcepurpose, and the expected source kind all match. - 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. - 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.jsonremainslegacy_proxyfor broad/api/exam-importtraffic.
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 typecheckThe 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.