Skip to content

Phase 1a.4: dark surfaces onto --surface-ink, --ruby-on-ink, and two live AA fixes - #540

Merged
pftg merged 10 commits into
masterfrom
phase-1a4-dark-surfaces
Aug 21, 2026
Merged

pftg merged 10 commits into
masterfrom
phase-1a4-dark-surfaces

Conversation

@pftg

@pftg pftg commented Aug 21, 2026 •

Copy link
Copy Markdown
Member

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:

ratio AA-normal
--color-ruby #cc342d 3.67:1 fails (large-text only)
--ruby-on-ink #e85a52 5.39:1 passes, with headroom

For ruby text/icons on the dark band. Ruby backgrounds keep --color-ruby with white on top.

2. The dark band unified — all of it. It was three groups that had to move together:

  • footer.css background-color: black
  • 12 .fl-builder-bottom-edge-layer .fl-shape-content .fl-shape fills across 9 files
  • 5 section bands: .home-services, .about-achievements, .careers-testimonial, .service-overview, .use-case-details

Moving 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 at rgb(20,17,15) meeting .home-services at rgb(0,0,0).

3. Three live WCAG AA failures fixed. Homepage SERVICES and CLIENTS + CASE STUDIES were at 4.1:1 on black — live today. Migrating the bands then dropped about-achievements-eyebrow and service-overview-eyebrow to 3.67:1, because the old ruby is worse on --surface-ink than 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:

seams: []          aaFailures: []

Live values: both dark painters compute rgb(20, 17, 15); --ruby-on-ink resolves to #e85a52; eyebrows 4.1 → 6.02:1.

Gates — and why there are no baselines here

bin/hugo-build clean.

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:

Suite Failures on untouched master
bin/rake test:critical 13 of 55
bin/rake test:system 18 of 126

My 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-color change 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:

gh workflow run test.yml --ref phase-1a4-dark-surfaces \
  -f screenshots=true -f update-baselines=true

Same rule ci-gates.md already 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-button has 720 occurrences, so "three button roles" is a multi-PR migration, not a unit.

Knowledge recorded

  • .okf/architecture/css-pipeline.md — reading color off 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 32460674225 on the branch). Not recorded here — Linux rides the parallel PR, per Paul 2026-08-19:

desktop/blog/index/_pagination             desktop/services/_cta-contact_us
desktop/blog/special/codeblocks/bare       desktop/services/_footer
desktop/blog/special/codeblocks/indented   desktop/services/_overview
desktop/contact_us                         desktop/services/_services
desktop/homepage/_clients                  mobile/blog/index/_pagination
desktop/homepage/_cta-contact_us           mobile/blog/special/codeblocks/indented
desktop/homepage/_footer                   mobile/services
desktop/homepage/_services
desktop/homepage/_technologies

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.png at 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.yml triggers on pull_request and workflow_dispatch only — no push trigger — so this does not turn master red; and on PRs the job is continue-on-error.

pftg and others added 3 commits August 21, 2026 09:00
…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>
@coderabbitai

coderabbitai Bot commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6dbe4c41-bb62-4a31-a873-9cc4d683667e


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

❤️ Share

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

@github-actions

github-actions Bot commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

pftg and others added 5 commits August 21, 2026 09:20
…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
pftg force-pushed the phase-1a4-dark-surfaces branch from a253463 to 715ea1b Compare August 21, 2026 07:52
pftg and others added 2 commits August 21, 2026 09:53
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
pftg merged commit f6298d9 into master Aug 21, 2026
4 of 5 checks passed
@pftg
pftg deleted the phase-1a4-dark-surfaces branch August 21, 2026 08:07
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>
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant