Phase 1a.4: dark surfaces onto --surface-ink, --ruby-on-ink, and two live AA fixes - #540
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>
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.