Prove spoken-language transcription end to end; fix CORS for X-Request-ID - #45
Merged
Merged
Conversation
…t-ID A user reported Spanish audio coming back as English. The report predates the Deepgram cutover (#38); the current auto path (detect_language=true) already keeps the spoken language, and Deepgram's `multi` mode was rejected because it wrecks Korean and Chinese (ADR-004 has the probe table). So this change adds the proof and hardening rather than a provider change: - backend/tests/fixtures/audio/: short synthetic clips (macOS voices) for es-MX, es-ES, en-US, ko, zh and an English-then-Spanish mix. - tests/test_language_detection.py: recorded-response tests pinning that auto asks for detection and stores whatever Deepgram detects, for every offered language; Spanish text is stored verbatim. - tests/live/: real fixtures through real Deepgram, `pytest -m live` (excluded from the default run via pytest.ini). - frontend/e2e/tests/multilingual-upload.spec.js: uploads the Spanish and the mixed clip through the real UI and asserts Spanish text plus a Spanish badge (opt-in with CLIO_LIVE_E2E=1). - NoteDetailPage: the language badge now shows "Spanish" instead of "es", carries a lang attribute and a test id; the option list is hoisted so the badge and the re-transcribe dialog share it. Found while running the browser proof: the frontend sends X-Request-ID on note creation (#41) but CORS_ALLOW_HEADERS did not list it, so on any cross-origin deployment (dev stack, CI e2e) the browser dropped the POST after preflight. Added the header and tests/test_cors_preflight.py. Production is same-origin and was not affected.
…language Review finding: the badge text is an English label (Spanish), so lang="es" declared the wrong language for that content. The detected code is now exposed as data-language for tests and tooling; the e2e assertion follows.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A user reported Spanish audio transcribed as English. Grounding on production showed the report predates the Deepgram cutover (#38, deployed 2026-06-29) and the current auto path already keeps the spoken language. This PR adds the proof and hardening instead of a provider change, and fixes a CORS defect found while proving it.
What
docs/adr/004-language-detection-strategy.md— keepdetect_language=true;language=multirejected (wrecks ko/zh, probe table inside).backend/tests/fixtures/audio/— es-MX, es-ES, en-US, ko, zh, mixed en→es (348 KB total, synthetic voices).tests/test_language_detection.py(16 tests, recorded provider shapes).tests/live/—pytest -m live, excluded from the default run.frontend/e2e/tests/multilingual-upload.spec.js— real upload → real Deepgram → Spanish text + Spanish badge. Opt-in withCLIO_LIVE_E2E=1.langattribute anddata-testid="note-language".x-request-idadded toCORS_ALLOW_HEADERS+tests/test_cors_preflight.py. The browser droppedPOST /api/notes/after preflight on any cross-origin deployment (dev stack, CI e2e). Production is same-origin and unaffected.Evidence
pytest: 139 passed, 6 live deselected.pytest -m live: 6 passed against real Deepgram.ruff check: clean.tsc --noEmit: clean.npm run lint: 0 errors (12 pre-existing warnings).multilingual-upload.spec.js: 2/2 passed against the dev stack; screenshots inspected (Spanish badge, untranslated Spanish text; mixed clip keeps both languages).healthandregistrationpass when run alone (failures were 429 throttling under the parallel run);comprehensive-harnessandproduction-sweeplook for anh1"Record Voice Note" that the page no longer has ("New Voice Note").Not in scope
production-sweep.spec.jsruns against production and registers users there; flagged, not changed.Acceptance mapping
Owner-confirmed acceptance, three clauses, and where each is pinned:
tests/live/test_deepgram_live.py(es-MX, es-ES) and the Playwright Spanish case.test_mixed_english_spanish_keeps_both_languages(live) and the Playwright mixed case.test_spanish_text_is_kept_not_translated(unit) and the Playwright assertion that the Spanish note does not contain the English rendering. The explicit, user-invoked Re-transcribe action does overwrite the transcript by design; that path is unchanged here and stays covered by the pre-existingtest_retranscribe_task_happy_path.Review
Fresh-context adversarial review: approve with minors. Both addressed in the follow-up commit: the badge no longer carries a
langattribute (its label is English), the detected code is exposed asdata-languageinstead; this section adds the acceptance mapping.