feat(validation): phase 11 — the walk that found what the checks could not
All checks were successful
PR checks / checks (pull_request) Successful in 1m26s

The checks were green before this phase started and are green now. What found
anything was the part no script does: fifty pages at three widths in a real
browser, a signup walked against its store, and a full brand mount applied and
restarted.

D51 — the chrome and the head follow the mount; the consent sentence does not.
With a complete brand.json mounted, forty-nine pages came back rebranded and
/beta did not. applyBrand.mjs rewrites files in dist/client and /beta renders
per request, so its HTML never exists as a file to rewrite; liveBrand() was
there for exactly that and was used for betaOptInUrl alone. Everything around
the form — title, OG tags, header lockup, footer Source and Discord links —
came from the shared chrome, and the shared chrome was baked. renderBrand()
picks by Astro.isPrerendered, in one place, so the other forty-nine keep taking
the value the boot rewrite will replace. CONSENT_TEXT stays a constant: it is
stored verbatim in a person's row, so following a mounted name would change the
recorded text of a consent already given.

D52 — the documentation half gets phase 10's skip-link fix. Starlight's skip
link targets the page <h1>, which is no more focusable than the <main> phase 10
fixed, so following it moved the viewport and not the focus on forty pages. A
PageTitle override adds tabindex="-1".

D53 — no twelfth check. The external-link sweep (73 of 74 alive) and the
brand-mount walk stay throwaway scripts: one would make the build depend on
other people's uptime and the other needs Chrome on the runner.

Also recorded and deliberately not fixed: Starlight's heading anchor links
measure under 24px at 390, and are exempt under SC 2.5.8's Equivalent clause
because the mobile table of contents links to every one of the same anchors.

npm run verify green — fourteen steps, both suites, all eleven checks.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-25 15:16:08 -05:00
parent 58883951a4
commit de9d25bbe7
8 changed files with 211 additions and 8 deletions

View File

@@ -113,3 +113,37 @@ export function liveBrand() {
cache = { mtimeMs, value: Object.freeze(merged) };
return cache.value;
}
/* =========================================================================================
THE CHROME, WHICH RENDERS BOTH WAYS (phase 11)
=========================================================================================
The two accessors above are each correct for a page that only ever renders one way. The
header, the footer and `Base.astro`'s head are neither: the same components render at
build time for the forty-nine prerendered pages and at request time for `/beta`.
Phase 11's brand walk is what found that. With a full brand mounted, every page came
back rebranded except `/beta`, which still carried the stock site name in its title, its
OG tags and its header lockup, and the stock Discord and Gitea links in its footer — the
one page whose whole job is to ask a person for their address under a stated identity.
`/beta` already read the mount, but only for `betaOptInUrl`; everything around the form
came from the chrome, and the chrome was baked.
Calling `liveBrand()` from the chrome unconditionally would fix `/beta` and quietly move
a build-time value onto the runtime path for the other forty-nine, where a build machine
that happened to have a mount would bake mounted text into HTML the boot rewrite then
has nothing to replace. `isPrerendered` is the honest discriminator, so it is the one
used, in one place, rather than the same reasoning repeated in three components:
- prerendered -> the stock value, which `applyBrand.mjs` rewrites at boot,
- on demand -> the mount, read now.
The consent sentence is deliberately NOT here. It names the operator of the list in a
statement a person agrees to and which is stored verbatim in their row, so making it
follow a mounted name would change the recorded text of an existing consent. The org
lead settled that on 2026-08-25: the chrome and the head are brandable, `CONSENT_TEXT`
stays a constant and changes only with a consent-version bump.
*/
export function renderBrand(astro) {
return astro?.isPrerendered === false ? liveBrand() : brand;
}