docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
# scroll-area — alcance de tema: análisis y propuesta
> Generado por `node --import tsx/esm scripts/theming-census.ts --report`.
> Lo **medido** y la **propuesta** se regeneran; el **Veredicto** (§5) se conserva.
> Vista de conjunto: [README](./README.md) · método y protocolo:
> [`PLAN-theming.md`](../../process/PLAN-theming.md) §1, §2, §7.
uix(scroll-area): temable — 94 % → 100 %, y la clave que el guard leía muerta la escriben CINCO componentes
CERO claves acuñadas. El componente llegaba con `global` a cero, `private` a
cero y trece claves públicas que ya cubrían su cromo entero; lo único fuera de
alcance era UN literal. Este commit lo firma, adjudica sus tres silenciosas y
escribe los artefactos que le faltaban.
QUÉ ENTRA
- **El literal se firma como identidad**: `opacity: 1` en
`[data-scroll-area-scrollbar][data-state='visible']` deshace el `0` del
estado oculto de la regla de encima — es el otro extremo de un par, no un
knob. Un `--scroll-area-visible-opacity` sería una clave cuyo único valor
sensato es `1`, y además asimétrica: el `0` hermano el censo ni lo cuenta.
Precedente literal en `navigation-menu.css:360` y `select.css:363`.
- **Tres adjudicaciones en el ledger**, todas MEDIDAS sobre los nodos reales:
- `auto-max-block` — su regla pide `[data-autosize]` y el escenario monta el
modo fijo. Forzado sobre la raíz real: `max-block-size` none -> 1234px, y
al quitar el token vuelve a `none`. NO es decorativa: la escriben
`combobox`, `command`, `gradient-picker`, `select` y `palabras` sobre su
propio ScrollArea. Retirarla habría roto cinco componentes. El atributo lo
estampa el envoltorio de eidos desde una prop, no lo declara el morfo, así
que la excepción de demo de PLAN §7.8 tampoco lo abre.
- `transition-duration` / `transition-ease` — SON la transición que el guard
congela para poder medir lo demás. Medidos sin congelar: 0.12s -> 11.5s y
cubic-bezier(0.4, 0, 0.2, 1) -> steps(4), en la barra y en el thumb.
- README con su sección «Talla y tema» (13 claves por grupo) y veredicto §5 de
la ficha con las cifras.
QUÉ NO SE TOCA
- `thumb-bg-hover` se queda con el modificador DETRÁS: es un hover NEUTRO, y
los hovers neutros están EXCLUIDOS del codemod de D-TH.6 porque migran a la
capa de estado (firma 3). Su migración sigue bloqueada por morfo — el thumb
lleva `archetype: 'thumb'`, que no recibe velo.
- `base.ts` y `generated/base.css`: sin cambio de contrato no hay nada que
regenerar. 13 -> 13 claves.
ARTEFACTOS
- Censo: 94 % (17 knobs · 15 públicos · 1 literal · 1 sistema) -> **100 %**
(16 · 15 · 0 literal · 1 excepción · 1 sistema). Global 68 %, no baja.
- Sonda antes/después: **0 diffs sobre 896 valores computados**, 7 estados,
4 nodos (raíz · viewport · barra vertical · thumb).
- Captura 2× antes y después: idénticas.
- Centinela R-5.4: **10/13**, las 3 restantes adjudicadas -> verde.
- component-audit PASS · eidos-lint 17 morfo-backed / 1 eidos-only / **0
invalid** · `vitest run src/uix/eidos` 35/36 ficheros (el rojo conocido es
`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con **cero**
errores en ficheros de scroll-area.
- Prettier: los hunks de deriva del fichero son los MISMOS que en HEAD (3 en el
README, 3 en el CSS, ambos preexistentes); mi bloque no añade ninguno.
NOTA DE CONCURRENCIA: la pestaña `Tokens` de su demo (paso 11 del protocolo) la
escribí yo, pero entró en HEAD por `9fc38b19a` + `c88b2f861` de otra sesión, que
la arrastró con un `git add` derivado y lo declaró. No se re-commitea aquí.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Medido**: 2026-08-24 · **Alcance** : **100%** — 15 de 15 knobs por token público
- **Knobs de apariencia**: 16 — público 15 · privado 0 · global 0 · literal 0 · sistema 1 · excepción 1 _(los dos últimos, fuera del ratio)_
docs(theming): el informe habla el idioma nuevo — y el fleco del README, cerrado
Al rendir cuentas del repaso de los 7 salió un fleco: el README de
gradient-builder mencionaba `checker-color` por su clave SUELTA, sin el
prefijo `--gradient-builder-`, y el codemod busca tokens completos — quedó con
el nombre muerto. Dos líneas corregidas, más las dos del §5 de su ficha.
Y la causa de fondo: las 170 fichas del informe llevaban desde el codemod
citando el contrato con los nombres viejos en sus secciones generadas.
Regenerado entero (`--report`): 69 fichas cambian, los 171 veredictos §5
escritos a mano sobreviven (verificado), `docs:check` 0.
El censo del informe registra 5.199 knobs · 1.837 públicos — cuatro menos que
el suelo del codemod, que son EXACTAMENTE las cuatro declaraciones de hover
bespoke que la firma 3 retiró (checkbox, splitter, switch, drp ×2 −1 nueva del
checked). El alcance global sigue en 37 %.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Contrato hoy** (`lib/recipes/base.ts`): 13 pública(s) — `auto-max-block` , `bg` , `radius` , `scrollbar-padding` , `scrollbar-size` , `track-bg` , `hover-track-bg` , `thumb-bg` , `thumb-bg-hover` , `thumb-radius` , `thumb-min-size` , `transition-duration` , `transition-ease`
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Eje `size` **: no · **ficheros** : `scroll-area.css`
## 1. Knobs fuera de alcance
### 1.1 Directo a primitivo global (0)
_Ninguno._
### 1.2 A través de un privado (0)
_Ninguno._
uix(scroll-area): temable — 94 % → 100 %, y la clave que el guard leía muerta la escriben CINCO componentes
CERO claves acuñadas. El componente llegaba con `global` a cero, `private` a
cero y trece claves públicas que ya cubrían su cromo entero; lo único fuera de
alcance era UN literal. Este commit lo firma, adjudica sus tres silenciosas y
escribe los artefactos que le faltaban.
QUÉ ENTRA
- **El literal se firma como identidad**: `opacity: 1` en
`[data-scroll-area-scrollbar][data-state='visible']` deshace el `0` del
estado oculto de la regla de encima — es el otro extremo de un par, no un
knob. Un `--scroll-area-visible-opacity` sería una clave cuyo único valor
sensato es `1`, y además asimétrica: el `0` hermano el censo ni lo cuenta.
Precedente literal en `navigation-menu.css:360` y `select.css:363`.
- **Tres adjudicaciones en el ledger**, todas MEDIDAS sobre los nodos reales:
- `auto-max-block` — su regla pide `[data-autosize]` y el escenario monta el
modo fijo. Forzado sobre la raíz real: `max-block-size` none -> 1234px, y
al quitar el token vuelve a `none`. NO es decorativa: la escriben
`combobox`, `command`, `gradient-picker`, `select` y `palabras` sobre su
propio ScrollArea. Retirarla habría roto cinco componentes. El atributo lo
estampa el envoltorio de eidos desde una prop, no lo declara el morfo, así
que la excepción de demo de PLAN §7.8 tampoco lo abre.
- `transition-duration` / `transition-ease` — SON la transición que el guard
congela para poder medir lo demás. Medidos sin congelar: 0.12s -> 11.5s y
cubic-bezier(0.4, 0, 0.2, 1) -> steps(4), en la barra y en el thumb.
- README con su sección «Talla y tema» (13 claves por grupo) y veredicto §5 de
la ficha con las cifras.
QUÉ NO SE TOCA
- `thumb-bg-hover` se queda con el modificador DETRÁS: es un hover NEUTRO, y
los hovers neutros están EXCLUIDOS del codemod de D-TH.6 porque migran a la
capa de estado (firma 3). Su migración sigue bloqueada por morfo — el thumb
lleva `archetype: 'thumb'`, que no recibe velo.
- `base.ts` y `generated/base.css`: sin cambio de contrato no hay nada que
regenerar. 13 -> 13 claves.
ARTEFACTOS
- Censo: 94 % (17 knobs · 15 públicos · 1 literal · 1 sistema) -> **100 %**
(16 · 15 · 0 literal · 1 excepción · 1 sistema). Global 68 %, no baja.
- Sonda antes/después: **0 diffs sobre 896 valores computados**, 7 estados,
4 nodos (raíz · viewport · barra vertical · thumb).
- Captura 2× antes y después: idénticas.
- Centinela R-5.4: **10/13**, las 3 restantes adjudicadas -> verde.
- component-audit PASS · eidos-lint 17 morfo-backed / 1 eidos-only / **0
invalid** · `vitest run src/uix/eidos` 35/36 ficheros (el rojo conocido es
`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con **cero**
errores en ficheros de scroll-area.
- Prettier: los hunks de deriva del fichero son los MISMOS que en HEAD (3 en el
README, 3 en el CSS, ambos preexistentes); mi bloque no añade ninguno.
NOTA DE CONCURRENCIA: la pestaña `Tokens` de su demo (paso 11 del protocolo) la
escribí yo, pero entró en HEAD por `9fc38b19a` + `c88b2f861` de otra sesión, que
la arrastró con un `git add` derivado y lo declaró. No se re-commitea aquí.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 1.3 Literales (0)
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
uix(scroll-area): temable — 94 % → 100 %, y la clave que el guard leía muerta la escriben CINCO componentes
CERO claves acuñadas. El componente llegaba con `global` a cero, `private` a
cero y trece claves públicas que ya cubrían su cromo entero; lo único fuera de
alcance era UN literal. Este commit lo firma, adjudica sus tres silenciosas y
escribe los artefactos que le faltaban.
QUÉ ENTRA
- **El literal se firma como identidad**: `opacity: 1` en
`[data-scroll-area-scrollbar][data-state='visible']` deshace el `0` del
estado oculto de la regla de encima — es el otro extremo de un par, no un
knob. Un `--scroll-area-visible-opacity` sería una clave cuyo único valor
sensato es `1`, y además asimétrica: el `0` hermano el censo ni lo cuenta.
Precedente literal en `navigation-menu.css:360` y `select.css:363`.
- **Tres adjudicaciones en el ledger**, todas MEDIDAS sobre los nodos reales:
- `auto-max-block` — su regla pide `[data-autosize]` y el escenario monta el
modo fijo. Forzado sobre la raíz real: `max-block-size` none -> 1234px, y
al quitar el token vuelve a `none`. NO es decorativa: la escriben
`combobox`, `command`, `gradient-picker`, `select` y `palabras` sobre su
propio ScrollArea. Retirarla habría roto cinco componentes. El atributo lo
estampa el envoltorio de eidos desde una prop, no lo declara el morfo, así
que la excepción de demo de PLAN §7.8 tampoco lo abre.
- `transition-duration` / `transition-ease` — SON la transición que el guard
congela para poder medir lo demás. Medidos sin congelar: 0.12s -> 11.5s y
cubic-bezier(0.4, 0, 0.2, 1) -> steps(4), en la barra y en el thumb.
- README con su sección «Talla y tema» (13 claves por grupo) y veredicto §5 de
la ficha con las cifras.
QUÉ NO SE TOCA
- `thumb-bg-hover` se queda con el modificador DETRÁS: es un hover NEUTRO, y
los hovers neutros están EXCLUIDOS del codemod de D-TH.6 porque migran a la
capa de estado (firma 3). Su migración sigue bloqueada por morfo — el thumb
lleva `archetype: 'thumb'`, que no recibe velo.
- `base.ts` y `generated/base.css`: sin cambio de contrato no hay nada que
regenerar. 13 -> 13 claves.
ARTEFACTOS
- Censo: 94 % (17 knobs · 15 públicos · 1 literal · 1 sistema) -> **100 %**
(16 · 15 · 0 literal · 1 excepción · 1 sistema). Global 68 %, no baja.
- Sonda antes/después: **0 diffs sobre 896 valores computados**, 7 estados,
4 nodos (raíz · viewport · barra vertical · thumb).
- Captura 2× antes y después: idénticas.
- Centinela R-5.4: **10/13**, las 3 restantes adjudicadas -> verde.
- component-audit PASS · eidos-lint 17 morfo-backed / 1 eidos-only / **0
invalid** · `vitest run src/uix/eidos` 35/36 ficheros (el rojo conocido es
`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con **cero**
errores en ficheros de scroll-area.
- Prettier: los hunks de deriva del fichero son los MISMOS que en HEAD (3 en el
README, 3 en el CSS, ambos preexistentes); mi bloque no añade ninguno.
NOTA DE CONCURRENCIA: la pestaña `Tokens` de su demo (paso 11 del protocolo) la
escribí yo, pero entró en HEAD por `9fc38b19a` + `c88b2f861` de otra sesión, que
la arrastró con un `git add` derivado y lo declaró. No se re-commitea aquí.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
_Ninguno._
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
uix(scroll-area): temable — 94 % → 100 %, y la clave que el guard leía muerta la escriben CINCO componentes
CERO claves acuñadas. El componente llegaba con `global` a cero, `private` a
cero y trece claves públicas que ya cubrían su cromo entero; lo único fuera de
alcance era UN literal. Este commit lo firma, adjudica sus tres silenciosas y
escribe los artefactos que le faltaban.
QUÉ ENTRA
- **El literal se firma como identidad**: `opacity: 1` en
`[data-scroll-area-scrollbar][data-state='visible']` deshace el `0` del
estado oculto de la regla de encima — es el otro extremo de un par, no un
knob. Un `--scroll-area-visible-opacity` sería una clave cuyo único valor
sensato es `1`, y además asimétrica: el `0` hermano el censo ni lo cuenta.
Precedente literal en `navigation-menu.css:360` y `select.css:363`.
- **Tres adjudicaciones en el ledger**, todas MEDIDAS sobre los nodos reales:
- `auto-max-block` — su regla pide `[data-autosize]` y el escenario monta el
modo fijo. Forzado sobre la raíz real: `max-block-size` none -> 1234px, y
al quitar el token vuelve a `none`. NO es decorativa: la escriben
`combobox`, `command`, `gradient-picker`, `select` y `palabras` sobre su
propio ScrollArea. Retirarla habría roto cinco componentes. El atributo lo
estampa el envoltorio de eidos desde una prop, no lo declara el morfo, así
que la excepción de demo de PLAN §7.8 tampoco lo abre.
- `transition-duration` / `transition-ease` — SON la transición que el guard
congela para poder medir lo demás. Medidos sin congelar: 0.12s -> 11.5s y
cubic-bezier(0.4, 0, 0.2, 1) -> steps(4), en la barra y en el thumb.
- README con su sección «Talla y tema» (13 claves por grupo) y veredicto §5 de
la ficha con las cifras.
QUÉ NO SE TOCA
- `thumb-bg-hover` se queda con el modificador DETRÁS: es un hover NEUTRO, y
los hovers neutros están EXCLUIDOS del codemod de D-TH.6 porque migran a la
capa de estado (firma 3). Su migración sigue bloqueada por morfo — el thumb
lleva `archetype: 'thumb'`, que no recibe velo.
- `base.ts` y `generated/base.css`: sin cambio de contrato no hay nada que
regenerar. 13 -> 13 claves.
ARTEFACTOS
- Censo: 94 % (17 knobs · 15 públicos · 1 literal · 1 sistema) -> **100 %**
(16 · 15 · 0 literal · 1 excepción · 1 sistema). Global 68 %, no baja.
- Sonda antes/después: **0 diffs sobre 896 valores computados**, 7 estados,
4 nodos (raíz · viewport · barra vertical · thumb).
- Captura 2× antes y después: idénticas.
- Centinela R-5.4: **10/13**, las 3 restantes adjudicadas -> verde.
- component-audit PASS · eidos-lint 17 morfo-backed / 1 eidos-only / **0
invalid** · `vitest run src/uix/eidos` 35/36 ficheros (el rojo conocido es
`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con **cero**
errores en ficheros de scroll-area.
- Prettier: los hunks de deriva del fichero son los MISMOS que en HEAD (3 en el
README, 3 en el CSS, ambos preexistentes); mi bloque no añade ninguno.
NOTA DE CONCURRENCIA: la pestaña `Tokens` de su demo (paso 11 del protocolo) la
escribí yo, pero entró en HEAD por `9fc38b19a` + `c88b2f861` de otra sesión, que
la arrastró con un `git add` derivado y lo declaró. No se re-commitea aquí.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 1.4 Excepciones firmadas (1) — fuera del ratio
tooling(theming): el censo aprende a leer la válvula del canon — clase `exception`
Global 58 % → **59 %** sin tocar una línea de CSS: 54 knobs que eran deuda
resultan ser desviaciones que el canon ya había firmado.
`recipe-contract` §3 dice que una desviación anotada `/* literal: <razón> */`
EN SU PROPIA DECLARACIÓN es válida, y `component-audit` la honra desde siempre
(`declarationWindow` + `/literal:/i` en R-2.1, R-2.6 y R-2.7). El censo era el
único instrumento que no: su `strip()` blanquea los comentarios ANTES de
clasificar, así que las **81 anotaciones del catálogo** contaban como literales
sin excusa. Dos instrumentos, un canon, dos respuestas — y la que mandaba era la
del que no sabía leerlo.
Ahora un literal anotado cae en la clase **`exception`, fuera del ratio** como
`system`, y por la misma razón: no es que un tema no lo alcance, es que el canon
ya aceptó por escrito que ahí no va un token.
**54 knobs en 12 componentes**: `prose` 21 (su escala editorial em-relativa, que
su README documenta como decisión — «No 5× duplicated scale»), `proof-of-human`
16 (la escena de tono fijo), `palabras` 3, `timeline` 2 (73 % → **77 %**),
`result` 1 (86 % → **90 %**), y siete más con una cada uno.
Detalles que costaron medición:
- **La anotación vale para la DECLARACIÓN entera**, no sólo para su primera
línea: un valor partido en varias líneas lleva la nota al final. Se comprueban
todas las líneas que abarca la declaración.
- **`strip()` blanquea en el sitio** (sustituye por espacios, conserva los
saltos), así que el cuerpo despojado y el crudo quedan alineados línea a línea
y basta con guardar el crudo al lado.
- Muta-prueba: retirar una anotación de `prose` mueve el knob de `exception` a
`literal` (21 → 20) y el conteo vuelve al restaurarla.
Efecto colateral bueno: cada ficha gana una **§1.4 «Excepciones firmadas»** que
las LISTA con su razón. Estaban escritas en el CSS y no se leían desde ninguna
parte; ahora la ficha del componente las enseña, que es donde se decide si una
sigue siendo cierta.
Las 163 fichas cambian porque la plantilla cambia (sección nueva + la línea de
reparto); el README de la auditoría gana la fila de la clase y la nota de que
`system` y `exception` quedan fuera del denominador.
Guards: `--names` 4.105 claves, DESVIADAS 0 · component-audit PASS · docs:check
0 · `check` con 72 errores globales y 0 en los ficheros tocados.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Literales que llevan su anotación `/* literal: <razón> */` en la propia
declaración: la válvula de recipe-contract §3, la misma que honra
`component-audit` . **Una desviación firmada no es deuda** — se listan para que la
razón se lea, no para acuñarlas.
uix(scroll-area): temable — 94 % → 100 %, y la clave que el guard leía muerta la escriben CINCO componentes
CERO claves acuñadas. El componente llegaba con `global` a cero, `private` a
cero y trece claves públicas que ya cubrían su cromo entero; lo único fuera de
alcance era UN literal. Este commit lo firma, adjudica sus tres silenciosas y
escribe los artefactos que le faltaban.
QUÉ ENTRA
- **El literal se firma como identidad**: `opacity: 1` en
`[data-scroll-area-scrollbar][data-state='visible']` deshace el `0` del
estado oculto de la regla de encima — es el otro extremo de un par, no un
knob. Un `--scroll-area-visible-opacity` sería una clave cuyo único valor
sensato es `1`, y además asimétrica: el `0` hermano el censo ni lo cuenta.
Precedente literal en `navigation-menu.css:360` y `select.css:363`.
- **Tres adjudicaciones en el ledger**, todas MEDIDAS sobre los nodos reales:
- `auto-max-block` — su regla pide `[data-autosize]` y el escenario monta el
modo fijo. Forzado sobre la raíz real: `max-block-size` none -> 1234px, y
al quitar el token vuelve a `none`. NO es decorativa: la escriben
`combobox`, `command`, `gradient-picker`, `select` y `palabras` sobre su
propio ScrollArea. Retirarla habría roto cinco componentes. El atributo lo
estampa el envoltorio de eidos desde una prop, no lo declara el morfo, así
que la excepción de demo de PLAN §7.8 tampoco lo abre.
- `transition-duration` / `transition-ease` — SON la transición que el guard
congela para poder medir lo demás. Medidos sin congelar: 0.12s -> 11.5s y
cubic-bezier(0.4, 0, 0.2, 1) -> steps(4), en la barra y en el thumb.
- README con su sección «Talla y tema» (13 claves por grupo) y veredicto §5 de
la ficha con las cifras.
QUÉ NO SE TOCA
- `thumb-bg-hover` se queda con el modificador DETRÁS: es un hover NEUTRO, y
los hovers neutros están EXCLUIDOS del codemod de D-TH.6 porque migran a la
capa de estado (firma 3). Su migración sigue bloqueada por morfo — el thumb
lleva `archetype: 'thumb'`, que no recibe velo.
- `base.ts` y `generated/base.css`: sin cambio de contrato no hay nada que
regenerar. 13 -> 13 claves.
ARTEFACTOS
- Censo: 94 % (17 knobs · 15 públicos · 1 literal · 1 sistema) -> **100 %**
(16 · 15 · 0 literal · 1 excepción · 1 sistema). Global 68 %, no baja.
- Sonda antes/después: **0 diffs sobre 896 valores computados**, 7 estados,
4 nodos (raíz · viewport · barra vertical · thumb).
- Captura 2× antes y después: idénticas.
- Centinela R-5.4: **10/13**, las 3 restantes adjudicadas -> verde.
- component-audit PASS · eidos-lint 17 morfo-backed / 1 eidos-only / **0
invalid** · `vitest run src/uix/eidos` 35/36 ficheros (el rojo conocido es
`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con **cero**
errores en ficheros de scroll-area.
- Prettier: los hunks de deriva del fichero son los MISMOS que en HEAD (3 en el
README, 3 en el CSS, ambos preexistentes); mi bloque no añade ninguno.
NOTA DE CONCURRENCIA: la pestaña `Tokens` de su demo (paso 11 del protocolo) la
escribí yo, pero entró en HEAD por `9fc38b19a` + `c88b2f861` de otra sesión, que
la arrastró con un `git add` derivado y lo declaró. No se re-commitea aquí.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `scroll-area.css:104` | `[data-scroll-area-scrollbar][data-state='visible']` | `opacity` | `1` |
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## 2. Sistema transversal (1) — informativo, fuera del ratio
Un tema los alcanza **a nivel de sistema** , por diseño (recipe-contract §2).
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `scroll-area.css:113` | `[data-scroll-area-scrollbar]:focus-visible` | `outline` | `var(--focus-ring-width) solid var(--focus-ring-color)` |
## 3. Privados de la receta — ¿de dónde sale su valor?
_La receta no declara privados propios en su CSS._
## 4. Propuesta de corrección
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (0)
Valor **verbatim** del CSS de hoy: el default no se mueve, sólo cambia quién
puede moverlo. Nombres derivados de recipe-contract §1 (ejes lógicos, talla
al final) y theming §6.7 (slots de color, modificador delante). Un token con
DOS valores distintos es una colisión de nombre: son dos knobs, o el nombre
no distingue lo que debería — se marca `⚠` .
| token (`--scroll-area-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
### 4.2 Sin nombre mecánico (1)
- **⚠ decisión: `1` es un valor identidad o geometría de layout, no un knob de tema — el perímetro de «knob» es D-TH.2, sin firmar** — 1: `opacity` .
### 4.4 Lo que hay que comprobar a mano (PLAN-theming §1.3 · §7.4)
- [ ] **Privado que no deriva de un público** — §3 lo marca; el privado debe leer el público o desaparecer.
- [ ] **Velo o acento en el nodo equivocado** (`archetype: 'item'` en un envoltorio, un `background` en shorthand que mata la capa de estado) — se mide desde el píxel hacia arriba.
- [ ] **Doble animación** al mover un sello a una superficie con animación propia — registro de `animationstart` /`animationend`.
- [ ] **Diff de computed = 0** en reposo · hover · abierto · disabled · foco, por talla, antes y después.
- [ ] **Centinela por token nuevo** : valor imposible en el root → el nodo lo sigue. Si no, el token miente.
## 5. Veredicto
<!-- veredicto:start -->
uix(scroll-area): temable — 94 % → 100 %, y la clave que el guard leía muerta la escriben CINCO componentes
CERO claves acuñadas. El componente llegaba con `global` a cero, `private` a
cero y trece claves públicas que ya cubrían su cromo entero; lo único fuera de
alcance era UN literal. Este commit lo firma, adjudica sus tres silenciosas y
escribe los artefactos que le faltaban.
QUÉ ENTRA
- **El literal se firma como identidad**: `opacity: 1` en
`[data-scroll-area-scrollbar][data-state='visible']` deshace el `0` del
estado oculto de la regla de encima — es el otro extremo de un par, no un
knob. Un `--scroll-area-visible-opacity` sería una clave cuyo único valor
sensato es `1`, y además asimétrica: el `0` hermano el censo ni lo cuenta.
Precedente literal en `navigation-menu.css:360` y `select.css:363`.
- **Tres adjudicaciones en el ledger**, todas MEDIDAS sobre los nodos reales:
- `auto-max-block` — su regla pide `[data-autosize]` y el escenario monta el
modo fijo. Forzado sobre la raíz real: `max-block-size` none -> 1234px, y
al quitar el token vuelve a `none`. NO es decorativa: la escriben
`combobox`, `command`, `gradient-picker`, `select` y `palabras` sobre su
propio ScrollArea. Retirarla habría roto cinco componentes. El atributo lo
estampa el envoltorio de eidos desde una prop, no lo declara el morfo, así
que la excepción de demo de PLAN §7.8 tampoco lo abre.
- `transition-duration` / `transition-ease` — SON la transición que el guard
congela para poder medir lo demás. Medidos sin congelar: 0.12s -> 11.5s y
cubic-bezier(0.4, 0, 0.2, 1) -> steps(4), en la barra y en el thumb.
- README con su sección «Talla y tema» (13 claves por grupo) y veredicto §5 de
la ficha con las cifras.
QUÉ NO SE TOCA
- `thumb-bg-hover` se queda con el modificador DETRÁS: es un hover NEUTRO, y
los hovers neutros están EXCLUIDOS del codemod de D-TH.6 porque migran a la
capa de estado (firma 3). Su migración sigue bloqueada por morfo — el thumb
lleva `archetype: 'thumb'`, que no recibe velo.
- `base.ts` y `generated/base.css`: sin cambio de contrato no hay nada que
regenerar. 13 -> 13 claves.
ARTEFACTOS
- Censo: 94 % (17 knobs · 15 públicos · 1 literal · 1 sistema) -> **100 %**
(16 · 15 · 0 literal · 1 excepción · 1 sistema). Global 68 %, no baja.
- Sonda antes/después: **0 diffs sobre 896 valores computados**, 7 estados,
4 nodos (raíz · viewport · barra vertical · thumb).
- Captura 2× antes y después: idénticas.
- Centinela R-5.4: **10/13**, las 3 restantes adjudicadas -> verde.
- component-audit PASS · eidos-lint 17 morfo-backed / 1 eidos-only / **0
invalid** · `vitest run src/uix/eidos` 35/36 ficheros (el rojo conocido es
`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con **cero**
errores en ficheros de scroll-area.
- Prettier: los hunks de deriva del fichero son los MISMOS que en HEAD (3 en el
README, 3 en el CSS, ambos preexistentes); mi bloque no añade ninguno.
NOTA DE CONCURRENCIA: la pestaña `Tokens` de su demo (paso 11 del protocolo) la
escribí yo, pero entró en HEAD por `9fc38b19a` + `c88b2f861` de otra sesión, que
la arrastró con un `git add` derivado y lo declaró. No se re-commitea aquí.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Medido y CERRADO al 100 % el 2026-08-24** (94 % → 100 %, contrato **13 → 13**
claves —ninguna acuñada—, centinela **10/13** con 3 adjudicadas, diff de
computed **0 sobre 896 valores** en 7 estados, 4 nodos).
**No entra una sola clave, y ése ES el resultado.** El componente llegaba con
`global` a cero, `private` a cero y trece claves públicas que ya cubrían todo su
cromo. Lo único fuera de alcance era **un literal** : el `opacity: 1` de
`[data-scroll-area-scrollbar][data-state='visible']` . Es identidad y va firmado
con su anotación: **deshace el `0` del estado oculto de la regla de encima** , así
que es el otro extremo de un par, no un knob. Acuñar
`--scroll-area-visible-opacity` habría creado una clave cuyo único valor sensato
es `1` — y además una asimetría, porque el `0` del hermano el censo ni lo cuenta.
Precedente literal: `navigation-menu.css:360` y `select.css:363` , la misma frase
sobre el mismo par.
**Las tres silenciosas del centinela están VIVAS, y una de ellas es la más
consumida del contrato.** Medidas una a una sobre los nodos reales:
- **`auto-max-block`** — su regla es
`[data-scroll-area][data-autosize] [data-scroll-area-viewport]` y el escenario
monta el modo fijo por defecto. Forzando `data-autosize` sobre la raíz real:
`max-block-size` pasa de `none` a `1234px` , y al quitar el token vuelve a
`none` . **No es decorativa** : la escriben `combobox` , `command` ,
`gradient-picker` , `select` y `palabras` sobre su propio ScrollArea para cerrar
la altura del panel. Retirarla habría roto cinco componentes.
⚠ El atributo lo estampa el ENVOLTORIO de eidos desde una prop, no lo declara
el morfo, así que la excepción de demo de PLAN §7.8 tampoco lo abre.
- **`transition-duration` / `transition-ease` ** — la clase ya conocida: el guard
congela `transition` para poder medir todo lo demás, y estos DOS tokens SON la
transición. Medidos sin congelar: `0.12s → 11.5s` y
`cubic-bezier(0.4, 0, 0.2, 1) → steps(4)` , en la barra y en el thumb.
**`thumb-bg-hover` se queda con el modificador DETRÁS, a propósito.** La
gramática de D-TH.6 pediría `hover-thumb-bg` , pero los hovers neutros están
EXCLUIDOS del codemod: migran a la capa de estado por la firma 3, y renombrar lo
condenado es churn. Su migración además está bloqueada por morfo — el thumb lleva
`archetype: 'thumb'` , que no recibe velo — y sigue siendo el único knob de la
firma 3 sin resolver.
**Lo que este componente enseña**: un contrato ya completo se cierra ADJUDICANDO,
no acuñando; y la clave que el instrumento leía muerta era justamente la que
cinco componentes escriben desde fuera.
docs(theming): la auditoría de alcance de tema, componente a componente, con su propuesta
El censo medía el eje y no lo explicaba: 5.205 knobs en dos tablas del plan no
dicen QUÉ knob de QUÉ línea no alcanza un tema, ni qué token habría que crear.
Ahora `theming-census.ts --report` escribe la auditoría entera bajo
`docs/audit/theming/`: un README con la vista de conjunto y 170 fichas — 162
recetas con CSS + 8 componentes sin receta, el árbol completo de
`eidos/components/`.
Cada ficha de receta: knobs fuera de alcance con fichero:línea Y selector
(agrupados por clase), sistema transversal aparte, los privados con la columna
que decide («¿deriva de un público?»), y una PROPUESTA de corrección — el token
a declarar en `base.ts` con su valor VERBATIM y su scope TSC. La propuesta
deriva los nombres de recipe-contract §1 y theming §6.7; donde la doctrina no
decide, marca `⚠ decisión` en vez de inventar. Y no propone acuñar lo que la
doctrina prohíbe: lo que posee una capa compartida, el foco, la capa de estado,
un token prestado de otra receta, un shorthand o un eje físico.
Las 8 fichas sin receta dicen —medido, no supuesto— dónde vive su visual: el
componente que componen (icon-button → button), la capa que consumen (affix →
viewport-placement) o la receta ajena que pinta sus attrs (svg → badge/button).
Defectos del instrumento corregidos en el mismo pase, todos encontrados
mirando la salida: un `@import` pegado al primer selector se comía 2 knobs de
color-picker (el suelo del censo no puede moverse); `:not(:disabled)` se leía
como estado y producía `hover-disabled-*`; un knob que lee un privado se
proponía a sí mismo en vez de resolverse por talla; `--icon-size-sm` se
reportaba como préstamo del componente `icon` (ahora el préstamo se verifica
contra las claves del dueño en `base.ts`); y el default de talla salía sin
nombrar en vez de `-md`.
Verificación: censo global idéntico al suelo publicado (5205 · 1621/33% · 856 ·
1880 · 614 · 234) y COMPONENTE A COMPONENTE contra la tabla §9 del plan — 0
diferencias en 162 · regenerar dos veces da el árbol idéntico · el bloque de
veredicto escrito a mano sobrevive · docs:check 0 errores sobre 813 docs ·
prettier limpio (el árbol generado entra en .prettierignore junto a
eidos/generated).
Las 10 primeras fichas llevan ya su veredicto de revisión: análisis correcto en
las 10, propuesta apta en 2 (gradient-builder como piloto, combobox con cinco
correcciones — dos de ellas evitaban romper el default), y 5 que no se
tokenizan en solitario porque son alias de --calendar-*/--field-* y esperan la
decisión de familia. Cuatro destaparon privados con prefijo ajeno o abreviado
declarados en su propio CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
<!-- veredicto:end -->