Skip to content

fix(report): Urdu rendered as tofu whenever the STT mislabelled the language (bd-osmk0, bd-gipr1) - #307

Merged
hyasin270 merged 1 commit into
developfrom
bd-osmk0-report-tofu
Aug 19, 2026
Merged

fix(report): Urdu rendered as tofu whenever the STT mislabelled the language (bd-osmk0, bd-gipr1)#307
hyasin270 merged 1 commit into
developfrom
bd-osmk0-report-tofu

Conversation

@hyasin270

Copy link
Copy Markdown
Contributor

Rifat reported a coach debrief that was "only empty boxes with no content" (HITL sheet R66). The screenshot was a floating image in the sheet that the Sheets API will not return; pulling it out of an authenticated PDF export showed the teacher hero report with every Urdu glyph painted as a box while the English chrome rendered perfectly.

The chain

  1. hero-report.service resolved lang = language || analysis.language || session.transcript_language || 'en'. transcript_language is an STT label, and since 2026-08-11 Soniox has returned en/hindi/javanese/sindhi for Urdu classroom audio (bd-bfy69, still open — the upstream cause). So an Urdu-bodied report went down the Latin arm.
  2. hero-report.template's Latin arm named only 'Fraunces' / 'Lexend'. The NastaliqUrdu @font-face was embedded but never referenced from any rule in that branch.
  3. Railway's Chromium has no system fonts, so those glyphs had nothing to fall back to. macOS silently substitutes a system Nastaliq — which is exactly why every local render looked correct.

Measured on prod: 44 already-generated reports carry non-Latin script while sitting in a non-ur/ar branch.

What changed

  • hero-report.template.js — the Urdu/Arabic faces are a permanent fallback in every branch, never gated on lang. Latin still resolves to Lexend/Fraunces first. Same fix bd-2644 applied to the coach card.
  • .pframe .pcap — LLM-generated photo captions were pinned to Latin-only Lexend in every branch, so they tofu'd even on a correctly-labelled Urdu report. The bd-2362 class.
  • report-language.js (new)resolveReportLanguage() constrains the answer to LANGUAGE_OFFER, so an unofferable STT label can no longer choose the script branch or the language the narrative LLM is told to write in. Unofferable lands on offerDefaultLanguage() (ur), not the emergency English floor. Split out so it is testable without booting the service's dependency graph.

Verification

CSS.getPlatformFontsForNode, before and after, same instrument:

Urdu run resolves to
before SYSTEM Noto Nastaliq Urdu, isCustomFont=false — absent on Railway
after EMBEDDED face, in all three stacks
  • 32 new tests, red-first against this tree — 9 font assertions failed before the template change; the language suite could not resolve its module.
  • Full suite: zero new failures. Four suites differed under the parallel run; all four pass in isolation both with and without the change (flaky under worker contention).

Not fixed here

bd-bfy69 — Soniox transcribing Urdu into Devanagari and mislabelling the language. 67 sessions since 11 Aug. That script reaches coaches directly in the FICO evidence field (R62/R63/R64) and there is no Devanagari font in the repo, so it will still not render. This PR stops the Urdu damage; it does not fix the transcription.

Closes: bd-osmk0
Closes: bd-gipr1

🤖 Generated with Claude Code

…age — 44 reports rendered as tofu

Rifat reported a coach debrief that was "only empty boxes with no content"
(R66). The screenshot was in the feedback sheet as a floating image the Sheets
API will not return; pulling it out of an authenticated PDF export showed the
teacher hero report with every Urdu glyph painted as a box while the English
chrome rendered perfectly.

