Skip to content

fix(cli): settle post-seek font subset loads before audit screenshots#2251

Merged
vanceingalls merged 1 commit into
mainfrom
07-11-fix_cli_settle_post-seek_font_subset_loads_before_audit_screenshots
Jul 11, 2026
Merged

fix(cli): settle post-seek font subset loads before audit screenshots#2251
vanceingalls merged 1 commit into
mainfrom
07-11-fix_cli_settle_post-seek_font_subset_loads_before_audit_screenshots

Conversation

@vanceingalls

@vanceingalls vanceingalls commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

What

Turns on a post-seek font-readiness wait by default for every visual-audit seek path (snapshot, check, compare, validate, layout) via waitForCompositionFonts. A seek can reveal glyphs whose font subsets were never requested before — forcing layout, giving the loader one frame, then awaiting document.fonts.ready. Pass waitForFontsMs: 0 to opt out.

Why

Multiple wild reports: Traditional Chinese and Microsoft YaHei text (declared via local @font-face) came back blank in check/snapshot output despite the font being present and correctly rendering in the real browser/draft render. CJK fonts commonly split into unicode-range subsets that only start loading once something actually lays out with that codepoint range — awaiting fonts.ready immediately (the old behavior) raced the load request.

Validation

Updated + new unit tests in captureCompositionFrame.test.ts (24 tests, including the new default-on behavior and the waitForFontsMs: 0 opt-out). Full CLI capture test suite green.

🤖 Generated with Claude Code

@miga-heygen miga-heygen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#2251 — settle post-seek font subset loads before audit screenshots

Verdict: LGTM 🟢

Fixes CJK snapshot race: unicode-range @font-face subsets only start loading when first laid out. After a seek reveals new glyphs, fonts.ready is already resolved (no subsets were requested yet), so the old code screenshotted blank CJK glyphs.

Fix: force synchronous layout (document.body.offsetHeight), wait one rAF for the browser to flip fonts.status to "loading", THEN await fonts.ready. If nothing is loading after the rAF, resolves immediately (no wasted wait on Latin-only comps). Bounded by 500ms deadline.

On by default for all visual-audit seek callers (snapshot, check, compare, validate, layout). waitForFontsMs: 0 disables. Existing render-grade callers with animationFrameSettle: "none" explicitly pass 0 — no behavior change for those paths. Clean.

Review by Miga

miguel-heygen
miguel-heygen previously approved these changes Jul 11, 2026

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head 8821646. Forced layout + rAF + fonts.ready ordering is bounded by the timeout and hidden-document rAF is covered by the deadline; waitForFontsMs=0 preserves opt-out. Targeted tests and required checks are green. APPROVE.

@james-russo-rames-d-jusso james-russo-rames-d-jusso left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 8821646.

Clean fix for the CJK-subset race — classify: this is a NARROW, not a preempt. Forcing a synchronous layout via void document.body?.offsetHeight; at packages/cli/src/capture/captureCompositionFrame.ts:308-314 triggers font resolution, which registers pending subsets in document.fonts synchronously; the one-rAF wait gives that registration a tick to reflect in fonts.status; the status !== "loading" || !ready short-circuit avoids awaiting a stale already-resolved ready promise from a previous generation. Bounded by the setTimeout(resolveWait, ms) deadline so fonts.ready never resolving can't hang the audit.

Opt-out semantics: undefined → default 500ms, explicit 0 → disabled entirely. Tests cover the default-on flip and the waitForFontsMs: 0 opt-out. Default-on is the right flip for the visual-audit surface (snapshot / check / compare / validate / layout are all users of seekCompositionTimeline and none should screenshot before glyphs paint) — the existing internal call at the layered-audit path already passes waitForFontsMs: 0 so the new default doesn't double-charge that route.

LGTM from my side.

Review by Rames D Jusso

jrusso1020
jrusso1020 previously approved these changes Jul 11, 2026

@jrusso1020 jrusso1020 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving per the channel stamp-flow: Rames-D and Magi both cleared, CI clean at 8821646.

@vanceingalls vanceingalls force-pushed the 07-11-fix_cli_settle_post-seek_font_subset_loads_before_audit_screenshots branch from 8821646 to 8bbd5a6 Compare July 11, 2026 21:18
@vanceingalls vanceingalls force-pushed the 07-11-fix_engine_densify_drawelement_self-verify_with_parallel_worker_count branch from a2a6810 to 1b95af8 Compare July 11, 2026 21:18
Base automatically changed from 07-11-fix_engine_densify_drawelement_self-verify_with_parallel_worker_count to main July 11, 2026 21:28
@vanceingalls vanceingalls dismissed stale reviews from jrusso1020 and miguel-heygen July 11, 2026 21:28

The base branch was changed.

@vanceingalls vanceingalls merged commit 68690e6 into main Jul 11, 2026
22 of 31 checks passed
@vanceingalls vanceingalls deleted the 07-11-fix_cli_settle_post-seek_font_subset_loads_before_audit_screenshots branch July 11, 2026 21:28
Sign up for free to 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.

5 participants