You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/audit/theming/toggle.md

157 lines
12 KiB

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
# toggle — 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.
docs(theming): la cola eran TREINTA Y CUATRO, no once — y dos huecos más del instrumento Ejecuta P3, P4 y P5 del plan de la revisión del 24. P4 — LA COLA DEL HANDOFF ESTABA MAL, Y ERA MI ERROR La bala que escribí al cerrar la tanda listaba once pendientes. Contados contra el censo y el registro §8 son treinta y cuatro, y la lista sin separar tampoco servía, porque mezcla dos cosas distintas: - 16 que NUNCA han pasado por el eje (sin entrada §8 ni README): field-langs, chronos, mockup, sidebar, image-adjustments, separator, chat-message, fab, tags-input, chat-typing, collapsible, toolbar, scroll-area, tabs, slider, toast. Ésa es la cola de verdad. - 18 que SÍ pasaron y sólo les falta el README «Talla y tema»: el paso se volvió obligatorio después de que cerraran y e522e04e6 recuperó 21, pero éstos quedaron fuera. No es cola de tokenización, es deuda de documentación. Queda escrito además cómo regenerar la lista, para que nadie la escriba de memoria otra vez: alcance < 100 % y sin sección «Talla y tema», y el desempate entre A y B es si tiene entrada en §8. P3 — LA FECHA DE MEDIDA DE SEIS FICHAS select, calendar, radio-group, rating-group, toggle y card se midieron y commitearon pasada la medianoche; sus fichas decían 23. La fecha es parte del artefacto. P5 — DOS HUECOS DE INSTRUMENTO EN §13 - eidos-lint no conoce las exenciones que el test de vitest SÍ tiene (CSS_ONLY_LAYERS, WIP_TRACKS, KNOWN_MISSING_MORFO, raíces competidoras): sobre spin-field muere con «No morfo file» en vez de eximirlo. El guard de la suite y el script de línea de comandos discrepan sobre la misma ley, y el que se corre a mano es el que miente. - La columna `size` del censo se apaga cuando el eje de talla SUBE al contrato: la calcula leyendo bloques [data-size] del CSS, así que promover una escala con scope 'size:{k}' —la forma canónica— la borra del recuento. Bajó de 57 a 55 justo al hacerlo mejor. El instrumento premia la forma vieja. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Medido**: 2026-08-24 · **Alcance**: **100%** — 24 de 24 knobs por token público
uix(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Knobs de apariencia**: 25 — público 24 · privado 0 · global 0 · literal 0 · sistema 1 · excepción 3 _(los dos últimos, fuera del ratio)_
- **Contrato hoy** (`lib/recipes/base.ts`): 126 pública(s) — `height-xs`, `height-sm`, `height-md`, `height-lg`, `height-xl`, `padding-inline-xs`, `padding-inline-sm`, `padding-inline-md`, `padding-inline-lg`, `padding-inline-xl`, `gap-xs`, `gap-sm`, `gap-md`, `gap-lg`, `gap-xl`, `font-family`, `line-height`, `letter-spacing`, `font-size-xs`, `font-size-sm`, `font-size-md`, `font-size-lg`, `font-size-xl`, `font-weight-xs`, `font-weight-sm`, `font-weight-md`, `font-weight-lg`, `font-weight-xl`, `radius`, `radius-sm`, `radius-md`, `radius-lg`, `radius-xl`, `radius-full`, `border-width`, `shadow`, `transition-duration`, `transition-ease`, `primary-track`, `primary-element`, `primary-hover`, `primary-border`, `primary-solid`, `primary-solid-hover`, `primary-text`, `primary-contrast`, `neutral-track`, `neutral-element`, `neutral-hover`, `neutral-border`, `neutral-solid`, `neutral-solid-hover`, `neutral-text`, `neutral-contrast`, `risk-track`, `risk-element`, `risk-hover`, `risk-border`, `risk-solid`, `risk-solid-hover`, `risk-text`, `risk-contrast`, `threat-track`, `threat-element`, `threat-hover`, `threat-border`, `threat-solid`, `threat-solid-hover`, `threat-text`, `threat-contrast`, `secondary-track`, `secondary-element`, `secondary-hover`, `secondary-border`, `secondary-solid`, `secondary-solid-hover`, `secondary-text`, `secondary-contrast`, `affirm-track`, `affirm-element`, `affirm-hover`, `affirm-border`, `affirm-solid`, `affirm-solid-hover`, `affirm-text`, `affirm-contrast`, `palette-track`, `palette-element`, `palette-hover`, `palette-border`, `palette-solid`, `palette-solid-hover`, `palette-text`, `palette-contrast`, `solid-bg`, `solid-fg`, `solid-border`, `solid-hover-bg`, `solid-hover-border`, `solid-on-bg`, `solid-on-fg`, `solid-on-border`, `solid-on-hover-bg`, `solid-on-hover-border`, `outline-bg`, `outline-fg`, `outline-border`, `outline-hover-bg`, `outline-hover-border`, `outline-on-bg`, `outline-on-fg`, `outline-on-border`, `outline-on-hover-bg`, `outline-on-hover-border`, `ghost-bg`, `ghost-fg`, `ghost-border`, `ghost-hover-bg`, `ghost-hover-border`, `ghost-on-bg`, `ghost-on-fg`, `ghost-on-border`, `ghost-on-hover-bg`, `ghost-on-hover-border`, `disabled-opacity`, `invalid-border`
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`**: sí · **ficheros**: `toggle.css`
## 1. Knobs fuera de alcance
uix(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 1.1 Directo a primitivo global (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(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. 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(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 1.2 A través de un privado (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(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. 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(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. 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(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. 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(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 1.4 Excepciones firmadas (3) — 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(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| # | fichero:línea | selector | propiedad | valor |
| ---: | --- | --- | --- | --- |
| 1 | `toggle.css:162` | `[data-toggle][data-block]` | `inline-size` | `100%` |
| 2 | `toggle.css:175` | `[data-toggle][data-icon-only] [data-toggle-body]` | `width` | `1px` |
| 3 | `toggle.css:176` | `[data-toggle][data-icon-only] [data-toggle-body]` | `height` | `1px` |
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 |
| ---: | --- | --- | --- | --- |
uix(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| 1 | `toggle.css:157` | `[data-toggle]:focus-visible` | `outline` | `var(--focus-ring-width) solid var(--focus-ring-color)` |
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
## 3. Privados de la receta — ¿de dónde sale su valor?
| privado | declaraciones | valor(es) | origen | ¿deriva de un público? |
| --- | ---: | --- | --- | :-: |
| `--_toggle-height` | 5 | `var(--toggle-height-md)`, `var(--toggle-height-xs)`, `var(--toggle-height-sm)`, `var(--toggle-height-lg)`, `var(--toggle-height-xl)` | public | **sí** |
| `--_toggle-padding-inline` | 5 | `var(--toggle-padding-inline-md)`, `var(--toggle-padding-inline-xs)`, `var(--toggle-padding-inline-sm)`, `var(--toggle-padding-inline-lg)`, `var(--toggle-padding-inline-xl)` | public | **sí** |
| `--_toggle-gap` | 5 | `var(--toggle-gap-md)`, `var(--toggle-gap-xs)`, `var(--toggle-gap-sm)`, `var(--toggle-gap-lg)`, `var(--toggle-gap-xl)` | public | **sí** |
| `--_toggle-font-size` | 5 | `var(--toggle-font-size-md)`, `var(--toggle-font-size-xs)`, `var(--toggle-font-size-sm)`, `var(--toggle-font-size-lg)`, `var(--toggle-font-size-xl)` | public | **sí** |
| `--_toggle-font-weight` | 5 | `var(--toggle-font-weight-md)`, `var(--toggle-font-weight-xs)`, `var(--toggle-font-weight-sm)`, `var(--toggle-font-weight-lg)`, `var(--toggle-font-weight-xl)` | public | **sí** |
uix(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `--_toggle-radius` | 6 | `var(--toggle-radius)`, `var(--toggle-radius-sm)`, `var(--toggle-radius-md)`, `var(--toggle-radius-lg)`, `var(--toggle-radius-xl)`, `var(--toggle-radius-full)` | public | **sí** |
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
| `--_toggle-bg` | 3 | `var(--toggle-solid-bg)`, `var(--toggle-outline-bg)`, `var(--toggle-ghost-bg)` | public | **sí** |
| `--_toggle-fg` | 3 | `var(--toggle-solid-fg)`, `var(--toggle-outline-fg)`, `var(--toggle-ghost-fg)` | public | **sí** |
| `--_toggle-border` | 3 | `var(--toggle-solid-border)`, `var(--toggle-outline-border)`, `var(--toggle-ghost-border)` | public | **sí** |
| `--_toggle-hover-bg` | 3 | `var(--toggle-solid-hover-bg)`, `var(--toggle-outline-hover-bg)`, `var(--toggle-ghost-hover-bg)` | public | **sí** |
| `--_toggle-hover-border` | 3 | `var(--toggle-solid-hover-border)`, `var(--toggle-outline-hover-border)`, `var(--toggle-ghost-hover-border)` | public | **sí** |
| `--_toggle-on-bg` | 3 | `var(--toggle-solid-on-bg)`, `var(--toggle-outline-on-bg)`, `var(--toggle-ghost-on-bg)` | public | **sí** |
| `--_toggle-on-fg` | 3 | `var(--toggle-solid-on-fg)`, `var(--toggle-outline-on-fg)`, `var(--toggle-ghost-on-fg)` | public | **sí** |
| `--_toggle-on-border` | 3 | `var(--toggle-solid-on-border)`, `var(--toggle-outline-on-border)`, `var(--toggle-ghost-on-border)` | public | **sí** |
| `--_toggle-on-hover-bg` | 3 | `var(--toggle-solid-on-hover-bg)`, `var(--toggle-outline-on-hover-bg)`, `var(--toggle-ghost-on-hover-bg)` | public | **sí** |
| `--_toggle-on-hover-border` | 3 | `var(--toggle-solid-on-hover-border)`, `var(--toggle-outline-on-hover-border)`, `var(--toggle-ghost-on-hover-border)` | public | **sí** |
## 4. Propuesta de corrección
- **Tiene eje `size`**: los tokens dimensionales van por talla (`{part}-{eje}-{k}`) apuntando al bundle `--size-{k}-*`, nunca al primitivo crudo (theming §5; el guard `recipe-css-contract` prohíbe el primitivo).
uix(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (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
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 (`--toggle-…`) | scope TSC | valor propuesto | usos |
| --- | --- | --- | ---: |
uix(theming): el censo aprende que un privado DERIVADO sí alcanza — 50 % → 56 % Seis puntos de alcance sin tocar una línea de componente: **la medición estaba mal, no el código**. EL DEFECTO. F0 encargaba «detección "privado que deriva de público" (leer `--_c-x: var(--c-y)` en la misma receta y reclasificar)». Se implementó a medias: el censo CALCULA `derives` y lo imprime en la columna «¿deriva de un público?» de la §3 de cada ficha, pero **el contador nunca lo usó** — esos knobs seguían puntuando como deuda. Medido: **240 privados en 59 componentes** estaban en ese estado, es decir, haciendo exactamente lo que la doctrina prescribe («privados sólo si derivan de públicos») y penalizados por ello. Lo destapó tokenizar `avatar`: sus 17 privados YA leían públicos (`--_avatar-size: var(--avatar-size-md)`), así que no había nada que tokenizar — había que arreglar el instrumento. LA CORRECCIÓN. Segunda pasada tras recoger privados y knobs: un knob que lee `var(--_c-x)` pasa a `public` si ese privado alcanza un público. El cierre es **TRANSITIVO** (`--_a: calc(var(--_b) * .3)` alcanza si `--_b` alcanza) con conjunto de visitados para que un ciclo no lo cuelgue. **Muta-prueba** (obligatoria, memoria `a-guard-that-inspects-nothing-passes`): apuntar `--_avatar-radius` al primitivo crudo baja avatar de 75 % a 72 % y el knob vuelve a `private`; revertirlo lo devuelve a 75 % y deja el árbol idéntico. EFECTO MEDIDO: - Global **50 % → 56 %** · privados 625 → 341 · al 100 % 10 → 14 · <20 % 22 → 20. - `avatar` 36 % → **75 %**, `picker-shell` 76 % → **95 %**, `menu-dial` 25 % → 38 %, y otras 51 fichas con cifras nuevas — **ninguna por cambio de código**. - Los READMEs de `picker-shell` y `menu-dial` se actualizan con la cifra nueva y con la razón, para que nadie crea que el componente cambió. ⚠ **Cualquier cifra anterior a este commit no es comparable con las de ahora.** Queda escrito en el handoff. Y un hueco de F0 que sale al hacerlo, registrado en §13: **el test del SUELO que el plan pedía NO EXISTE** («alcance global ≥ el de hoy y literales ≤ 614 — el número sube o el test falla»). Hoy nada impide que el alcance BAJE entre sesiones: sólo se vería mirando la cifra a mano. Con el censo ya endurecido, es el momento de escribirlo. Gates: `component:audit` 162 PASS / 4 NEEDS-WORK (preexistentes) · `--names` DESVIADAS 0 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · el censo compila. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
### 4.2 Sin nombre mecánico (3)
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
- **⚠ decisión: `100%` 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: `inline-size`.
- **⚠ decisión: `width` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 1: `width`.
- **⚠ decisión: `height` es shorthand o eje físico — hay que partirlo en ejes lógicos antes de nombrarlo (recipe-contract §1, R-4.4)** — 1: `height`.
### 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(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje Tres knobs fuera de alcance, ninguno por doctrina. - **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la escala global `--radius-*` A PELO, así que la única forma de redondear un toggle era mover el radio de todo el sistema — el agujero que tenía `navigation-menu`, y el único de los CINCO componentes con escala `rounded` que no tenía la suya (button, badge, image y color-swatch la declaran). Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de `size` se conserva intacto: son pasos de `rounded`, no de talla. - **El tinte inválido**: `var(--color-threat-element)` a pelo → `invalid-border` con ese valor (la costura, PLAN §2-A). - **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio: el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la técnica sr-only. Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %** (3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2 nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid / disabled / block / icon-only / tono, con `transition` y `animation` congeladas — porque el escenario de la demo monta UN toggle solid, apagado y válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas. Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y `{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron las de reposo) — «montar más puede medir menos», esta vez dentro de un componente. El guard aprende tres cosas, cada una nacida de una medición: - barrer el **producto cartesiano** de varios ejes (un solo eje da la misma secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia); - **quitar** un atributo con `null`, porque sellar `data-invalid` toda la corrida hacía que el borde inválido ganase a los otros seis bordes; - aplicar el barrido también en el **pase de hover**, que no barría nada — que es literalmente la razón escrita en el ledger de `radio-group.hover-segmented-segment-fg`. Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo doce seguidos contra el mismo dev server; a solas, verdes). De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí: con `data-color=primary`, `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las demás por una razón que conviene escribir: el propio guard ESTAMPA `data-color=neutral` para probarlas, que es justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de transición, que ES lo que el guard congela). Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS · `eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y `[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro controles de formulario comparten el patrón. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**EJECUTADO 2026-08-23 — 81 % → 100 %, contrato 119 → 126 claves.**
Tres knobs fuera de alcance y una firma. Ninguno era doctrina: los tres eran
sistema leído a pelo o literales sin anotar.
- **El radio (§1.2, 1 knob · 6 fuentes)**. El bloque de `base.ts` decía «No
`--toggle-radius-*` aliases» y la receta leía `--radius-default` y la escala
global `--radius-*` directamente. Es exactamente el agujero que
`navigation-menu` tenía —«pinned to `--radius-default` ("decoupled from
size", a line that read Radix as a rule when Radix paints nothing) … not
reachable by a theme short of moving `--radius-default` for the whole
system»— y el catálogo ya lo había resuelto en los CUATRO componentes con
escala `rounded`: `button`, `badge`, `image` y `color-swatch` declaran sus
`radius-{paso}` y el reposo lee UNO de ellos. Toggle es el único que no.
Entran `radius` (el reposo, default `var(--radius-default)`, que así SIGUE
siguiendo el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El
desacople de `size` se conserva intacto: son pasos de `rounded`.
- **El tinte inválido (§1.1, 1 knob)**: `var(--color-threat-element)` a pelo →
`--toggle-invalid-border` con ese valor. La costura de PLAN §2-A.
- **Los tres literales (§1.3)** se FIRMAN con `/* literal: */` y salen del
ratio: el `100%` de `data-block` es identidad, y el par `1px` del cuerpo
`sr-only` ES la técnica (precedente `text-blur` / `text-scramble`).
**Diff de computed: VACÍO.** 416 valores en 7 estados (sonda estándar) más
1.150 valores en 25 celdas de variante / `rounded` / `on` / `invalid` /
`disabled` / `block` / `icon-only` / tono (barrido dirigido: el escenario monta
UN toggle `solid`, apagado y válido). Capturas 2× antes y después, idénticas.
**Centinela R-5.4: 70/126, 56 adjudicadas.** Empezó en **36/126** y la
diferencia NO es adjudicación, es instrumento: el guard sólo sabía barrer UN
eje, y aquí las claves `{variante}-*` y `{variante}-on-*` son las mismas tres
variantes en dos ESTADOS distintos. Forzar el estado con `prepareWith` cambiaba
una mitad por la otra (36 → 46, y las de reposo murieron) — «montar más puede
medir menos», esta vez dentro de un componente. El guard aprende a barrer el
PRODUCTO CARTESIANO de varios ejes (`variant` × `state` × `invalid`), y a
quitar un atributo con `null`, porque sellar `data-invalid` toda la corrida
hacía que el borde inválido ganase a los otros seis bordes. Con eso, 58/126. Y
el barrido llegó también al PASE DE HOVER, que no barría nada: 70/126, con las
doce claves de hover vivas (es literalmente la razón que
`radio-group.hover-segmented-segment-fg` tenía escrita en el ledger).
De las 56 restantes, 48 son la cascada de paleta por PATRÓN — medida aquí, con
un matiz que conviene escribir: **las ocho `neutral-*` caen con las demás
porque el propio guard estampa `data-color=neutral` para probarlas**, que es
justo lo que enciende el bloque genérico. Las otras 8 están medidas una a una
(los cinco pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el
par de transición, que ES lo que el guard congela).
**Anotado, fuera por D-TH.5**: `[data-toggle]:hover` y
`[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara
antes, así que **un toggle inválido bajo el puntero pierde su tinte**.
Arreglarlo mueve píxel y es una decisión de escala del sistema — los cuatro
controles de formulario (checkbox, switch, pin-input, toggle) comparten el
patrón. No se toca aquí.
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 -->

Powered by TurnKey Linux.