Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions .okf/architecture/css-pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ title: CSS Build Pipeline (PostCSS + per-bundle PurgeCSS)
description: PostCSS pipeline that concatenates per-page CSS resource slices and purges unused rules per bundle before shipping.
resource: postcss.config.js
tags: [css, build, performance]
timestamp: 2026-08-21T04:17:19Z
timestamp: 2026-08-21T07:45:14Z
verified:
- { by: claude/opus-5, at: 2026-08-21T07:45:14Z }
- { by: claude/opus-5, at: 2026-08-21T07:08:22Z }
- { by: claude/opus-5, at: 2026-08-21T04:17:19Z }
- { by: claude/opus-5, at: 2026-08-21T01:43:19Z }
generated:
by: process:okf-migrate
at: 2026-07-12T00:00:00Z
by: claude/opus-5
at: 2026-08-21T07:45:14Z
sources:
- resource: "/workflows/css-maintainability-plan.md"
title: "css-maintainability-plan"
Expand Down Expand Up @@ -82,6 +84,17 @@ limitation below is demonstrated somewhere in this file:
| `getComputedStyle(el)` | the value that won the cascade for that element | which selector produced it (another rule with the same value is indistinguishable), or what is actually visible - an overlay can cover it |
| screenshot + pixel sample | what was painted | why |

**Read the element that PAINTS the text, not the one that matches your
selector** (2026-08-21). Auditing eyebrow contrast, `[class*="eyebrow"]`
matched `.fl-module` wrappers whose own `color` is inherited-but-unpainted; the
audit reported 1.12:1 (near-black on black, i.e. invisible) for a page that
renders fine. Walking down to the deepest element holding the text gave the
real 4.1:1 - a genuine AA failure that the bogus reading would have buried
under an implausible one. FL-Builder markup nests
`.fl-module > .fl-module-content > .fl-rich-text`, so the wrapper is almost
never the painter. A computed-style reading that contradicts the render is the
instrument being wrong, not the page.

Only the last is a fact about the rendered page; the rest are facts about
intermediate representations. The technique for each, and the overlay trap that
breaks the naive form of `getComputedStyle`, are below:
Expand Down Expand Up @@ -214,6 +227,34 @@ Sweep result: 12 shape-layer rules across 9 page bundles were still `#000000`
and are now `var(--surface-ink)`. Any future dark-surface token move must
include them - `grep -rn 'fill: *#000' themes/beaver/assets/css/pages/`.

# The dark band is THREE groups, and a subset ships a seam

Moving "the footer to `--surface-ink`" is not one edit. Measured while doing it
on 2026-08-21:

| Group | Count | Where |
|---|---|---|
| footer background | 1 | `footer.css` |
| bottom-edge SVG fills | **12** | `.fl-builder-bottom-edge-layer .fl-shape-content .fl-shape` across 9 `pages/*.css` |
| section bands | **5** | `.home-services`, `.about-achievements`, `.careers-testimonial`, `.service-overview`, `.use-case-details` — each `> .fl-row-content-wrap` |

A first pass moved the footer and the 12 fills and left the 5 bands at `#000`,
which CREATED the seam the migration exists to remove: `.home-proof`'s edge
computed `rgb(20, 17, 15)` meeting `.home-services` at `rgb(0, 0, 0)`. An earlier
attempt had moved the footer alone and was reverted for the mirror-image reason.

**And the text on those bands moves with them.** `--color-ruby` measures 4.10:1
on `#000` but only **3.67:1** on `--surface-ink`, so migrating a band makes any
ruby text on it worse. Two eyebrows that passed the first pass failed after the
bands moved. Band and accent are one change; see
[design/site-palette.md](/design/site-palette.md) for `--ruby-on-ink`.

The check that catches a subset, run per page in the browser: for each
`.fl-builder-bottom-edge-layer`, compare the shape's computed `fill` against the
NEXT row's `.fl-row-content-wrap` background, and flag any pair that differs
while either side is dark.


# Legacy liability: FL-Builder export CSS

