oficina / home Public

The seven utilities keep class, and ruling 20 had to say so

Ruling 20 as first written would have shipped an accessibility bug.
rst-sr-only, rst-mono, rst-m-hide, rst-grow, rst-nm, rst-danger and
rst-cell-mut have no attribute twin at v0.22.0 — five .rst-sr-only
selectors, zero [rst-sr-only]. An agent following the bullet literally
writes <span rst-sr-only>, nothing matches, and screen-reader-only text
renders visible.

tokens.css and rastrillo §6-v3 both say utilities stay class. That also
explains the six surviving class= occurrences in v0.22.0 partials: they
are the utilities, not residue awaiting a flip, so the count now
explains itself.

Also: the graveyard said tokens.css pairs every class with a twin. The
header says every COMPONENT rule; utilities are unpaired by design.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 23e4dae7c86813ed188a4d5104d9368fdb9f0a10 parent 06d635a
1 file changed, +16 −2
  • AGENTS.md +16 −2

CI passed — run details

diff --git a/AGENTS.md b/AGENTS.md
index d17dde8..7767872 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -192,10 +192,24 @@ quietly ignored).
spelling, not two. No permanent class fallback" and drops the class
selectors before 1.0; this app has no `rst-` markup yet, so it starts on
the spelling that survives — free today, a sweep after the first
- template. Record the graveyard, so neither dead reason is revived:
+ template.
+
+ **The seven utilities are the exception, and they are not a loophole.**
+ `rst-sr-only`, `rst-mono`, `rst-m-hide`, `rst-grow`, `rst-nm`,
+ `rst-danger` and `rst-cell-mut` keep `class=`, because at v0.22.0 they
+ have **no attribute twin at all** — five `.rst-sr-only` selectors, zero
+ `[rst-sr-only]`. tokens.css's header says why ("Utilities keep the class
+ spelling and are not paired… they stay class after the move") and §6-v3
+ agrees ("`class` is for utilities and the app's own CSS"). Write
+ `<span rst-sr-only>` and nothing matches, so screen-reader-only text
+ renders **visible**. Kinds, variants and parts are attributes; these
+ seven are classes. This is also what the 6 surviving `class=` occurrences
+ in v0.22.0's partials are — utilities, not residue awaiting a flip.
+
+ Record the graveyard, so neither dead reason is revived:
- *"The attribute grammar is ruled but not released."* Dead since
**v0.21.0**, this repo's *first* pin. tokens.css there pairs every
- class with an attribute twin and says so in its own header: "TWO
+ *component* rule with an attribute twin and says so in its own header: "TWO
SPELLINGS, ON PURPOSE, FOR ONE RELEASE." The original claim — zero bare
`rst-*` selectors against ~528 class occurrences — was verified on
2026-08-30 against v0.20.x, was true then, and was already false by the