Branch review round three: unmatched brackets, braceMatchEnd, quoted motion declarations, and every CSS reader in check; red then green open
On branch fiesta-1-1
Fixes Astra's round-three findings 4, 5 and 6, and the flaw behind them: CSS readers in check that do not read through the shared scanner, or that guess at structure. Model: Claude Opus 5.5 (claude-opus-5-5), default reasoning.
Commits:
- d37c5b9: brackets
- 94c6b3e: motion gate
- 072d79e: rules, selectors and headings
- 9797a6f: themes, and the gallery's highlight gate moved into check
- 31caf70: tokens.css presence gates
- a92e384: the no-anchor tokens.css
Hub CI passed on a92e384: gofmt, no-rastrillo, size, history and 50-suite@48. Sizes are unchanged: 23,823 / 23,104 / 23,217 gzipped. Nothing under css/, js/, i18n/, icons/ or releases/ changed.
None of the 26 stylesheets is refused (css/, both releases, the seed). Their declaration records are byte for byte the same before and after.
Astra's inputs as rejection controls
| Finding | Input | Before | After | |---|---|---|---| | 4 | :root { --rst-review-probe: ); color: red; } | passes TestTheNewRuleGateHasNoKnownHoles | refused: "a ) closes the {" | | 5 | quoted "{" and "}" across two rules around the reduce block | motion gate passes .missed | names .missed | | 6 | .moving { --rst-proof: "; transition: none;"; } | motion gate passes | names .moving |
Red run, by assertion, on 2ed4142's readers:
baseline_test.go:898: appending :root { --rst-review-probe: ); color: red; } to 1.0.0's tokens.css passes the gate; it changes 1.0 pages
baseline_test.go:1028: declarationsOf("a { --b: ); color: red }"): <nil>, want an error naming the a ) closes
(and 8 more bracket inputs read without error)
css_test.go:557: the motion gate passes .missed, which still moves under reduced motion
css_test.go:557: the motion gate passes .moving, which still moves under reduced motion
css_test.go:573: braceMatchEnd("@media x { a { b: \"}\"; } c { d: \"{\"; } } e { f: \"}\" }", 10) = 23, want 39Green: go test ./check, then the hub.
What changed. There is one bracket reader on cssSpan:
checkCSSBrackets, called fromcssWithoutComments;braceMatchEnd, which now returns an error for an unmatched block;cssItemsandcssDeclarations, which step over brackets with it.
A { inside ( or [ is refused. The motion gate reads declarations with declarationsOf. It now checks 34 declarations in tokens.css where it checked 36: the old comma split cut two :has(a, b) selectors in half. A capitalised TRANSITION was also missed before, and property names are now read in lower case.
Mutations, each red then reverted:
- M1: no bracket check in the comment reader
- M2:
cssDeclarationslets a stray closer through - M3:
braceMatchEndsteps one byte - M4: a closer with nothing open let through
- M5: a closer of the wrong kind let through
- M6:
{inside brackets let through - M7: a disable read from any value holding "transition: none"
- M8: property names read as written
The sweep
Each CSS reader in check, and in any other _test.go that reads css/ or releases/, is now either routed through the scanner and declaration reader or noted as unable to make a gate pass wrongly. The full table is in the report.
Routed:
leafRules(built from the declaration reader)splitSelectorList,endsOnControlElementcssRules(refuses whatreadStylesheetrefuses)- class and attribute selector reading,
tokensStyle floorBlock(commentAt)themeTokens, the scheme-number gate, the theme gates,themePropSet,pressNumber,splitLightDark- the gallery highlight gate, moved into check
shapeLeaks- the token-reference gate (
varRefs) - the modal, focus ring, sr-only, colour-literal, hidden-button, stage-art, sign-in and face gates
- the forced-colours and print blocks, the retired header rule
- zoom floors, type step, target floor
- search landmark, profile placeholder, anchor contract
styleProperties,stripHas- the no-anchor rewrite
Noted: absence checks (fail closed), value parsers fed by the reader, mutations with browser controls, and drives that only serve bytes.
Red on the old readers (probes at 2ed4142):
OLD splitSelectorList("[a=\"]\"], [b]") = ["[a=\"]\"], [b]"]
OLD endsOnControlElement("[title=\"]\"] a") = false
OLD styledClasses: rst-y=true rst-w=true (only a string names them)
OLD tokensStyle: rst-z=true rst-v=true (only a string names them)
OLD strings.Index for the heading = 99, want 119
OLD readLeafRules(nested) = [{selector:cursor: pointer; [rst-d] body: color: red }], err <nil>
OLD parseCSSRules("@import \"x.css\"; [ rst-PAGE] { padding: 0; }") = one selector "@import \"x.css\"; [ rst-PAGE]"
OLD parseTokens(blockBody(:root)) --rst-x = "2" (the commented-out one)
OLD splitLightDark("light-dark(\"a, b\")") = "\"a", "b\"", true
OLD schemeNumberProblems(a toggle only in a string) = 2 blocks, problems []
OLD var pattern finds quoted --rst-a, misses var( --rst-b )
OLD stripHas dropped 0 and left the :has() ruleMutations, each red then reverted:
| Group | Mutations | |---|---| | Shared readers | S1 to S8 | | Theme readers | T1 to T5 | | tokens.css readers and the no-anchor rewrite | U1 to U5 |
Some first tries failed to compile or survived, and were replaced. The report says which.
Equivalence on the shipped files:
- leaf, interactive and floor rules, classes and vocabulary: identical;
- theme tokens, token sets and dark numbers: identical;
stripHas: drops the same 48 rules and leaves the same 5825 declarations.
Browser drives run locally: the footer pair, the card escape, both spellings, the floor, the console :has() drive, the two accent drives, the button stack and the no-anchor dropdown.
Concerns
- internal/tokens' production
blockBodyandparseTokens, behind the gallery's tokens page, read theme:rootblocks the old way. They are production code, so I left them: worth a follow-up. - Selector substring checks (tap inventory, icon rule, depth_media) could still match a key inside a quoted attribute value in a selector. No shipped selector does this.
- Some checks now refuse more than before: brackets, nested rules and statements in
cssRules, exact values where substrings were, and:after. All shipped files pass.