From 18e02e1fd647894ecc5529b7c6d6f622cf91affd Mon Sep 17 00:00:00 2001 From: noah Date: Sun, 26 Jul 2026 14:34:39 -0400 Subject: [PATCH 1/2] test(fork): pin the terminal font fallback to the CSS mono stack FORK_TERMINAL_FONT_FALLBACK backs up the `--font-mono` read in custom/terminalFont.ts, and is character-identical to the --fork-font-mono declaration in theme.custom.css after whitespace normalization. Nothing enforced that: editing one and forgetting the other left the safety net silently backing up a stack it no longer matched, with every existing guard still green. The existing guards assert that Geist Mono leads and that JetBrains Mono is present in both stacks, so they cover the two ordering constraints but not equality of the stacks as a whole. Both sides are whitespace-collapsed because `vp fmt` decides where the CSS value wraps across lines. Co-Authored-By: Claude Opus 5 (1M context) --- apps/web/src/__fork_guards__/geistTypography.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/web/src/__fork_guards__/geistTypography.test.ts b/apps/web/src/__fork_guards__/geistTypography.test.ts index 7b395a6c530..bd8f42d0aa9 100644 --- a/apps/web/src/__fork_guards__/geistTypography.test.ts +++ b/apps/web/src/__fork_guards__/geistTypography.test.ts @@ -146,6 +146,18 @@ describe("fork guard: geist-typography", () => { expect(FORK_TERMINAL_FONT_FALLBACK).toContain('"JetBrains Mono"'); }); + it("keeps the module's fallback stack identical to the CSS mono stack", () => { + // FORK_TERMINAL_FONT_FALLBACK backs up the `--font-mono` read, so it has to + // stay the stack the cascade would have produced. Nothing else pins the two + // together: edit one, forget the other, and the safety net quietly stops + // matching what it backs up while every other guard here stays green. + // Collapsed on both sides — `vp fmt` decides where the CSS value wraps. + const collapse = (stack: string) => stack.replace(/\s+/gu, " ").trim(); + const declared = readSibling("../theme.custom.css").match(/--fork-font-mono:([^;]*);/u); + expect(declared).not.toBeNull(); + expect(collapse(declared?.[1] ?? "")).toBe(collapse(FORK_TERMINAL_FONT_FALLBACK)); + }); + it("keeps the terminal wired to the fork-owned font module", () => { const drawer = readSibling("../components/ThreadTerminalDrawer.tsx"); expect(drawer).toContain("fontFamily: resolveTerminalFontFamily(mount)"); From 4495f72c673322bb3ee06a7096d8f94677d1f502 Mon Sep 17 00:00:00 2001 From: noah Date: Sun, 26 Jul 2026 14:48:08 -0400 Subject: [PATCH 2/2] test(fork): compare the mono stacks as family lists, scoped to the marker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses review on #13. The first version compared two serializations of a font stack when the invariant is about the stack, and read the raw file where every sibling guard reads markerBlock(). A mutation matrix run against real vitest got 5 of 11 cases wrong: false positives CSS re-quoted to single quotes CSS commas without spaces inline comment inside the value false negatives a later .dark override with a different stack the declaration escaping the marker scope The false positives matter as a class: a guard that goes red on a reformat gets its failures read as noise, and the next person normalizes the CSS to match the string literal instead of asking whether the stack changed. Three changes. Parse both sides into a family list, so quoting and spacing stop counting as drift and the failure diff is an array diff rather than a 130-character string diff. Read through markerBlock(), matching every other guard here, so a declaration that loses its scoping fails. And assert the declaration appears exactly once, so a second copy cannot win the cascade while the guard checks whichever came first — the same shape as sidebarV2Rain.test.ts's "a sixth would mean the grid grew" assertion. The same matrix is now 11 of 11. Also corrects the rationale comment: the constant is what the cascade produces in a *marked* build. Co-Authored-By: Claude Opus 5 (1M context) --- .../__fork_guards__/geistTypography.test.ts | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/apps/web/src/__fork_guards__/geistTypography.test.ts b/apps/web/src/__fork_guards__/geistTypography.test.ts index bd8f42d0aa9..6420bf69385 100644 --- a/apps/web/src/__fork_guards__/geistTypography.test.ts +++ b/apps/web/src/__fork_guards__/geistTypography.test.ts @@ -43,6 +43,15 @@ function markerBlock(css: string): string { return css.slice(start, end); } +/** A CSS font stack as a comparable list — quoting and spacing are noise. */ +function fontFamilies(stack: string): string[] { + return stack + .replace(/\/\*[\s\S]*?\*\//gu, "") + .split(",") + .map((family) => family.trim().replace(/^["']|["']$/gu, "")) + .filter((family) => family.length > 0); +} + interface TerminalProbe { readonly target: ForkTerminalFontTarget; /** Every value written to `options.fontFamily`, in order. */ @@ -148,14 +157,19 @@ describe("fork guard: geist-typography", () => { it("keeps the module's fallback stack identical to the CSS mono stack", () => { // FORK_TERMINAL_FONT_FALLBACK backs up the `--font-mono` read, so it has to - // stay the stack the cascade would have produced. Nothing else pins the two - // together: edit one, forget the other, and the safety net quietly stops - // matching what it backs up while every other guard here stays green. - // Collapsed on both sides — `vp fmt` decides where the CSS value wraps. - const collapse = (stack: string) => stack.replace(/\s+/gu, " ").trim(); - const declared = readSibling("../theme.custom.css").match(/--fork-font-mono:([^;]*);/u); + // stay the stack the cascade produces in a marked build. Nothing else pins + // the two together: edit one, forget the other, and the safety net quietly + // stops matching what it backs up while every other guard here stays green. + const css = readSibling("../theme.custom.css"); + // Exactly one declaration: a second — a `.dark` variant, a media query, a + // stale copy quoted in a comment — would win the cascade in some state + // while this guard went on checking whichever came first in the file. + expect(css.match(/--fork-font-mono:/gu)).toHaveLength(1); + // Compared as family lists, not text: `vp fmt` decides where the value + // wraps, and `Consolas` and `"Consolas"` are the same family to CSS. + const declared = markerBlock(css).match(/--fork-font-mono:([^;]*);/u); expect(declared).not.toBeNull(); - expect(collapse(declared?.[1] ?? "")).toBe(collapse(FORK_TERMINAL_FONT_FALLBACK)); + expect(fontFamilies(declared?.[1] ?? "")).toEqual(fontFamilies(FORK_TERMINAL_FONT_FALLBACK)); }); it("keeps the terminal wired to the fork-owned font module", () => {