A large portion of shipped CSS (~75K lines at audit time) is
Expand Down
14 changes: 14 additions & 0 deletions .okf/build/ci-gates.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ generated:
by: process:okf-migrate
at: 2026-07-31T16:30:00Z
verified:
- by: claude/opus-5
at: 2026-08-21T07:53:17Z
- by: claude/opus-5
at: 2026-08-07T00:00:00Z
- by: claude/sonnet-5
Expand Down Expand Up @@ -238,6 +240,18 @@ Two more, hit re-recording Linux baselines from CI on 2026-08-20 (see [test-gate
- **"no checks reported" has TWO causes - check `mergeable_state` FIRST**: (a) the bot's baseline commit carries `[ci skip]`, so a record dispatch leaves the PR with no new run; (b) far more silent, an UNMERGEABLE PR produces ZERO checks at all - `pull_request` runs are built against a merge ref GitHub cannot compute, so it creates nothing rather than erroring. On 2026-08-20 (b) was the real blocker and (a) was wrongly blamed for 25 minutes; `gh api repos/OWNER/REPO/pulls/N --jq .mergeable_state` returned `dirty`. A baseline record takes ~20 min while master keeps moving, and the record commit plus any `.okf/log.md` edit conflicts easily - merge master and the checks appear. Never read missing checks as "still running" or "passing."
- **Record mode has no accept/reject gate**: `FORCE_SCREENSHOT_UPDATE=true` overwrites every baseline blind, with no diff review before the commit. Screen the result by per-file byte-size delta and visually inspect only the outliers - sub-pixel noise lands under ~1.2%, real content changes stand out (2026-08-20: mermaid_post +21%/+24%, nav/use_cases -10%).

**And the outliers are often SOMEBODY ELSE'S work** (2026-08-21). A record
dispatched for a one-colour change wrote 84 Linux baselines: 76 under the noise
floor, 7 footers and CTA bands that were genuinely the change, and one at
**12.44%** - `desktop/blog/tag.png`, whose diff showed different blog POSTS
("108 posts tagged rails" against 106). Content published since the previous
recording, folded into an unrelated PR. A baseline record snapshots the whole
site, not your diff. `bin/record-baselines <glob>` filters that locally; a CI
dispatch has no filter, so screen and drop after the fact - the record commit
can simply be rebased out (`git rebase --onto <sha>^ <sha>`), and on a PR the
screenshot job is `continue-on-error` (`test.yml:72`) so stale baselines report
without blocking.

**Stale Linux baselines drift silently on master** while the PR screenshot gate stays `continue-on-error` (report-only, see below) - two live examples found 2026-08-20: PR #470 updated only the `macos/` mermaid baselines and left `linux/` stale; and `linux/desktop/nav/use_cases.png` was still encoding copy banned by `.okf/content/claims-canon.md` ("Rated 4.8/5 by 32 clients", "2011") that was corrected on the live site on 2026-08-14 - the LIVE SITE was correct, only the frozen PNG carried the stale wording, which is why the banned-string ratchet (a text grep) never caught it. A frozen baseline PNG is not covered by any text validator.

# R3-2 correctness + cost fixes (2026-07-31)
Expand Down
37 changes: 35 additions & 2 deletions .okf/build/test-gates.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ title: Test gates and when they block commits
description: bin/qtest --changed is the routine gate; bin/rake test:critical at milestones; bin/test AND bin/dtest once at PR prep (or on explicit confirmation) for themes/, layouts/, or CSS changes.
tags: [testing, visual-regression, gates]
status: stable
generated: { by: claude/opus-5, at: 2026-08-21T06:44:05Z }
generated: { by: claude/opus-5, at: 2026-08-21T07:42:17Z }
verified:
- { by: claude/opus-5, at: 2026-08-21T07:42:17Z }
- { by: claude/opus-5, at: 2026-08-21T06:44:05Z }
- { by: claude/opus-5, at: 2026-08-21T06:36:48Z }
- { by: claude/opus-5, at: 2026-08-21T06:27:54Z }
Expand All @@ -19,7 +20,7 @@ verified:
- { by: claude/sonnet-5, at: 2026-08-20T00:00:00Z }
- { by: claude/opus-5, at: 2026-08-20T21:43:35Z }
- { by: claude/opus-5, at: 2026-08-20T21:47:30Z }
timestamp: 2026-08-21T06:44:05Z
timestamp: 2026-08-21T07:42:17Z
---

# The suites
Expand All @@ -40,6 +41,38 @@ is `simple-page`); the changed-file→page map lives in the script itself -
extend it when adding components or critical files. The macOS full suite remains the only dedup-trap catcher
(Linux font resolution masks it) - never finish a component on qtest alone.

# Run the suite on PRISTINE master before trusting a green screenshot run

A green screenshot run proves nothing until you know the suite is green with NO
change in the tree. Measured in a worktree on 2026-08-21:

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

A phase-1a.4 CSS change reported "55 screenshots compared, no failures" in that
same worktree - green ONLY because the run had rewritten the baselines with this
machine's output. That is not verification against the repo's baselines, it is
replacement of them, and committing the result bakes local render drift into the
repo, mixed in with the intended change and indistinguishable from it.

The tell that something else was moving: a blog screenshot diff showed the
article body VERTICALLY SHIFTED. A `background-color` change cannot move layout,
and it nearly got accepted anyway because it arrived batched with diffs that
genuinely were the intended recolour.

So establish the baseline-of-the-baseline first - `git checkout origin/master --
themes/ test/fixtures/screenshots/`, build, run. If master is not green here,
this machine cannot produce trustworthy baselines: record them where the
canonical ones came from (`gh workflow run test.yml --ref <branch> -f
screenshots=true -f update-baselines=true`), which is the rule
[ci-gates](/build/ci-gates.md) already states for Linux, for the same reason.

Correctness of the CHANGE is still establishable without the suite - browser
measurement and pixel-sampling the live render - and should be, since that
evidence is independent of baseline drift.

# Tolerance policy

**0.0 for refactors** (a refactor must move zero pixels), **<=0.03 for
Expand Down
10 changes: 8 additions & 2 deletions .okf/design/course-landing-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ tags: [css, design, course, landing]
status: stable
generated:
by: claude/opus-5
at: 2026-08-13T00:00:00Z
at: 2026-08-21T07:49:13Z
verified:
- { by: claude/opus-5, at: 2026-08-21T07:49:13Z }
- by: human:pftg
at: 2026-08-13T00:00:00Z
---
Expand Down Expand Up @@ -60,6 +61,11 @@ mistake-grid CTA, or a module card.

# Citations

* [Component library + the shuffle2 reference](../../docs/projects/2605-tech-for-non-technical-founders/30-39-architecture-design/course-landing-components-2026-08.md)
* Component library + the shuffle2 reference:
`docs/projects/2605-tech-for-non-technical-founders/30-39-architecture-design/course-landing-components-2026-08.md`
(repo-relative, and the same path as this concept`s `resource:`). Written as a
PATH, not a markdown link: a link escaping the bundle with `../../` resolves
correctly on disk but the validator cannot follow it out of `.okf/`, so it
warns forever and invites someone to "fix" a link that was never broken.
* [Visual scroll gate](../workflows/visual-scroll-gate.md)
* [ICP profile](../content-strategy/icp-primary-website-target.md)
27 changes: 15 additions & 12 deletions .okf/design/site-palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ resource: themes/beaver/assets/css/foundations/css-variables.css
tags: [design, palette, css, tokens, adr]
generated:
by: claude/opus-5
at: 2026-08-20T00:00:00Z
timestamp: 2026-08-21T03:17:09Z
at: 2026-08-21T07:45:14Z
timestamp: 2026-08-21T07:45:14Z
---

# Resolved: LIGHT (ADR-0003, 2026-08-20)
Expand Down Expand Up @@ -106,8 +106,8 @@ Two consequences, and the second is the one that is easy to miss:
footer/dark-surface migration cannot ship before the on-dark accent is
decided, or it degrades contrast on every band it touches.

**Candidates derived and measured 2026-08-21. Recommended: `#e85a52`, named
`--ruby-on-ink`.**
**DECIDED and SHIPPED 2026-08-21: `#e85a52`, named `--ruby-on-ink`**, in
`foundations/css-variables.css` (PR #540). Candidates as measured:

| Candidate | on `--surface-ink` | on `#000` | on white |
|---|---|---|---|
Expand All @@ -127,14 +127,17 @@ general accent trades an AA failure on dark for one on light. The ramp has
`--ruby-700` for "text-on-light where AA needs more" and no counterpart for
dark; that gap is the whole issue.

Not yet applied - it changes the rendered colour on every dark band, which is
Paul's call. Tracked in
`docs/projects/2608-site-design-system/README.md` under Outstanding.

**Until it is named: do not apply a ruby text token to any surface in the
section below.** Neither of the two automated gates catches this - those
homepage sections carry no contrast test, and the screenshot suite passes a
colour change of this size.
Applied in PR #540 to the four eyebrows that measured below AA:
`home-services-eyebrow` and `home-clients-eyebrow` (4.10 -> 6.02),
`about-achievements-eyebrow` and `service-overview-eyebrow` (3.67 -> pass after
their bands migrated). NOT swept site-wide - only rules measured failing on a
dark surface were changed, which is what the reverted 41-rule sweep got wrong.

**Still true after the decision: neither automated gate catches a contrast
regression here.** Those homepage sections carry no contrast test, and the
screenshot suite passes a colour change of this size. Ruby text landing on a dark
surface must be measured in the browser, per the ladder in
[architecture/css-pipeline.md](/architecture/css-pipeline.md).

# Where dark is still deliberate

Expand Down
8 changes: 8 additions & 0 deletions .okf/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ sessions verify the same concept concurrently and a rebase conflicts on the
verification really happened, and dropping one falsifies the provenance the
field exists to carry (2026-08-20, `build/test-gates.md`).

**Reference files OUTSIDE the bundle by PATH, not by a `../../` markdown link**
(2026-08-21). Such a link resolves fine on disk but the validator cannot follow
it out of `.okf/`, so it warns on every run forever - and a permanent warning
invites someone to "fix" a link that was never broken. Put the canonical
repo-relative path in `resource:` (or `sources:`) frontmatter and write the path
as inline code in the body. Removing the one instance took the bundle's
cross-link warnings to zero.

**Stamp actual UTC - take it from `date -u`, never compose it** (2026-08-20).
Eighteen stamps across nine concepts were written as local time carrying a `Z`
suffix, putting them ~2h in the future. That is not cosmetic HERE of all
Expand Down
Loading
Loading