The chain, end to end:

  1. hero-report.service resolved
       lang = language || analysis.language || session.transcript_language || 'en'
     transcript_language is an STT label, and since 2026-08-11 Soniox has been
     returning 'en' / 'hindi' / 'javanese' / 'sindhi' for Urdu classroom audio
     (bd-bfy69, still open). So an Urdu-bodied report went down the Latin arm.
  2. hero-report.template's Latin arm named ONLY 'Fraunces'/'Lexend'. The
     NastaliqUrdu @font-face was embedded but never referenced from any rule in
     that branch.
  3. Railway's Chromium has no system fonts, so those glyphs had nothing to
     fall back to. macOS silently substitutes a system Nastaliq, which is
     exactly why every local render looked correct.

Measured on prod: 44 already-generated reports carry non-Latin script while
sitting in a non-ur/ar branch.

Verified with CSS.getPlatformFontsForNode, before and after, same instrument:
BEFORE the Urdu run resolved to the SYSTEM 'Noto Nastaliq Urdu'
(isCustomFont=false — absent on Railway); AFTER it resolves to the EMBEDDED
face in all three stacks. Latin still resolves to Lexend/Fraunces first; the
fallbacks only catch what those cannot draw.

Also fixed .pframe .pcap, which pinned LLM-generated photo captions to
Latin-only Lexend in EVERY branch — so those tofu'd even on a correctly
labelled Urdu report. That is the bd-2362 class: the small-print element
nobody re-checks after the main stacks are fixed.

Tests: 20 + 12 new, red-first against this tree (9 font assertions failed
before the template change; the language suite could not resolve its module).
Full suite shows zero new failures — the four suites that differed under the
parallel run all pass in isolation both with and without the change.

Closes: bd-osmk0
Closes: bd-gipr1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@hyasin270
hyasin270 merged commit 5a93e8e into develop Aug 19, 2026
2 checks passed
@hyasin270
hyasin270 deleted the bd-osmk0-report-tofu branch August 19, 2026 18:27
hyasin270 added a commit that referenced this pull request Aug 19, 2026
…age — 44 reports rendered as tofu (#307) (#308)

Rifat reported a coach debrief that was "only empty boxes with no content"
(R66). The screenshot was in the feedback sheet as a floating image the Sheets
API will not return; pulling it out of an authenticated PDF export showed the
teacher hero report with every Urdu glyph painted as a box while the English
chrome rendered perfectly.

The chain, end to end:

  1. hero-report.service resolved
       lang = language || analysis.language || session.transcript_language || 'en'
     transcript_language is an STT label, and since 2026-08-11 Soniox has been
     returning 'en' / 'hindi' / 'javanese' / 'sindhi' for Urdu classroom audio
     (bd-bfy69, still open). So an Urdu-bodied report went down the Latin arm.
  2. hero-report.template's Latin arm named ONLY 'Fraunces'/'Lexend'. The
     NastaliqUrdu @font-face was embedded but never referenced from any rule in
     that branch.
  3. Railway's Chromium has no system fonts, so those glyphs had nothing to
     fall back to. macOS silently substitutes a system Nastaliq, which is
     exactly why every local render looked correct.

Measured on prod: 44 already-generated reports carry non-Latin script while
sitting in a non-ur/ar branch.

Verified with CSS.getPlatformFontsForNode, before and after, same instrument:
BEFORE the Urdu run resolved to the SYSTEM 'Noto Nastaliq Urdu'
(isCustomFont=false — absent on Railway); AFTER it resolves to the EMBEDDED
face in all three stacks. Latin still resolves to Lexend/Fraunces first; the
fallbacks only catch what those cannot draw.

Also fixed .pframe .pcap, which pinned LLM-generated photo captions to
Latin-only Lexend in EVERY branch — so those tofu'd even on a correctly
labelled Urdu report. That is the bd-2362 class: the small-print element
nobody re-checks after the main stacks are fixed.

Tests: 20 + 12 new, red-first against this tree (9 font assertions failed
before the template change; the language suite could not resolve its module).
Full suite shows zero new failures — the four suites that differed under the
parallel run all pass in isolation both with and without the change.

Closes: bd-osmk0
Closes: bd-gipr1

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant