Files
hyperframes/packages
James Russo c336508d4e fix(producer): treat 4xx from Google Fonts as deterministic "not served", not as failClosed trigger (#957)
After c8e8fdcf added a Google Fonts supplement-fetch to the Path 1
(bundled-font) branch, every `plan()` call against a composition whose
CSS named a non-Google family that Google Fonts 400s on (e.g.
`"Segoe UI"`, `"Arial"`, `"Futura"`) started failing on distributed
renders with `FONT_FETCH_FAILED`. Distributed renders default to
`failClosedFontFetch: true`, and the existing code treated *all* non-2xx
responses uniformly: throw if failClosed, swallow otherwise.

That conflates two very different failure modes:

  - **4xx** is a *deterministic* answer — Google Fonts does not serve
    this family, and won't serve it on retry either. The byte-identical-
    retry contract distributed renders rely on is unaffected; the render
    falls back to embedded faces / the composition's font-family chain
    (which is what it would have done pre-c8e8fdcf anyway). No reason
    to fail-close here.

  - **5xx** (and network / DNS / fetch exceptions) is *non-deterministic*
    infrastructure failure. A retry might succeed and produce different
    pixel output than the first attempt — exactly what
    `failClosedFontFetch` is meant to protect against. Keep failing
    closed in this mode.

Fix: split the !res.ok branch in both the CSS fetch and the woff2 fetch
inside `fetchGoogleFont` — only `>= 500` paired with failClosed throws;
4xx returns `[]` in both modes. Network/DNS exceptions in the catch
block are unchanged (still failClosed-gated).

This:
  - Unblocks distributed renders for compositions that name any
    cross-alias system font Google doesn't serve (Segoe UI, Arial, etc.).
  - **Preserves the current regression baseline** — Google Fonts
    actually *does* serve some non-canonical names (e.g. "Helvetica" and
    "Helvetica Neue" both return HTTP 200 with real @font-face rules,
    confirmed via curl), so the supplement-fetch still runs and binds
    those real faces to the composition's CSS family names exactly as
    today. style-7-prod (which uses `"Helvetica Neue", Helvetica, Arial,
    sans-serif`) continues to render against real Helvetica glyphs.
  - Leaves the FONT_ALIASES table and call-site untouched. The fix is
    in the right place — the error semantics inside fetchGoogleFont —
    not in any composition-aware logic upstream.

Tests:
  - 2 new positive cases on `failClosedFontFetch: true`:
    400 and 404 responses no longer throw, render falls back cleanly.
  - 2 new negative cases on `failClosedFontFetch: true`:
    503 throws `FONT_FETCH_FAILED`, error includes URL + family.
  - 1 new case on `failClosedFontFetch: false`: 5xx swallowed as before.
  - The pre-existing "does NOT throw when the HTML uses a pre-bundled
    font" test was broken by c8e8fdcf (the supplement-fetch always fires
    for self-aliased bundled fonts now). Updated it to use a successful
    empty CSS response, which is the actual invariant we want.

12/12 tests pass.

Followup discussion: should `FONT_ALIASES` exist at all in a
deterministic cloud renderer? Today `font-family: "Helvetica"` in CSS
silently produces real Helvetica glyphs (via Google Fonts' undocumented
alias serving) and `font-family: "Segoe UI"` silently produces embedded
Roboto, with no warning to the author. That's a WYSIWYG violation worth
its own proposal — but not in scope for this fix.
2026-05-19 03:09:16 -04:00
..
2026-05-19 02:33:31 +00:00