Skip to main content

max / alloy

Carry the scripts the browser needs, and assert they arrived Alloy ships a browser as its default and carried google-noto-sans-vf and nothing else, so every CJK, Arabic, Hebrew, Indic and Thai page rendered as rows of missing glyphs. Fedora's own coverage metapackages rather than a hand-picked list, because the failure mode of hand-picking is that the script left out is the one nobody here reads. 62 MiB over 4 packages for CJK, whose faces are genuinely large, and 13 MiB over 95 for the rest. The assertion is the point of the second half. This is the third arrival of one defect class: the emoji alias named a font the image never installed, the swayosd unit sat at a path udev does not read, and now this. All three were configuration that was correct about something absent, and in all three the build was green while a user looked at missing glyphs or a dead key. `dnf install` proves a package name resolves; it does not prove a metapackage still pulls the faces it pulled last release, which is what can rot across a Fedora bump. Ten languages, counts unpinned at -ge 1 so a repackaging does not fail the build. Plus the two claims the change makes about itself: that <prefer> leaves Atkinson as the sans and IosevkaTerm as the monospace, and that declining emoji survives, since neither metapackage carries an emoji font. HOME=/etc/skel is load-bearing there. The aliases are per-user, so the build's root context does not see them: on this image a plain `fc-match sans-serif` answers Noto Sans while the same query under the skeleton answers Atkinson. A guard without it would have asserted the base's opinion and passed while claiming to check Alloy's. Verified both ways before landing: it passes on the built image and fails on the bare base, naming the language it could not cover.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-30 04:22 UTC
Signed with PGP, not checked
Commit: d2ec40ac318d4249d8285ab036b0f650b738955a
Parent: bb91e8d
2 files changed, +70 insertions, -0 deletions
@@ -454,6 +454,32 @@
454 454 grim slurp \
455 455 # Browser (Gecko default; ungoogled-chromium is opt-in Flatpak per docs/STACK.md)
456 456 firefox \
457 + # Script coverage for the browser. Until now the image carried
458 + # google-noto-sans-vf (Latin, Greek, Cyrillic) and nothing else, so
459 + # Firefox rendered every CJK, Arabic, Hebrew, Indic and Thai page as
460 + # rows of missing glyphs. Shipping a browser as the default and then
461 + # not carrying the fonts a large share of the web is written in is the
462 + # same defect class as the emoji alias that named a font the image
463 + # never installed: the config was fine, the coverage was absent, and
464 + # nothing said so.
465 + #
466 + # These are Fedora's own coverage metapackages rather than a hand-
467 + # picked list, because the failure mode of hand-picking is a script
468 + # nobody on this end reads being the one left out. Cost stated rather
469 + # than absorbed: -cjk-sans is 62 MiB over 4 packages (the CJK faces are
470 + # simply large), -other-sans is 13 MiB over 95.
471 + #
472 + # No fontconfig change goes with this. The aliases in
473 + # etc/skel/.config/fontconfig/fonts.conf use <prefer>, which leaves
474 + # fontconfig free to fall through to a font that has the glyph, so
475 + # Atkinson stays the sans for Latin text and Noto covers what it
476 + # cannot.
477 + #
478 + # Emoji is untouched and still deliberately absent (docs/STACK.md):
479 + # neither metapackage carries an emoji font, which is why declining
480 + # emoji survives this line.
481 + default-fonts-cjk-sans \
482 + default-fonts-other-sans \
457 483 # Containers: the three backends behind `alloy pkg box`'s isolation
458 484 # dial (docs/STACK.md#containers). The user picks a level, not a
459 485 # tool. podman is the runtime and is what `workspace` calls
@@ -1016,6 +1042,40 @@
1016 1042 || { echo "/etc/skel/$rel is gone; the night render of it has nothing to switch back to" >&2; exit 1; }; \
1017 1043 done
1018 1044
1045 + # Script coverage, and the two claims that come with it.
1046 + #
1047 + # This is the third arrival of one defect class, so it gets an assertion rather
1048 + # than a comment. The emoji alias named a font the image never installed. The
1049 + # swayosd unit sat at a path udev does not read. Both were configuration that was
1050 + # correct about a thing that was absent, and in every case the build was green and
1051 + # the failure was a user staring at missing glyphs or a dead key. `dnf install`
1052 + # only proves a package name still resolves; it does not prove a metapackage still
1053 + # pulls the faces it pulled last release, and that is the part that can rot
1054 + # quietly across a Fedora bump.
1055 + #
1056 + # Ten languages rather than two, because the failure mode of a short list is that
1057 + # the script left out is the one nobody here reads and therefore nobody notices.
1058 + # The counts are deliberately not pinned: `-ge 1` is the claim that matters, and a
1059 + # fixed number would fail on a Fedora rebuild that merely repackages a family.
1060 + #
1061 + # `HOME=/etc/skel` is load-bearing and not decoration. Alloy's aliases live in
1062 + # etc/skel/.config/fontconfig/fonts.conf, which is per-user, so the build's root
1063 + # context does not see them: measured on this image, a plain `fc-match sans-serif`
1064 + # answers "Noto Sans" while the same query under the skeleton answers "Atkinson
1065 + # Hyperlegible". A guard written without it would have asserted the base's opinion
1066 + # and passed while claiming to check Alloy's.
1067 + RUN set -eux; \
1068 + for lang in ja zh-cn zh-tw ko ar he hi th bn ta; do \
1069 + [ "$(fc-list ":lang=$lang" family | wc -l)" -ge 1 ] \
1070 + || { echo "no font covers '$lang'; every page in that script renders as missing glyphs" >&2; exit 1; }; \
1071 + done; \
1072 + HOME=/etc/skel fc-match sans-serif | grep -q 'Atkinson Hyperlegible' \
1073 + || { echo "sans-serif is no longer Atkinson; the added coverage outranked Alloy's own pick" >&2; exit 1; }; \
1074 + HOME=/etc/skel fc-match monospace | grep -q 'IosevkaTerm Nerd Font Mono' \
1075 + || { echo "monospace is no longer IosevkaTerm; a cell grid would get mismeasured icons" >&2; exit 1; }; \
1076 + [ "$(fc-list ':charset=1F600' family | wc -l)" -eq 0 ] \
1077 + || { echo "an emoji font arrived; docs/STACK.md says none is shipped, so update the decision or drop the font" >&2; exit 1; }
1078 +
1019 1079 # =====================================================================
1020 1080 # bootc validation — fails the build if the image isn't a valid
1021 1081 # bootable container.
@@ -391,6 +391,16 @@
391 391
392 392 Alloy declines to prescribe. Nothing Alloy authors is serif; the browser and any long-form reading surface fall through to the system default (Source Serif 4 or Liberation Serif on Fedora). fontconfig alias covers the fallback chain politely without adopting a serif font as an Alloy commitment.
393 393
394 + ### Non-Latin scripts: **Fedora's coverage metapackages**
395 +
396 + `default-fonts-cjk-sans` and `default-fonts-other-sans`. Alloy's three picks above cover Latin, Greek and Cyrillic and nothing else, and Alloy ships a browser as the default. Every CJK, Arabic, Hebrew, Indic and Thai page rendered as rows of missing glyphs until 2026-07-29. That is not a curation position, it is the coverage-absent-and-silent defect this stack keeps producing, arrived at from a third direction after the emoji alias and the `swayosd` unit path.
397 +
398 + Fedora's metapackages rather than a hand-picked font list: the failure mode of hand-picking is that the script left out is the one nobody here reads. Cost is 62 MiB over 4 packages for CJK, whose faces are genuinely large, and 13 MiB over 95 for everything else.
399 +
400 + No fontconfig change accompanies this. The aliases use `<prefer>`, so fontconfig falls through to a font that has the glyph; Atkinson stays the sans for Latin text and Noto covers what it cannot.
401 +
402 + This does not disturb the emoji position below. Neither metapackage carries an emoji font.
403 +
394 404 ### Emoji: **not shipped**
395 405
396 406 No emoji font is installed, and the fontconfig `emoji` alias is gone rather than pointing at one. Alloy uses no emoji in its own copy, so nothing it draws needs the coverage. Emoji in a web page or a third-party notification render as missing glyphs; that is the accepted cost, not an oversight.