fix(android): bundle the typefaces instead of fetching them at runtime
android / Build + lint + test (push) Successful in 4m19s

Typography.kt resolved Fraunces, Inter and JetBrains Mono through the Play
Services font provider, which fetches them over the network on first use.
Same rule-164 problem the web client had, with a second failure mode on
top: the provider is absent entirely on devices without Play Services, so
the app fell back to the platform default and stopped looking like
Minstrel — quietly, with no error.

The five static instances now live in res/font, vendored by the same
tools/vendor-fonts.py that produces the web bundle. Both clients draw
from one list of faces so they cannot drift apart. Cost is ~0.86 MB of
APK; the runtime path is removed rather than kept as a fallback — the
ui-text-google-fonts dependency, its version-catalog entry and the
provider certificate hashes in font_certs.xml are all gone.

Two things about fetching TTFs that are worth writing down, because both
fail by succeeding:

Google Fonts picks the format from the User-Agent, and there is no
parameter to ask for one. A modern UA gets woff2, which res/font cannot
load. The obvious "use an old UA" fix gets EOT — an IE-only format that
downloads happily, has a plausible size, and is entirely useless here. An
Android 4.4 UA is what actually yields TrueType.

css2 also collapses a multi-weight request to 400 for legacy clients, so
asking for Medium silently returns Regular: a valid TrueType file that
renders at the wrong weight everywhere. Each weight is therefore fetched
on its own URL, and the script now asserts OS/2 usWeightClass on every
download — that field is the only thing distinguishing the two files.

Verified before wiring: all five carry TrueType magic, the 400/500 pairs
differ, and their usWeightClass reads 400/400/500/500/400 as declared
beside them in the FontFamily.

Not covered: there is no guard for this on the Android side. The web
equivalent is asserted by no-external-assets.test.ts, but the Android
tree has no source-inspection test pattern to follow and no way to
falsify one without a local Gradle run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQ31KQpYbStyK5y58UmPLH
This commit is contained in:
2026-09-09 14:13:57 -04:00
co-authored by Claude Opus 5
parent 16005054eb
commit b52a00df66
10 changed files with 99 additions and 68 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.