oficina / sheets Public

docs: reverse the markup rule to the attribute grammar, adopt doctor

The class-spelling rule in this file was correct when written: at
v0.20.0 tokens.css had no bare rst-* attribute selectors, so
rst-btn="primary" would have rendered unstyled. That is no longer true.

Verified against the pinned v0.22.0 tokens.css rather than taken from
the upgrade notes: every class selector has an attribute twin, and
rastrillo enforces it with TestEveryClassSelectorHasAnAttributeTwin.
Both spellings are (0,1,0), so pairing changes no cascade. The class
spelling is scheduled for removal before 1.0.

Two artefacts of my own first measurement are worth recording, because
both looked like findings about rastrillo and were findings about my
regex. Harvesting base names with [a-z0-9-] truncates .rst-shell__brand
at the underscore, inventing "class-only components" that do not exist —
the class spelling is BEM, pairing __element with -element. And matching
[rst- across the whole file picks up prose inside comments. Neither
survived being checked; the seven genuinely class-only names are all
utilities, which is what the grammar prescribes.

rastrillo doctor has also landed, so the "adopt it the day it lands"
step is now the step itself.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01APtNStXDZ5H2fAc1ZuGqtS
Paul Campbell pushed by paul@keymail.dev bbe6853246293850e503799203d73204303c726b parent f013d2e
1 file changed, +31 −11
  • AGENTS.md +31 −11
diff --git a/AGENTS.md b/AGENTS.md
index 6822a46..8a06b74 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -142,17 +142,37 @@ relying on remembering one, make it a test instead.
**Frontend**
- No build step. Jspreadsheet CE is vendored as a static asset, not fetched
from a CDN and not bundled.
-- **Write `class="rst-*"` today.** The shipped `ui/tokens.css` has zero
- bare `rst-*` attribute selectors against ~528 `.rst-` class selector
- occurrences (it does carry `[data-tone=]`, `[aria-*]` and `[type=]`, so
- "zero attribute selectors" was imprecise); the attribute grammar is
- ruled but *not started*, and its staged path ships dual-matching CSS
- first. Writing `rst-btn="primary compact"` now renders unstyled against a
- frozen `static/tokens.css`. Run the codemod when the dual-grammar release
- lands — not before.
-- **Re-copy `static/tokens.css` on every rastrillo upgrade.** It is frozen
- at scaffold time while partials upgrade with the module. Adopt
- `rastrillo doctor` the day it lands and delete this step.
+- **Write the attribute grammar: `rst-btn="primary compact"`, not
+ `class="rst-btn rst-btn--primary"`.** This reverses the earlier rule in
+ this file, which was written against v0.20.0 where the attribute
+ spelling genuinely did not exist. It landed in v0.21.0 and is complete
+ in the pinned v0.22.0: measured against
+ `$(go env GOMODCACHE)/github.com/carlosframework/rastrillo@v0.22.0/ui/tokens.css`,
+ every class selector has an attribute twin, and rastrillo enforces that
+ itself with `TestEveryClassSelectorHasAnAttributeTwin`. Both spellings
+ are specificity `(0,1,0)`, so pairing changes no cascade. The class
+ spelling is scheduled for removal before 1.0.
+ - The grammar: a bare attribute is the KIND (`rst-callout`); a token in
+ its value is a VARIANT, matched with `~=` so values compose like a
+ class list; a PART is its own flat attribute (`rst-callout-body`),
+ never a value.
+ - **Utilities stay classes.** Seven names are class-only by design, and
+ correctly so: `rst-grow`, `rst-mono`, `rst-sr-only`, `rst-m-hide`,
+ `rst-danger`, `rst-nm`, `rst-cell-mut`. An attribute says what a thing
+ *is*; a class says what is being applied to it.
+ - `rst-tone` pairs with `data-tone` rather than with a class.
+ - Adopt per screen, never per element — mixed spellings inside one
+ component match neither.
+- **Run `rastrillo doctor` on every rastrillo upgrade**, and
+ `rastrillo doctor --fix` to re-copy what drifted. `static/tokens.css` is
+ frozen at scaffold time while the partials it styles keep upgrading with
+ the module, so an app can run new markup against old CSS and see nothing
+ worse than a slightly wrong screen. `doctor` shipped in the pinned
+ v0.22.0 (verified: `rastrillo doctor --help` offers `-fix`, `-force`,
+ `-theme`). It reports a version mismatch as a mismatch rather than as
+ drift and refuses `--fix` across one, since copying newer assets into an
+ app built against an older framework manufactures the fault it is
+ looking for.
- Don't build on `.rst-page-header::after` — the rake line is retired in
favour of `--rst-header-rule`.
- 300-line JS module cap, test-enforced, ratchet-down only. The vendored