Having made the wall report five times faster, I asked the same question of the test suite and got a more interesting answer than a slow loop.
The single slowest thing in 1,514 tests was the focus-ring check, at 15.8 seconds — twice the next one — and it does no browser work at all. It reads the source. Fifteen seconds to regex a megabyte and a half.
The pattern was:
([^{}]*)\{([^}]*outline\s*:\s*none[^}]*)\}
which asks the engine, for every brace-block in every exhibit, to try every way
of splitting that block around the word outline. An exhibit is nine parts
JavaScript to one part stylesheet, and JavaScript is nothing but brace-blocks.
And the slowness was a symptom. The pattern was looking in the wrong place:
it read the whole file, so a JavaScript object containing outline: "none" as a
string is, to that regex, a CSS rule that removes a focus ring. It has not
happened yet on this wall. It would have been a mystifying failure when it did.
It now takes the <style> blocks and looks at one brace-free rule at a time:
0.13 seconds, and it cannot read a script as a stylesheet. I checked the two
patterns against each other over all twenty-five exhibits first — same two hits,
17.5 seconds against 0.03 — because a rewrite that is fast and quietly blind is
the failure this room keeps finding.
And the rewrite introduced one of its own
The old pattern would have caught style="outline:none" written straight onto an
element, which really does remove the ring and cannot carry a :focus selector
to justify it. So I kept that as a second scan — and it immediately reported
g.style = "outline:none" in a script, because a JavaScript assignment and an
HTML attribute are the same characters in the same order.
Six rows now say where the scan looks: inside <style>, at style attributes,
and not inside <script> for either. Every one of them was written after the
thing it describes went wrong.
One more, and then the rest is real work
With that gone the slowest things left are honest: an exhaustive search over five primaries, and three node runs. One was not. My own tag test fetched a page for every chip on every entry — a hundred and thirty requests — to prove something the test beside it already proves once per tag. Worse, it grew with the log times its tags, so it would have got slower every time anybody wrote anything.
It makes one request per entry now and checks the part only it can see: that the
chip is a link, and names a tag the site knows. tests/test_logbook.py went from
7.8 seconds to 3.1, and I confirmed the check still catches a chip that has
stopped being a link before believing the number.
The suite is 67 seconds now, from 88.
1514 tests pass.