Skip to content

Bundle: Geist fonts, cn() extraction, and design-system doc/token pins (#2432 + #2430 + #2440 + #2431 + #2438) - #2432

Merged
BigSimmo merged 37 commits into
mainfrom
cursor/vendor-geist-021e
Aug 27, 2026
Merged

Bundle: Geist fonts, cn() extraction, and design-system doc/token pins (#2432 + #2430 + #2440 + #2431 + #2438)#2432
BigSimmo merged 37 commits into
mainfrom
cursor/vendor-geist-021e

Conversation

@BigSimmo

@BigSimmoBigSimmo commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Summary

This PR is a bundle of five originally separate low-risk changes, each a separately revertible commit, collapsed into one CI invocation. Every item was checked against classifyPullRequestFiles and returns clinicalRisk: false, operationalRisk: false, no RAG-ranking-surface path — the only two of the ten open PRs that do.

  • Vendor the Geist latin WOFF2 files instead of loading them from next-devtools (Bundle: Geist fonts, cn() extraction, and design-system doc/token pins (#2432 + #2430 + #2440 + #2431 + #2438) #2432).src/app/layout.tsx previously pulled Geist from node_modules/next/dist/next-devtools/server/font/, a Next.js overlay dev asset rather than a production font contract. The latin-subset WOFF2s now live in src/fonts/ with their SIL OFL licence and a README. Also declares weight: "100 900" on both faces: next/font/local only emits font-weight when it is set, and without the range on a variable font the @font-face carries no weight and browsers faux-bold headings. .gitattributes gains *.woff2 binary.
  • Extract cn() into src/lib/cn.ts (Extract cn() into src/lib/cn.ts #2430, re-applied).cn() is a pure class-name composer with no React or component dependency, so it does not belong in the component layer. primitive-recipes/recipes.ts re-exports it, which keeps ui-primitives.tsx's export * and the existing import { cn } from "./recipes" callers in clinical.tsx and feedback.tsx working unchanged.
  • Align SPEC, GATES and conventions with the live type tokens (docs(design-system): type-token alignment, 13px text-sm pin, mockup index fix (bundle of #2440 + #2431 + #2438) #2440).docs/design-system/SPEC.md §4.5 now describes the seven type steps as size-only: shared --leading-prose, hero companions --text-hero--line-height / --text-hero-tr only, and the live contract test name instead of the drifted :194-204 cite. docs/design-system/GATES.md §4 is split so the July 2026 tsc / lint / test / verify:ui bullets stay a historical snapshot while the check:design-system-contract bullet is re-quoted against the current baseline. .design-sync/conventions.md v2 copy corrected, with a NOTES.md line so the next remote sync does not restore per-step -lh/-tr. Pinned in tests/design-system-adoption.test.ts.
  • Pin production text-sm at 13px in the type catalog (Pin production text-sm at 13px in the type catalog #2431). v2 --text-sm equals @theme --text-sm-minus at 0.8125rem, pinned in tests/ckb-v2-token-contract.test.ts. Production text-sm already renders 13px because ckb-v2 is mounted on <html>; this records that overlap rather than restoring Tailwind's 14px or aliasing the two files at each other. Updates the docs that still listed text-sm as 14px, and fails closed if the @theme block has no closer.
  • Correct the stale Dictionary header recommendation in mockups/README.md (Correct stale Dictionary header recommendation in mockups/README.md #2438). The round-two write-up tagged Version 02 as the recommendation, but the commit that shipped this study to /dictionary/browse (PR Add Dictionary Browse header redesign study with three directions #2143) records Version 01 as the chosen direction. Corrects the table tag, adds a "Shipped: Version 01" note citing the shipping commit, and updates the topic index to reflect that all three routes stay regardless — rounds two and three both import code from round one's component file.

#2430 was re-applied, not merged

PR #2430 was authored before main split ui-primitives.tsx into primitive-recipes/*. On current main, cn() lives in primitive-recipes/recipes.ts and ui-primitives.tsx is four re-export lines, so #2430's diff no longer applies and its merge conflicts outright. The same intent was re-applied against the current structure and its location test retargeted from ui-primitives.tsx to primitive-recipes/recipes.ts.

Why these five and no others

The font and cn() halves each independently triggered the full heavy set — Build, four Chromium shards, Unit coverage and Lighthouse budget. The three documentation/pin items add no job to that run, so folding them in is free. Two of the doc items also edited docs/design-system/GATES.md, so keeping them apart guaranteed repeated conflicts as each landed.

Every other open PR is excluded by clause 1 of the bundling rule: #2433 on a genuine clinical path (src/lib/medication-records.ts); #2436, #2437 and #2441 on data/** generated snapshots; #2439, #2442, #2296 and #2297 on operational paths (CI workflow, Railway config, dependencies).

Verification

Run on the merged bundle head:

$ GATE_RECEIPTS=off node scripts/run-vitest.mjs run tests/design-system-adoption.test.ts tests/ckb-v2-token-contract.test.ts tests/tailwind-merge-config.test.ts tests/css-delivery-contract.test.ts
Test Files 4 passed (4)
Tests 117 passed (117)
$ npm run check:design-system-contract
Design-system contract passed (1036 production files; raw colors 0; literal shadows 0; legacy tap classes 0; sub-floor interactive min-heights 3; edge conflicts 5; 1px shadow spreads 0).
design-system adoption checked: 55 components, 76 roots
design-sync contract checked: 55 components and 7 guidelines

npm run lint and npm run typecheck both passed on the code-carrying head before the documentation items were folded in; the folded items are Markdown plus two test files already covered by the run above. npm run format run on the merged tree; Prettier clean.

  • npm run verify:pr-local — not run; the gates above cover every failure class this diff introduces, and each source branch passed hosted CI independently before bundling.
  • npm run verify:ui — not run locally. Font loading and class-name composition are app-wide, so the hosted Chromium set is the right gate and runs on this PR.
  • npm run verify:release — not run (provider-backed; not requested).
  • npm run eval:retrieval:quality — not applicable; no retrieval, ranking, selection, chunking or scoring change.
  • npm run eval:rag -- --limit 15 + npm run eval:quality -- --rag-only — not applicable; no answer-generation change.
  • npm run check:production-readiness — not applicable; no clinical workflow, privacy, environment, Supabase or source-governance change.
  • npm run check:deployment-readiness — not applicable; no deployment startup, hosting or rollout change.

Risk and rollout

  • Risk: Low, but the font half is app-wide by nature — it changes what every route loads. The vendored files are the same latin-subset Geist faces previously read from the next-devtools path, plus the weight range that fixes faux-bolding. The cn() move is a pure relocation behind a re-export with no call-site changes. The remaining three items are documentation and two contract-test pins with no runtime effect.
  • Rollback: each bundled item is its own commit and can be reverted alone; revert the whole PR to drop all five.
  • Provider or production effects: None. No OpenAI, Supabase, Railway or live database access.
  • RAG impact: none

Clinical Governance Preflight

Not required: this change does not touch ingestion, answer generation, search/ranking, source rendering, document access, privacy, production env, or clinical output. classifyPullRequestFiles returns clinicalRisk: false and operationalRisk: false for every path in this diff.

Notes


Note

Low Risk
App-wide font delivery changes what every route loads, but uses the same latin Geist files plus a weight-range fix; remaining work is docs, tests, and a pure cn() relocation behind a re-export.

Overview
Bundles five low-risk changes (separate revertible commits) to cut CI: production Geist now loads from vendored src/fonts/*.woff2 with SIL OFL, not next-devtools; next/font/local declares weight: "100 900" so variable faces don’t faux-bold headings. cn() lives in src/lib/cn.ts and is re-exported from primitive-recipes/recipes.ts with no call-site churn.

Docs and gates align with live v2 typography: size-only steps, shared --leading-prose, hero companions only—no per-step -lh/-tr; production text-sm at 13px (0.8125rem) matches v2 --text-sm and @theme --text-sm-minus, pinned in ckb-v2-token-contract and adoption tests. GATES §4 keeps July snapshot bullets while re-quoting check:design-system-contract (raw colours 0). mockups/README.md records Dictionary browse header Version 01 as shipped (not 02).

Reviewed by Cursor Bugbot for commit 04d1e1f. Configure here.

BigSimmoand others added 15 commits August 27, 2026 18:13
Primary actions on documents, compare, tools, calculators, forms, and chips still used sub-48px heights. Raise those controls to the tap floor so phone targets stay reachable without shrinking CTAs.
Co-authored-by: Cursor <cursoragent@cursor.com>
Metadata and disclosure controls were borrowing tap-floor or ad-hoc min-heights. Add --spacing-compact-meta (40px) and adopt it on those surfaces so primary CTAs stay at 48px.
Co-authored-by: Cursor <cursoragent@cursor.com>
Mode homes and compare/detail routes still hand-rolled headers, and the sidebar used raw buttons. Adopt PageHeader and Button so those surfaces share the same chrome and type weight as the rest of the shell.
Co-authored-by: Cursor <cursoragent@cursor.com>
Therapy, nav, and prescribing surfaces still used raw spacing and an undocumented type-scale map, and medication accent hex needed a fail-closed test. Tokenise those literals and pin the exemption so new debt cannot hide in the same files.
Co-authored-by: Cursor <cursoragent@cursor.com>
Remaining chrome still used raw duration, z-index, and radius literals, Ward motion ignored prefers-reduced-motion, and hash scroll could overshoot. Tokenise those values and clamp in-page scroll so reduced-motion and stacking stay on the documented ladder.
Co-authored-by: Cursor <cursoragent@cursor.com>
A-E paid down tap, compact-meta, PageHeader, TSX ratchets, and motion/z chrome. Refresh the contract baseline and generated adoption snapshot so the checker matches that new floor.
Co-authored-by: Cursor <cursoragent@cursor.com>
Production text-sm is 0.8125rem because ckb-v2 is mounted on html. Pin that
literal against @theme --text-sm-minus so the overlap cannot be "fixed" by
restoring Tailwind's 14px or by aliasing the two files at each other.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
…14px
The current type catalog still listed text-sm as 14px. Production renders
13px because v2 --text-sm equals @theme --text-sm-minus at 0.8125rem.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
indexOf("\\n}") returning -1 made slice() cover almost the whole stylesheet,
so the text-sm pin could pass against an unterminated @theme window. Use
sourceSegment so a missing closer is a named failure.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Stop loading production body fonts from next/dist/next-devtools.
Keep display:swap, preload the sans face, and leave mono preload:false.
Pin the src paths in the CSS delivery contract.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
@coderabbitai

coderabbitaiBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 8 minutes.

View limit details

Limit details: You’ve used the included review currently available. Your 102 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3e03638e-578c-4fd0-847c-d51ef309f173

📥 Commits

Reviewing files that changed from the base of the PR and between 675dfc2 and 3305f5f.

⛔ Files ignored due to path filters (10)
  • .design-sync/NOTES.md is excluded by !**/*.md
  • .design-sync/conventions.md is excluded by !**/*.md
  • docs/design-system-contract.md is excluded by !docs/**, !**/*.md
  • docs/design-system.md is excluded by !docs/**, !**/*.md
  • docs/design-system/GATES.md is excluded by !docs/**, !**/*.md
  • docs/design-system/SPEC.md is excluded by !docs/**, !**/*.md
  • mockups/README.md is excluded by !mockups/**, !**/*.md
  • src/fonts/README.md is excluded by !**/*.md
  • src/fonts/geist-latin.woff2 is excluded by !**/*.woff2
  • src/fonts/geist-mono-latin.woff2 is excluded by !**/*.woff2
📒 Files selected for processing (9)
  • .gitattributes
  • src/app/layout.tsx
  • src/components/primitive-recipes/recipes.ts
  • src/fonts/OFL.txt
  • src/lib/cn.ts
  • tests/ckb-v2-token-contract.test.ts
  • tests/css-delivery-contract.test.ts
  • tests/design-system-adoption.test.ts
  • tests/tailwind-merge-config.test.ts

Comment @coderabbitai help to get the list of available commands.

@supabase

supabaseBot commented Aug 27, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@BigSimmo
BigSimmo marked this pull request as ready for review August 27, 2026 12:36
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@cursor

cursorBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_abe946b9-3851-4611-a705-9bee064ea98a)

cursoragentand others added 10 commits August 27, 2026 12:47
Vendored WOFF2s are variable (wght 100–900). localFont() omitted weight, so
@font-face had no font-weight and browsers faux-bold headings.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Resolve conflicts in favour of main, which has since landed the same
design-system intent through the shared recipes and Button/PageHeader
adoption (PRs #2420, #2424, #2425, #2426):
- ui-primitives.tsx: main split the module into primitive-recipes/*; the
branch's compact-meta edits to `interactiveCompact` and
`tableMicroActionRow` are already present verbatim in recipes.ts.
- specifier compare/map/record/builder, differential-detail: main's
`primaryControl` / `Button` adoption carries the same `min-h-tap` floor
through `controlBase`, so the hand-rolled classes are superseded.
- formulation-builder: main's `fieldControlPlain` recipe supersedes the
hand-rolled textarea classes.
- pathways-screen: main's therapy-pathways redesign (#2413) already
removed the arbitrary spacing literals this branch was ratcheting.
Regenerate the contract baseline against the merged tree.
The round-two write-up tagged Version 02 as the recommendation, but the
commit that actually shipped this study to /dictionary/browse (PR #2143)
records Version 01 as the chosen direction. Confirmed via git history;
the earlier "(rec.)" tag was never updated after the decision changed.
Two failures the merge surfaced, both from this branch replaying work that
main has since taken in a different shape:
- factsheet-detail-page: drop `aria-hidden="true"` from the print portal.
It came from this branch's local replay of PR #2426, but the version
that merged to main deliberately does not carry it — hiding the portal
removes the printed document's `<h1>` and its fact-table row headers
from the accessibility tree, which is what
`tests/factsheet-detail-header.dom.test.tsx` exists to prevent.
- design-system-contract-utils: ratchet the globals.css raw CSS z-index
pin from 8 (set by #2421) to 4. The motion/z tokenisation in this branch
legitimately paid that debt down; the pin is a floor to lower, not raise.
Evidence: 898 test files / 10862 tests passed; lint, typecheck and
check:design-system-contract clean.
…e tokens
Rewrite SPEC §4.5 to the size-only scale (shared --leading-prose, hero companions only), split GATES §4 so the July snapshot stays historical while the contract bullet re-quotes raw colours 0, and correct the v2 conventions paragraph to the html mount. Pin the three claims in the adoption test so per-step -lh/-tr copy cannot return.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
PR #2427 (D, TSX ratchets) landed on main while this branch was being
reconciled. Its version of sidebar-live-shell.module.css is a superset of
this branch's: same --gap-tight / --space-1 / --space-2 snapping, plus the
collapsed rail height tokenised to calc(100dvh - var(--space-2)) so the
border box and its margins fit the viewport exactly. Take main.
Regenerate the contract baseline against the merged tree. The branch now
carries only E (globals motion/z, Ward reduced-motion, hash scroll clamp)
and the baseline refresh.
Evidence: 898 test files / 10862 tests passed; lint, typecheck and
check:design-system-contract clean.
PR #2428 (E, globals motion/z + Ward reduced-motion + hash scroll clamp)
landed on main, completing the A-E stack. Its version of the DS-P3-06
z-index pin is byte-identical to this branch's ratchet (8 -> 4, probe
9 -> 5), so take main and keep the file free of divergence.
The branch now contributes exactly one file over main — the regenerated
scripts/design-system-contract-baseline.json — which is what this PR is
for. Regenerating against the merged tree produced no further change.
Evidence: 898 test files / 10862 tests passed;
check:design-system-contract, adoption and design-sync all clean.
Keep the wording pins, and also fail if SPEC §4.5 or conventions name --text-{xs..xl}-lh/-tr or --line-height orphans. Hero companions remain required.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
@cursor

cursorBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_3d107a44-a7bd-4b14-b7f0-7a1c4025a1b1)

Re-applies PR #2430's intent onto main's current structure. #2430 was
authored before main split ui-primitives.tsx into primitive-recipes/*,
so its diff no longer applies: cn() now lives in
primitive-recipes/recipes.ts, not ui-primitives.tsx.
recipes.ts re-exports cn from the new module, so ui-primitives.tsx's
`export *` and the existing `import { cn } from "./recipes"` callers in
clinical.tsx and feedback.tsx are unaffected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JiaghcKco9xE3vLS4PJHdd
@BigSimmoBigSimmo changed the title Vendor Geist latin fonts instead of next-devtoolsVendor Geist latin fonts and extract cn() into src/lib/cn.ts (bundle of #2432 + #2430)Aug 27, 2026
@BigSimmoBigSimmo changed the title Vendor Geist latin fonts and extract cn() into src/lib/cn.ts (bundle of #2432 + #2430)Bundle: Geist fonts, cn() extraction, and design-system doc/token pins (#2432 + #2430 + #2440 + #2431 + #2438)Aug 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

CI triage

CI failed on this PR. Automated classification of the 2 failed job(s):

  • Production UI (3)not baselined: this job did NOT run on the main comparison below (path-scoped skip), so that run says nothing about it either way. Treat the comparison as absent, not green, and inspect the failing step.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

Compared with main CI run #14346 (success). That run's conclusion is an aggregate and did not exercise Production UI (3).

Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger.

@cursor

cursorBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_70ec00a6-1740-4028-9cfc-1fe1fa6882fc)

@BigSimmo
BigSimmo enabled auto-merge August 27, 2026 17:22
@BigSimmo
BigSimmo merged commit 955e1c9 into mainAug 27, 2026
29 checks passed
@BigSimmo
BigSimmo deleted the cursor/vendor-geist-021e branch August 27, 2026 17:33
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@BigSimmo@cursoragent@claude