From 994d2bc21e3c1e73f9fa02114f1e6d92b2b7a27d Mon Sep 17 00:00:00 2001 From: Samraaj Bath Date: Sat, 4 Jul 2026 04:29:50 -0700 Subject: [PATCH] Band coverage for never-visible occupying items, page-height trust guard, font materialization integrity - Items never visible at the canonical viewport (carousel slides off-screen at every captured width) now fall through to per-viewport geometry bands when they occupy layout, instead of freezing canonical geometry - The explicit-height probe trust excludes body/html/main and any wrapper whose height matches the page scrollHeight - page-height nodes keep flowing, and the layout height gate stays meaningful - @font-face and style-rule url() harvesting resolves against the OWNING stylesheet's href (walking @import nesting), not document.baseURI; font bytes are magic-byte validated at the storage choke point (HTML bodies from catch-all 200 routes are rejected); font-face dedup prefers the variant whose source actually resolved, deterministically 415 tests pass (16 new), typecheck clean. Co-Authored-By: Claude Fable 5 --- compiler/src/capture/capture.ts | 26 ++++ compiler/src/capture/walker.ts | 52 ++++++-- compiler/src/generate/css.ts | 30 ++++- compiler/src/infer/fonts.ts | 62 +++++++--- compiler/test/css.test.ts | 61 ++++++++++ compiler/test/fontIntegrity.test.ts | 152 ++++++++++++++++++++++++ compiler/test/fontUrlResolution.test.ts | 136 +++++++++++++++++++++ 7 files changed, 491 insertions(+), 28 deletions(-) create mode 100644 compiler/test/fontIntegrity.test.ts create mode 100644 compiler/test/fontUrlResolution.test.ts diff --git a/compiler/src/capture/capture.ts b/compiler/src/capture/capture.ts index 270c083..010a2aa 100644 --- a/compiler/src/capture/capture.ts +++ b/compiler/src/capture/capture.ts @@ -182,6 +182,28 @@ export function looksLikeVideoFile(bytes: Buffer): boolean { return false; } +/** Container-magic check for accepted font bytes, mirroring `looksLikeVideoFile`. A router that + * answers 200+HTML for an unknown `/media/*` path (common on SPA hosts) otherwise gets stored as + * a `.woff2`; the browser rejects it as a font and the whole page falls through to a system + * fallback. Accept only the real font-container signatures — woff2 (`wOF2`), woff (`wOFF`), + * OpenType/CFF (`OTTO`), TrueType (`\x00\x01\x00\x00` or `true`/`ttcf`), and EOT (the version + * header at bytes 8..11 is `\x01\x00\x01\x00`/`\x02\x00\x01\x00`, so key EOT off its unique + * 0x504C signature at offset 34) — and explicitly reject an HTML/text body. */ +export function looksLikeFontFile(bytes: Buffer): boolean { + if (bytes.length < 4) return false; + const b0 = bytes[0]!, b1 = bytes[1]!, b2 = bytes[2]!, b3 = bytes[3]!; + // A leading `<` (`= 36 && bytes[34] === 0x4c && bytes[35] === 0x50) return true; + return false; +} + /** * A `` candidate for the HTML media resource-selection algorithm. `media`/`type` are the * raw attribute strings (null/undefined when absent, matching a missing attribute). @@ -1047,6 +1069,10 @@ export async function captureSite(opts: { // page stored under first-stored-wins ships a corrupt file). Left unstored, the // asset surfaces in visual_assets_missing instead. if (type === "video" && !looksLikeVideoFile(bytes)) return; + // Same guard for fonts: a 200+HTML body (SPA router answering an unknown /media/* path) must not + // be stored as a .woff2. Left unstored, the face surfaces as failed, so the font graph can fall + // back to a correctly-resolved duplicate url instead of shipping an impostor the browser rejects. + if (type === "font" && !looksLikeFontFile(bytes)) return; const a = assetMap.get(url) ?? recordAsset(url, type, null, null, "network"); if (a.storedAs) return; // A `.lottie` (dotLottie) asset is a ZIP archive, not bare lottie-web JSON. lottie-web's diff --git a/compiler/src/capture/walker.ts b/compiler/src/capture/walker.ts index 4d523c9..0cb039b 100644 --- a/compiler/src/capture/walker.ts +++ b/compiler/src/capture/walker.ts @@ -80,6 +80,10 @@ export type FontFace = { display?: string; unicodeRange?: string; stretch?: string; + // Url of the stylesheet this face was declared in (undefined for an inline