Phase 1a.4: one eyebrow style (4 variants → 1) - #528
Conversation
"ONE eyebrow style" - first bundle-group. The canonical form is the blog's, which shipped in Phase 2 and the plan records as already done (pages/blog-list.css `.blog-eyebrow`): 12px / 700 / 0.14em tracking / uppercase / --color-ruby. services-critical.css carried a near-miss: --color-ruby and weight 600, no size, tracking or transform. Now matches, keeping `text-align: center` which is layout rather than type. The markup already says "SERVICES" in caps, so `text-transform` is a no-op here and the visible delta is size, weight and tracking only - worth knowing before reading the diff as larger than it is. Verified by looking, not by a green suite: the section screenshot at 0.02 tolerance would not reliably catch a small type change, so I read the rendered `services/_overview.png`. The eyebrow renders small, ruby, tracked and legible above the H1. Gate: bin/test - [snap_diff] 53 screenshots compared, 3 failures, all the intended eyebrow change (services/_overview, services/_services, mobile/services), reviewed and accepted. bin/hugo-build clean. macOS only. Three variants remain for the following commits: careers-critical.css, components/content-block.css, and pages/friday-report.css (which also deviates on colour, using --ruby-700). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
careers-critical.css, components/content-block.css and pages/friday-report.css now match pages/blog-list.css `.blog-eyebrow`: 12px / 700 / 0.14em / uppercase / --color-ruby. Four variants become one. friday-report was the largest deviation - 13px, weight 600, 0.18em tracking, and --ruby-700 rather than --color-ruby. **The suite is green and that proves nothing here.** None of these three pages is in the screenshot set, so `[snap_diff] 53 screenshots compared, no failures` means "not captured", not "unchanged" - exactly the trap the phase brief warns about for eyebrows. Verified by computed style in the rendered production build instead: fontSize 12px · fontWeight 700 · letterSpacing 1.68px (= 0.14em x 12) · textTransform uppercase · color rgb(204,52,45) **Contrast measured, because this commit darkens nothing and lightens one thing.** Moving friday-report from --ruby-700 to --color-ruby reduces contrast. Against that page's actual background - rgb(253,245,244), a warm tint rather than white - the ratio is **4.77:1**. That passes AA for normal text (4.5:1), but the margin is thin: on pure white the same pair is ~5.1:1, and any future darkening of that tint would push it under. Recorded so the next person to touch that surface knows the eyebrow is the constraint. Gate: bin/test - [snap_diff] 53 screenshots compared, no failures, no baseline moved. bin/hugo-build clean. macOS only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 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. Comment |
Screenshot diffs detected
|
Review caught it and the cascade confirms it: `pages/careers.css:1215` re-declares the identical selector (`.fl-builder-content .careers-why-us-eyebrow .fl-rich-text`) with `font-weight: 600`, and pages/ loads AFTER critical/ at equal specificity. My edit to careers-critical.css could never take effect. Reverted rather than left in. A change that looks like work and does nothing is worse than no change: it reads as "careers is done" to the next person, and the green suite would not contradict them because careers is not in the screenshot set at all. Scope correction that follows from the same finding: **"one eyebrow style" is 41 FL eyebrow rules across 8 files**, not the four I found by grepping for the obvious names - homepage (11), single-service (7), about-us (6), single-use-cases (5), services-critical (4), careers (3), careers-critical (3), use-cases (2). Aligning 41 copies is the wrong shape anyway; the intent is ONE definition. That needs a centralised rule plus a load-order decision so it wins against the per-page declarations, which is a design call rather than a sweep. What remains in this branch is verified and effective: services-critical (rendered and read), components/content-block, and pages/friday-report (computed style confirmed, contrast measured at 4.77:1). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Attempted the full sweep review asked for (all 41 FL eyebrow rules) and reverted it — it introduces a WCAG AA failure. Measured in the rendered production build:
The canonical eyebrow ( "One eyebrow style" cannot be one style. Eyebrows sit on both light and dark surfaces, so the canonical form needs a dark-surface variant with a lighter ruby — a design decision, not a mechanical sweep. This PR keeps only the three conversions verified safe on light surfaces: Branch is green: |
Measured in the rendered production build, and the second consequence is the one worth having: | Token | on #000 | on --surface-ink #14110f | |---|---|---| | --color-ruby #cc342d | 4.10 FAIL | 3.67 FAIL | | --color-ruby-hover #e04a42 | 5.23 pass | 4.68 pass (thin) | | --ruby-700 #9e2620 | 2.75 FAIL | 2.46 FAIL | **1. "ONE eyebrow style" is self-contradictory as written.** The canonical eyebrow was designed against the blog's LIGHT surfaces. Applied site-wide it drops home-services-eyebrow and home-clients-eyebrow to 4.10:1 on their dark band - below AA for normal text, which 12px unambiguously is. I swept all 41 rules, measured, and reverted rather than ship it. **2. Migrating the dark bands to --surface-ink makes contrast WORSE.** #14110f is lighter than #000, so ruby-on-dark falls 4.10 -> 3.67. That links the two blocked items: the footer/dark-surface work cannot ship before the on-dark accent is decided, or it degrades contrast on every band it touches. Nothing in the plan connects them, and a sweep done in either order alone would have regressed accessibility silently - those homepage sections carry no contrast test. Only --color-ruby-hover clears AA on both grounds, and it is named for a hover state, so using it as a static accent is semantically wrong. The ramp has --ruby-700 for "text-on-light where AA needs more" and no counterpart for dark. Naming one is a design call, not a sweep, so it goes to Outstanding rather than into a commit. Docs only. bin/hugo-build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two review findings, both verified and fixed.
**friday-report had no screenshot coverage, and the test said to add it here.**
`desktop_site_test.rb` carried, verbatim: "No screenshot baseline yet: the 2608
site-wide recolour is mid-flight and would churn it immediately. Record with the
bundle's first visual PR." This IS that PR - 1a.4 moved `.friday-eyebrow` onto
the canonical style - so computed-style checks alone were the only thing
guarding a visual change.
Adding the assertion was not enough on its own: `friday_report` is not in
`CRITICAL_TESTS`, so `bin/test` skipped it and the suite reported 34 runs / 53
screenshots exactly as before. Coverage that never executes is the same
"looks like work, does nothing" failure as the careers eyebrow earlier on this
branch, so `friday_report` is now in the critical list. Suite goes 34 -> 36 runs,
87 -> 99 assertions, and two baselines record.
Baselines reviewed before committing, not merely captured: mean brightness 0.963
(not a black or error frame) and the render read end to end - nav, hero, the
canonical ruby eyebrow, canon-compliant proof chips, disclaimer, report body.
**The AA blocker was only in the project README, which is not on the path.**
`design/site-palette.md` now carries the measured table and a standing rule:
until an on-dark ruby is named, do not apply a ruby text token to any of the
three deliberate dark surfaces. AGENTS.md routes sessions through OKF, not
through a project README - the same "recorded but not on the path" failure this
branch already hit once with the stitch route.
Gate: bin/test - 36 runs, 99 assertions, 0 failures, [snap_diff] 53 screenshots
compared, no failures, plus 2 newly recorded. bin/hugo-build clean.
okf_validate .okf exits 0 conformant; --strict exits 1 by design on this bundle.
NOT done, and flagged for the fourth time: Linux baselines. Scoped out by Paul
("handled in parallel PR, ignore for now") and unrecordable locally without
planting false drift.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
**My PurgeCSS check was a false green.** I cited `grep -rc 'c-button--primary' _dest/public-dev/css/*.css` returning nothing. That command returns nothing whether or not the component is adopted: public-dev is built in DEV mode where PurgeCSS is disabled, and this CSS is emitted INLINE in the HTML rather than under css/*.css. Re-verified against the production tree - `grep -rl 'c-button' _dest/public-test/` returns nothing and components.css is not referenced from index.html - so the conclusion survives, but the evidence I published for it did not. Both are now recorded, because "right answer, wrong proof" is the failure that makes the NEXT claim untrustworthy. **The live buttons are five families, not one.** `.fl-button`, `.btn`/ `.btn-primary` (navigation), `.btn--primary` (shortcodes/cta), `.action-button` (use-cases) and `.pp-button` (services). My "sweep `.fl-button`" framing would have left four families outside the roles. **The tags deliverable had vanished from the matrix.** My four-row table silently replaced "tags to ink site-wide" - an actual scope item - with the `--rr-*` alias deletion, which the brief lists separately. An executor reading it would skip the 17-bundle tag work entirely. Tags restored as an OPEN row, honestly marked NOT investigated, and the alias row relabelled as the separate deletion item. **The plan linked to a blocker absent from this branch.** It was cut from a stale origin/master predating #528. Rebased onto current master; the ruby-on-dark Outstanding entry the note points at now exists here. Docs only; bin/hugo-build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ed (#529) * "Three button roles" is already built and never adopted Investigated the last untouched 1a.4 item. `components/c-button.css` already defines exactly three roles - --primary (ruby/white), --secondary (white/dark), --tertiary (transparent/ruby) - and is already tokenised apart from four `#ffffff` literals. I tokenised those literals, then checked whether it mattered and reverted: **`c-button--*` appears ZERO times in any template or content file**, and PurgeCSS strips it from every shipped bundle - `grep -rc 'c-button--primary' _dest/public-dev/css/*.css` returns nothing. The component was built and never adopted; the live buttons are FL Builder's `.fl-button`. Reverting rather than shipping was the point. A tidy diff against dead code reads as "button roles: done" to the next person and changes nothing a visitor sees - the third instance of that failure on this phase, after the careers eyebrow (overridden by a later file) and the friday screenshot assertion (excluded from CRITICAL_TESTS). The real item is either adopting c-button in templates (a markup migration) or bringing `.fl-button` onto the three roles (another sweep through the per-page FL export CSS). Both are larger than the plan line implies, and the second is the same legacy-export problem as the footer and eyebrow items. The tertiary role also sits on the on-dark AA blocker wherever it lands on a dark band. Recorded in Outstanding. Docs only; bin/hugo-build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Correct the 1a.4 plan against what execution actually found Recording measured reality in the plan itself, because the next session reads the plan and would otherwise re-estimate the same four items the same way. One of four items was what the line said. The alias deletion shipped first try with zero visual delta. The other three are materially different work: * Footer onto surface-ink is not a footer change - it is one edge of a dark region built from a CSS background, an SVG fill on a pointer-events:none shape layer, and a painter still unidentified. 7+ bundles, 1b in size. * One eyebrow style cannot be one style - the canonical form was designed against LIGHT surfaces and drops two homepage eyebrows to 4.10:1 when applied site-wide. Swept, measured, reverted. * Three button roles is already built and never adopted - c-button--* appears zero times in markup and PurgeCSS strips it from every bundle. And the connection nothing in the plan made: **two of them are gated by the same missing token.** --color-ruby is 4.10:1 on #000 and 3.67:1 on --surface-ink, so the dark-surface migration makes contrast WORSE. Eyebrows and the tertiary button role both sit on it. Also recorded, because it is the transferable part: the estimates were written against the TOKEN layer while the work is against the FL-Builder export CSS that redeclares everything per page. Three changes this phase looked complete, passed every gate, and did nothing at runtime - an eyebrow rule overridden by a later file, a screenshot assertion excluded from CRITICAL_TESTS, and a tokenisation of purged dead code. The plan now tells the next session to verify a change reaches the rendered page before counting it done. Docs only; bin/hugo-build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Fix all four review findings, including a false green in my own evidence **My PurgeCSS check was a false green.** I cited `grep -rc 'c-button--primary' _dest/public-dev/css/*.css` returning nothing. That command returns nothing whether or not the component is adopted: public-dev is built in DEV mode where PurgeCSS is disabled, and this CSS is emitted INLINE in the HTML rather than under css/*.css. Re-verified against the production tree - `grep -rl 'c-button' _dest/public-test/` returns nothing and components.css is not referenced from index.html - so the conclusion survives, but the evidence I published for it did not. Both are now recorded, because "right answer, wrong proof" is the failure that makes the NEXT claim untrustworthy. **The live buttons are five families, not one.** `.fl-button`, `.btn`/ `.btn-primary` (navigation), `.btn--primary` (shortcodes/cta), `.action-button` (use-cases) and `.pp-button` (services). My "sweep `.fl-button`" framing would have left four families outside the roles. **The tags deliverable had vanished from the matrix.** My four-row table silently replaced "tags to ink site-wide" - an actual scope item - with the `--rr-*` alias deletion, which the brief lists separately. An executor reading it would skip the 17-bundle tag work entirely. Tags restored as an OPEN row, honestly marked NOT investigated, and the alias row relabelled as the separate deletion item. **The plan linked to a blocker absent from this branch.** It was cut from a stale origin/master predating #528. Rebased onto current master; the ruby-on-dark Outstanding entry the note points at now exists here. Docs only; bin/hugo-build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The re-record was dispatched to CI on this branch (run 32526977795, native
amd64 - the only trusted way to record linux/ baselines; local ARM Docker
plants false drift) and succeeded. FORCE_SCREENSHOT_UPDATE re-records
EVERYTHING, so the bot commit touched 83 files and needed screening.
Screened with the gate's OWN instrument rather than by eye or by file size:
capybara-screenshot-diff counts a pixel as differing only above
perceptual_threshold = 2.0 dE00, and the default tolerance is now 0.0001 of
the frame. Computing that same libvips dE00 fraction for every file in the bot
commit splits it cleanly:
keep 77 would FAIL the gate, so the rewrite is real
drop 6 difference_level exactly 0.00000000 - would have PASSED
The 6 dropped are pure encoder churn with zero perceptual difference:
desktop+mobile course/landing, desktop+mobile blog/special/codeblocks/text,
clients/agent-inbox/_overview, clients/single-full.
Of the 77 kept, 8 are NEW keys with no linux baseline at all - friday_report
(desktop+mobile) and the three register pilots next/{editorial,precision,
rescue-room} (desktop+mobile) - and the rest span 0.000139 to 0.973.
Why the Linux set is broader than the macOS one (77 vs 50), which looks wrong
until you check it: earlier PRs re-recorded only the macOS side. #528 committed
macos/mobile/services.png and left its linux/ twin stale, so linux/mobile/services
carries a visible vertical shift that macOS no longer has - confirmed by
painting the dE00 mask over the capture: identical content, offset position.
The reverse also holds - linux/desktop/blog/special/inline_style_post barely
moves (0.000139) because the Linux blog baselines were already re-recorded
after #520, while macOS was 25% stale. Neither OS is a subset of the other.
Two kept files were inspected directly rather than accepted on their number:
linux/desktop/404.png (0.001235) is a 4px-wide strip at the right edge - a
scrollbar artifact, page content identical, and 4 x 640 px is exactly the
reported difference_level; linux/mobile/services.png (0.1389) is the #528
shift above. Both render correctly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ
…pting The macOS visual suite has been red on master since #540. `bin/rake test:system` at clean HEAD: 79 runs, 26 failures, 134 screenshots compared, 48 failures. All 48 are correctly-detected staleness, not regressions - nothing here was verified by difference_level alone. Why they went stale: a green run restores the git-HEAD image over the fresh capture, so any change small enough to pass fossilizes the baseline. #540 was large enough to fail and simply was not re-recorded; the rest had been accumulating under the old 0.02 default since #520 and #528. Classification (baseline-vs-candidate pixel transitions, not diff levels): 42 #540 dark-surface recolour. rgb(0,0,0) -> rgb(20,17,15) accounts for 94-100% of every changed pixel in each file (--surface-ink #14110f). Footers, CTA bands, contact_us, both pagination frames, codeblock frames - the same surfaces #540's own commit message lists as failing. 3 Post `description` backfilled by #520, which the post template renders as a grey lead above the body, pushing content down. Verified the rendered text is the frontmatter string verbatim, e.g. stimulus-keyboard-event-filter: "In the last update of Stimulus v3.2.2, the ability to filter the event by PageDown and PageUp keys was added." (desktop+mobile code_highlight_post, inline_style_post) 2 Course module eyebrow added by #552 - "MODULE 1 - HYPOTHESIS & SMOKE TEST" now renders in ruby above the H1, shifting the page down. (desktop+mobile course/chapter) 1 services/_testimonials-header: a 1px vertical offset from #528's eyebrow consolidation. #528 touched services-critical.css and content-block.css and re-recorded only the two sections that exceeded 0.02; the sections below the eyebrow shifted 1px, passed under the old default, and fossilized. Measured, not inferred: realigning the baseline by dy=+1 drops the residual to exactly 0.0000, i.e. the content is pixel-identical and only its position moved. Evidence that these are stale baselines rather than flaky rendering: two consecutive runs of DesktopSiteTest#test_services reported difference_levels identical to 17 decimal places (_technologies 0.013838252314814815, _use-cases 0.01749807098765432, _testimonials-header 0.005922550154320988), and a second full-suite run produced the same 48-file set. One instrument error worth recording, since it nearly became a finding: the first transition script loaded each baseline from a reused temp filename, and libvips caches operations by filename - so runs 2..n silently re-compared image 1. It reported services/_footer's baseline as a pure-black frame. A brightness audit over all 155 tracked macOS baselines refuted it (darkest mean is 69/255, none below 1.0), and reloading from git buffers fixed it. The control that keeps the rewritten script honest: an unchanged baseline (desktop/vibe_code_rescue) reports exactly 0 changed pixels. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ
…easured SECTION_CONFIGS was introduced one day ago as an explicitly TEMPORARY shield holding ~22 section screenshots at the old 0.02 tolerance while their drift was unmeasured, with the exit condition written into its own comment: "delete it once they are measured and re-recorded." Measured both ways on the full macOS system suite, same environment, only this variable changed: shield in place 134 screenshots compared, 48 failures shield emptied 134 screenshots compared, 50 failures Cost of deleting it: +2 screenshots, both on /services/ - desktop/services/_use-cases (0.017498) and desktop/services/_technologies (0.013838). Both are the same 1px vertical offset from #528's eyebrow consolidation already classified in the previous commit: realigning baseline to candidate by one pixel drops the residual to exactly 0.0000 in several bands, so the content is pixel-identical and only its position moved. Both are re-recorded here, which is the last thing the exit condition asked for. Deleted: SECTION_CONFIGS, screenshot_config_for, extract_section_key, test/support/screenshot_section_config.rb and its unit test. That file existed so the table could be unit-tested without booting Hugo or Capybara; with the table gone there is no logic left to test, only a constant. DEFAULT_SCREENSHOT_CONFIG moves onto ApplicationSystemTestCase unchanged at 0.0001. Per-call tolerances are untouched - ~30 calls pin their own, mostly 0.03, and those still win over the default. Gates, all on this exact tree: bin/rake test:unit 287 runs, 6143 assertions, 0 failures bin/hugo-build clean, 8 validators passed bin/rake test:system 79 runs, 218 assertions, 0 failures [snap_diff] 134 screenshots compared, no failures The suite was run with the shield deleted BEFORE these two baselines were accepted, and reported exactly the 2 predicted failures and no others - so the deletion is measured, not assumed. .okf/build/test-gates.md is updated: the shield paragraph is replaced by the measurement, and a misattribution is corrected. That file claimed all five failing /services/ screenshots were the #540 dark-surface recolour; only the two large ones are. The three small ones carry 0.13% or less of the black->ink transition and are #528's 1px shift. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ
The re-record was dispatched to CI on this branch (run 32526977795, native
amd64 - the only trusted way to record linux/ baselines; local ARM Docker
plants false drift) and succeeded. FORCE_SCREENSHOT_UPDATE re-records
EVERYTHING, so the bot commit touched 83 files and needed screening.
Screened with the gate's OWN instrument rather than by eye or by file size:
capybara-screenshot-diff counts a pixel as differing only above
perceptual_threshold = 2.0 dE00, and the default tolerance is now 0.0001 of
the frame. Computing that same libvips dE00 fraction for every file in the bot
commit splits it cleanly:
keep 77 would FAIL the gate, so the rewrite is real
drop 6 difference_level exactly 0.00000000 - would have PASSED
The 6 dropped are pure encoder churn with zero perceptual difference:
desktop+mobile course/landing, desktop+mobile blog/special/codeblocks/text,
clients/agent-inbox/_overview, clients/single-full.
Of the 77 kept, 8 are NEW keys with no linux baseline at all - friday_report
(desktop+mobile) and the three register pilots next/{editorial,precision,
rescue-room} (desktop+mobile) - and the rest span 0.000139 to 0.973.
Why the Linux set is broader than the macOS one (77 vs 50), which looks wrong
until you check it: earlier PRs re-recorded only the macOS side. #528 committed
macos/mobile/services.png and left its linux/ twin stale, so linux/mobile/services
carries a visible vertical shift that macOS no longer has - confirmed by
painting the dE00 mask over the capture: identical content, offset position.
The reverse also holds - linux/desktop/blog/special/inline_style_post barely
moves (0.000139) because the Linux blog baselines were already re-recorded
after #520, while macOS was 25% stale. Neither OS is a subset of the other.
Two kept files were inspected directly rather than accepted on their number:
linux/desktop/404.png (0.001235) is a 4px-wide strip at the right edge - a
scrollbar artifact, page content identical, and 4 x 640 px is exactly the
reported difference_level; linux/mobile/services.png (0.1389) is the #528
shift above. Both render correctly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ
* Re-record 48 stale macOS baselines: every diff classified before accepting The macOS visual suite has been red on master since #540. `bin/rake test:system` at clean HEAD: 79 runs, 26 failures, 134 screenshots compared, 48 failures. All 48 are correctly-detected staleness, not regressions - nothing here was verified by difference_level alone. Why they went stale: a green run restores the git-HEAD image over the fresh capture, so any change small enough to pass fossilizes the baseline. #540 was large enough to fail and simply was not re-recorded; the rest had been accumulating under the old 0.02 default since #520 and #528. Classification (baseline-vs-candidate pixel transitions, not diff levels): 42 #540 dark-surface recolour. rgb(0,0,0) -> rgb(20,17,15) accounts for 94-100% of every changed pixel in each file (--surface-ink #14110f). Footers, CTA bands, contact_us, both pagination frames, codeblock frames - the same surfaces #540's own commit message lists as failing. 3 Post `description` backfilled by #520, which the post template renders as a grey lead above the body, pushing content down. Verified the rendered text is the frontmatter string verbatim, e.g. stimulus-keyboard-event-filter: "In the last update of Stimulus v3.2.2, the ability to filter the event by PageDown and PageUp keys was added." (desktop+mobile code_highlight_post, inline_style_post) 2 Course module eyebrow added by #552 - "MODULE 1 - HYPOTHESIS & SMOKE TEST" now renders in ruby above the H1, shifting the page down. (desktop+mobile course/chapter) 1 services/_testimonials-header: a 1px vertical offset from #528's eyebrow consolidation. #528 touched services-critical.css and content-block.css and re-recorded only the two sections that exceeded 0.02; the sections below the eyebrow shifted 1px, passed under the old default, and fossilized. Measured, not inferred: realigning the baseline by dy=+1 drops the residual to exactly 0.0000, i.e. the content is pixel-identical and only its position moved. Evidence that these are stale baselines rather than flaky rendering: two consecutive runs of DesktopSiteTest#test_services reported difference_levels identical to 17 decimal places (_technologies 0.013838252314814815, _use-cases 0.01749807098765432, _testimonials-header 0.005922550154320988), and a second full-suite run produced the same 48-file set. One instrument error worth recording, since it nearly became a finding: the first transition script loaded each baseline from a reused temp filename, and libvips caches operations by filename - so runs 2..n silently re-compared image 1. It reported services/_footer's baseline as a pure-black frame. A brightness audit over all 155 tracked macOS baselines refuted it (darkest mean is 69/255, none below 1.0), and reloading from git buffers fixed it. The control that keeps the rewritten script honest: an unchanged baseline (desktop/vibe_code_rescue) reports exactly 0 changed pixels. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ * Delete the SECTION_CONFIGS shield - its exit condition was met, and measured SECTION_CONFIGS was introduced one day ago as an explicitly TEMPORARY shield holding ~22 section screenshots at the old 0.02 tolerance while their drift was unmeasured, with the exit condition written into its own comment: "delete it once they are measured and re-recorded." Measured both ways on the full macOS system suite, same environment, only this variable changed: shield in place 134 screenshots compared, 48 failures shield emptied 134 screenshots compared, 50 failures Cost of deleting it: +2 screenshots, both on /services/ - desktop/services/_use-cases (0.017498) and desktop/services/_technologies (0.013838). Both are the same 1px vertical offset from #528's eyebrow consolidation already classified in the previous commit: realigning baseline to candidate by one pixel drops the residual to exactly 0.0000 in several bands, so the content is pixel-identical and only its position moved. Both are re-recorded here, which is the last thing the exit condition asked for. Deleted: SECTION_CONFIGS, screenshot_config_for, extract_section_key, test/support/screenshot_section_config.rb and its unit test. That file existed so the table could be unit-tested without booting Hugo or Capybara; with the table gone there is no logic left to test, only a constant. DEFAULT_SCREENSHOT_CONFIG moves onto ApplicationSystemTestCase unchanged at 0.0001. Per-call tolerances are untouched - ~30 calls pin their own, mostly 0.03, and those still win over the default. Gates, all on this exact tree: bin/rake test:unit 287 runs, 6143 assertions, 0 failures bin/hugo-build clean, 8 validators passed bin/rake test:system 79 runs, 218 assertions, 0 failures [snap_diff] 134 screenshots compared, no failures The suite was run with the shield deleted BEFORE these two baselines were accepted, and reported exactly the 2 predicted failures and no others - so the deletion is measured, not assumed. .okf/build/test-gates.md is updated: the shield paragraph is replaced by the measurement, and a misattribution is corrected. That file claimed all five failing /services/ screenshots were the #540 dark-surface recolour; only the two large ones are. The three small ones carry 0.13% or less of the black->ink transition and are #528's 1px shift. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ * chore: update screenshot baselines [ci skip] * Screen the CI Linux record: drop 6 zero-difference rewrites, keep 77 The re-record was dispatched to CI on this branch (run 32526977795, native amd64 - the only trusted way to record linux/ baselines; local ARM Docker plants false drift) and succeeded. FORCE_SCREENSHOT_UPDATE re-records EVERYTHING, so the bot commit touched 83 files and needed screening. Screened with the gate's OWN instrument rather than by eye or by file size: capybara-screenshot-diff counts a pixel as differing only above perceptual_threshold = 2.0 dE00, and the default tolerance is now 0.0001 of the frame. Computing that same libvips dE00 fraction for every file in the bot commit splits it cleanly: keep 77 would FAIL the gate, so the rewrite is real drop 6 difference_level exactly 0.00000000 - would have PASSED The 6 dropped are pure encoder churn with zero perceptual difference: desktop+mobile course/landing, desktop+mobile blog/special/codeblocks/text, clients/agent-inbox/_overview, clients/single-full. Of the 77 kept, 8 are NEW keys with no linux baseline at all - friday_report (desktop+mobile) and the three register pilots next/{editorial,precision, rescue-room} (desktop+mobile) - and the rest span 0.000139 to 0.973. Why the Linux set is broader than the macOS one (77 vs 50), which looks wrong until you check it: earlier PRs re-recorded only the macOS side. #528 committed macos/mobile/services.png and left its linux/ twin stale, so linux/mobile/services carries a visible vertical shift that macOS no longer has - confirmed by painting the dE00 mask over the capture: identical content, offset position. The reverse also holds - linux/desktop/blog/special/inline_style_post barely moves (0.000139) because the Linux blog baselines were already re-recorded after #520, while macOS was 25% stale. Neither OS is a subset of the other. Two kept files were inspected directly rather than accepted on their number: linux/desktop/404.png (0.001235) is a 4px-wide strip at the right edge - a scrollbar artifact, page content identical, and 4 x 640 px is exactly the reported difference_level; linux/mobile/services.png (0.1389) is the #528 shift above. Both render correctly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ * OKF: how to screen a CI re-record, and why neither OS baseline set is a subset of the other Records the Linux leg of the re-record in .okf/log.md and lifts two rules into test-gates.md that were learned doing it: - Screen a FORCE_SCREENSHOT_UPDATE record with the gate's own instrument (the libvips dE00 fraction above perceptual_threshold 2.0, compared to the 0.0001 default), not by eye or file size. 83 files split 77 keep / 6 drop with no judgement call. - Neither OS baseline set is a subset of the other, because earlier PRs re-recorded only the OS they ran on. Do not reason about one from the other. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ * Correct four overclaims the re-record itself introduced Independent review measured what the evidence actually supports: - run-to-run noise is ~1e-6, not 0 (test-gates said 0.0 while the code comment in the same PR said 1e-6 - one PR, two numbers) - realigning 1px zeroes SEVERAL BANDS, not the page: a sub-pixel shift re-rasterizes glyphs, so _use-cases still differs in 22,895 px after the best alignment. Content identical on inspection; the conclusion holds, the sentence did not - "nothing unexplained" is really "every dominant cause explained" - three files carry a secondary 1px shift and two carry #540's sibling --ruby-on-ink token - 20.10 still pointed at test/support/screenshot_section_config.rb, which this PR deletes Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Second 1a.4 item. Four eyebrow variants converge on the blog's canonical form —
the one the plan records as already done.
Canonical
pages/blog-list.css .blog-eyebrow— 12px / 700 / 0.14em / uppercase /--color-rubyservices-critical.css--color-ruby, weight 600 — no size, tracking or transformcareers-critical.csscomponents/content-block.csspages/friday-report.css--ruby-700The green suite proves nothing for three of these
Only the services page is in the screenshot set. For careers, content-block and
friday-report,
[snap_diff] 53 screenshots compared, no failuresmeans "notcaptured", not "unchanged" — exactly the trap the phase brief flags for
eyebrows.
Verified by computed style in the rendered production build instead:
For services, which is captured, I read the rendered
_overview.png— theeyebrow sits small, ruby and tracked above the H1.
Contrast, measured
This commit lightens one thing: friday-report moves
--ruby-700→--color-ruby.Against that page's actual background —
rgb(253,245,244), a warm tint, notwhite — the ratio is 4.77:1. Passes AA for normal text (4.5:1), but the
margin is thin: the same pair on pure white is ~5.1:1, and any darkening of that
tint pushes it under. Recorded so the next person to touch that surface knows
the eyebrow is the binding constraint.
Gates
bin/test— commit 1: 3 baselines moved (services), reviewed and accepted.Commit 2:
53 screenshots compared, no failures, no baseline moved.bin/hugo-buildclean1a.4 remaining
Three button roles (not started). Footer onto
surface-inkstays blocked —see #526; it needs dividers and adjacent dark sections migrated together across
7+ bundles.
🤖 Generated with Claude Code