rastrillo / fiesta Public

Ask every enclosing header for its heading, and read unrespelled classes off the element, not the notes

Two ways past the Row Rule check, both found in review.

A heading was only asked of the nearest row. A toolbar inside a
page header with no h1 passed, as did one inside a titleless section
head, though the menu still has nothing beside it to act on. Every
page header and section head around a dropdown now needs its
heading, whatever row sits between them.

Every respelling note was reported as a breach. Most notes are about
escaped markup in a code sample, such as class="rst-box",
which is text and holds no dropdown, so a page documenting the class
spelling would have failed the rule. The notes are no longer read.
What the check needs to know is whether the respeller left an
element's class list alone while it still names a component class,
since a dropdown or row written that way is one the check cannot
see; that is read off the parsed element, and utility classes with
no attribute twin, such as rst-sr-only, do not count.

Each control was red by its exact message before the change: the
titleless page header and section head around a toolbar, in both
spellings; the unreadable class list (it read as a respelling note);
and the escaped code sample (it read as a breach). Mutations, each
caught by name: checking only the nearest row for its heading turns
the four heading controls red; never reporting an unread class list
turns that control red.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 939f3759cff86a3c78026c29da5d7d97b601aa84 parent d49fca4
1 file changed, +63 −13
  • check/rows_rule_test.go +63 −13

CI passed — run details

CI log
=== gofmt ===
=== no-rastrillo ===
go test -run '^(TestFiestaNeverImportsRastrillo|TestThePublicPackagesLinkNoBrowser)$' -count=1 .
ok  	amadan.net/rastrillo/fiesta	0.207s
=== size ===
go test ./internal/build -run '^TestTheOneLinkIsUnder25KiBGzipped$' -count=1 -v
=== RUN   TestTheOneLinkIsUnder25KiBGzipped
    build_test.go:138: fiesta-plain.css: 153737 bytes, 22431 bytes gzipped (21.9 KiB of the 25.0 KiB limit)
    build_test.go:138: fiesta-signal.css: 153832 bytes, 22542 bytes gzipped (22.0 KiB of the 25.0 KiB limit)
    build_test.go:138: fiesta.css: 156651 bytes, 23146 bytes gzipped (22.6 KiB of the 25.0 KiB limit)
