Skip to content

chore(devx): Phase 4 — font-pinned canonical rendering stack for visual tests - #403

Merged
pftg merged 4 commits into
masterfrom
claude/devx-phase4-rendering-stack
Jul 30, 2026
Merged

chore(devx): Phase 4 — font-pinned canonical rendering stack for visual tests#403
pftg merged 4 commits into
masterfrom
claude/devx-phase4-rendering-stack

Conversation

@pftg

@pftg pftg commented Jul 30, 2026

Copy link
Copy Markdown
Member

Summary

Phase 4 of the approved DevX plan — the fix for "bin/rake test:critical is red on every machine that isn't blessed". Root cause: the linux/ screenshot baselines are recorded by an Alpine/musl Docker image whose text rendering diverges 3–28% from every glibc Linux (the documented reason a CI screenshot job was removed in #386). This PR defines ONE pinned rendering stack and installs it identically in the Docker recorder and on bare metal:

  • .dev/Dockerfile: ruby:3.4-alpineruby:4.0-slim (glibc — Chrome for Testing is glibc-only, so Alpine could never host the pinned browser; also retires the third stray Ruby version). Installs pinned Chrome for Testing + matching chromedriver from .dev/cft-version (141.0.7390.37), wired through the CHROME_BIN/CHROMEDRIVER_PATH hooks from Phase 3 (chore(devx): Phase 3 — test portability + baseline overwrite safety #400 — this PR is stacked on it and auto-retargets to master when it merges). Browser runtime libs are resolved across Debian's t64 package renames so the build works on either side of the transition.
  • .dev/fonts.conf: deterministic fontconfig (hintslight, grayscale antialiasing, no embedded bitmaps, no autohint) installed as /etc/fonts/local.conf; font set pinned to fonts-noto-core + fonts-freefont-ttf + fonts-dejavu-core.
  • bin/setup-test-env: installs the identical stack on bare-metal Linux — CfT cached under ~/.cache/jt-cft/<version>/, same fonts and fontconfig; eval "$(bin/setup-test-env --print-env)" exports the browser env vars.
  • .gitignore: !.dev negation (the blanket .* rule silently dropped the two new pin files from the first commit — the documented .agents/ trap, now recorded for .dev/ too).

Verified in this container (bare-metal side)

  • bin/setup-test-env end-to-end: CfT 141.0.7390.37 + matching chromedriver download and report their versions; fonts install; fontconfig lands at /etc/fonts/local.conf.
  • A system screenshot test runs green through the pinned stack (color_system_test: 1 run, 3 assertions, 0 failures).

⚠️ Remaining step before merge (needs a Docker-capable machine)

This agent container cannot pull Docker Hub images through its proxy, so the image build and re-baseline could not run here:

  • bin/docker-rebuild (or bin/dc build t) — build the new Debian image
  • FORCE_SCREENSHOT_UPDATE=true bin/dtest — re-record all linux/ baselines on the new stack
  • Commit the re-recorded baselines to this branch (repo rule: baseline updates ride the commit that changes rendering)
  • Acceptance check: bare-metal eval "$(bin/setup-test-env --print-env)" && bin/rake test:critical → 0 environmental screenshot failures

Until the re-baseline lands, the committed linux/ baselines are still Alpine-rendered and bin/dtest on the new image will report diffs — expected, not a regression.

Part of the phased DevX series: #397, #399, #400 (base), #401.


🤖 Generated with Claude Code

https://claude.ai/code/session_01PXHeUErqoiyH9xN1mjC8cH


Generated by Claude Code

claude added 3 commits July 30, 2026 14:56
Phase 3 of the DevX plan:

- setup_capybara.rb: CHROME_BIN and CHROMEDRIVER_PATH env overrides for
  machines where Chrome is not auto-discoverable (agent containers,
  custom installs). Proven end-to-end: color_system test green in a
  container using Playwright Chromium + a matching chromedriver.
- Dirty-baseline guard promoted from bin/qtest to system-test load:
  every runner (bin/test, bin/dtest, rake tasks) now refuses to start
  while test/fixtures/screenshots is dirty - snap_diff rewrites the
  committed baselines in place on every run, so a dirty start is
  unjudgeable and one `git add -A` from committing corrupted baselines.
  Companion task `rake test:screenshots:reset`; bypass with
  ALLOW_DIRTY_SCREENSHOTS=1. Degrades to a no-op without git.
- Force encoding "bom|utf-8" on all 11 File.read sites in lib/
  (course_validators.rb, sync/post_storage.rb): validators crashed with
  "invalid byte sequence in US-ASCII" under non-UTF-8 locales.
  LANG=C bin/validate-course now passes.

Verification: guard aborts on a dirtied PNG with the fix message and
passes clean; reset task restores; course_validators unit suite green
(32 runs); full validator run green under LANG=C.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXHeUErqoiyH9xN1mjC8cH
Phase 4 of the DevX plan. The linux/ screenshot baselines were recorded
on Alpine/musl, which renders text 3-28% differently from every glibc
Linux (dev machines, agent containers, CI runners) - the root cause of
"25 failures on any non-blessed machine". Define ONE pinned stack and
install it identically everywhere:

- .dev/Dockerfile: ruby:3.4-alpine -> ruby:4.0-slim (glibc; also
  retires the third stray Ruby version). Pinned Chrome for Testing +
  matching chromedriver from .dev/cft-version (141.0.7390.37), wired
  via the CHROME_BIN/CHROMEDRIVER_PATH hooks from Phase 3. Browser
  runtime libs resolved across Debian's t64 package renames.
- .dev/fonts.conf: deterministic fontconfig (hintslight, grayscale AA,
  no embedded bitmaps, no autohint) installed as /etc/fonts/local.conf
  in the image; fonts-noto-core + freefont + dejavu pinned as the font
  set.
- bin/setup-test-env: installs the identical stack on bare-metal Linux
  (CfT cached in ~/.cache/jt-cft/<version>, same fonts + fontconfig);
  `eval "$(bin/setup-test-env --print-env)"` exports the browser env.

Verified bare-metal in this container: CfT 141.0.7390.37 + matching
driver install cleanly, fontconfig lands, and a system screenshot test
runs green through the pinned stack.

NOT yet done (this container cannot pull Docker Hub images through the
agent proxy): build the new image and re-record linux/ baselines via
FORCE_SCREENSHOT_UPDATE=true bin/dtest - that one-time re-baseline must
ride this PR from a Docker-capable machine before merge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXHeUErqoiyH9xN1mjC8cH
… cft-version and fonts.conf

The repo .gitignore ignores all dotfiles (.*); tracked files under .dev/
survived, but the two NEW rendering-stack pins were silently excluded
from the previous commit - the exact trap documented in .okf for
.agents/. Added the !.dev negation and committed both files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXHeUErqoiyH9xN1mjC8cH
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@pftg, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 33 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 44824816-9e9c-473a-98e7-59b0d2222dc1

📥 Commits

Reviewing files that changed from the base of the PR and between 16c6712 and 58b71f2.

📒 Files selected for processing (6)
  • .dev/Dockerfile
  • .dev/cft-version
  • .dev/fonts.conf
  • .gitignore
  • .okf/log.md
  • bin/setup-test-env

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Base automatically changed from claude/devx-phase3-test-portability to master July 30, 2026 15:17
@pftg
pftg marked this pull request as ready for review July 30, 2026 15:19
@pftg
pftg merged commit 45c8823 into master Jul 30, 2026
2 checks passed
@pftg
pftg deleted the claude/devx-phase4-rendering-stack branch July 30, 2026 15:19
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.

2 participants