rastrillo / fiesta Public

The browser harness, Node runner, colour maths, spelling grammar, axe and the drive helpers

Task 3 of the Fiesta part-1 plan: the test infrastructure the ported
gates and drives will stand on, from rastrillo at SEED, e14b745.

internal/harness is rastrillo's harness/ without the virtual
authenticator: prfshim.go and the webauthn boot are left out, and
RASTRILLO_CHROME and RASTRILLO_BROWSER_OPTIONAL become FIESTA_CHROME
and FIESTA_BROWSER_OPTIONAL. watch.go, junk.go, screen.go and the three
test files are byte for byte SEED's. One change to New beyond the
removal: the graceful chromedp.Cancel is registered only once the
browser has started. With FIESTA_CHROME=/nonexistent the SEED shape
hung until go test's own alarm, because chromedp.Cancel on a context
whose browser never started waits on c.allocated, which only the
post-start goroutine closes, after the context watcher has taken the
one buffered token. A failed boot now cancels the two contexts itself
and fails as "harness: browser boot: fork/exec /nonexistent: no such
file or directory" in 0.003s.

internal/nodetest is rastrillo's nodetest/ with RequireEnv renamed
FIESTA_TEST_REQUIRE_NODE, the testdata scripts included.
internal/markup is rastrillo's internal/markup/, verbatim.

internal/axe carries the vendored engine and its README from
ui/testdata/axe, the pin test from ui/axe_test.go with axeDir ".",
and two new files: axe.go (Script, DefaultTags, Violation, untagged)
and run.go (Run, behind the browser tag, so chromedp stays out of the
plain build graph as it does for the harness). Run's expression is
a11y_test.go's axeRun and scan folded together: the engine is
evaluated into the page if window.axe is missing, the tags default to
the five WCAG 2.2 AA tags, fewer than five passing rules is
ErrNothingScanned, and violations come back sorted by id with one
selector per node. Checked by hand on a page with a planted image-alt
violation: found whole, out of scope when scoped to a button (2 rules,
under the floor), and an error for a selector matching nothing.
README.md is verbatim, and its prose names rastrillo paths; drafted
replacement text is in the task report for copy review, since it is
read by people.

check/colour.go is ui/colour.go from the "OKLCH -> sRGB" header
through ContrastRatio, every name and signature as it was, except
normalHex: its only caller, checkWash, is outside the range and stays
in rastrillo, and staticcheck's U1000 refuses an unexported function
nothing calls. check/colour_test.go is the tests of that range from
ui/colour_test.go unchanged: TestContrastRatioControls,
TestOklchHexControls with hueOf and angleDiff, TestDeltaEOKControls,
TestOnlyWhiteReachesFullLuminance and BenchmarkColourContrastRatio.
TestFloorConstantsAreTheStandard and TestLuminanceRisesWithLightness
reach the engine's constants and stepLightness, so they stay behind.

check/colourhelp_test.go, untagged, is canonColours with everything it
reaches: oklchClip and the srgbSer and oklchSer regexes, verbatim.

check/rig_browser_test.go is the shared drive helpers, each verbatim
except where named: sizingDoc links /fiesta.js where SEED linked
/rastrillo.js; stylesheets and pressFallbackRig read fiesta.TokensCSS,
fiesta.ThemeCSS and fiesta.ThemeNames; RequireAnchorPositioning quotes
with jsStr, this file's copy of galleryrig's identical jsString. The
dependencies that moved with them, beyond the brief's list:
fixtureImages (ui/mediagrid_browser_test.go), jsStr, probeScripted,
forcedRoot, and the types typeReading, fontReading, point and
targetReading. sizingMux is sizingMuxWith(t, pages, fiesta.Script),
and sizingMuxWith serves /tokens.css and /theme.css (day: no SEED mux
read a ?theme= query), /shell.css, /images/, /icons/<slug>.svg, and
every /<name>.js and /i18n/<name>.js through the lookup, which 404s
for a file it lacks. A keep list in each test file is the use
staticcheck asks for until the drives that call each helper land.

TestTheDepthFixtureServesItsStylesheets serves depthDoc() with its
script tags stripped, fetches /tokens.css and /theme.css (200, non-
empty), reads --rst-radius off the page, and flushes the harness.
Without the strip the page would 404 on /fiesta.js, which Task 4
writes; the smoke test that loads every script waits for it.

The Makefile's BROWSER_PKGS is now internal/harness check, so the
suite has six roles and the step is 50-suite@6. go.mod requires
chromedp v0.14.2, cdproto 20250724212937 and go-json-experiment/json
20250725192818, rastrillo's pins.

Preservation tests, green on first run:
  FIESTA_TEST_REQUIRE_NODE=1 go test ./internal/... ./check/ -count=1
    ok internal/axe, internal/markup, internal/nodetest, check
  make browser.internal.harness browser.check
    ok internal/harness 7.755s; ok check 0.677s
  make ci: gofmt, no-rastrillo, root, staticcheck, govulncheck,
    gitleaks, browser.internal.harness, browser.check, all green.
Negative control:
  FIESTA_CHROME=/nonexistent go test -tags browser -run
    TestScreenPassesACleanPage ./internal/harness/ -count=1
  --- FAIL: TestScreenPassesACleanPage (0.00s)
      junk_test.go:75: harness: browser boot: fork/exec /nonexistent:
      no such file or directory
Human

Prompt

Task 3 of the Fiesta part-1 plan: port the test infrastructure (harness, Node, colour, spelling and drive helpers) from rastrillo at SEED, per the task brief and the preflight rulings.

From this commit's own message. The prompt ledger has no entries for it — which is what a squashed, rebased or amended commit looks like, and what every commit looks like in a repo without a ledger.

Summary

