Phase 1a.4: dark surfaces onto --surface-ink, --ruby-on-ink, and two live AA fixes - #540
Merged
Merged
Conversation
…by-on-ink The dark band was two painters disagreeing: footer.css set `background-color: black` while 12 `.fl-builder-bottom-edge-layer .fl-shape-content .fl-shape` rules across 9 page files set `fill: #000000`. Moving either alone produces a visible seam where the SVG edge meets the footer, which is why an earlier attempt at this was reverted. Both move together here. Also lands the token that was blocking the rest of 1a.4: --ruby-on-ink: #e85a52 Measured on --surface-ink #14110f: --color-ruby #cc342d 3.67:1 fails AA-normal, large-text only --ruby-on-ink #e85a52 5.39:1 passes AA-normal with headroom That is for ruby TEXT/icons on the dark band. Ruby BACKGROUNDS keep --color-ruby with white on top, which is unaffected. Footer text was checked against the new band before shipping: links #969798 6.43:1, body #fff 18.80:1, both AA. Verified in the browser rather than from source: both painters now compute to rgb(20, 17, 15), so the seam is closed, and --ruby-on-ink resolves to #e85a52. Desktop 1920 and mobile 390 both read correctly - the warm ink is legibly different from pure black and every footer element survives. Gates: bin/hugo-build clean. bin/qtest --changed reported [snap_diff] 55 screenshots compared, 10 failures - all 10 are surfaces containing the dark band (both footers, both CTA bands, contact_us, the two pagination frames, three codeblock frames). Baselines were reset to HEAD first, because the tree carried 10 dirty PNGs from an earlier session that would have made the comparison meaningless. Accepted deliberately, with the pixel check rather than the diff metric: old baseline srgba(0,0,0,1) new render srgba(20,17,15,1) The 0.06-0.81 difference_levels are pixel COUNTS, not perceptual magnitude - a whole band shifting slightly moves most pixels in frame. macOS baselines only; Linux rides the parallel PR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Measured in the browser, not inferred: the SERVICES and CLIENTS + CASE STUDIES eyebrows paint --color-ruby #cc342d on an #000000 section band at 4.1:1, which fails WCAG AA for normal text. They are live on the homepage today. Moved to --ruby-on-ink (the token added in the previous commit): 4.1 -> 6.02:1, AA pass. Re-measured after rebuild rather than assumed. The light-surface eyebrow on the same page (home-why-us-eyebrow, ruby on white) is untouched and still reads 5.13:1 - this is the check the earlier blanket eyebrow sweep failed, which is why that one was reverted. This also had to happen alongside the band work rather than after it: on --surface-ink #14110f the old ruby measures 3.67:1, so unifying the dark surfaces without fixing the text would have made these two worse. Scope deliberately stopped here. 18 eyebrow rules paint ruby and 36 hardcoded black backgrounds remain, but only the failures I could MEASURE are fixed - sweeping all of them blind is precisely what produced the reverted regression. The remaining blacks include code-block surfaces, which are a separate design decision, not a token rename. An instrument note, since it nearly cost a wrong conclusion: the first measurement read `color` off the `.fl-module` WRAPPER and reported 1.12:1 - near black on black, which would be invisible - on a page that plainly renders fine. The painted text lives deeper in the tree. Walking down to the element that actually holds the text gave the real 4.1:1. A computed-style reading that contradicts the render is the instrument being wrong, not the page. Gates: bin/hugo-build clean. bin/qtest --changed reported [snap_diff] 5 screenshots compared, 2 failures - both use-cases footer surfaces carrying the previous commit's band change on a page that run had not covered. Pixel-verified as the same intentional shift, srgba(0,0,0,1) -> srgba(20,17,15,1), and accepted. macOS only; Linux rides the parallel PR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
One entry, on the architecture/css-pipeline.md instrument ladder: reading `color` off the element your selector matched rather than the one that paints the text reported 1.12:1 for eyebrows on a page that renders fine. FL-Builder nests .fl-module > .fl-module-content > .fl-rich-text, so the wrapper is almost never the painter, and the bogus reading would have buried the real 4.1:1 AA failure under an implausible one. Gates: v0.2 okf_validate .okf exits 0. Stamped with measured UTC. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
|
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 |
Contributor
Screenshot diffs detected
|
…meet Codex review caught a real defect in the previous commit: moving the 12 bottom-edge shape fills to --surface-ink while the section bands they abut stayed #000 CREATED the seam this phase exists to remove. Verified in the browser before fixing - .home-proof's edge computed rgb(20,17,15) meeting .home-services at rgb(0,0,0). Only 5 bands are involved, and they are exactly the ones adjacent to a migrated edge: .home-services homepage.css .about-achievements about-us.css .careers-testimonial careers.css .service-overview single-service.css .use-case-details single-use-cases.css Moving them exposed two more AA failures, which is the interaction that makes these inseparable: --color-ruby measures 3.67:1 on --surface-ink, so any ruby text on a migrated band gets WORSE. about-achievements-eyebrow and service-overview-eyebrow both dropped to 3.67:1 and are moved to --ruby-on-ink. Re-measured every affected page in the browser afterwards - homepage, about-us, careers, a single-service page and a single-use-case page - checking for BOTH dark seams and AA failures, and on careers/about-us widening the sweep from eyebrows to every text element sitting on the ink band. All five report zero seams and zero failures. This is why the previous commit's "scope stopped here" was wrong rather than conservative: the bands were not optional follow-up work, they were the other half of the same change. The 31 remaining hardcoded blacks genuinely are separate - none of them abuts a migrated edge, and several are code-block surfaces. Gates: bin/hugo-build clean. bin/test reported [snap_diff] 55 screenshots compared, 3 failures - homepage _services, _technologies and _clients, all the migrated band. Pixel-verified srgba(0,0,0,1) -> srgba(20,17,15,1) and accepted. macOS only; Linux rides the parallel PR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
I accepted 15 macOS baselines across the previous commits and presented
"55 screenshots compared, no failures" as evidence the change was clean. That
evidence was worthless, and worse than worthless because it looked strong.
The check I skipped: run the suite on PRISTINE master. Doing it now, with
master's CSS and master's baselines and no change of mine in the tree:
bin/rake test:critical 13 of 55 screenshots fail
bin/rake test:system 18 of 126 screenshots fail
So this worktree's macOS rendering does not match the committed macOS baselines
at all, independently of anything I did. My run was green only because I had
overwritten the baselines with this machine's output - I was not verifying
against the repo's baselines, I was replacing them. Accepting them would bake
this machine's drift into the repo, mixed in with the intended colour change and
indistinguishable from it.
The blog code_highlight diff is the tell I should have followed sooner: the
article body is VERTICALLY SHIFTED, and a background-color change cannot move
layout. I nearly accepted it as "the same intentional shift" because it arrived
in the same batch as changes that were.
So all 15 baselines are reverted to master's. The CSS commits stand - their
correctness is established independently of the screenshot suite, by browser
measurement and pixel sampling of the live render:
both dark painters compute rgb(20, 17, 15), seam closed
--ruby-on-ink resolves to #e85a52
eyebrows 4.1 -> 6.02:1 on the homepage, 3.67 -> AA-pass on about-us
zero dark seams and zero AA failures across all 5 affected pages
Baselines must be re-recorded where the canonical ones were produced, not here:
gh workflow run test.yml --ref phase-1a4-dark-surfaces \
-f screenshots=true -f update-baselines=true
That is the same rule ci-gates.md already states for Linux - record where the
renderer matches - and it applies to macOS from this worktree for the same
reason.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The rule I most needed today and did not have. A green screenshot run proves nothing until you know the suite is green with NOTHING changed: bin/rake test:critical 13 of 55 fail on untouched master in this worktree bin/rake test:system 18 of 126 My phase-1a.4 run reported "55 screenshots compared, no failures" and I quoted it as evidence. It was green only because the run had rewritten the baselines with this machine's output - replacement, not verification. Recorded with the tell I should have followed sooner: a blog diff showed the article body vertically SHIFTED, and a background-color change cannot move layout. It nearly passed because it arrived batched with diffs that genuinely were the intended recolour, which is the general hazard - a batch of expected changes is where an unexpected one hides. Also recorded: correctness of the change itself is establishable without the suite, by browser measurement and pixel-sampling the live render, and that evidence is independent of baseline drift. That is what carries this PR. Gates: v0.2 okf_validate .okf exits 0. Stamped with measured UTC. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two concepts corrected against what actually shipped on this branch. 1. design/site-palette.md carried `#e85a52` as a RECOMMENDATION and said "Not yet applied - Paul's call". Both false: it is in css-variables.css and applied. That staleness is not cosmetic - a cold session reading it would conclude the phase was still gated on a decision, which is precisely the false state that produced hours of adjacent work instead of CSS. Now recorded as decided and shipped, with WHERE it was applied: the four eyebrows that measured below AA, not a site-wide sweep, because sweeping is what the reverted 41-rule attempt got wrong. Re-stated because it survives the decision unchanged: neither automated gate catches a contrast regression on those bands. 2. architecture/css-pipeline.md documented how to HUNT the shape layer but never what the dark band is made of. It is three groups - 1 footer background, 12 bottom-edge SVG fills across 9 page files, 5 section bands - and moving a subset ships a seam. Both failure directions are now on record: moving the footer alone (reverted earlier), and moving footer+fills while leaving the bands black (this branch, caught in review). With the coupling that makes them inseparable: --color-ruby is 4.10:1 on #000 but 3.67:1 on --surface-ink, so migrating a band makes ruby text on it worse. Two eyebrows that were fine before the bands moved failed after. Gates: v0.2 okf_validate .okf exits 0. Both concepts stamped with measured UTC. Verified with flatten + grep -o and a positive control, per the counting caveat in build/test-gates.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Swept the bundle for claims that rot, after site-palette.md was found carrying a closed blocker as open. Two outcomes. 1. workflows/site-redesign-rollout.md needs no fix, BY DESIGN - it states that phase status comes from git rather than any document, and records reasoning rather than a state snapshot. Adding current status would make it worse. Worth stating as the counter-example to site-palette: the difference between a concept that rots and one that does not is whether it stores STATE or REASONING. 2. The bundle's one remaining cross-link warning was not a broken link. design/course-landing-components.md referenced a repo doc with `../../docs/projects/...`, which resolves correctly on disk - verified by listing the target from the concept's own directory - but the validator cannot follow a link out of .okf/, so it warned on every run. A permanent warning is worse than noise: it invites someone to "fix" a link that was never broken. The canonical path was already in that concept's `resource:` frontmatter, so the body link duplicated it. Converted to inline code; the bundle's broken-link warnings are now zero. Convention recorded in index.md. Postscript, recorded in the log: the control I used to confirm this (`grep -ci 'cross-link'`) returned 1 and looked like a regression, because it matched the words inside the new log entry's own heading. The real message form is `cross-link target not found`, which returns 0. A search term general enough to match your own prose about a thing does not measure the thing. Gates: v0.2 okf_validate .okf exits 0, zero `cross-link target not found`. Edited concept stamped with measured UTC. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pftg
force-pushed
the
phase-1a4-dark-surfaces
branch
from
August 21, 2026 07:52
a253463 to
715ea1b
Compare
Dispatched test.yml -f update-baselines=true on this branch, because this worktree's macOS render is drifted and cannot produce trustworthy baselines. The bot recorded 84 Linux baselines for a change that moves one colour. Screened them by the byte-size procedure ci-gates.md already documents: 76 of 84 under the ~1.2% noise floor 7 of 84 footers and CTA bands - genuinely this change 1 of 84 desktop/blog/tag.png at 12.44% Diffing that outlier showed DIFFERENT BLOG POSTS - "108 posts tagged rails" against 106, different titles and dates. Content published since the previous recording, folded into an unrelated PR by a record that snapshots the whole site rather than the diff. The record commit is dropped from the branch (rebase --onto, backup tag first). The PR is CSS-only and 84 mostly-unrelated binaries make its visual evidence unreadable; and the screenshot job is continue-on-error on pull_request (test.yml:72), so a stale Linux baseline reports without blocking. Linux rides its own PR per Paul 2026-08-19. Recorded in ci-gates.md beside the existing "record mode has no accept/reject gate" rule, which had the screening procedure but not this consequence: the outliers you find are often somebody else's work, and there is no CI-side filter - bin/record-baselines <glob> does it locally, a dispatch cannot, so the filtering has to happen after the fact. Gates: v0.2 okf_validate .okf exits 0. Stamped in this file's own block form; verified rows diffed against the merge base, additions only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Making debt legible rather than silent, per the async-first rule. The 1a.4 recolour invalidates 16 Linux baselines - all dark-band surfaces - listed in the log entry and mirrored into the PR body, which is where whoever picks up the Linux work will actually look. The reds were read from CI run 32460674225 and checked against the failing surfaces rather than assumed, per ci-gates.md's "a slow failure and a fast failure are different failures". Not recorded on this PR deliberately: Linux rides a parallel PR (Paul 2026-08-19). A record was dispatched and dropped when screening found content drift in it, and re-dispatching to curate it here would take that instruction the other way. Two facts that make merging safe rather than reckless, both verified in the workflow file: test.yml triggers on pull_request and workflow_dispatch ONLY - no push trigger - so merging cannot turn master red; and on PRs the job is continue-on-error. Which is also precisely the silent-drift condition ci-gates.md already documents, now with a concrete list attached instead of a general warning. Gates: v0.2 okf_validate .okf exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pftg
added a commit
that referenced
this pull request
Aug 21, 2026
Codex pre-merge on #552 returned 4 findings. Three accepted, one declined. ACCEPTED - all three are the same failure: records written before the opus review changed the implementation, never swept after. 1. OKF log and 20.06 described a tag-first derivation; the shipped template is prefix-only (the tag branch was deleted as dead code in review). A future maintainer could have restored deleted code or debugged nonexistent behavior. Both records now state prefix-only + name dict. 2. 20.06's gate line said "verifiers on sonnet" blanket - written before Paul's routing table finalized. Now stage-specific: code review = opus, design critique = fable, mechanical = sonnet. 3. The cold-session ledger still scheduled the Linux dispatch and Direction 2, both complete. Rows updated; judging now correctly blocked on Paul's Claude Design pass alone. DECLINED - recording macOS course/chapter baselines from this machine. The merge-base run measured 13 failures on UNTOUCHED master here, so a local macOS record poisons the repo with machine drift (the exact mechanism #540 reverted). Cost acknowledged: those two keys stay red on macOS runs (diff 3.2%/11.4% vs 0.03 tolerance) until recorded on a healthy Mac - now tracked as an OUTSTANDING item in the 20.06 ledger, not just the PR body. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pftg
added a commit
that referenced
this pull request
Aug 21, 2026
Codex pre-merge on #552 returned 4 findings. Three accepted, one declined. ACCEPTED - all three are the same failure: records written before the opus review changed the implementation, never swept after. 1. OKF log and 20.06 described a tag-first derivation; the shipped template is prefix-only (the tag branch was deleted as dead code in review). A future maintainer could have restored deleted code or debugged nonexistent behavior. Both records now state prefix-only + name dict. 2. 20.06's gate line said "verifiers on sonnet" blanket - written before Paul's routing table finalized. Now stage-specific: code review = opus, design critique = fable, mechanical = sonnet. 3. The cold-session ledger still scheduled the Linux dispatch and Direction 2, both complete. Rows updated; judging now correctly blocked on Paul's Claude Design pass alone. DECLINED - recording macOS course/chapter baselines from this machine. The merge-base run measured 13 failures on UNTOUCHED master here, so a local macOS record poisons the repo with machine drift (the exact mechanism #540 reverted). Cost acknowledged: those two keys stay red on macOS runs (diff 3.2%/11.4% vs 0.03 tolerance) until recorded on a healthy Mac - now tracked as an OUTSTANDING item in the 20.06 ledger, not just the PR body. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pftg
added a commit
that referenced
this pull request
Aug 21, 2026
* Persist the clean-slate v2 pivot so any session can resume it Paul approved the revised strategy (plan mode) and asked that all project artifacts let a separate session finish the work when interrupted. The approved plan lived only in a session-local plans file - invisible to a cold session - so this commit moves the whole state into the repo. New plan of record: docs/projects/2608-site-design-system/20-29-strategy/ 20.06-clean-slate-v2-plan.md - the dual-run v2 rail (root layouts/next/, clean bundles, functional partials reused verbatim), /next/ non-indexed production staging, page-by-page cutover, legacy frozen with the 780 button sites and 39 blacks dropped as work-done-twice. Carries a COLD-SESSION STATE LEDGER with per-item status and exact next actions, updated in the same commit as the work it describes. Decisions of record captured: 2-direction design competition, FULLY OPEN (rebrand allowed - ruby/LIGHT hold on the live site only until Paul picks); Claude Design and stitch COLLABORATE (the old "Rescue Room" project renders extraction, which is why previews looked like course reuse); sub-agent model routing - code review on opus, docs/panels on sonnet, mechanical on haiku, Fable never inherited by spawns (CLAUDE.md updated). Supersession markers placed where a cold session would otherwise read stale direction as current: 2608 README pivot banner + inline markers on the "no authority" paragraph and the phase table; 20.01 Phase-2 banner; OKF site-redesign-rollout.md pivoted (old lane model kept under a superseded heading) + log entry. Author != verifier: a sonnet reviewer attacked the staged diff against its own acceptance bar and returned 3 findings, all fixed before this commit - two unmarked stale assertions in the README (the file a cold session reads FIRST) and a ledger status claiming IN PROGRESS for work not yet started. Its spot-checks verified bin/qtest:69-78 hole, enhanced-meta-tags noindex, sitemap private-filter, and all three fl-line counts as written. Gates: bin/hugo-build clean; v0.2 okf_validate exits 0; concept stamped with measured UTC. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Phase 2.3: course module eyebrow - Module N + canonical name Course lessons carry the canonical eyebrow (12px/700/0.14em/uppercase/ruby) above the H1: "Module 2 · Validate the Problem". Derived from the "N.N ·" title prefix; names mirror the canonical module map in how-this-course-works. 25 lessons render (census 5/6/2/5/7 across Modules 1-5); quickstart, faq, walkthroughs, reference pages correctly get none. Browser-measured: computed spec exact (letter-spacing 1.68px = 0.14em @ 12px), 5.13:1 on white - AA pass. Desktop 1920 + mobile 390 inspected. Opus diff review (author != verifier) returned 4 findings; all addressed before this commit: - F2/F3: the module-N tag branch was DEAD CODE - the 6 tagged lessons are a strict subset of the 25 prefixed ones, and hasPrefix "module-" without a digit check would render "Module card" from an unrelated tag. Tag branch deleted; derivation is the anchored prefix regex alone (11 lines -> 6). - F4 (design): the digit-only eyebrow duplicated the number already visible in the H1 one line below - decorative, not helpful, failing CLAUDE.md's own gate language. Fixed by adding the module NAME, which the H1 does not carry. - F1 (baselines): course/chapter desktop+mobile baselines are invalidated by design. Handling per the recorded procedure - see the attribution run in the next commit / PR body; local macOS records are untrustworthy on this machine, Linux records ride a CI dispatch on the branch, screened. The reviewer also verified: regex safe against every real title (rendered census, zero false positives on digit-leading titles), findRESubmatch empty slice guarded by `with`, eyebrow rule survives production PurgeCSS verbatim, no competing cascade (the one other header-p rule is @media print). Also rides: model routing final form in CLAUDE.md (critical decisions + editing/outlining = fable; coding, code review, content writing = opus; mechanical = sonnet), 20.06 ledger status, OKF log entry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Track A: shared design-competition brief (20.07) + routing refinements One brief, two tools: the identical fully-open contract runs in stitch (agent- driven; direction 2 generating now) and in a NEW Claude Design project (Paul- driven) - identical wording keeps outputs comparable, and the doc warns off the old "Rescue Room" project, which renders the extracted system this competition steps back from. Carries its own status ledger per the cold-session rule. Constraints are only the hard ones: no stock people, no logo walls/carousels/ repeated CTAs, claims-canon on any company fact, no extraction from the current site. Everything else - palette, typography, identity - open, per Paul's fully-open decision. Routing refinements from Paul recorded in CLAUDE.md: design critique joins fable (with critical decisions and editing/outlining); the /impeccable judging panel therefore runs on fable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Track A ledger: Direction 2 landed - Institutional Authority Dark midnight-navy/charcoal, IBM Plex Sans, forensic-artifact narrative. Canon flags recorded for judging: invents a 90-day guarantee (not in canon); dark chrome contradicts the peer-set evidence ADR-0003 cited - panel weighs both, since the brief was fully open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Linux baselines for course/chapter, screened from the CI record The branch dispatch recorded 72 baselines for a change that adds one line to one template. Screened per the recorded procedure (ci-gates.md): kept exactly the 2 course keys this PR invalidates - desktop +0.84%, mobile +1.71%, both consistent with an added eyebrow line - and dropped the other 70, which are whole-site record noise and would fold unrelated drift into this PR (the blog/tag.png content-drift incident, 2026-08-21). The bot's whole-record commit is replaced by this screened one via force-with-lease; backup of the bot ref is the run itself (32479029380). macOS course/chapter keys remain UNRECORDED deliberately - the merge-base run proved this machine's macOS render is drifted (13 failures on untouched master), so local records would poison the repo. Listed in the PR handoff. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Apply codex findings: sync three records to the shipped implementation Codex pre-merge on #552 returned 4 findings. Three accepted, one declined. ACCEPTED - all three are the same failure: records written before the opus review changed the implementation, never swept after. 1. OKF log and 20.06 described a tag-first derivation; the shipped template is prefix-only (the tag branch was deleted as dead code in review). A future maintainer could have restored deleted code or debugged nonexistent behavior. Both records now state prefix-only + name dict. 2. 20.06's gate line said "verifiers on sonnet" blanket - written before Paul's routing table finalized. Now stage-specific: code review = opus, design critique = fable, mechanical = sonnet. 3. The cold-session ledger still scheduled the Linux dispatch and Direction 2, both complete. Rows updated; judging now correctly blocked on Paul's Claude Design pass alone. DECLINED - recording macOS course/chapter baselines from this machine. The merge-base run measured 13 failures on UNTOUCHED master here, so a local macOS record poisons the repo with machine drift (the exact mechanism #540 reverted). Cost acknowledged: those two keys stay red on macOS runs (diff 3.2%/11.4% vs 0.03 tolerance) until recorded on a healthy Mac - now tracked as an OUTSTANDING item in the 20.06 ledger, not just the PR body. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Track A: Claude Design project created and seeded from the session Paul pointed out DesignSync reaches claude.ai/design from here - no copy-paste handoff needed. Created "JetThoughts - From-Scratch Competition (2608)" (a5f25203-6dd9-45c6-a978-5842152d1389) and seeded 8 files: the fully-open BRIEF.md, both directions' DESIGN.md summaries (with the ruby-locked disclosure on D1 and the canon flags on D2), and both full-page renders (2560px) as preview cards. The old "Rescue Room" project stays untouched - it renders the extracted system. Paul's move shrinks to: open the project, run/iterate the brief, or critique the two seeded directions. Everything cross-pollinates before the fable critic and the judging board. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 21, 2026
pftg
added a commit
that referenced
this pull request
Aug 21, 2026
…0x) (#560) * Screenshot tolerance 0.02 -> 0.0001: the visual gate was blind by 50x DEFAULT_SCREENSHOT_CONFIG demanded that ~41,472 pixels of a 1920x1080 frame differ before an assertion failed, so real changes passed green. services/_testimonials-header sat at difference_level 0.005923 through an entire dark-surface recolour and reported no change. Measured on DesktopSiteTest#test_services at clean HEAD, 7 screenshots compared per run: 0.02 gives 2 failures, this commit gives 3. Run-to-run noise is 0.0 - repeat runs return difference_levels identical to 16 decimal places, and 2 of the 7 stay green at the new floor - so 0.0001 (~207 px) clears jitter without tripping on it. The ~30 calls that pin their own tolerance are untouched; only the floor for calls pinning nothing moved. Passing quietly is worse than failing, because it fossilizes the baseline: the gem writes the fresh capture over the baseline PNG, then a PASS restores the git-HEAD image back over it. A green run therefore never refreshes anything, and every sub-tolerance change leaves the committed PNG showing the old render until something large enough to fail arrives and the accumulated drift gets accepted in one lump nobody can attribute. Corollary now documented: only a RED run leaves a committable candidate, and deleting the PNG first does nothing since the base is read from git HEAD. SECTION_CONFIGS is KEPT at 0.02 on purpose. Its 7 keys equalled the old default, making it a silent no-op; lowering the default inverts that into a load-bearing shield holding ~22 section screenshots at the old tolerance until their drift is measured. Deleting it here would drop those to 0.0001 unmeasured and would also corrupt the headline number: with the shield removed the same test fails 5 instead of 3, which is +3 rather than the +1 this change actually costs. The two extra are exactly the screenshots whose names hit a SECTION_CONFIGS key (services/_use-cases 0.017498, services/_technologies 0.013838), since keys match the tail after "/_" - /_technologies matches technologies, /_testimonials-header does not match testimonials. That mapping went from inert to safety-critical with no coverage, so it moves to test/support/screenshot_section_config.rb and is pinned by test/unit/screenshot_section_config_test.rb. It had to move: requiring application_system_test_case.rb from a unit test boots Hugo, Capybara and that file's dirty-fixtures abort. The guard was verified by mutation - splitting the key on "-" so _testimonials-header matches the testimonials shield turns the suite red, reverting turns it green - and the system path re-measured identical (same 3 failures, same difference_levels) after the extraction. test-gates.md also documents two blind spots tolerance cannot fix. Captures are viewport-only at scroll top (1920x1080 desktop, 360x800 mobile, test/support/setup_capybara.rb:85-86), so below-fold content is invisible at ANY tolerance - a table-cell edit measures difference_level exactly 0 on mobile even at tolerance 0, and every failure region here caps at the viewport height. And perceptual_threshold = 2.0 (test/support/setup_snap_diff.rb:25) means vips only counts a pixel as differing above CIE dE00 2.0, so a sub-threshold recolour contributes zero differing pixels at any tolerance. Coverage fixes are out of scope. Live doctrine swept truthful: the tutorial documented a SCREENSHOT_TOLERANCE env var that exists nowhere in the codebase (and claimed a 1% default the code never had), a helper named assert_stable_problematic_screenshot with its own section and three call sites, and a per-OS tolerance-multiplier table - none of which exist in test/, bin/ or lib/; visual-qa-criteria pinned 0.02. A doctrine file names its own mechanisms, so its fiction looks executable and gets copied. Gates: bin/rake test:unit 289 runs, 6090 assertions, 0 failures. bin/hugo-build clean. okf_validate: 0 errors, 111 -> 112 warnings (exactly the one section-7 date heading this log entry adds). Screenshot suites are red on the stale #540 baselines by design - that is the gate biting: Screenshot does not match for 'desktop/services/_testimonials-header': ({"difference_level":0.005922550154320988}) which passed silently before this commit. Those baselines are NOT re-recorded here; that is the follow-up's job. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Docs: 20.10 §4 gate-blindness marked FIXED (verifier residual P3) The list taught the 2% blindness in present tense with 'left as-is deliberately' - three claims made false by the previous commit. Edit prescribed verbatim by the delta re-clear. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
pftg
added a commit
that referenced
this pull request
Aug 21, 2026
…ional-cto/ (#563) Pilot C of the three-register design comparison (10.01), and the first one with no Claude Design artifact behind it - pilots A and B each translated one, this register is built from the research column itself ("precise, engineered, nothing hidden"). Cool white with #fafafa panels, structural 1px borders in #e4e4e7 / #d4d4d8, zero radius, ink #18181b. The BORDERS are the design: the hero is two grid cells butted against one vertical rule rather than a card floating beside the copy, the stats and case cards are cells sharing single hairlines, and the comparison table is ruled in both directions like a spec sheet. Inter 400/500/600/700 for prose, JetBrains Mono 400 for every label, numeral and button. COPY IS UNCHANGED, again - `diff` against pilot B's stub is six lines (title, description, `register`, `font`) and nothing else. Both screenshot tests assert the same strings as pilots A and B, so a copy edit reaching only one pilot fails. Ruby is the standard #cc342d and RESTRAINED to four jobs: a 6px square ahead of each eyebrow, the comparison's active-column rule, the step numeral, and the filled primary CTA. It never washes or tints a surface. Devices with no slot in the anatomy were translated: the brand mark is an outlined hairline box (pilot B's is a solid block), list markers are 1px dashes, the timeline is a numbered protocol whose numeral gutter is divided by a full-height rule, and the leading zero is CSS because "01" belongs to this register, not to the shared anatomy. The accent does NOT die on the inverted band here, which is the interesting register-fidelity result. Pilot B's deep red is 2.31:1 on ink and had to invert to paper; #cc342d is 3.46:1 on #18181b - under the 4.5:1 text floor, over the 3:1 a filled button's edge needs, with white-on-ruby at 5.13:1 inside it - so the closing CTA stays ruby. Measured, not assumed. Structural hairlines step up to #71717a (3.67:1) on that band, because a register whose design IS its geometry cannot let the geometry dissolve when the ground goes dark. Two defects the browser caught that the source could not: - The comparison's "theirs" column rendered in FULL INK. `.rr-table tbody td` scores 0,1,2 on its two tag names and outranks the template's `.rr-td-muted` at 0,1,0, so the comparison stopped comparing while the CSS still read correct. Caught by walking computed colours per row, not by reading the file. The same shape is live in next-editorial.css - pilot B's muted column is actually its body tone. Fixed here by scoping the override past the default. - A `gap:1px over a line-coloured ground` grid shows that ground as an empty cell whenever the last row is partial: `auto-fit` collapses only tracks empty in EVERY row, so three stats in two phone-width tracks left a grey block. Single column below 640px. - (Also: the month-one panel shipped with padding-right: 0 and its bullets flush to the panel edge. Found by looking at the screenshot.) Gates, with the instruments proven rather than trusted. bin/hugo-build clean. bin/rake test:unit 292 runs, 6164 assertions, 0 failures. The pilot-glob gates in next_rail_test.rb already reach this page and it was PROVEN by smoothing this pilot's quote and watching the failure name next/pilots/precision/fractional-cto/index.html. PurgeCSS set-diff empty across 56 selectors on a PRODUCTION build, and an injected orphan `.rr-th-probe` rule was stripped from the bundle (byte-identical hash), so the diff bites; the positional column selectors and the muted-column fix both survive the purge. Computed font-weight walk: 123 elements, zero synthesized - Inter 400 (39) / 500 (5) / 600 (14) / 700 (1) and JetBrains Mono 400 (63), every pair backed by a loaded face. Contrast walk 122 elements at 1440 AND 390, zero failures, worst passing 4.63:1, and the walk was proven live by an injected 1.67:1 probe that it caught alone. All four buttons clear their non-text edge (3.46-5.13:1) and label (5.13-17.72:1). Zero console messages, zero non-2xx, zero third-party hosts - JetBrains Mono is REUSED from pilot B's binary rather than duplicated. No horizontal overflow at 390; the table scrolls in its own box (348 visible / 680 content); h1 lands at 36px mobile, 60px desktop. Scoped desktop + mobile screenshots green against these committed macOS baselines, with pilots A and B still green in the same run (8 runs, 6 screenshots, 0 failures). Known and NOT introduced here: the full critical suite has 9 pre-existing stale macOS baseline failures (the #540 recolour backlog item), and qtest escalates to --all for this change because the new static font files are unmapped. Claude-Session: https://claude.ai/code/session_011SP5gaqXEgUie8pdFrmbeJ Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
pftg
added a commit
that referenced
this pull request
Aug 21, 2026
…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
pftg
added a commit
that referenced
this pull request
Aug 21, 2026
…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
pftg
added a commit
that referenced
this pull request
Aug 21, 2026
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
pftg
added a commit
that referenced
this pull request
Aug 22, 2026
* 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 1a.4 — the dark-surface work, unblocked and shipped. CSS only; no baselines (see Gates).
What changed
1. The token that was blocking the phase.
--ruby-on-ink: #e85a52, measured on--surface-ink #14110f:--color-ruby#cc342d--ruby-on-ink#e85a52For ruby text/icons on the dark band. Ruby backgrounds keep
--color-rubywith white on top.2. The dark band unified — all of it. It was three groups that had to move together:
footer.cssbackground-color: black.fl-builder-bottom-edge-layer .fl-shape-content .fl-shapefills across 9 files.home-services,.about-achievements,.careers-testimonial,.service-overview,.use-case-detailsMoving any subset leaves a seam. My first pass moved the first two and created the seam it was meant to remove — codex caught it, and the browser confirmed
.home-proof's edge atrgb(20,17,15)meeting.home-servicesatrgb(0,0,0).3. Three live WCAG AA failures fixed. Homepage
SERVICESandCLIENTS + CASE STUDIESwere at 4.1:1 on black — live today. Migrating the bands then droppedabout-achievements-eyebrowandservice-overview-eyebrowto 3.67:1, because the old ruby is worse on--surface-inkthan on black. All four now use--ruby-on-ink.That interaction is why the bands and the text are one change, not two.
Evidence — from the live render, not the suite
Measured in the browser on all five affected pages (homepage, about-us, careers, a single-service page, a single-use-case page), checking for both dark seams and AA failures, widened on two pages from eyebrows to every text element on the ink band:
Live values: both dark painters compute
rgb(20, 17, 15);--ruby-on-inkresolves to#e85a52; eyebrows 4.1 → 6.02:1.Gates — and why there are no baselines here
bin/hugo-buildclean.I originally accepted 15 macOS baselines and reported "55 screenshots compared, no failures." That evidence was worthless. Running the suite on pristine master — master's CSS, master's baselines, nothing of mine:
bin/rake test:criticalbin/rake test:systemMy run was green only because it had rewritten the baselines with this machine's output. That's replacement, not verification, and committing it would bake local render drift into the repo, mixed in with the intended recolour and indistinguishable from it.
The tell I should have followed sooner: a blog diff showed the article body vertically shifted — a
background-colorchange cannot move layout. It nearly passed because it arrived batched with diffs that genuinely were the intended recolour.All 15 baselines are reverted. They need recording where the canonical ones came from:
Same rule
ci-gates.mdalready states for Linux, for the same reason.Scope
31 hardcoded blacks remain, none adjacent to a migrated edge; several are code-block surfaces — a design decision, not a token rename.
.fl-buttonhas 720 occurrences, so "three button roles" is a multi-PR migration, not a unit.Knowledge recorded
.okf/architecture/css-pipeline.md— readingcoloroff the element your selector matched rather than the one that paints reported 1.12:1 for eyebrows on a page that renders fine; FL-Builder nests three levels deep..okf/build/test-gates.md— run the suite on pristine master before trusting a green run.🤖 Generated with Claude Code
Handoff — 16 stale Linux baselines
This PR invalidates these Linux baselines (from CI run
32460674225on the branch). Not recorded here — Linux rides the parallel PR, per Paul 2026-08-19:All 16 are dark-band surfaces. The reds were checked against the run, not assumed.
A record was dispatched and then dropped: screening it by byte-size found
desktop/blog/tag.pngat 12.44%, whose diff showed different blog posts ("108 posts tagged rails" vs 106) — content drift from a blind whole-site record, not this change.Merging is safe:
test.ymltriggers onpull_requestandworkflow_dispatchonly — nopushtrigger — so this does not turn master red; and on PRs the job iscontinue-on-error.