--- PASS: TestTheOneLinkIsUnder25KiBGzipped (0.02s)
PASS
ok  	amadan.net/rastrillo/fiesta/internal/build	0.024s
=== history ===
history: 23 commits; release tags: v1.0.0
=== suite ===
--- shard 0 of 48 ---
==> shard 0 of 48: make root
go build ./...
go vet ./...
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh root 'internal/gallery@3 cmd/fiesta@2 internal/www@2'
ok  	amadan.net/rastrillo/fiesta	5.620s
ok  	amadan.net/rastrillo/fiesta/check	7.054s
ok  	amadan.net/rastrillo/fiesta/example	0.201s
?   	amadan.net/rastrillo/fiesta/hack/seed/english	[no test files]
ok  	amadan.net/rastrillo/fiesta/internal/axe	0.086s
ok  	amadan.net/rastrillo/fiesta/internal/build	1.115s
ok  	amadan.net/rastrillo/fiesta/internal/codeview	0.003s
?   	amadan.net/rastrillo/fiesta/internal/harness	[no test files]
ok  	amadan.net/rastrillo/fiesta/internal/markup	0.005s
ok  	amadan.net/rastrillo/fiesta/internal/nodetest	0.331s
ok  	amadan.net/rastrillo/fiesta/internal/site	2.768s
ok  	amadan.net/rastrillo/fiesta/internal/tokens	0.011s
suite: root took 13s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m10.340000s 0m1.710000s
--- shard 1 of 48 ---
==> shard 1 of 48: make test.internal.gallery~1of3
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'internal.gallery~1of3'
gotest: slice 1 of 3 of ./internal/gallery/ runs 36 of 107 test tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	61.570s
suite: test.internal.gallery~1of3 took 62s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m46.440000s 0m1.100000s
--- shard 2 of 48 ---
==> shard 2 of 48: make test.internal.gallery~2of3
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'internal.gallery~2of3'
gotest: slice 2 of 3 of ./internal/gallery/ runs 35 of 107 test tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	60.941s
suite: test.internal.gallery~2of3 took 62s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m45.850000s 0m1.230000s
--- shard 3 of 48 ---
==> shard 3 of 48: make test.internal.gallery~3of3
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'internal.gallery~3of3'
gotest: slice 3 of 3 of ./internal/gallery/ runs 36 of 107 test tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	54.752s
suite: test.internal.gallery~3of3 took 62s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m40.020000s 0m0.990000s
--- shard 4 of 48 ---
==> shard 4 of 48: make test.cmd.fiesta~1of2
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'cmd.fiesta~1of2'
gotest: slice 1 of 2 of ./cmd/fiesta/ runs 7 of 12 test tests
ok  	amadan.net/rastrillo/fiesta/cmd/fiesta	46.848s
suite: test.cmd.fiesta~1of2 took 48s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m31.270000s 0m1.920000s
--- shard 5 of 48 ---
==> shard 5 of 48: make test.cmd.fiesta~2of2
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'cmd.fiesta~2of2'
gotest: slice 2 of 2 of ./cmd/fiesta/ runs 5 of 12 test tests
ok  	amadan.net/rastrillo/fiesta/cmd/fiesta	50.029s
suite: test.cmd.fiesta~2of2 took 51s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m33.970000s 0m2.150000s
--- shard 6 of 48 ---
==> shard 6 of 48: make test.internal.www~1of2
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'internal.www~1of2'
gotest: slice 1 of 2 of ./internal/www/ runs 11 of 25 test tests
ok  	amadan.net/rastrillo/fiesta/internal/www	59.639s
suite: test.internal.www~1of2 took 66s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m45.090000s 0m1.400000s
--- shard 7 of 48 ---
==> shard 7 of 48: make test.internal.www~2of2
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'internal.www~2of2'
gotest: slice 2 of 2 of ./internal/www/ runs 14 of 25 test tests
ok  	amadan.net/rastrillo/fiesta/internal/www	56.942s
suite: test.internal.www~2of2 took 63s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m42.880000s 0m1.500000s
--- shard 8 of 48 ---
==> shard 8 of 48: make staticcheck
go run honnef.co/go/tools/cmd/staticcheck@v0.8.2 -tags browser ./...
suite: staticcheck took 8s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m8.410000s 0m0.670000s
--- shard 9 of 48 ---
==> shard 9 of 48: make govulncheck
go run golang.org/x/vuln/cmd/govulncheck@v1.8.0 ./...
=== Symbol Results ===

No vulnerabilities found.