Adds internal/harness, internal/nodetest, internal/markup and internal/axe, the colour arithmetic and its tests in check/, the shared drive helpers in check/rig_browser_test.go, and the two browser roles in the Makefile with the suite step renamed 50-suite@6.
Agent notes
Later porting tasks delete from the files they copy every helper this commit moved; the full list is in the task report. internal/axe/README.md still names rastrillo paths and needs copy review. The keep lists in check/colourhelp_test.go and check/rig_browser_test.go shrink as drives land.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 3079cd592c12dadaf758ff6b6ded1494084aac23 parent a06d9e8
30 files changed, +3635 −3
  • .amadan/ci.d/{50-suite@4 => 50-suite@6} +0 −0
  • Makefile +3 −3
  • check/colour.go +311 −0
  • check/colour_test.go +242 −0
  • check/colourhelp_test.go +75 −0
  • check/rig_browser_test.go +552 −0
  • go.mod +14 −0
  • go.sum +21 −0
  • internal/axe/README.md +35 −0
  • internal/axe/axe.go +48 −0
  • internal/axe/axe.min.js +12 −0
  • internal/axe/axe_test.go +56 −0
  • internal/axe/run.go +123 −0
  • internal/harness/chrome.go +40 −0
  • internal/harness/doc.go +18 −0
  • internal/harness/junk.go +77 −0
  • internal/harness/junk_test.go +78 −0
  • internal/harness/rig.go +207 −0
  • internal/harness/rig_test.go +77 −0
  • internal/harness/screen.go +46 −0
  • internal/harness/watch.go +153 −0
  • internal/harness/watch_test.go +119 −0
  • internal/markup/markup.go +158 −0
  • internal/markup/markup_test.go +383 −0
  • internal/markup/rewrite.go +566 −0
  • internal/nodetest/nodetest.go +108 −0
  • internal/nodetest/nodetest_test.go +101 −0
  • internal/nodetest/testdata/echo.mjs +6 −0
  • internal/nodetest/testdata/fail.mjs +5 −0
  • internal/nodetest/testdata/hang.mjs +1 −0

CI passed — run details

CI log
=== gofmt ===
=== no-rastrillo ===
go test -run '^(TestFiestaNeverImportsRastrillo|TestThePublicPackagesLinkNoBrowser)$' -count=1 .
ok  	amadan.net/rastrillo/fiesta	1.217s
=== suite ===
--- shard 0 of 6 ---
==> shard 0 of 6: make root
go build ./...
go vet ./...
FIESTA_TEST_REQUIRE_NODE=1 go test -count=1 ./...
ok  	amadan.net/rastrillo/fiesta	0.452s
ok  	amadan.net/rastrillo/fiesta/check	0.055s
ok  	amadan.net/rastrillo/fiesta/internal/axe	0.007s
?   	amadan.net/rastrillo/fiesta/internal/harness	[no test files]
ok  	amadan.net/rastrillo/fiesta/internal/markup	0.014s
ok  	amadan.net/rastrillo/fiesta/internal/nodetest	0.373s
--- shard 1 of 6 ---
==> shard 1 of 6: make staticcheck
go run honnef.co/go/tools/cmd/staticcheck@v0.8.2 -tags browser ./...
--- shard 2 of 6 ---
==> shard 2 of 6: make govulncheck
go run golang.org/x/vuln/cmd/govulncheck@v1.8.0 ./...
No vulnerabilities found.
--- shard 3 of 6 ---
==> shard 3 of 6: make gitleaks
go run github.com/zricethezav/gitleaks/v8@v8.30.1 git --no-banner --redact --log-opts='--full-history --diff-filter=tuxdb HEAD' .
8:38PM INF Unknown SCM platform. Use --platform to include links in findings. host=amadan.net
8:39PM INF 1 commits scanned.
8:39PM INF scanned ~1727510 bytes (1.73 MB) in 2.08s
8:39PM INF no leaks found
--- shard 4 of 6 ---
==> shard 4 of 6: make browser.internal.harness
./hack/gotest.sh browser 'internal.harness'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
ok  	amadan.net/rastrillo/fiesta/internal/harness	6.497s
--- shard 5 of 6 ---
==> shard 5 of 6: make browser.check
./hack/gotest.sh browser 'check'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
ok  	amadan.net/rastrillo/fiesta/check	0.743s
.amadan/ci.d/{50-suite@4 => 50-suite@6}

Loading diff…

Makefile

Loading diff…

check/colour.go

Loading diff…

check/colour_test.go

Loading diff…

check/colourhelp_test.go

Loading diff…

check/rig_browser_test.go

Loading diff…

go.mod

Loading diff…

go.sum

Loading diff…

internal/axe/README.md

Loading diff…

internal/axe/axe.go

Loading diff…

internal/axe/axe.min.js

Loading diff…

internal/axe/axe_test.go

Loading diff…

internal/axe/run.go

Loading diff…

internal/harness/chrome.go

Loading diff…

internal/harness/doc.go

Loading diff…

internal/harness/junk.go

Loading diff…

internal/harness/junk_test.go

Loading diff…

internal/harness/rig.go

Loading diff…

internal/harness/rig_test.go

Loading diff…

internal/harness/screen.go

Loading diff…

internal/harness/watch.go

Loading diff…

internal/harness/watch_test.go

Loading diff…

internal/markup/markup.go

Loading diff…

internal/markup/markup_test.go

Loading diff…

internal/markup/rewrite.go

Loading diff…

internal/nodetest/nodetest.go

Loading diff…

internal/nodetest/nodetest_test.go

Loading diff…

internal/nodetest/testdata/echo.mjs

Loading diff…

internal/nodetest/testdata/fail.mjs

Loading diff…

internal/nodetest/testdata/hang.mjs

Loading diff…