Your code is affected by 0 vulnerabilities.
This scan also found 2 vulnerabilities in packages you import and 5
vulnerabilities in modules you require, but your code doesn't appear to call
these vulnerabilities.
Use '-show verbose' for more details.
suite: govulncheck took 6s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m3.010000s 0m0.360000s
--- shard 10 of 48 ---
==> shard 10 of 48: make gitleaks
go run github.com/zricethezav/gitleaks/v8@v8.30.1 git --no-banner --redact --log-opts='--full-history --diff-filter=tuxdb HEAD' .
4:22AM INF Unknown SCM platform. Use --platform to include links in findings. host=amadan.net
4:22AM INF 23 commits scanned.
4:22AM INF scanned ~8282101 bytes (8.28 MB) in 5.98s
4:22AM INF no leaks found
suite: gitleaks took 8s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m7.020000s 0m0.260000s
--- shard 11 of 48 ---
==> shard 11 of 48: make browser.internal.harness
./hack/gotest.sh browser 'internal.harness'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: ./internal/harness/ runs its 10 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/harness	4.242s
suite: browser.internal.harness took 10s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m1.650000s 0m1.220000s
--- shard 12 of 48 ---
==> shard 12 of 48: make browser.check~1of13
./hack/gotest.sh browser 'check~1of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 1 of 13 of ./check/ runs 16 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	84.391s
suite: browser.check~1of13 took 93s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m46.490000s 0m13.340000s
--- shard 13 of 48 ---
==> shard 13 of 48: make browser.check~2of13
./hack/gotest.sh browser 'check~2of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 2 of 13 of ./check/ runs 17 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	94.263s
suite: browser.check~2of13 took 103s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m48.970000s 0m13.220000s
--- shard 14 of 48 ---
==> shard 14 of 48: make browser.check~3of13
./hack/gotest.sh browser 'check~3of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 3 of 13 of ./check/ runs 15 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	88.236s
suite: browser.check~3of13 took 97s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m39.690000s 0m10.680000s
--- shard 15 of 48 ---
==> shard 15 of 48: make browser.check~4of13
./hack/gotest.sh browser 'check~4of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 4 of 13 of ./check/ runs 15 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	83.793s
suite: browser.check~4of13 took 92s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m51.480000s 0m15.300000s
--- shard 16 of 48 ---
==> shard 16 of 48: make browser.check~5of13
./hack/gotest.sh browser 'check~5of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 5 of 13 of ./check/ runs 17 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	75.834s
suite: browser.check~5of13 took 84s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m37.060000s 0m12.780000s
--- shard 17 of 48 ---
==> shard 17 of 48: make browser.check~6of13
./hack/gotest.sh browser 'check~6of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 6 of 13 of ./check/ runs 17 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	74.748s
suite: browser.check~6of13 took 83s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m41.820000s 0m14.330000s
--- shard 18 of 48 ---
==> shard 18 of 48: make browser.check~7of13
./hack/gotest.sh browser 'check~7of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 7 of 13 of ./check/ runs 17 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	82.897s
suite: browser.check~7of13 took 92s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m43.590000s 0m14.470000s
--- shard 19 of 48 ---
==> shard 19 of 48: make browser.check~8of13
./hack/gotest.sh browser 'check~8of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 8 of 13 of ./check/ runs 17 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	86.547s
suite: browser.check~8of13 took 95s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m43.340000s 0m14.700000s
--- shard 20 of 48 ---
==> shard 20 of 48: make browser.check~9of13
./hack/gotest.sh browser 'check~9of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 9 of 13 of ./check/ runs 17 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	76.420s
suite: browser.check~9of13 took 85s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m28.670000s 0m8.890000s
--- shard 21 of 48 ---
==> shard 21 of 48: make browser.check~10of13
./hack/gotest.sh browser 'check~10of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 10 of 13 of ./check/ runs 17 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	80.373s
suite: browser.check~10of13 took 89s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m37.090000s 0m11.740000s
--- shard 22 of 48 ---
==> shard 22 of 48: make browser.check~11of13
./hack/gotest.sh browser 'check~11of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 11 of 13 of ./check/ runs 17 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	78.827s
suite: browser.check~11of13 took 88s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m41.440000s 0m14.210000s
--- shard 23 of 48 ---
==> shard 23 of 48: make browser.check~12of13
./hack/gotest.sh browser 'check~12of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 12 of 13 of ./check/ runs 17 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	81.239s
suite: browser.check~12of13 took 90s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m44.290000s 0m15.330000s
--- shard 24 of 48 ---
==> shard 24 of 48: make browser.check~13of13
./hack/gotest.sh browser 'check~13of13'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 13 of 13 of ./check/ runs 17 of 216 browser tests
ok  	amadan.net/rastrillo/fiesta/check	78.502s
suite: browser.check~13of13 took 87s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m35.720000s 0m10.300000s
--- shard 25 of 48 ---
==> shard 25 of 48: make browser.internal.gallery~1of18
./hack/gotest.sh browser 'internal.gallery~1of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 1 of 18 of ./internal/gallery/ runs 5 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	38.285s
suite: browser.internal.gallery~1of18 took 46s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m11.880000s 0m3.480000s
--- shard 26 of 48 ---
==> shard 26 of 48: make browser.internal.gallery~2of18
./hack/gotest.sh browser 'internal.gallery~2of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 2 of 18 of ./internal/gallery/ runs 5 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	50.310s
suite: browser.internal.gallery~2of18 took 62s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m9.890000s 0m2.470000s
--- shard 27 of 48 ---
==> shard 27 of 48: make browser.internal.gallery~3of18
./hack/gotest.sh browser 'internal.gallery~3of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 3 of 18 of ./internal/gallery/ runs 5 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	58.408s
suite: browser.internal.gallery~3of18 took 66s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m12.130000s 0m3.910000s
--- shard 28 of 48 ---
==> shard 28 of 48: make browser.internal.gallery~4of18
./hack/gotest.sh browser 'internal.gallery~4of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 4 of 18 of ./internal/gallery/ runs 6 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	49.515s
suite: browser.internal.gallery~4of18 took 62s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m10.120000s 0m2.590000s
--- shard 29 of 48 ---
==> shard 29 of 48: make browser.internal.gallery~5of18
./hack/gotest.sh browser 'internal.gallery~5of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 5 of 18 of ./internal/gallery/ runs 6 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	57.606s
suite: browser.internal.gallery~5of18 took 65s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m14.400000s 0m4.860000s
--- shard 30 of 48 ---
==> shard 30 of 48: make browser.internal.gallery~6of18
./hack/gotest.sh browser 'internal.gallery~6of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 6 of 18 of ./internal/gallery/ runs 5 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	57.968s
suite: browser.internal.gallery~6of18 took 66s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m12.220000s 0m3.770000s
--- shard 31 of 48 ---
==> shard 31 of 48: make browser.internal.gallery~7of18
./hack/gotest.sh browser 'internal.gallery~7of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 7 of 18 of ./internal/gallery/ runs 5 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	55.922s
suite: browser.internal.gallery~7of18 took 63s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m10.020000s 0m2.560000s
--- shard 32 of 48 ---
==> shard 32 of 48: make browser.internal.gallery~8of18
./hack/gotest.sh browser 'internal.gallery~8of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 8 of 18 of ./internal/gallery/ runs 5 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	58.954s
suite: browser.internal.gallery~8of18 took 66s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m13.890000s 0m4.360000s
--- shard 33 of 48 ---
==> shard 33 of 48: make browser.internal.gallery~9of18
./hack/gotest.sh browser 'internal.gallery~9of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 9 of 18 of ./internal/gallery/ runs 6 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	64.389s
suite: browser.internal.gallery~9of18 took 72s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m18.630000s 0m7.090000s
--- shard 34 of 48 ---
==> shard 34 of 48: make browser.internal.gallery~10of18
./hack/gotest.sh browser 'internal.gallery~10of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 10 of 18 of ./internal/gallery/ runs 2 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	60.328s
suite: browser.internal.gallery~10of18 took 68s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m9.960000s 0m2.410000s
--- shard 35 of 48 ---
==> shard 35 of 48: make browser.internal.gallery~11of18
./hack/gotest.sh browser 'internal.gallery~11of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 11 of 18 of ./internal/gallery/ runs 2 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	61.773s
suite: browser.internal.gallery~11of18 took 70s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m10.080000s 0m2.410000s
--- shard 36 of 48 ---
==> shard 36 of 48: make browser.internal.gallery~12of18
./hack/gotest.sh browser 'internal.gallery~12of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 12 of 18 of ./internal/gallery/ runs 2 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	62.172s
suite: browser.internal.gallery~12of18 took 70s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m14.280000s 0m4.570000s
--- shard 37 of 48 ---
==> shard 37 of 48: make browser.internal.gallery~13of18
./hack/gotest.sh browser 'internal.gallery~13of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 13 of 18 of ./internal/gallery/ runs 4 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	64.623s
suite: browser.internal.gallery~13of18 took 72s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m14.910000s 0m5.160000s
--- shard 38 of 48 ---
==> shard 38 of 48: make browser.internal.gallery~14of18
./hack/gotest.sh browser 'internal.gallery~14of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 14 of 18 of ./internal/gallery/ runs 5 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	65.821s
suite: browser.internal.gallery~14of18 took 73s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m15.090000s 0m5.130000s
--- shard 39 of 48 ---
==> shard 39 of 48: make browser.internal.gallery~15of18
./hack/gotest.sh browser 'internal.gallery~15of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 15 of 18 of ./internal/gallery/ runs 5 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	66.214s
suite: browser.internal.gallery~15of18 took 74s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m15.240000s 0m5.200000s
--- shard 40 of 48 ---
==> shard 40 of 48: make browser.internal.gallery~16of18
./hack/gotest.sh browser 'internal.gallery~16of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 16 of 18 of ./internal/gallery/ runs 5 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	60.353s
suite: browser.internal.gallery~16of18 took 68s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m12.290000s 0m4.060000s
--- shard 41 of 48 ---
==> shard 41 of 48: make browser.internal.gallery~17of18
./hack/gotest.sh browser 'internal.gallery~17of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 17 of 18 of ./internal/gallery/ runs 5 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	65.627s
suite: browser.internal.gallery~17of18 took 73s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m15.040000s 0m5.390000s
--- shard 42 of 48 ---
==> shard 42 of 48: make browser.internal.gallery~18of18
./hack/gotest.sh browser 'internal.gallery~18of18'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 18 of 18 of ./internal/gallery/ runs 6 of 84 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	67.209s
suite: browser.internal.gallery~18of18 took 75s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m16.500000s 0m5.950000s
--- shard 43 of 48 ---
==> shard 43 of 48: make browser.internal.gallery.history
./hack/gotest.sh browser 'internal.gallery.history'
gotest: on ip-172-31-17-22, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: ./internal/gallery/history/ runs its 3 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery/history	30.995s
suite: browser.internal.gallery.history took 38s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m20.120000s 0m1.890000s
--- shard 44 of 48 ---
==> shard 44 of 48: make browser.internal.www~1of4
./hack/gotest.sh browser 'internal.www~1of4'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 1 of 4 of ./internal/www/ runs 4 of 22 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/www	67.214s
suite: browser.internal.www~1of4 took 75s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m29.390000s 0m1.950000s
--- shard 45 of 48 ---
==> shard 45 of 48: make browser.internal.www~2of4
./hack/gotest.sh browser 'internal.www~2of4'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 2 of 4 of ./internal/www/ runs 6 of 22 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/www	64.994s
suite: browser.internal.www~2of4 took 73s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m43.490000s 0m2.490000s
--- shard 46 of 48 ---
==> shard 46 of 48: make browser.internal.www~3of4
./hack/gotest.sh browser 'internal.www~3of4'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 3 of 4 of ./internal/www/ runs 6 of 22 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/www	79.130s
suite: browser.internal.www~3of4 took 87s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m49.790000s 0m2.710000s
--- shard 47 of 48 ---
==> shard 47 of 48: make browser.internal.www~4of4
./hack/gotest.sh browser 'internal.www~4of4'
gotest: on ip-172-31-17-22, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 4 of 4 of ./internal/www/ runs 6 of 22 browser tests
ok  	amadan.net/rastrillo/fiesta/internal/www	75.761s
suite: browser.internal.www~4of4 took 83s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m43.870000s 0m2.820000s
diff --git a/check/rows_rule_test.go b/check/rows_rule_test.go
index 910fd84..5a9d3b0 100644
--- a/check/rows_rule_test.go
+++ b/check/rows_rule_test.go
@@ -1,6 +1,7 @@
package check
import (
+ "regexp"
"slices"
"strings"
"testing"
@@ -43,15 +44,13 @@ var shellChrome = []string{"rst-shell-tail", "rst-shell-rail-foot"}
// every example is TestEveryDropdownSitsInARow.
//
// The markup is respelled first, so a class-spelled dropdown is visited
-// and a class-spelled row counts as its attribute twin.
+// and a class-spelled row counts as its attribute twin. The respeller's
+// notes are not read: most are about escaped markup in a code sample,
+// which is text and holds no dropdown. What matters is an element whose
+// class list it left alone, and that is found on the parsed element.
func dropdownsOutOfRow(src string) []string {
- respelled, notes := markup.Respell([]byte(src))
+ respelled, _ := markup.Respell([]byte(src))
var out []string
- // A class list the respeller could not read is a dropdown or a row
- // this check might not see; it is a breach of the check, not a pass.
- for _, n := range notes {
- out = append(out, "the markup could not be respelled: "+n.String())
- }
doc, err := xhtml.Parse(strings.NewReader(string(respelled)))
if err != nil {
return append(out, "the markup does not parse: "+err.Error())
@@ -69,6 +68,9 @@ func dropdownsOutOfRow(src string) []string {
walk(doc)
header := slices.IndexFunc(order, func(n *xhtml.Node) bool { return nodeCarries(n, "rst-page-header") })
for at, n := range order {
+ if c, ok := unrespelled(n); ok {
+ out = append(out, `a class list could not be respelled, so the check cannot read it: <`+n.Data+` class="`+c+`">`)
+ }
if !isDropdown(n) {
continue
}
@@ -76,13 +78,19 @@ func dropdownsOutOfRow(src string) []string {
for row != nil && groupsControls(row) {
row = row.Parent
}
- switch {
- case row == nil || !isRow(row):
+ if row == nil || !isRow(row) {
out = append(out, "a dropdown sits in "+describe(row)+", not in a row")
- case nodeCarries(row, "rst-page-header") && !holds(row, "h1"):
- out = append(out, "a page header holds a dropdown and no h1")
- case nodeCarries(row, "rst-box-head") && !holds(row, "h2", "h3", "h4", "h5", "h6"):
- out = append(out, "a section head holds a dropdown and no heading")
+ }
+ // Every header and section head around the menu needs its
+ // heading, not only the nearest row: a toolbar inside a titleless
+ // page header is still a menu with nothing beside it to act on.
+ for p := n.Parent; p != nil; p = p.Parent {
+ if nodeCarries(p, "rst-page-header") && !holds(p, "h1") {
+ out = append(out, "a page header holds a dropdown and no h1")
+ }
+ if nodeCarries(p, "rst-box-head") && !holds(p, "h2", "h3", "h4", "h5", "h6") {
+ out = append(out, "a section head holds a dropdown and no heading")
+ }
}
if header >= 0 && at < header && !inShellChrome(n) {
out = append(out, "a dropdown comes before the page header")
@@ -91,6 +99,26 @@ func dropdownsOutOfRow(src string) []string {
return out
}
+// unrespelled returns the class list of an element the respeller left
+// as it was while it still names a component class: a dropdown or a row
+// written that way is one this check would never see. Utility classes
+// such as rst-sr-only have no attribute twin and stay classes by design.
+func unrespelled(n *xhtml.Node) (string, bool) {
+ for _, a := range n.Attr {
+ if a.Key != "class" {
+ continue
+ }
+ for _, name := range rstClassName.FindAllString(a.Val, -1) {
+ if _, _, ok := markup.Attribute(name); ok {
+ return a.Val, true
+ }
+ }
+ }
+ return "", false
+}
+
+var rstClassName = regexp.MustCompile(`rst-[A-Za-z0-9_-]+`)
+
func isDropdown(n *xhtml.Node) bool { return n.Data == "details" && nodeCarries(n, "rst-dropdown") }
// nodeCarries reports whether n has the attribute name, whatever its value.
@@ -187,6 +215,28 @@ func TestTheRowCheckNamesEachBreach(t *testing.T) {
`<div rst-box-head><details rst-dropdown><summary>S</summary><div rst-dropdown-menu><h2>P</h2></div></details></div>`,
[]string{"a section head holds a dropdown and no heading"}},
+ {"in a toolbar inside a page header with no title",
+ `<header rst-page-header><div rst-lbar><details rst-dropdown><summary>Menu</summary></details></div></header>`,
+ []string{"a page header holds a dropdown and no h1"}},
+ {"class-spelled, in a toolbar inside a page header with no title",
+ `<header class="rst-page-header"><div class="rst-lbar"><details class="rst-dropdown"><summary>Menu</summary></details></div></header>`,
+ []string{"a page header holds a dropdown and no h1"}},
+ {"in a toolbar inside a section head with no heading",
+ `<div rst-box-head><div rst-lbar><details rst-dropdown><summary>Menu</summary></details></div></div>`,
+ []string{"a section head holds a dropdown and no heading"}},
+ {"class-spelled, in a toolbar inside a section head with no heading",
+ `<div class="rst-box-head"><div class="rst-lbar"><details class="rst-dropdown"><summary>Menu</summary></details></div></div>`,
+ []string{"a section head holds a dropdown and no heading"}},
+ {"a class list the respeller cannot read",
+ `<main rst-page><details class=rst-dropdown{{.Open}}></details></main>`,
+ []string{`a class list could not be respelled, so the check cannot read it: <details class="rst-dropdown{{.Open}}">`}},
+
+ {"escaped markup in a code sample",
+ `<p><code>class=&quot;rst-box&quot;</code></p>`, nil},
+ {"in a toolbar inside a page header with its title",
+ `<header rst-page-header><h1>T</h1><div rst-lbar><details rst-dropdown><summary>Menu</summary></details></div></header>`, nil},
+ {"class-spelled, in a toolbar inside a section head with its heading",
+ `<div class="rst-box-head"><h2>P</h2><div class="rst-lbar"><details class="rst-dropdown"><summary>Menu</summary></details></div></div>`, nil},
{"class-spelled, in a section head with its heading",
`<div class="rst-box-head"><h2>P</h2><details rst-dropdown></details></div>`, nil},
{"in a toolbar, inside a form, after the toolbar's search",