astra
alpha-0.1-background
alpha-0.1-dir-prefs
alpha-0.1-sec-dom
menubar-v4-safe
active-uix
morfo-runtime
morfo-driven-soma
semantuix
glm-5
main
sium-v1.0
${ noResults }
2089 Commits (af0c6d9bdf4b02b97186c20bfe17210ce0873214)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
af0c6d9bdf |
docs(theming): el handoff registra que ya no queda rojo del bloque viejo
Cabecera: `drawer` (24), `metrics` (18) y `color-picker` (25) están medidos uno a uno y adjudicados por escrito — el guard R-5.4 pasa en los tres. Los tres hallazgos reales que salieron esperan firma en §13. Firma nueva (9): el eje `size` del `color-picker` muere en el portal. Dos lecciones del instrumento, con su fecha: los tokens que SON la transición no se miden congelando, y una lectura inmediata de una propiedad en transición devuelve el valor viejo — ni `!important` en línea la mueve. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
27dc6dba35 |
uix(theming): los dos rojos que quedaban — y el eje `size` del picker MUERE EN EL PORTAL
Medidos uno a uno los 18 de `metrics` y los 25 de `color-picker`, los últimos del bloque viejo que el guard R-5.4 arrastraba sin adjudicar. Los dos quedan en verde. Sin cambios de código: esto es medición y registro. `metrics`: los 18 están VIVOS. Ninguno miente; lo que faltaba era el escenario. Seis piden el paso `xxl` (la demo llega a `xl`), dos el icono SIN `data-color` (su defecto sólo pinta cuando no hay color, y todos los de la demo llevan uno), dos las formas `circle`/`square`, cuatro la fila de acciones, uno el gráfico en `end`, uno el borde de la variante `outline`, y dos el sello de sema durante el hold (`data-event-family=signal` + `phase=active`): el destello del valor sólo se mide estampando el sello a mano, porque cuando el guard lee ya se ha ido. `color-picker`: 23 de 25 vivos, y los otros dos son un DEFECTO REAL. EL EJE `size` MUERE EN EL PORTAL, dos veces. `--_color-picker-content-width` se declara TRES veces y no lo consume NADIE: la anchura del panel la fija `--_popover-content-width-override`, cableada al paso `md`. Un picker `sm` y uno `lg` abren el MISMO panel de 344 px, y `content-width-sm`/`-lg` son dos públicos que no mueven nada. Lo mismo con las muestras dentro del panel (`--_color-picker-swatch-size` clavado a `md`): fuera del portal los tres pasos alcanzan (20/24/28 px → 1234 px), dentro sólo el `md`. La causa es una y vale como ley: el portal es una FRONTERA DE CASCADA — un privado declarado en la raíz del componente no la cruza. Misma familia que la capa `list-surface` inalcanzable desde `:root`. El arreglo honesto es una escala por talla en el ámbito del CONTENIDO (que sí lleva su `data-size`); mueve píxel en `sm` y `lg`, así que es firma → §13. Tres cegueras del instrumento, medidas: - El guard CONGELA las transiciones antes de medir —el arreglo que hizo medibles radio-cards y compañía— y `transition-duration`/`transition-ease` SON la transición: sin congelar alcanzan (0.12s → 11.5s). Es genérico: cualquier componente con esos dos públicos los reportará muertos. - Una lectura inmediata de una propiedad EN TRANSICIÓN devuelve el valor VIEJO. Es lo que hacía ilegible el fondo del cuentagotas: ni con `!important` en línea se movía, porque la transición aún no había corrido. - La DEMO pisa el cuentagotas con su regla de ámbito (`.cp-tools-row` le pone `inline-size:auto` y `background`), así que sus dos tokens sólo se miden devolviéndole el consumo del token. Gates: `theming:sentinel metrics` y `color-picker` en verde (54/72 y 46/71, el resto adjudicado por escrito) · `check` sin errores propios · `docs:check` 0/0 · formato sin regresión (los tres ficheros ya venían avisados en HEAD). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
f25f5bb1d0 |
uix(drawer): los 24 rojos medidos uno a uno — y uno era un DEFECTO REAL: el velo no pinta
Sin cambios de código: 24 adjudicaciones medidas y dos hallazgos. El guard queda
en VERDE.
EL VELO DEL CAJÓN NO PINTA. Su regla es
background: color-mix(in srgb,
var(--drawer-overlay-bg) var(--drawer-overlay-opacity), transparent)
y **soma escribe `--drawer-overlay-opacity: 1` INLINE** en el nodo del velo — es
su progreso de arrastre, un número sin unidad. `color-mix` exige ahí un
PORCENTAJE: con `1` la función entera es inválida y el fondo cae a `transparent`.
Medido: el velo abierto computa `rgba(0, 0, 0, 0)`; escribiendo `80%` en el
propio nodo, pinta. Y VISTO en captura: el fondo tras el cajón sale desenfocado
pero **sin atenuar** — el `backdrop-filter` funciona y el tinte no existe. Un
cajón modal sin velo.
No se arregla aquí porque mueve píxel y toca soma (§7.8). Puede arreglarse de un
lado o del otro —que soma escriba un porcentaje, o que la receta no use ese slot
como porcentaje—, y la lección general queda escrita en §13: **un valor que soma
escribe inline y una receta consume tiene que compartir UNIDAD**, o el fallo es
silencioso.
SEGUNDO HALLAZGO: las tallas son canal de valor en el eje que manda. Soma escribe
`width` (o `height`, según el lado) inline en el contenido, así que
`content-width-{sm,md,lg}` no puede ganar desde `:root` en un cajón
izquierda/derecha; el eje cruzado sí alcanza (`height-sm` forzado: 260px →
976px). Misma clase que el `item-gap` de carousel y el `preview-z` de drag-drop,
que se retiraron — pero aquí el token sigue siendo la fuente del valor que soma
resuelve, así que retirarlo o no es firma tuya.
Los otros 22 son lo esperable, y quedan medidos con su valor: el asa —que la demo
no monta y cuyo tamaño INTERCAMBIA ejes según el lado (36px→1234px de largo,
4px→1234px de grosor)—, el anillo de arrastre, el padding `full`, la cabecera y
el pie opcionales, y la z de la variante inline.
Gates: centinela 29/54 con las 24 adjudicadas, exit 0 · docs:check 0 · captura de
la página con el cajón abierto mirada.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
cd6a9f4e3e |
uix(theming): revisión adversarial del bloque — la pasada de HOVER envenenaba a todos los tokens de reposo
Cinco hipótesis, un hallazgo real, cuatro refutadas. Bloque de CATORCE componentes; global del eje 56 % → **62 %**. HALLAZGO REAL — la anomalía de `float-panel` tenía causa, y era del guard. `resize-grip-fg` movía aislado y leía muerto en una corrida completa. Instrumenté el propio guard para probar UNA clave y salió `moved=true`; luego, en la corrida entera, muerto. La causa: **la pasada de HOVER deja el puntero sobre el último nodo que tocó**, y una regla `:hover` gana a la de reposo con la que comparte nodo — el asa re-apunta su color al acento al pasar el ratón. Es decir: **cualquier token de reposo probado DESPUÉS de un token `hover-*` podía leer muerto**. Es exactamente la clase que F2-A arregló con el clic-foco, una pasada más tarde: allí se aparcó el puntero tras ABRIR, aquí faltaba aparcarlo tras HOVERAR. Arreglado. Y entonces el propio guard delató DOS excepciones STALE — `float-panel.resize-grip-fg` y `media-player.track` —, retiradas: dos tokens que el ledger daba por muertos están vivos. Se confirma la regla de F2-A: **un falso negativo siempre tiene causa**; registrarlo como «sin causa» era el paso previo, no el final. REFUTADA «hay tokens huérfanos»: comprobación ESTRICTA —comentarios despojados, que es el hueco por el que `popover.bg` sobrevivió, sobre todo el CSS del árbol— de las **553 claves** de los catorce bloques: ninguna declarada sin que una regla la lea. REFUTADA «el cambio de instrumento rompió algo»: los **27 componentes con ledger re-verificados** tras aparcar el puntero — cero regresiones. Los tres rojos que quedan (`drawer` 24, `metrics` 16, `color-picker` 23) son ANTERIORES al bloque y están anotados con lo que ya se descartó de cada uno. REFUTADA «quedan fantasmas del barrido en lo tocado»: pasa de 9 a **8** — el `--color-content-tertiary` de float-panel murió con su costura. Los ocho restantes son de componentes que este bloque no tocó. CONFIRMADO, y ya estaba escrito: hay gates FINOS. `popover` mide 1 nodo en reposo (7 en abierto), `drawer` 1, `context-menu` 1 + 14 en abierto, `color-picker` 5 + 12. Cada veredicto lo dice, y lo que sostiene esas cifras es el forzado a mano de sus estados, no la sonda. Guards: `--names` sin desviadas · docs:check 0 · censo 62 % (2.877 públicos de 5.137 knobs; `global` 1.145 → 912). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
608e7d5507 |
uix(password-field): temable — 41 % → 62 %, y el guard queda EN VERDE
7 claves (23 → 30). Censo password-field 41 % → **62 %**; el centinela pasa a verde con **las siete adjudicaciones medidas**, incluidas las tres que este componente arrastraba sin medir. Cosido: el tracking del input enmascarado —los puntos leen mejor algo sueltos—, el chip de bloq-mayús (radio y peso; su peso llevaba un `500` muerto detrás de un token que ya vale 500) y **los cuatro peldaños del medidor de fuerza**. LOS CUATRO PELDAÑOS SON UNA ESCALA DE INTENCIÓN, no cuatro colores sueltos: cada uno lee su rol —pérdida, riesgo, cumplimiento, afirmación— y ahora un tema puede recorrer la escala entera sin tocar los roles del sistema. De paso muere otra referencia con respaldo: el primer peldaño leía `var(--color-loss-solid, var(--color-threat-solid))` y el primitivo SÍ existe, así que el respaldo era ruido. LO QUE NO SE ACUÑA, Y ES COMPOSICIÓN: el `padding-inline` del medidor y el `font-size` de su rótulo leen privados de FIELD (`--_field-control-*`), porque este componente monta un Field. Se teman en la ficha del dueño — mandato de composición, `theming-audit` §5.3-3. Siete adjudicaciones, todas medidas: los cuatro peldaños sólo pintan bajo su `data-strength` y la demo arranca con el campo vacío (fuerza 0, ningún segmento activo); las dos de transición las congela el guard; y la opacidad deshabilitada vive en el disparador de visibilidad, no en la raíz — por eso mi primera medición dio «sin efecto» y hubo que buscar el nodo que la regla señala. Gates: sonda antes/después **0 diffs en 3.060 valores** (14 nodos × 8 estados) · centinela 23/30 con las siete adjudicadas, exit 0 · censo --only 62 % · `--names` sin desviadas · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check 0 · docs:check 0 · captura mirada (campo, medidor de cuatro segmentos y rótulo en su sitio). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
ab96ae783b |
uix(context-menu): temable — 53 % → 90 %, y el instrumento aprende a abrir un menú contextual
11 claves (18 → 29). Censo context-menu 53 % → **90 %** con `global` a CERO. EL INSTRUMENTO NO SABÍA ABRIRLO. Un menú contextual se abre con clic DERECHO y con nada más, así que sonda y guard medían UN nodo: el disparador. Los dos aprenden el modo (`openBy: 'contextmenu'` en `COMPONENT_OVERRIDES`, clic derecho en la sonda) y pasan a ver **14 nodos** en el estado abierto; el guard, de un baremo ciego a **27/29**. Cosido el cromo propio del panel y del disparador: tipografía y tinta del contenido, tinta e interlineado de la fila, el galón del submenú (dos bordes girados 45°, un solo trazo), el encabezado de grupo (tinta, peso y tracking de versalitas) y el contorno DISCONTINUO que marca el disparador abierto — el estilo `dashed` es identidad de la afordancia; el grosor y el color son knobs. Dos limpiezas de paso: el `font-family` leía `var(--style-label-font-family, var(--style-label-font-family))` —respaldo de sí mismo— y el peso del encabezado llevaba un `500` muerto detrás de un token que ya vale 500. DOS ADJUDICACIONES MEDIDAS, y una es la TERCERA ocurrencia del mismo hallazgo: `content-font-family` no puede ganar porque el plano `overlay` impone la tipografía del panel (§12.9, pendiente de tu firma — ya medido en `popover` y en `float-panel`). La otra es el ítem deshabilitado, que la demo no monta: forzado, 0.55 → 0.123. Gates: sonda antes/después **0 diffs en 600 valores** (8 estados, 14 nodos en el abierto) · centinela 27/29 · censo --only 90 % · `--names` sin desviadas · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check 0 · docs:check 0 · captura del panel mirada (encabezado en versalitas, filas, casillas, galón del submenú y separadores en su sitio). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
db5812aa36 |
uix(metrics): temable — 74 % → 82 %, y el SEGUNDO prefijo abreviado del día
4 claves (68 → 72) y 16 ocurrencias renombradas. Censo metrics 74 % → **82 %** con `global` a CERO. `--_mi-*` VIOLABA theming §6 r5 —«no abrevies el nombre del componente»—, segundo caso del día tras `--cp-*` de `color-picker`. Renombrado a `--_metrics-icon-*`: son el conmutador del icono por variante (soft / solid / outline), que ya derivaba de públicos y del puente de paleta, así que el censo los reclasifica solo. 16 ocurrencias, todas en su propio CSS. Cosido: el ritmo del trend y **las TRES formas del icono** — una clave por valor de `data-shape`, porque el radio es lo único que las distingue. Dos adjudicaciones medidas: el icono de la demo corre la forma `rounded`, así que las otras dos sólo pintan bajo su propio valor; forzadas, 9999px → 1234px y 6px → 1234px. Los 16 rojos que quedan son anteriores: la talla `xxl` que la demo no monta y el fondo y la tinta base del icono, que su variante pisa. Gates: sonda antes/después **0 diffs en 1.590 valores** (8 nodos × 7 estados) · censo --only 82 % · `--names` sin desviadas · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check 0 · docs:check 0 · captura mirada (tarjeta, icono redondeado, trend y sparkline en su sitio). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
b4510fbf82 |
uix(float-panel): temable — 59 % → 84 %, muere un fantasma y queda una anomalía registrada
12 claves (28 → 40). Censo float-panel 59 % → **84 %** con `global` a CERO. Cosido: las dos VARIANTES que ajustan desde el default elevado (`outline-*`, `ghost-*`), los botones de su barra (`action-*`, `hover-action-*`) y el asa de redimensionado. MUERE UNO DE LOS NUEVE FANTASMAS DEL BARRIDO de esta mañana: el asa leía `var(--color-content-tertiary, var(--color-content-secondary))` y ese primitivo NO EXISTE, así que pintaba el respaldo. El contrato guarda lo que de verdad pintaba, con lo que la referencia muerta desaparece sin mover un píxel. ONCE ADJUDICACIONES MEDIDAS: la demo monta la variante por DEFECTO —ni outline ni ghost— y no tiene botón de acción genérico, sólo el control de cierre; se forzó el atributo de variante y se montó el botón donde el CSS lo selecciona, y el radio del asa sólo pinta bajo `:focus-visible`. Las once alcanzan. Y UNA ANOMALÍA REGISTRADA EN VEZ DE ESCONDIDA: `resize-grip-fg` **mueve** bajo una réplica a mano de la secuencia del propio guard —congelar transiciones, blur, aparcar el ratón, escribir en `:root` y en cada nodo con el prefijo, fotografiar los mismos props con `::before`/`::after`/`::placeholder`— (oklch(0.5032 0 0) → rgb(1,2,3)), y aun así el guard lo da por muerto. Descartado que el nodo no lleve el atributo (lo lleva), que la regla necesite un estado (es la regla base), que sea el valor centinela (es el mismo) y que sea HMR (dos corridas). Queda adjudicado CON la medición y marcado como anomalía en §13: el token está vivo, lo que está en duda es la lectura. Es por donde debe empezar la revisión adversarial de este bloque — el precedente de F2-A dice que estos casos sí tienen causa. Lo rojo que queda son 12 tokens anteriores, y seis de ellos —`bg`, `border`, `border-width`, `shadow`, `font-family`, `line-height`— son el mismo conjunto que en `popover`: el PLANO de profundidad gana sobre el panel (§12.9, pendiente de firma). Gates: sonda antes/después **0 diffs en 1.890 valores** (9 nodos × 7 estados) · censo --only 84 % · `--names` sin desviadas · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check 0 · docs:check 0 · captura mirada (cabecera, botón de cierre y asa de la esquina en su sitio). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
caf08d1701 |
uix(nav-tree): temable — 4 % → 96 %, y 18/18 en el guard sin una sola excepción
17 claves nuevas (1 → 18): tenía UNA sola pública (`indent`) y todo lo demás iba a primitivo crudo. Censo nav-tree 4 % → **96 %**; global del eje 61 %. LA FILA ES LINK + TRIGGER A LA VEZ. Las reglas los tratan juntos —mismo padding, misma tinta, mismo radio, mismo hover— así que el knob es de la FILA (`row-*`), no de cada parte: es una pseudo-parte, el molde firmado de las regiones de `waveform`. Sus estados llevan el modificador DELANTE, que es lo que la gramática pide para lo interactivo (`hover-row-fg`, `active-row-fg`, `disabled-row-fg`), y la estela —los ancestros de la página actual— es contextual y va DETRÁS (`trail-row-fg`). El disparador sí tiene lo suyo: el suelo de 24 px del blanco táctil (WCAG 2.5.8) y su padding. Y el galón es una escuadra dibujada con dos bordes (`::after` con `border-inline-end` + `border-block-end` girado 45°): su lado es un knob y el grosor del trazo otro — mismo molde que la esquina de `text-focus`. LA SUITE CAZÓ UN INCUMPLIMIENTO HEREDADO, tercera vez en el eje: el contrato copió `var(--font-size-sm)` verbatim del CSS, y ésa es la coordenada CRUDA que `recipe-css-contract` prohíbe en un token de receta. Corregido al bundle (`var(--size-sm-font-size)`), que computa idéntico. El «valor verbatim» arrastra el defecto del CSS de partida siempre que el CSS ya lo tuviera. DOS CEGUERAS MÁS DEL GUARD, medidas y arregladas: 1. **La fila es un `<div>` pelado sin atributo propio**, así que el `gap` entre link y trigger leía muerto moviendo 4px → 1234px. 2. **No leía el ANCHO de un borde que no fuera el de arriba**: el galón tiñe los de inline-end y block-end. Añadidos los tres lados que faltaban (los COLORES por lado ya se añadieron con `prose`, hoy mismo). Con las dos: **18/18 en vivo, sin una sola excepción**. Los nueve componentes con ledger re-verificados tras tocar las PROPS del guard: sin regresiones ni STALE. Lo que queda fuera: el `100%` de la fila (identidad) y el anillo de foco (sistema). Gates: sonda antes/después **0 diffs en 22.140 valores** (102 nodos × 8 estados) · centinela 18/18 · censo --only 96 % · `--names` sin desviadas · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check 0 · docs:check 0 · captura del escenario mirada (raíl, galones, estela y fila activa intactos). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
78dfa236fd |
uix(drawer): temable — 57 % → 72 %, el disparador gemelo del de popover
10 claves (44 → 54). Censo drawer 57 % → **72 %**; global del eje 61 %.
Mismo cromo que el disparador de `popover` y con la misma corrección:
`min-block-size` lee el BUNDLE de talla (`--size-md-control-height`) y no el
primitivo crudo que el CSS traía. Aquí no hay estado abierto que teñir, así que
el hover lleva una sola clave.
LO QUE QUEDA FUERA ES LA FIRMA DE SALIDA, y no se cose aquí: los cuatro
`border-{side}: var(--border-width-thick) solid transparent` son la base que las
reglas de `data-last-action` tiñen al cerrar. La misma matriz vive en `popover` y
`dialog`, ya ha derivado entre las tres, y es mapeo transversal según la tabla
morfo→eidos → §13.
Los ocho privados son canales de valor (los `*-override` que el wrapper escribe
desde sus props, y el par `panel-width/height` de la variante persistente) y los
cinco literales, identidad.
UNA ADJUDICACIÓN, MEDIDA, Y DE UNA CLASE NUEVA DEL INSTRUMENTO: el guard ABRE el
cajón antes de probar, y entonces el velo tapa el disparador — la pasada de hover
no puede posarse en él (Playwright se niega a hacer hover sobre un nodo que no
recibe puntero). Con el cajón cerrado y hover a mano, `hover-trigger-bg` alcanza
(oklch(0.931 0 0) → rgb(1,2,3)).
Lo rojo que queda son **24 tokens anteriores** a este commit —el asa de arrastre,
el anillo de arrastre, los anchos y altos por talla, los gaps de cabecera y pie—,
todos de partes o estados que la demo no monta. Este commit no los empeora.
Gates: sonda antes/después **0 diffs en 390 valores** (8 estados) · censo --only
72 % · `--names` sin desviadas · component-audit PASS · eidos-lint 0 invalid ·
suite eidos con el único rojo conocido · rtl:check 0 · docs:check 0 · captura del
escenario mirada (disparador con su cromo intacto).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5336fd0009 |
uix(aura): temable — 43 % → 80 %, y doce silencios que son diseño
13 claves (24 → 37). Censo aura 43 % → **80 %**; global del eje 61 %. Su texto de estado y su detalle bajan UN paso del bundle por talla, y las TRES coordenadas viajan juntas (tamaño, interlineado, tracking): doce declaraciones, doce valores distintos, doce claves — 1:1, sin inflación. El valor sigue siendo del bundle; el knob pasa a ser del componente. La decimotercera es `idle-opacity`: el reposo no desaparece, se retira a media opacidad. Fuera por identidad: el `--radius-full` del anillo (redondo por definición), los cuatro `100%` del canvas y del SVG, y el `1px` × 2 de la región viva — la técnica sr-only, la misma de `text-blur`. DOCE ADJUDICACIONES, TODAS MEDIDAS, Y NINGUNA ES DEUDA: - **Las seis tintas de estado y el halo pintan el FONDO DEL INDICADOR**, y la demo corre con el canvas WebGL montado: la regla `[data-aura-indicator]:has(canvas)` pone `background: none` A PROPÓSITO — el orbe ES la presencia, y un disco detrás enturbia su silueta. Quitando el canvas en vivo, el gradiente vuelve y las siete siguen al token (oklch(0.6434 0 0) → rgb(1,2,3) dentro del radial-gradient). - **El arco y el halo son SLOTS del anillo que sólo existen en los estados de trabajo**; la demo se queda en la pista. Montados como `<circle data-aura-ring-slot>` dentro del SVG real —que es exactamente lo que el CSS selecciona—: 2px → 1234px, 1px → 1234px, 0.5 → 0.123. - Las dos de transición, congeladas por el guard como en todo el catálogo. Y una ceguera más del instrumento, la tercera de la sesión: **el guard no veía el SVG del anillo** porque sus `<circle>` no llevan atributo `data-aura*`. `extraNodes` los mete en el conjunto medido. Gates: sonda antes/después **0 diffs en 1.710 valores** (9 nodos × 7 estados) · centinela 25/37 con las doce adjudicadas · censo --only 80 % · `--names` sin desviadas · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check 0 · docs:check 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
3fe8b974a6 |
uix(color-picker): temable — 51 % → 75 %, y un prefijo ABREVIADO fuera de todo el árbol
20 claves de costura (54 → 71) y cinco nombres renombrados. Global del eje 60 % → **61 %**. `--cp-*` VIOLABA theming §6 r5 («no abrevies el nombre del componente»). Cinco nombres —`checker`, `checker-cell`, `current-color`, `channel-gradient`, `trigger-color`— y **45 ocurrencias en 8 ficheros**, tres de ellos de SOMA: el provider los estampa inline, su test los lee y sus tipos los declaran. Renombrados a `--_color-picker-*` con `git ls-files` delante; dos de ellos —el damero y el gradiente de canal— ya derivaban de un público, así que el censo los reclasifica solo. Precedente: los `--gb-*` / `--_ntp-*` de F2-A. Cosido: el ritmo del componente, la tinta de la etiqueta, la tipografía del disparador y la del VALOR —que es metadato: mono, regular, tinta e interlineado propios—, el borde de la muestra, el raíl del canal y su pulgar, el hueco del anillo de la muestra y el borde del cuentagotas. UNA SOMBRA QUE SON DOS Y HACEN UNA COSA: el pulgar del canal lleva contorno + elevación en un solo `box-shadow`, así que se acuña como UN token y la regla de foco lo compone con su tercer anillo, en vez de repetir las dos sombras. EL INSTRUMENTO NO VEÍA DOS FAMILIAS DE NODO, y las dos se arreglaron midiendo: las muestras del picker **son `<ColorSwatch>`** (llevan `data-color-swatch`, no `data-color-picker-*`) y sus sliders de canal **son SLIDERS** (el pulgar y el raíl llevan `data-slider-*`). Cuatro tokens vivos leían muertos por eso. LO ROJO QUE QUEDA ES ANTERIOR A ESTE COMMIT: el guard reporta 23 sin adjudicar —las muestras, la rueda de tono (`hue-0..360` + `saturation-floor`), el ancho del panel por talla, el cuentagotas y las dos de transición—, todos del bloque que ya existía. Antes eran **24**, así que la cifra baja. Su pase de medición queda anotado en §13 con dos causas ya descartadas: el panel SÍ abre y sobrevive al blur, al parqueo del ratón y al forzado de `data-size`, y el guard ya ve sus nodos. Lo que este commit añadió está medido: dos adjudicadas montando el disparador de muestra dentro del panel abierto, el resto en vivo. Gates: sonda antes/después **0 diffs en 1.350 valores** (8 estados), medida DOS veces —una tras el renombrado, otra tras la costura— · tests de soma del color-picker **7/7** tras el renombrado · censo --only 75 % · `--names` sin desviadas · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check 0 · 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 |
|
|
f0bd4bc594 |
uix(popover): temable — 46 % → 67 %, y un huérfano que el guard de huérfanos no veía
Once claves para el disparador + una RETIRADA (36 → 46). Global del eje 60 %. EL DISPARADOR GENÉRICO ES CROMO PROPIO. El que no lleva el arquetipo `field-trigger` —que tiene su tratamiento aparte— montaba alto, padding, borde, radio, superficie y tinta sobre primitivos crudos. Dos notas: `trigger-height` lee el BUNDLE de talla (`--size-md-control-height`) y no el primitivo que el CSS traía, y hover y abierto llevan CADA UNO su par de claves aunque hoy compartan valor — son dos estados, y un tema puede querer el abierto más marcado. `bg` RETIRADO: ninguna regla CSS lo consumía. El único sitio del corpus que lo nombraba era un COMENTARIO de `popover-arrow.svelte` («fill: var(--popover-bg)»), y el test `does not leave declared public recipe variables orphaned` busca el nombre como TEXTO en los ficheros del componente — así que un comentario mantiene vivo un token para siempre. La superficie del panel la pinta el plano de profundidad (`--depth-overlay-surface`), que es lo que un plano debe poseer; el comentario queda corregido y el hueco del test, en §13. LOS DOCE QUE SIGUEN FUERA SON LA FIRMA DE SALIDA, y no se cosen aquí: `data-last-action` × 3 intents × 4 lados tiñendo el borde durante el cierre. La misma matriz está repetida en `drawer` (22 reglas) y `dialog` (9) — y ya ha derivado: dialog tiñe sólo `border-top-color` mientras popover y drawer usan el shorthand con `--border-width-medium`, así que en dos de tres el GROSOR también cambia al salir. La tabla morfo→eidos la sitúa como mapeo transversal («`events[].prewrite` → tinting the exit anim by cause»), misma fila que los arquetipos: es canal visual de sema, no cromo de componente. Coserlo tres veces sería triplicar un vocabulario que debe vivir una vez → §13. DOS CEGUERAS DEL INSTRUMENTO, arregladas: 1. La página tiene CINCO disparadores y el guard abría el primero del documento —un ejemplo de más abajo—, no el del escenario: las partes que el escenario monta nunca entraban. `openWith` apuntando al escenario. 2. `content-z` se consume sobre el ENVOLTORIO FLOTANTE (`:has(> [data-popover-content])`), un nodo sin atributo `data-popover*` que el filtro no veía: leía muerto moviendo 80 → 4321. TRECE ADJUDICACIONES, TODAS MEDIDAS: nueve son partes que la demo no monta (Title, Description) y dos el overlay opcional —montados en el panel ABIERTO con los atributos que el CSS selecciona, alcanzan—. **Las dos que no son de montaje**: `font-family` y `line-height` no pueden ganar porque el plano `overlay` impone la tipografía del panel — el hallazgo §12.9, que espera tu firma y afecta a VEINTE componentes. Aquí queda medido otra vez. Gates: sonda antes/después **0 diffs en 420 valores** (8 estados; el escenario monta un disparador y el panel portala fuera, así que el estado `abierto` es el que mide el panel: 7 nodos) · centinela 33/46 · censo --only 67 % · `--names` sin desviadas · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check 0 · docs:check 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
befd1987fe |
uix(radio-cards): 61 % es su techo — 21 de sus 23 knobs no son suyos
Una sola clave nueva (`invalid-border`, 39 → 40) y su veredicto §5. RadioCards es un **skin sobre RadioGroup**: renderiza `<RadioGroup.Provider>` y su indicador ES un radio. Por eso lee `--radio-group-item-size-*`, `--radio-group-indicator-*` y el puente de paleta del anfitrión (`--_radio-group-palette-*`, declarado en el host `[data-radio-group]` donde esta tarjeta vive). El censo los marca «⤴ prestado» y el mandato de composición (`theming-audit` §5.3-3) dice que **se teman en la ficha del dueño**: coserlos aquí sería vocabulario paralelo y dejaría que un tema rompiera «un radio es un radio» sólo dentro de las tarjetas. Lo acuñado es lo que sí es suyo: el borde de la TARJETA en validación fallida. Los dos `--radius-full` del indicador son identidad (un radio es redondo por definición, misma clase que el `50%` de un círculo) y los cuatro literales son geometría del glifo (el `46%` del punto interior, el `100%` del SVG). LA LECCIÓN DE LA MEDICIÓN: la primera lectura forzada de `invalid-border` dio «sin efecto». No era el token: la tarjeta transiciona `border-color`, y leer justo después de escribir devuelve el valor de PARTIDA — exactamente el motivo por el que el guard congela las transiciones. Con la congelación puesta, `oklch(0.9555 0.0207 13.86)` → `rgb(1,2,3)`. **Una medición forzada a mano tiene que congelar también.** Queda escrito en el veredicto y en el ledger. Las otras cuatro adjudicaciones, con su medición: `horizontal-basis` sólo bajo `[data-orientation=horizontal]` (192px → 1234px), `disabled-opacity` sólo bajo `[data-disabled]` (0.4 → 0.123) y las dos de transición, que el guard congela (0,12s → 11,5s · cubic-bezier → steps(4)). Gates: sonda antes/después **0 diffs en 3.540 valores** (19 nodos × 7 estados) · centinela 35/40 con las cinco adjudicadas · censo --only 61 % · `--names` sin desviadas · component-audit PASS · eidos-lint 0 invalid · docs:check 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
001b1cdbd0 |
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
46da0edd1a |
uix(listbox): 68 % es su techo — coserlo como sus hermanos habría mentido
Sin cambios de código: su veredicto §5 y la incidencia registrada.
Cinco de sus nueve privados ADOPTAN la capa `list-surface` (el ritmo de fila que
`lib/list-surface.css` resuelve por talla sobre `data-list-surface`, compartido
con select, combobox, command y los tres menús); dos son el puente de paleta
THM-2 (misma razón que `tag-group`) y el noveno sí deriva de un público.
La cola decía «cose como sus hermanos», porque `dropdown-menu` y `context-menu`
sí acuñan el puente (`--dropdown-menu-item-height: var(--list-item-height)`).
Medido antes de copiarlo, con el menú abierto y la fila a 36 px:
tema escribe --dropdown-menu-item-height: 1234px en :root -> 36px
tema escribe --list-item-height: 1234px en :root -> 36px
**Ninguno alcanza.** Es cascada: la capa declara sobre
`[data-list-surface][data-size]` y el puente sobre `[data-{c}-content]`; las dos
ganan a `:root` siempre. Copiar el puente aquí habría subido la cifra sin dar
alcance a nadie — un token que miente, que es justo la clase que R-5.4 existe
para cazar.
Se arregla EN LA CAPA, no en el consumidor: dándole a `list-surface` una entrada
de receta como se hizo con `calendar-surface` (el gancho resuelve por talla, el
vocabulario vive en la receta). Toca diez componentes de golpe → §13, eje propio.
Y deja un aviso sobre el instrumento, también en §13: **el centinela da por
vivos los tokens de esta forma** porque escribe inline en el nodo, que gana a la
regla del gancho. Para un token que un tema sólo puede escribir en `:root`,
«mueve un computed» no equivale a «un tema lo alcanza».
Lo demás de su 32 %: el `background` del item resaltado es la incidencia ya
escrita del velo de estado (§12) y el `100%` de `[data-block]` es identidad.
docs:check 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5638d67fde |
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 |
|
|
1c4f9518bb |
uix(theming): tres techos que no son deuda — el PUENTE DE PALETA no se acuña
Sin cambios de código: los veredictos §5 de `tag-group` (65 %), `stepper` (79 %)
y `timeline` (73 %), y la clase registrada.
Los tres tienen `global` a CERO. Lo único fuera de alcance son sus privados
`--_{c}-palette-*`: el puente THM-2 que la capa compartida alimenta POR
INSTANCIA desde `[data-color]`. **Un público encima del puente
(`--tag-group-selected-bg: var(--_tag-group-palette-surface)`) dejaría que un
tema lo fijara y matara en silencio el `color=` de cada instancia** — la misma
clase de daño que «declarar un público de facto mata una escala» (`knob`). Y no
hace falta: los componentes ya exponen sus nueve roles × variante como claves
públicas (91 en `tag-group`). Ésa ES su superficie de color, y está completa.
`timeline` suma una segunda razón, también firmada: sus `--_timeline-hue-*` son
un CONMUTADOR —cada `data-intent` los re-apunta a las ranuras de rol y el
intent por defecto al puente—, y aplanarlo obligaría a duplicar cada regla por
intent (doctrina F2-B, cinco precedentes).
MEDIDO, para no adjudicar de oído: de las **687** declaraciones del catálogo que
leen un privado, **130 leen un `--_{c}-palette-*`**, y son las que dominan la
columna `private` de todo componente con paleta — tag-group 14/14, stepper
11/11, radio-group 10, checkbox 8, file-upload 8, calendar / editable / los tres
grids 7 cada uno.
Consecuencia que queda escrita en §13: **el techo de un componente con paleta no
es el 100 %**, y su cifra no compara con la de uno sin ella, porque el
denominador incluye un puente que por diseño no se acuña. Si algún día se quiere
comparabilidad, la salida es una clase `bridge` en el censo — no acuñar los
tokens. Los otros seis heredan la razón cuando les toque, pero ojo: ésos tienen
ADEMÁS knobs `global` y sí les toca trabajo real.
Los cuatro literales de los tres son identidad anotada: el `line-height: 1` del
botón de quitar y el del glifo del marcador, el `100%` de layout del stepper y
los dos `1em` que hacen que título y descripción del timeline hereden el tamaño
escalado del item en vez del tamaño UA del encabezado.
docs:check 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5fdef91fb9 |
uix(result): la COSTURA del texto — 23 % → 86 %, y `global` a cero
Quince claves. Misma corrección que en `chart`: el valor sigue siendo el del
canon —bundle de talla, ranuras de contenido, escalas de peso e interlineado,
familia mono— pero el knob pasa a ser del componente, que es lo que PLAN §2-A
exige y lo que permite retocar esta superficie sin mover el sistema entero.
POR PARTE, NO POR ROL — y es la diferencia con `chart`:
title-{font-size,font-weight,line-height,fg}
description-{font-size,line-height,fg}
extra-{font-size,fg}
code-{font-family,font-weight,letter-spacing,fg}
media-{font-size,fg}
Cinco partes con tipografía distinta y ningún estilo con nombre que juegue
«estado terminal de página» (`h2` está en el tamaño del título pero significa
otra cosa). Es la forma dominante del catálogo — `description-fg` ×8,
`title-font-size`… — mientras que en chart dos roles se repetían sobre 19 nodos
y por eso allí la costura fue por rol.
El `calc(var(--size-xl-font-size) * 3)` del glifo entra en su costura con el
multiplicador DENTRO del valor: el 3× es identidad documentada, y así el glifo
sigue a la escala en vez de congelarse.
DOCE ADJUDICACIONES, TODAS SOBRE NODOS REALES (la lección de `drag-drop`): con
los controles de la propia demo, no fabricando nodos. Los tres acentos de estado
sólo pintan bajo su `data-status` —chip—; el bloque `extra` es opcional
—casilla—; el código grande sólo existe en los estados http —chip `not-found`:
Azeret Mono → Zapfino, 600 → 123, 3,36px → 4,5px—; y la tinta POR DEFECTO del
glifo sólo gana SIN `data-status`, porque cada estado re-apunta el privado a su
acento por diseño —se quitó el atributo: oklch(0.61 0 0) → rgb(1,2,3)—.
Con la costura, `global` cae a CERO y el alcance a 86 %: los tres knobs que
faltan para el 100 % son literales de identidad (el `1em` del código grande, que
hereda la escala del glifo; el `line-height: 1` del glifo; el `100%` del extra).
Gates: sonda antes/después **0 diffs en 990 valores** (5 nodos × 7 estados) ·
centinela 15/27 con las doce adjudicadas y medidas · censo --only **86 %** con
`global` 13 → 0 · --names 27/27 conformes · component-audit PASS · eidos-lint 0
invalid · suite eidos con el único rojo conocido · rtl:check 0 · docs:check 0.
Global del eje tras las dos costuras: **57 % → 58 %** (2.677 → 2.727 públicos).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
643179de0f |
uix(chart): la COSTURA del texto — 49 % → 89 %, y `global` a cero
Seis claves. El valor sigue siendo el del canon; lo que faltaba era el knob.
CORRIGE MI LECTURA DE HACE DOS HORAS. Al tokenizar chart di por doctrina que
«el texto no recibe tokens del componente» porque su valor viene de la capa de
estilos con nombre, y dejé el CSS leyendo `var(--style-caption-font-size)` y
`var(--color-content-*)` A PELO. Eso es media doctrina: PLAN §2-A pide que TODO
knob de apariencia lea `--{c}-{slot}`. Sin la costura, un tema no puede aclarar
las anotaciones de un gráfico denso sin mover `caption` en toda la app, y
`getRecipeTokens()` / `/temas` no ven esa superficie.
El molde ya estaba escrito en la vertebración tipográfica
(`--accordion-trigger-font-family: var(--style-label-font-family)`), y D-TH.2
aclara que sólo los SEIS primitivos quedan fuera: «un componente que sólo LEE un
named style para un eje no es un primitivo y no está en el conjunto».
POR ROL, NO POR PARTE — y se decidió midiendo:
--chart-caption-font-size var(--style-caption-font-size)
--chart-caption-fg var(--style-caption-color)
--chart-label-font-size var(--style-label-font-size)
--chart-label-fg var(--style-label-color)
--chart-label-font-weight var(--style-label-font-weight)
--chart-gauge-label-font-size var(--size-xl-font-size)
Dos roles × tres ejes = 6 claves para 19 nodos de texto; nombrarlo por parte
habrían sido ~30 claves con dos valores. **Tamaño y tinta son ortogonales a
propósito**: `empty` y `bar-list-value` son tamaño `label` con tinta `caption`, y
el CSS lo dice. El readout del gauge no tiene rol en el canon —un `h2` es un
encabezado, no un dato— así que su costura toma el bundle de talla; con eso se
cierra la escotilla que dejé abierta en el commit anterior.
Tres nombres de mi primera propuesta no aguantaron la revisión y no entran:
`label-font-size` a secas chocaba con las seis partes `*-label` del componente
(se acepta el choque, pero nombrando por el ROL del canon, que dice la verdad:
las etiquetas de eje SON captions), `emphasis-*` inventaba vocabulario fuera de
§1/§6.7, y `fg-muted` se apoyaba en un único precedente. La tinta lee el color
DEL ROL (`var(--style-caption-color)`), no la ranura a pelo.
Y RETIRA UNA NOTA EQUIVOCADA DE §13: escribí que el censo penalizaba consumir la
capa tipográfica cuando no eres un primitivo. El censo medía bien; faltaba la
costura. Con ella, `global` cae a CERO y el alcance a 89 % — el techo, porque lo
que queda son los diez literales de identidad (nueve `100%` + el `max-content`
del tooltip). La lección queda escrita: cuando la métrica y la doctrina
discrepan, sospecha de la lectura antes que del instrumento. `listbox` (68 %,
ritmo de fila prestado de `list-surface`) es la misma pregunta un piso más
arriba y queda pendiente de revisar con este molde.
Gates: sonda antes/después **0 diffs en 161.850 valores computados** (16 rutas ×
7 estados) · centinela **43/45**, las dos de transición adjudicadas · censo
--only **89 %** con `global` 36 → 0 · --names 45/45 conformes · component-audit
PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check
0 · 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 |
|
|
0b3382fe67 |
uix(result): temable — 14 % → 23 %, la receta posee su CAJA y nada más
Cuatro claves nuevas (8 → 12). Censo result 14 % → **23 %**; global 57 %;
alcance <20 % 18 → 17.
Aplicación directa de la doctrina que cerró `chart`: lo que la receta posee es
su **caja** —el inset de página (`padding-block`/`-inline`) y el ritmo entre
bloques (`actions-margin-block-start`, `extra-margin-block-start`)—, más los
cuatro acentos de estado que ya tenía. Ni una clave más.
LO QUE NO SE ACUÑA, Y POR QUÉ:
Su tipo ya leía el BUNDLE DE TALLA (`var(--size-{xl,md,sm}-font-size)`), que es
literalmente lo que recipe-contract §1 prescribe; la tinta lee las ranuras de
contenido, el peso y el interlineado sus escalas, y el código grande la familia
mono del tema. Acuñar `--result-title-font-size` habría sido tipografía por
componente, prohibida hoy. El censo cuenta esas trece lecturas de canon como
`global`: es la nota de `listbox` y `chart` (next-features §13), **tercera
ocurrencia**, no deuda de este componente.
Los cuatro literales son identidad documentada: el `calc(var(--size-xl-font-size)
* 3)` del glifo de estado (el display es TRES veces el paso xl), el `1em` del
código grande que hereda esa escala a propósito, su `0.04em` de tracking óptico
y el `100%` del extra.
Higiene de paso: el privado `--_result-media-color` pasa a `--_result-media-fg`
— la gramática firmada (D-TH.6) dice `fg` y R-5.3 no mira los privados.
CINCO ADJUDICACIONES, TODAS SOBRE NODOS REALES:
El guard da 7/12. Las cinco que callan se midieron con los CONTROLES DE LA DEMO,
no fabricando nodos (la lección de `drag-drop`): los tres acentos sólo pintan
bajo su `data-status` —se pulsó su chip: oklch → rgb(1,2,3) en los tres— y el
bloque `extra` es opcional —se marcó su casilla: 16px → 1234px y 559,44px →
1234px—. Las cinco alcanzan.
Gates: sonda antes/después **0 diffs en 990 valores** (5 nodos × 7 estados) ·
censo --only 23 % · --names 12/12 conformes · component-audit PASS · eidos-lint
0 invalid · suite eidos con el único rojo conocido · rtl:check 0 · 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 |
|
|
15eb9c56c9 |
uix(chart): temable — 9 % → 49 %, y la ficha pedía 71 claves de las que 20 llevaban el mismo valor
22 claves nuevas fusionadas en el bloque existente (17 → 39). Censo chart 9 % → **49 %**; global **56 % → 57 %** (2.638 → 2.675 públicos; <20 % 19 → 18). LO QUE DECIDIÓ LA MEDICIÓN, no la ficha: Las 84 filas fuera de alcance colapsaban a **26 valores distintos** — 9× `content-secondary`, 9× `content-primary`, 9× `100%`, 6× `font-size-sm`, 6× `font-size-xs`, 6× `font-weight-medium`, 5× `surface-default`, 4× `radius-sm`. Nombrar por parte habría dado cinco claves para el pelo que separa marcas y nueve para la tinta de anotación: la inflación de `spinner` con otra cara. **El texto no recibe tokens de chart.** Toma su ROL DE TAMAÑO de los estilos con nombre del canon —`caption` (xs) para las anotaciones, `label` (sm) para el texto de cromo— y su tinta y su peso de las ranuras del sistema. Acuñar `--chart-label-font-size` sería tipografía por componente, prohibido el mismo día para text-effects. Precedente de consumir la capa: `code-block`, `kbd`, `announce`. Doce declaraciones cambian de `var(--font-size-xs|sm)` a `var(--style-caption|label-font-size)`, mismo valor. **La receta sólo posee la tinta de lo que NO es texto**, cinco claves y cada una un concepto que el CSS repite: `axis-fg` (eje + rejilla smith + conector del funnel), `grid-fg` (rejilla + radar), `separator-fg` (el pelo de superficie entre marcas contiguas: porción, punto activo, punto smith, pétalo, segmento), `smith-boundary-fg` y `track-bg` (raíl del bar-list y del gauge). Más 17 de geometría de cromo (gap, los pares row/column-gap, swatch, track, bar-segment). **Incumplimiento heredado, corregido**: el CSS leía la coordenada CRUDA `var(--control-height-sm, var(--space-7))` —lo que `recipe-css-contract` prohíbe— con un respaldo muerto. El contrato guarda el bundle `var(--size-sm-control-height)`, 1:1 con él. **Identidad fuera de contrato**: los nueve `100%` («ocupa a tu padre») y el `min-inline-size: max-content` del tooltip, misma clase ya adjudicada en `date-picker`. Por eso el techo es 49 %, y está escrito en el veredicto §5. EL INSTRUMENTO ESTABA CIEGO DE TRES MANERAS, arregladas ANTES de medir: 1. **La superficie de chart vive en DIECISÉIS rutas de demo**, una por tipo: `/chart` monta 58 nodos de los 302 de la página y el resto vive en rutas hermanas. El guard gana `urls`: un token está VIVO si ALGUNA superficie del componente lo sigue, y cada URL sólo re-prueba lo pendiente (el caso de una sola ruta cuesta exactamente lo que costaba). De paso `picker-shell` recibe la suya: su ruta propia es un 404 y se mide dentro del date-picker — pasa de 0/31 con seis sin adjudicar a 6/31 sin tener que saberlo. 2. **El guard no leía NINGUNA propiedad SVG.** Sin `fill` / `stroke` / `strokeWidth` / `fillOpacity` / `r` / `rx`, doce de las 39 claves de un componente que dibuja en SVG leían muertas estando vivas. Misma clase que el hueco de `filter` / `backdrop-filter` de ayer. 3. **El valor centinela se elegía por SUBCADENA**: `slice-stroke-width` recibía `rgb(1, 2, 3)` por contener «stroke» —inválido para una longitud— y leía muerta. La dimensión se decide ahora por el FINAL del nombre. Los 28 componentes con ledger re-verificados tras los tres cambios: cero regresiones, cero STALE. (Ojo: doce a la vez contra el mismo dev server dan falsos exit=1 por timeout; repetir a solas antes de creerse una regresión.) Gates: sonda **0 diffs en 161.850 valores computados** (16 rutas × 7 estados, 892 nodos en reposo) · centinela **37/39**, con `transition-duration` y `-ease` adjudicadas midiéndolas sin la congelación (0,12s → 11,5s · cubic-bezier → steps(4)) · censo --only 49 % · --names 39/39 conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido (`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con 72 errores globales y 0 en los ficheros tocados. Abre (→ next-features §13): el censo **penaliza consumir la capa tipográfica** si no eres un primitivo —las doce declaraciones correctas siguen contando `global`—, que es la nota de `listbox` con una segunda ocurrencia; y el número del gauge no tiene estilo con nombre que lo represente (un readout de dato no es un `h2`), así que sigue leyendo `--font-size-xl`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
5e7462a3ff |
uix(theming): text-scramble no tiene contrato que escribir — y el barrido de fantasmas, hecho
Sin cambios de código: su veredicto §5 y el registro.
Su 50 % no es ni deuda ni logro, es la suma de dos cosas que no son knobs:
- **Los dos literales son la técnica sr-only** (`width`/`height: 1px` en
`[data-text-scramble-sr]`), idéntica a `text-blur` y al resto del catálogo:
existe para que el lector de pantalla lea el texto entero mientras la versión
animada se parte en caracteres. Moverlos rompe la técnica.
- **Los dos «públicos» son tipografía que el componente no debería acuñar**
(`--text-scramble-font` / `-size`, con fallback y sin declarar): es la firma
1.bis pendiente. Escribirles contrato ahora sería acuñar exactamente lo que
esa firma propone retirar. Con esto, 1.bis son **7 claves en 4 de los 5**
componentes de la familia; `text-blur` es el único limpio: hereda.
Y el `font` apunta a un FANTASMA, medido en navegador: `var(--font-mono, …)` no
existe —el canónico es `--font-family-mono`— así que pinta `ui-monospace` e
**ignora la mono del tema** (`Azeret Mono`, que está ahí al lado).
EL BARRIDO MECÁNICO QUE PEDÍAN `--radius-xs` Y `--font-size-4xl`, HECHO:
5.793 custom properties declaradas en todo `src/uix/eidos` (fundación + capas +
recetas + `generated/`) contra los `var(--x, fallback)` de las recetas cuyo `--x`
sea vocabulario de SISTEMA → **9 referencias fantasma**. (Las que van sin
fallback ya las guarda `recipe-css-contract`; el hueco eran justo las que
«funcionan por accidente».) Tabla completa en next-features §13:
- `--color-content-tertiary` ×3 (float-panel, proof-of-human clock y
rotate-align) — **es el caso histórico** que `recipe-contract` §1 cita como
origen de su propia regla, y sigue vivo en tres recetas.
- `--style-{body,prose,label,caption}-font-variation-settings` ×4 (`text.css`) —
los estilos con nombre emiten 6 claves y ésta no está: **el eje de fuente
variable no llega nunca al primitivo `Text`**.
- `--font-family-sans` (palabras, track WIP) y `--font-mono` (text-scramble).
Ninguna se arregla aquí. El barrido debería ser un guard: misma lógica que el
test de fantasmas sin fallback que ya existe, con el filtro de vocabulario de
sistema encima.
Guards: censo `--only` sin cambio (50 %, es el veredicto lo que cambia) ·
component-audit PASS · docs:check 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5b10005ef7 |
docs(theming): apuntar para después — text-effects acuña tipografía propia contra el canon
Pregunta del autor (2026-08-22): «¿qué sentido tiene que text-effects introduzca diferentes nombres de tipografía cuando ya hay un canon establecido?». Ninguno. Queda apuntado como FIRMA PENDIENTE (CONTINUE §5 1.bis · PLAN §8 · next-features §13) para resolverlo después: Cinco claves del contrato acuñan tipografía: `text-focus.word-size` (3rem vía el fantasma `--font-size-4xl`) y `word-weight` (900) · `text-circular.weight` (900) y `font-size` (1.5rem) · `text-gradient.font-weight` (500, subida hoy). Son opiniones del seed react-bits que el protocolo «valor verbatim» convirtió en contrato sin la pregunta previa. La doctrina del propio eje (F2-B regla 2, cinco precedentes) dice que una receta CONSUME la capa tipográfica (`--style-*`) o HEREDA (`link` → `inherit`): un TextGradient dentro de un `h1` ES un h1. Resolución propuesta: retirar las cinco claves y heredar del contexto. Mueve defaults → firma. Con ello muere el fantasma `4xl` sin tocar el módulo de tipografía (canon, prohibido modificar). docs:check 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
652c3411ab |
docs(theming): las demos quedan FUERA del eje — sólo los componentes
Decisión del autor (2026-08-22): «las demos de los componentes no son importantes y no deben formar parte del plan, solo los componentes». Y sobre la escala: «las escalas tipográficas son las que están definidas en el módulo tipografía, esos son los valores canónicos» — prohibido tocar sus valores. Se retira del registro del eje (PLAN §8 · CONTINUE §3.bis · next-features §13) todo lo que hablaba de demos o del harness del sitio: los escenarios de text-gradient/text-blur, la tabla de tokens a mano de la pestaña API, las pestañas Tokens que faltan, las 37 referencias `--uix-font-size-*`. Nada de eso es trabajo del eje: la demo se toca sólo como INSTRUMENTO para que la sonda vea los nodos, y lo mínimo. Queda lo que sí es del componente: `text-focus.word-size` referencia `--font-size-4xl`, un paso que la escala canónica (`xxs..xxxl`, `lib/primitives/typography.ts`) no tiene y que entró como idioma Tailwind con el import de julio. El módulo de tipografía no se toca; el fix va en el consumidor, a un paso o estilo EXISTENTE, y espera firma porque `3rem` cae entre `xxl` y `xxxl` y mueve el default. docs:check 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
97a6f03d76 |
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %** (10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos. Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres literales. Sin eje `size` ni privados propios, así que declarar no puede matar una escala. LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO, no contra el CSS de partida: - **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight` contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya pintaba: `500` ES `var(--font-weight-medium)`. - **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo del marco asomando a cada lado. El knob es `border-width` —con `var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de la escala— y el hueco DERIVA de él. - **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje `scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es `calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110. Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter. Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el 2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro. FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y `--_text-gradient-play-direction` los escribe el wrapper INLINE desde `animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`. INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B aplicada por adelantado, no después): - La demo arranca con `showBorder=false`, así que sonda y centinela veían **2 nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa `DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una vez por talla) y el centinela una entrada `openWith` que no abre un panel sino que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica. - La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el centinela ya leía: un token de fondo podía moverse entre las dos corridas sin que el diff lo viera. Con la propiedad y la variante: **4 nodos**. Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el único efecto de hover es `animation-play-state`, que no es knob. LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene `2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token `text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y `--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit. Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y este renombrado la dejaba obsoleta al instante. Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) · centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7 conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 · docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**. Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene 2.392), no se reformatean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
e7219bb909 |
fix(theming): el slot de tinta es `fg` — R-5.3 me cazó tres claves, y el handoff de mañana
Los guards globales, corridos antes de cerrar la sesión, encontraron una regresión MÍA: `--names` daba **3 desviadas en 2 componentes** y `component:audit` había pasado de 4 a **6 NEEDS-WORK**. La causa: en `text-circular` y `text-focus` nombré tres claves con el slot `color` (`color`, `border-color`, `glow-color`) cuando la gramática firmada el 2026-08-20 dice que **el slot de tinta es `fg` y `color` como slot MUERE**. R-5.3 existe justamente para eso y funcionó — pero después de que yo lo escribiera, porque el guard es de catálogo y yo verificaba `--only`. Renombradas a `fg`, `border-fg` y `glow-fg`, con los destinos que el propio censo indica en su salida `--names`. Value-preserving verificado: **0 diffs** en text-circular (5.916 valores) y en text-focus (1.769), guards 5/6 y 8/8, `--names` **DESVIADAS 0**, audit de vuelta a **162 PASS / 4 NEEDS-WORK** (los cuatro preexistentes y ajenos al eje). La lección para el protocolo, y va al handoff: **la propuesta §4 generada usa el slot `color`**, así que es la cuarta manera en que falla — y como el paso 7 corre los guards con `--only`, la desviación de gramática sólo aparece al correr `--names` GLOBAL. Ese comando ya estaba en el paso 1 del handoff; ahora también se explica por qué no basta con el audit. Y el HANDOFF para mañana: cifras nuevas (56 %, sin contrato 25, al 100 % 16), la lista de los 24 componentes de F2-B con su alcance, las tres cosas que el bloque enseñó y hay que tener delante al seguir (las cuatro maneras en que falla la propuesta · declarar un público «de facto» puede MATAR una escala si detrás hay un privado por talla · cuenta los nodos que ve la sonda antes de creerte un gate verde), y la cola actualizada — con `mockup` marcado como SIN DEMO (404) y `text-scramble` como «0 % estructural, escribe el veredicto, no tokens». Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
9c9c0c8652 |
uix(text-focus): temable — 63 % → 100 %, y un primitivo FANTASMA que pintaba por accidente
8 claves en una entrada NUEVA de `recipes/base.ts`. Censo 63 % → **100 %**. Mismo patrón que text-circular: cinco públicos «de facto» consumidos con fallback y ninguno declarado, más tres que faltaban — los tres en la ESQUINA del marco de foco. **La esquina es una escuadra dibujada con bordes**: 1rem × 1rem con dos de sus cuatro lados a `0` según la posición. El tamaño es un knob, el grosor del trazo otro, el radio el tercero. Los desplazamientos `-0.625rem` NO son knobs: colocan la escuadra fuera del marco y se derivan del tamaño y el trazo. `border-color` y `glow-color` son el mismo acento en dos capas y se declaran aparte a propósito: un tema puede querer el halo de otro tono que el borde. EL HALLAZGO — **`--radius-xs` NO EXISTE** (→ next-features §13): La escala de radios del sistema es `sm | md | lg | xl | xxl` (+ none, full, default), sin `xs`. Esta receta escribía `border-radius: var(--radius-xs, 3px)` y **pintaba el fallback**, así que nadie lo notó nunca. Al tokenizarlo tal cual, la variable quedó vacía, la declaración inválida y las cuatro esquinas CUADRADAS: **48 diffs** — exactamente para lo que existe el gate. El contrato guarda `3px` verbatim, el valor que de verdad pintaba, y el diff vuelve a 0. Lo que abre: **un `var(--fantasma, fallback)` es una referencia muerta que funciona por accidente**, y el guard G2 que el plan menciona («referencias-fantasma contra el contrato derivado») o no existe o no cubre los fallbacks. Barrer el catálogo buscando `var(--…, …)` cuyo primer nombre no esté en el contrato derivado es un pase mecánico que se paga solo. Y un arreglo de instrumento: **`filter` y `backdrop-filter` faltaban en la lista de propiedades del guard**. `glow-color` vive dentro de un `drop-shadow()` y leía «no effect» estando vivo — `KNOB_PROPS` del censo sí las tenía, así que el censo contaba el knob y el guard no podía verlo. Con ellas, text-focus pasa a **8/8 sin una sola excepción**. Verificados los 30 componentes con ledger: cero regresiones, cero STALE. (De paso se retiró una adjudicación que había escrito con una razón equivocada antes de medir: el token sí movía el filter.) Gates: sonda antes/después = 0 diffs en 1.769 valores × 7 estados · censo --only 100 % · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
c5923c8e0a |
uix(text-circular): temable — 83 % → 100 %, declarando lo que ya consumía
6 claves en una entrada NUEVA de `recipes/base.ts`. Censo 83 % → **100 %**. Ya consumía CINCO públicos «de facto» (`var(--text-circular-x, <default>)`) pero **sin declarar ninguno**: un tema no los veía en `getRecipeTokens()` ni el panel de la demo los listaba. Tokenizar ha sido sobre todo DECLARAR lo que ya se consumía, más el `radius` que faltaba. - **Aquí declarar es seguro, al revés que en `knob`**: no hay privado por talla detrás del fallback, así que el público no puede matar una escala. - `color: currentColor` es correcto como token: una custom property no resuelve `currentColor` hasta el punto de uso, así que sigue tomando la tinta del nodo y no la del `:root` — verificado con el diff. - `char-transition` guarda una transición COMPLETA (`all 0.5s cubic-bezier(0, 0, 0, 1)`): el gesto del carácter al girar, verbatim, no cuatro ejes sueltos. EL HALLAZGO (→ next-features §13): **el guard congela las transiciones, y eso esconde los tokens cuyo trabajo ES la transición.** La congelación existe por una razón buena y documentada —una propiedad transicionada devuelve su valor inicial justo tras escribir el token, y un token vivo parecería muerto— pero deja ciego al guard ante `char-transition`. Medido sin congelar: alcanza (0.5s cubic-bezier → 9.5s linear). Si aparecen más tokens de esta clase —transición, animación, easing— merecen un pase propio sin congelación, como el que ya tiene el hover. Gates: sonda antes/después = 0 diffs en 5.916 valores × 7 estados · censo --only 100 % · R-5.4 5/6 con el mudo adjudicado · rtl:check 0 · docs:check 0 · check por fichero limpio · ledger verificado con import real (27 componentes). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
bfaae722b9 |
docs(theming): los cinco hallazgos que sólo vivían en el handoff pasan al registro
Auditoría de continuidad tras la pregunta del autor: ¿está TODO lo encontrado en el backlog? Contrastados los 21 hallazgos de la sesión contra `next-features.md` y el handoff. Resultado: 20 registrados, 1 sin registrar, y —lo importante— **cinco vivían SÓLO en el handoff**, que se reescribe cada sesión, mientras el registro permanente es `next-features.md`. Pasan a §13, con su medición: - **`knob.arc-width` significaba DOS cosas** con dos defaults distintos (la cara del dial y el puntero). El único que no estaba en ningún registro: sólo en el README del componente y en su commit. Queda además como aviso de CLASE — un mismo nombre con defaults distintos por sitio es una colisión aunque el override funcione, y conviene barrer el catálogo buscando más. - **`mockup` no tiene demo** (404), como `picker-shell`: 29 knobs sin sonda ni guard posibles. - **R-5.1 y R-5.2 no existen** (0 disparos): F3 no puede cerrarse sin escribirlas, y entonces harán falta las marcas `R-5.x exception:` que ya se pusieron en los 16 de F2-B. - **Los cuatro NEEDS-WORK del audit son PREEXISTENTES**, para que nadie los atribuya a este eje. - **El worktree con junction no hidrata** (403 de Vite): mordió en la propia revisión adversarial, que comparó contra una base muerta. Sin cambios de código. docs:check 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
5e8b4dba15 |
uix(skin-media-player): temable — 0 % → 22 %, y un techo que es NATURALEZA
10 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → 22 %, y ese techo bajo es lo correcto: **es un componente de TONO FIJO**. Sus cuatro objetos son cosas físicas —caoba, aluminio cepillado, cromo, teclas de marfil, una etiqueta de vino, un eje dorado— y esos tonos son la DEPICCIÓN, no roles de tema: «un tocadiscos no se vuelve azul porque el tema lo haga», dice su cabecera. La pintura vive en el SVG bajo la excepción que `recipe-css-contract.test.ts` ya reconoce para natural-time-picker, color-picker y proof-of-human. Lo que SÍ entra es el TAMAÑO, que la propia receta llamaba «design values: retune here, in one place»: - **El ancho base es POR SKIN**, no un número: un casete no mide lo que un tocadiscos (300 / 340 / 480 px). Mi primera lectura del CSS se quedó corta y escribió un solo `base-width`; el assert del script lo cazó al encontrar dos declaraciones, y la corrección salió de volver a leer el fichero entero. - La escala sigue el eje `size` del REPRODUCTOR (0.7 / 1 / 1.35 / 1.7), que él estampa en su raíz y el skin lee desde ahí — sin prop propia ni segundo vocabulario. - Más la opacidad de la lámpara apagada (0.18: «una bombilla apagada sigue enseñando su vidrio») y el radio del área de pulsación de las teclas. Fuera a propósito: el `aspect-ratio` de cada skin (proporción del objeto dibujado — cambiarla lo deforma), el `drop-shadow` del casete (su marrón es madera) y los cuatro `100%` de layout. EL HALLAZGO DE INSTRUMENTO (→ next-features §13): **un valor centinela GRANDE no prueba nada contra una propiedad capada**. El ancho es `min(100%, base × scale)`, así que el `1234px` del guard se capa al contenedor y los siete tokens de tamaño leen «no effect» aunque estén vivos. Con valores PEQUEÑOS (111/122/133 px y escalas 0.11/0.22/0.33) alcanzan EXACTAMENTE (133 × 0.11 = 14.625px). Es primo del caso ya registrado «un valor centinela igual al real lee como no efecto»: el centinela tiene que ser imposible **en la dirección en que la propiedad puede moverse**, y un guard que probara los dos extremos cazaría ambas familias. Y un error de proceso repetido, ya corregido: el fichero de excepciones volvió a romperse por comillas simples dentro de cadenas de comillas simples (`data-skin='record'`). Reescrito con comillas dobles, verificado con un import real (26 componentes en el ledger) y **re-corridos los 26 comprobando el código de salida REAL**: cero fallos. Gates: sonda antes/después = 0 diffs en 1.769 valores × 7 estados · censo --only 22 % · suite eidos 439/440 (el rojo conocido de este mismo componente, que no tiene morfo — preexistente y ajeno a este commit) · rtl:check 0 · docs:check 0 · check por fichero limpio. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
ab64efee77 |
uix(knob): temable — 29 % → 75 %, y un nombre que significaba dos cosas
33 claves en una entrada NUEVA de `recipes/base.ts`. Censo 29 % → 75 %. El knob ya tenía siete públicos «de facto» —consumidos como `var(--knob-x, <default>)`— pero **ninguno declarado**, así que un tema no los veía en `getRecipeTokens()`. Tokenizar ha sido sobre todo DECLARAR lo que ya se consumía, y separar dos cosas que compartían nombre. 1. **Cuatro `--knob-*` quedan FUERA a propósito**: `progress`, `angle`, `start-angle` y `sweep` los escribe el provider INLINE desde el estado del control (`knob-provider.svelte.ts:358`). Canal de valor, no superficie de tema \u2014 ningún contrato gana a un estilo inline. Misma clase que `carousel.item-gap` y que la `z` del preview de drag-drop que retiró la revisión adversarial. 2. **⚠ `--knob-arc-width` significaba DOS cosas con DOS defaults distintos**: el inset de la cara del dial (`--space-3`, líneas 80 y 113) y la separación superior del puntero (`--space-2`, línea 165). Un tema que lo escribiera movía las tres declaraciones a la vez, pero **sin tema cada una valía algo distinto** \u2014 «un nombre que no distingue lo que debería», que es la definición de colisión que usa el propio generador. Separado en `arc-width` (la cara) y `pointer-inset` (el puntero), cada uno con su valor verbatim: cambia la superficie de tema, **no el píxel**. 3. **Las coordenadas por talla SUBEN al TSC, y no era opcional.** El default por talla vivía en un privado y el público era un override que iba DELANTE (`var(--knob-gap, var(--_knob-gap))`): declarar `--knob-gap` en el contrato **habría matado la escala**, porque ganaría siempre. Con el patrón del resto del eje (coordenadas + resuelto por `data-size`) el default sigue vivo y el tema alcanza. Eje sm|md|lg|xl, sin xs; el diámetro es `control-height × 2` en cada talla, proporción del bundle conservada verbatim. `--_knob-value-digits` sigue privado: es el número de dígitos del valor máximo, dato del consumidor. Artefactos y gates: - Sonda antes/después = 0 diffs en 754 valores × 7 estados. Determinismo verificado. - R-5.4: 25/33; los ocho mudos adjudicados con su medición (la demo no monta etiqueta \u2014 0 nodos contados \u2014 ni estado de arrastre; forzados, los ocho mueven). - censo --only 75 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos 439/440 (el rojo conocido) · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con «Talla y tema» y tab `Tokens` en la demo (33 claves). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
3a47c1a53d |
test(theming): el suelo del alcance, con sus dos muta-pruebas — cierra F0.d
`src/uix/eidos/theming-reach-floor.test.ts`. El plan lo encargaba en F0 («un test que fije el suelo: el número SUBE o el test falla») y nunca se escribió, así que hasta hoy **nada impedía que el alcance BAJARA entre sesiones**: una receta podía cambiar un token público por un primitivo y sólo se vería leyendo el censo a mano. Cuatro trinquetes, medidos el 2026-08-22 tras el endurecimiento del censo: alcance global ≥ **56 %** · literales ≤ **564** · knobs sobre global crudo ≤ **1.156** · componentes al 100 % ≥ **14**. Cuando el eje avanza, se suben en el mismo commit que se lo gana. **LAS DOS MUTA-PRUEBAS** (memoria `a-guard-that-inspects-nothing-passes`: un guard sólo vale cuando lo has VISTO rojo). No se dan por supuestas — se ejecutaron: 1. Inyectar UN literal (`border-radius: 7px` en `mark`) → rojo en `maxLiteral` y en la sonda del clasificador. Revertido, verde, árbol idéntico. 2. Cambiar CINCO públicos de `tree-view` por primitivos crudos (92 % → 73 % en ese componente) → rojo en `maxGlobal`. Revertido, vuelve a 92 %. Y de ahí sale una observación que queda escrita en el propio test: **los techos son el detector FINO y el porcentaje el grueso.** Cinco knobs de ~4.700 no mueven un porcentaje redondeado, pero sí un techo — una regresión demasiado pequeña para esconderse de `reachPct` sigue disparando `maxGlobal`. Lo que el test NO asegura, a propósito: el alcance POR COMPONENTE, que ya gobiernan el censo `--only` y las excepciones R-5.x — un número bajo puede ser doctrina bien aplicada (`menu-dial` paga por consumir bien una capa compartida, `link` por heredar la tipografía ambiente). Y `system`, que es temable a nivel de sistema por diseño y queda fuera del ratio. Gates: los 5 tests en verde · suite eidos 439/440 (el único rojo sigue siendo el conocido `skin-media-player`) · prettier sobre el fichero nuevo · docs:check 0 · check limpio. `PLAN §5 F0.d` y la entrada de §13 quedan cerradas. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
a9acf8d0c4 |
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 |
|
|
a0fc8f4f1e |
uix(theming): revisión adversarial de F2-B — 4 hipótesis, 3 refutadas, 1 token que mentía
El plan (§7.7) exige una revisión escéptica antes de cerrar un bloque, y F2-B
no la tenía. Molde F2-A: worktree en la base del bloque (`8400e5bdd`) con su
propio dev server, medición independiente.
**REFUTADA \u2014 «el default cambió en algún sitio que la demo no mira».** 77 casos
FORZADOS (variantes, formas, tallas y estados que las demos NO montan, en los
21 componentes) comparados base vs HEAD: **0 diferencias**. Era la sospecha más
fuerte, porque cuatro componentes miden UN nodo (`link`, `code`, `skeleton`,
`link-preview`) y sus tokens viven justo en las variantes que la demo no
renderiza.
**REFUTADA \u2014 «hay tokens huérfanos».** 339 públicos de los 21 bloques, 0 sin
consumo. El primer extractor daba «SIN BLOQUE» en los 21 \u2014 el mismo antipatrón
que audita este eje \u2014 y se rehízo contando llaves; muta-prueba: un token falso
inyectado sale detectado y el árbol se restaura.
**REFUTADA \u2014 «el gate de 0 diffs pasó sobre casi nada».** Contados los nodos que
ve cada sonda; los cuatro de un nodo se cubrieron forzando sus variantes arriba.
**HALLAZGO REAL \u2014 `drag-drop.preview-z` mentía, y lo escondía una adjudicación
mía sobre un nodo SINTÉTICO.** El ledger lo daba por vivo («forzado → alcanza,
100 → 4321»), pero ese nodo lo había creado yo con JS. El preview REAL que soma
monta durante un arrastre lleva `z-index: 9999` **INLINE**
(`drag-drop-provider.svelte.ts:663,671`): el token resuelve a 4321 y el nodo
computa 9999. Ninguna cascada puede ganarle. **Retirado con 0 diffs** contra el
snapshot original (1.827 valores × 7 estados), misma clase que el `item-gap*`
de carousel que retiró la revisión de F2-A. Era el único público que drag-drop
tenía antes del eje; su alcance se mantiene en 89 %.
**La lección que generaliza, y va al protocolo**: una adjudicación «forzado →
alcanza» vale lo que valga el nodo que se forzó \u2014 si lo creaste tú, no lleva lo
que soma le pone. Re-verificado el resto de la misma clase contra nodos reales:
`clipboard` (indicador tras un clic real) y `picker-shell` (pie real) coinciden
con lo adjudicado y no llevan inline; el inline de `skeleton-line` es de
`inline-size`, no del eje tokenizado.
DOS HALLAZGOS DE INSTRUMENTO en la propia revisión (→ §13):
- **El orden de carga NO es el mismo en dev que en producción.** Medido con
`npm run build` + preview y CDP: en dev la receta de `link-preview` va ANTES
del plano `overlay`; en producción queda EN MEDIO de sus dos reglas. El
ganador coincide por casualidad. La fragilidad de §12.9 queda medida en los
dos entornos, y confirma que restaurar el par fue lo correcto.
- **Un worktree cuyo `node_modules` es una junction fuera del root NO HIDRATA**:
Vite responde 403 a `@fs/…` y SvelteKit no arranca, así que la página SSR se
ve pero ningún componente monta. La primera pasada de esta revisión comparó
contra una base MUERTA y devolvió «77 casos, 1 diferencia» sin que nada lo
delatara. Se arregla con `server: { fs: { allow: [...] } }`; queda escrito en
el handoff junto a la regla: **comprueba que un componente monta antes de
comparar**.
Gates: censo global 50 % · `--names` DESVIADAS 0 · drag-drop 89 % ·
component:audit PASS · eidos-lint 0 invalid · R-5.4 verde · suite eidos sin
rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio.
Worktree eliminado quitando la junction ANTES del `remove --force`, con el
`node_modules` real verificado intacto (memoria
`git-worktree-remove-recurses-into-junctions`).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
43b3e8a501 |
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca código y es la que importa. 1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré como «declaraciones muertas» apoyándome en los precedentes de `table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es neutral — **fija el empate a favor del plano** y con él su 1.25 donde la receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9 tiene pendiente para VEINTE componentes. Un empate por orden de carga se registra, no se resuelve dentro de un commit de tokenización. Y la medición era más débil de lo que el commit daba a entender: estable en cinco recargas **en DEV**, sin verificar en un bundle de producción. Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5 tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa razón. §12.9 y el README dicen ahora que el par se deja declarado A PROPÓSITO. 2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al 100 % o excepción escrita», y la válvula que `component-audit` lee es esa marca (`readmeException`), no la prosa. Tenía la razón documentada en veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2, los 16 habrían dado error. Una marca por clase medida — forward de paleta THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan. 3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el protocolo lo pide por componente: una sesión nueva habría arrancado con el mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8 firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus seis lecciones, y actualizada la memoria del eje. 4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el bloque, cada una nombrando la forma en que el instrumento mentía, más la lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso — `picker-shell` medía CERO y reportaba éxito. 5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`, `virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md (md→sm); los valores eran correctos (0 diffs), el texto no. Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la medición de quien los escribió, y el plan la exige antes de cerrar un bloque. El handoff nombra las dos hipótesis concretas que hay que atacar. Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves · `component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno con un commit de esta sesión en su código) · R-5.4 verde en los 22 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
ed2e3cd7ca |
uix(theming): cinco 0 % que NO son deuda — veredictos, no tokens inventados
`aspect-ratio`, `text-blur`, `cascade`, `motion` y `date-picker` figuran en el censo con alcance 0 % y sin entrada de contrato. Medidos uno a uno: **ninguno tiene contrato que escribir**. Este commit escribe sus cinco veredictos §5 en vez de fabricarles tokens. - **`aspect-ratio`** no es un componente con cromo: es una FACETA de `Box` (`[data-box][data-aspect-ratio]`). Su único knob global está **prestado de `box`** — la propia ficha lo marca ⤴ — y un token prestado trae la semántica de su dueño: acuñar `--aspect-ratio-width` sería un segundo nombre para el mismo eje. `--aspect-ratio` es canal de valor por instancia (16/9, 1…), no tema; los `100%` y el `object-fit` del hijo son identidad de layout. - **`text-blur`**: sus dos knobs son el `1px` de la técnica sr-only, la receta de accesibilidad que permite al lector de pantalla leer el texto entero mientras la versión animada se parte en segmentos. Moverlos rompe la técnica. - **`cascade`** y **`motion`**: su knob es el `opacity` del gate antiparpadeo (`[data-reveal-pending]` / `[data-animation-pending]`), mecánica del canal de motion. Un tema no puede querer que ese `0` sea otra cosa sin romper el propósito del gate; lo tematizable de motion (duraciones, easings, presets, escalonado) vive en `EidosConfig.motion`. - **`date-picker`**: su propia cabecera lo dice — «This recipe must NOT re-declare any of those… it owns ONLY the popover / calendar layout». Es un DateField compuesto cuyo cromo entero viene de `field.css` / `date-field.css`. Sus dos knobs son la corrección `max-content` que impide que el pie del popover (Clear / Cancel / Save) desborde: un único valor correcto, no una preferencia. REGISTRADO EN next-features §13: **el censo no distingue «0 % por deuda» de «0 % por naturaleza»**, y ya son cinco. Mientras los cuente igual que a un componente con deuda real, la cifra global miente por abajo y el gate de F3 («censo 100 %») es inalcanzable por construcción. Hace falta una clase más —`structural`, junto a `system`— o una marca en la ficha que los saque del denominador, como `LAYER_VOCABULARY` hizo con la familia calendar. Es la misma pregunta ya abierta para las capas compartidas, un piso más abajo. Sin cambios de código: cinco fichas y el registro. `docs:check` 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
471ba96d25 |
uix(menu-dial): temable — 0 % → 25 %, y las ranuras de la capa que NO se acuñan
3 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → 25 %. **La receta posee sólo el cromo del dial**, como dice su propia cabecera: las acciones son `Button` compuestos y la colocación flotante es de la capa `viewport-placement`. Lo suyo son tres cosas: el hueco del abanico, el paso del escalonado de entrada y el tinte del velo. **`--_viewport-placement-offset` y `-z` NO se acuñan, y ésa es la decisión del commit.** Son las RANURAS DE OVERRIDE que la capa compartida publica, y esta receta escribe en ellas su decisión — 20px en vez de los 16px por defecto de la capa, y el comentario del CSS deja claro que es decisión y no deriva. Acuñar `menu-dial-placement-offset` sería el vocabulario paralelo que la regla 2 de capas compartidas prohíbe: el eje es de la capa, y un tema lo mueve ahí. Es el mismo techo que `listbox` paga por consumir bien `list-surface` — el grueso del 75 % que no alcanza, y es correcto que no lo haga (§13). **El escalonado es tema, no motion**: `stagger-step` no es una duración de animación sino el INTERVALO entre hermanos (multiplica el índice de cada acción), y es lo que da carácter al abanico. Por eso entra al contrato. Artefactos y gates: - Sonda antes/después = 0 diffs en 1.856 valores × 8 estados. - R-5.4: 1/3, los dos mudos adjudicados con su medición — el velo sólo existe con el dial abierto (0 nodos en reposo, contados) y el escalonado sólo se aplica bajo `[data-stagger]` con la lista abierta; forzando ambos atributos con índice 3, alcanza (0.084s → 2.331s = 3 × 777ms). - censo --only 25 % · component:audit PASS · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con «Talla y tema» y tab `Tokens` en la demo (3 claves). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
9f24a31eb9 |
uix(mark): temable — 0 % → 60 %, y 3/3 en el guard
3 claves fusionadas en el bloque `mark` de `recipes/base.ts` (donde ya vivían los dos forwards de paleta). Censo 0 % → 60 %, cero globales y cero literales. **No tiene ni un knob de tipo, y es deliberado**: un resaltado hereda la tipografía ambiente del párrafo en que vive (`font: inherit`, `color: inherit`). Lo que posee es la decoración — el padding en sus dos ejes y el radio. **El padding es em-relativo y deliberadamente diminuto** (0.16em / 0.04em): el tinte tiene que leerse SIN romper el interlineado del párrafo que lo contiene, y eso es exactamente lo que esos dos números protegen. Queda escrito en el README para que quien los mueva sepa que está tocando el ritmo vertical del texto, no sólo el grosor del resaltado. Los dos forwards de paleta siguen privados (THM-2): el fondo tiñe con el rol y la tinta sólo cuando hay `data-color`, porque el defecto es `inherit`. Son el 40 % que no alcanza. Artefactos y gates: - Sonda antes/después = 0 diffs en 174 valores × 7 estados. - R-5.4: **3/3**, sin una sola entrada en el ledger. - censo --only 60 % · component:audit PASS · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con «Talla y tema» y tab `Tokens` en la demo (3 claves). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
1f692629e5 |
uix(scroll-frames): temable — 0 % → 33 %, porque es LAYOUT y no cromo
4 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → 33 %. **Es layout, no cromo** — la receta lo dice de entrada y la medición lo confirma: una pista alta cuyo viewport pegajoso fija el medio a sangre mientras la pista rueda. Lo único que pinta es el rótulo de carga, y ése es el contrato entero: su separación del borde inferior, el tipo, el tracking y la tinta. **`--_scroll-frames-viewport-block-size` se queda privado**: es la escotilla que el consumidor sobrescribe para encajar el viewport en un contenedor (`100%`) en vez de en la ventana (`100vh`), y su fallback es geometría de LAYOUT, no un valor de tema — quien lo mueve es el sitio de uso, no el tema. Con los `100%` del medio y de la pista (identidad, D-TH.2), el `line-height: 1` del rótulo y el `opacity` del sistema, forman el 67 % que no alcanza, y es correcto que no lo haga. Artefactos y gates: - Sonda antes/después = 0 diffs en 580 valores × 7 estados. - R-5.4: 0/4, los cuatro adjudicados con su medición — el rótulo sólo existe mientras se decodifican los fotogramas (0 nodos una vez cargado, contados) y forzándolo los cuatro mueven (24→1234px, 12→99px, 1.2→9px, rgb(1,2,3)). - censo --only 33 % · component:audit PASS · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con «Talla y tema» y tab `Tokens` en la demo (4 claves). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
151e5159b8 |
uix(clipboard): temable — 0 % → 63 %, todo en la píldora de «Copied!»
6 claves fusionadas en el bloque `clipboard` de `recipes/base.ts` (donde ya vivían los dos forwards de paleta). Censo 0 % → 63 %. **Todo lo tokenizable es el INDICADOR.** El host va `display: contents` y el trigger reusa la receta de `Button` por el patrón de consumidor, así que la receta sólo posee la píldora que aparece un instante tras copiar. - Los dos forwards de paleta siguen privados (THM-2): el fondo y la tinta del chip los leen a pelo, sin sitio donde meter un público sin duplicar la regla — son el 37 % que no alcanza. - `font-family` queda fuera por la misma razón que en code-block, kbd y announce: lo posee la capa tipográfica. - El padding es un shorthand de dos valores → dos knobs lógicos. - **Los `--motion-*` no son knobs de tema**: son los ganchos con que el indicador afina el preset `scale-fade` del canal de motion (escala 0.85, rápida). Pertenecen al canal, no al contrato, y la política de `prefers-reduced-motion` la emite el generador. Artefactos y gates: - Sonda antes/después = 0 diffs en 1.392 valores × 8 estados. - R-5.4: 0/6, los seis adjudicados con su medición — el indicador sólo existe un instante tras copiar (0 nodos en reposo, contados) y forzándolo los seis mueven su propiedad (gap 4→1234px, padding 2/8→1235/1236px, radio 9999→1237px, tipo 12→99px, peso 500→123). - censo --only 63 % · component:audit PASS · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con «Talla y tema» y tab `Tokens` en la demo (6 claves). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
d568577eb7 |
uix(announce): temable — 0 % → 88 %, y 9/9 en el guard
9 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → 88 %, cero
privados y cero literales.
**Es un SERVICIO de región viva ARIA, no un visual**: su host va
`display: contents` y la región está oculta por defecto. Todo el cromo del
contrato pertenece al caso minoritario en que el consumidor pide
`visuallyHidden={false}` y la región pasa a ser también un banner en pantalla —
padding en sus dos ejes, radio, el par anchura/color de borde, fondo, tinta,
tipo e interlineado.
- **`font-family` queda fuera a propósito**: lee `--style-label-font-family`,
la capa tipográfica, y un consumidor no re-declara el vocabulario de su capa
(mismo criterio que en code-block y kbd). Es el 12 % que no alcanza.
- **La regla oculta no se toca**: soma escribe el `style` en línea del sr-only
cuando `visuallyHidden` está activo, y la receta lo dice explícitamente. No
hay nada que tematizar ahí, y meterse sería competir con soma por el mismo
nodo.
Artefactos y gates:
- Sonda antes/después = 0 diffs en 377 valores × 7 estados.
- R-5.4: **9/9**, sin una sola entrada en el ledger.
- censo --only 88 % · component:audit PASS · suite eidos sin rojos nuevos ·
rtl:check 0 · docs:check 0 · check por fichero limpio.
- README con «Talla y tema» y tab `Tokens` en la demo (9 claves).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
7565eff47b |
uix(label): temable — 0 % → 100 % con dos claves
2 claves fusionadas en el bloque `label` de `recipes/base.ts` (donde ya vivía
el forward de paleta). Censo 0 % → **100 %**.
**Seis de sus ocho knobs son SISTEMA y no se acuñan.** `label` es uno de los
seis primitivos tipográficos: sus seis ejes consumen `--style-label-*` a través
de la escotilla por instancia (`var(--_label-{eje}, var(--style-label-{eje}))`),
la forma que D-TH.2-b fijó y la que hace que un `<Label>` y un
`<Text style="label">` se lean idénticos. La capa los posee; re-declararlos
sería el vocabulario paralelo que la regla 2 prohíbe.
Quedan DOS knobs propios, los que el primitivo añade por su cuenta: el `gap` al
icono o indicador que puede acompañar al texto, y `disabled-fg`, la tinta
cuando el consumidor marca la etiqueta como deshabilitada junto a su control.
`--_label-color` sigue privado: conmutador de dos fuentes (eje de tinta en
línea / forward de paleta cuando llega `data-color`), el mismo patrón ya
resuelto igual en `code`, `textarea`, `spinner` y `skeleton`.
Artefactos y gates:
- Sonda antes/después = 0 diffs en 174 valores × 7 estados.
- R-5.4: 1/2. `disabled-fg` adjudicado: la demo no monta ninguna etiqueta
deshabilitada (0 nodos, contados); forzada, alcanza (rgb(1,2,3)).
- censo --only 100 % · component:audit PASS · suite eidos sin rojos nuevos ·
rtl:check 0 · docs:check 0 · check por fichero limpio.
- README con «Talla y tema» y tab `Tokens` en la demo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
a6d4d4f5a3 |
uix(skeleton): temable — 0 % → 45 %, y dos privados que son conmutadores
9 claves fusionadas en el bloque `skeleton` de `recipes/base.ts` (donde ya vivía el forward de paleta). Censo 0 % → 45 %, cero globales. Nueve de sus once knobs pasaban por privado, y la lectura correcta es que **dos de esos privados NO son deuda: son conmutadores**. `--_skeleton-bg` y `--_skeleton-highlight` tienen DOS fuentes cada uno según haya `data-color` — la mezcla neutra cross-mode (un `color-mix` hacia `neutral-solid`, para que el placeholder siga siendo un gris visible en los dos modos: el `neutral-track` desnudo desaparece sobre una superficie clara) o el forward de paleta. Aplanarlos exigiría duplicar cada regla por color, así que se quedan — mismo criterio que el borde de foco de textarea y la tinta de spinner. Son el grueso del 55 % que no alcanza, y es honesto. - **Una coordenada por talla** (`size`) gobierna el alto del bloque, el diámetro del círculo (vía `aspect-ratio`) y el hueco entre líneas de la forma `text`. Ese hueco es `calc(size * 0.5)`: una PROPORCIÓN, construcción, no un knob. - **El radio es por FORMA, no por talla**: `radius-md` en `rect` y `50%` en `circle`, donde el `50%` es identidad (un círculo es redondo) — el knob es sólo el del rectángulo. La línea de la forma `text` lleva el suyo. - `duration` entra al contrato en vez de seguir en `1.4s` a pelo, igual que se hizo con el spinner (§13). Artefactos y gates: - Sonda antes/después = 0 diffs en 203 valores × 7 estados. - R-5.4: 8/9. `line-radius` adjudicado: sólo la forma `text` renderiza `[data-skeleton-line]` y la demo monta `rect` (0 líneas, contadas); forzada la forma, alcanza (4 → 1234px). - censo --only 45 % · component:audit PASS · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con «Talla y tema» y tab `Tokens` en la demo (9 claves). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
e3f39ce282 |
uix(virtual-grid): temable — 0 % → 73 %, gemelo exacto de virtual-list
12 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → 73 %, cero globales y cero privados. Es el **gemelo exacto de `virtual-list`**: mismo chasis, mismos valores, misma escala. Se tokeniza igual, y en su propio commit — un componente, un commit. **La talla mueve SÓLO el tipo del cromo**: las dimensiones de cada celda salen de las props (`rowSize` / `columnSize`), no de esta escala, así que hay UNA coordenada por talla y el `radius` está DESACOPLADO a propósito (modelo Radix, constante en las cinco). La escala tipográfica va un paso por debajo desde lg (xs→xs, sm→sm, md→sm, lg→md, xl→lg) y lee al bundle. El resuelto declara `parts: ['root']` porque el `data-size` se estampa en `[data-virtual-grid-root]`, un wrapper de eidos. Surface y outline comparten anchura y color de borde → un par de knobs. El `transparent` de ghost y los `100%` del viewport son identidad de variante y de layout: el 27 % que no alcanza, y es correcto que no lo haga. Artefactos y gates: - Sonda antes/después = **0 diffs en 20.010 valores** × 7 estados (111 nodos: la demo renderiza la ventana entera de celdas). - R-5.4: **12/12**, sin una sola entrada en el ledger. - censo --only 73 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con «Talla y tema» y tab `Tokens`; como en su gemelo, la demo no ataba referencia al stage y se ata una para que el panel lea los computados vivos. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
070145786f |
uix(virtual-list): temable — 0 % → 67 %, y 12/12 en el guard
12 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → 67 %, cero
globales y cero privados.
**La talla mueve SÓLO el tipo del cromo**, y eso acota el contrato antes de
nombrar nada: las dimensiones de cada item salen de las props
(`itemSize` / `estimateSize`), no de esta escala — lo dice el propio comentario
de la receta. Así que hay UNA coordenada por talla, `font-size`, y el `radius`
está DESACOPLADO a propósito (modelo Radix: constante en las cinco). Acuñar
`radius-{k}` habría sido vocabulario muerto.
La escala tipográfica va un paso por debajo desde lg (xs→xs, sm→sm, md→sm,
lg→md, xl→lg) — el patrón de `table`, `tree-grid` y `tree-view` — y lee al
bundle, no al primitivo crudo. El resuelto declara `parts: ['root']`: el
`data-size` se estampa en `[data-virtual-list-root]`, un wrapper de eidos.
Surface y outline comparten anchura y color de borde → un par de knobs. El
`transparent` de ghost y los `100%` del viewport son identidad de variante y de
layout (D-TH.2): son el 33 % que no alcanza, y es correcto que no lo haga.
Artefactos y gates:
- Sonda antes/después = 0 diffs en 3.451 valores × 7 estados.
- R-5.4: **12/12**, sin una sola entrada en el ledger.
- censo --only 67 % · component:audit PASS · eidos-lint invalid 0, class-hooks
0 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por
fichero limpio.
- README con «Talla y tema» y tab `Tokens` en la demo. La demo no ataba
ninguna referencia al stage, así que se ata una: sin ella el panel no puede
leer los computados en vivo (lo cazó `npm run check`, no una suposición).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
e4bcd505d1 |
uix(code): temable — 0 % → 100 %, y el harness que también le pisa el radio
6 claves fusionadas en el bloque `code` de `recipes/base.ts` (donde ya vivía el
forward de paleta). Censo 0 % → **100 %**: no queda un knob de apariencia fuera
del contrato.
**Seis de sus trece knobs son SISTEMA y no se acuñan.** `code` es el primitivo
tipográfico canónico: sus seis ejes de tipo consumen `--style-code-*` con la
escotilla por instancia (`var(--_code-{eje}, var(--style-code-{eje}))`), la
forma que D-TH.2-b fijó, y un primitivo no re-declara el vocabulario de su
capa. Lo que entra al contrato es el CROMO de las variantes `soft` y `outline`.
- El padding es em-relativo a propósito (la píldora crece con el código que
envuelve) y lo declaran IGUAL las dos variantes con cromo: un knob por eje,
no cuatro.
- `--_code-color` sigue privado: conmutador de dos fuentes (tinta de contenido
en línea / forward de paleta cuando llega `data-color`), mismo patrón que el
borde de foco de textarea.
- El `margin: 0` / `padding: 0` / `background: transparent` / `border: 0` de la
base es RESET: la variante `plain` es texto desnudo por identidad.
EL HALLAZGO — el harness pisa también a `code` (→ next-features §13, ampliado):
Medido con CDP: `[data-uix-docs] code` declara `font-family`, `font-size`,
`padding` y `border-radius` y gana **(0,1,1)** contra la regla BASE de la receta
**(0,1,0)**. En la página de documentación el radio del componente es el del
sitio (3px), no el suyo (4px). Sus reglas de VARIANTE (0,2,0) sí ganan, así que
el efecto es selectivo y por eso sólo `radius` lee muerto. **No es un caso
aislado**: es la misma familia de reglas del harness que tapa el `<pre>` de
code-block con siete propiedades. Cualquier decisión sobre esa regla cubre los
dos componentes.
Artefactos y gates:
- Sonda antes/después = 0 diffs en 174 valores × 7 estados. Determinismo
verificado.
- R-5.4: 0/6, los seis adjudicados con su medición — `radius` por el harness
(CDP), los otros cinco porque la demo monta sólo la variante `plain`, sin
cromo; forzando las variantes, los cinco alcanzan.
- censo --only 100 % · component:audit PASS · rtl:check 0 · docs:check 0 ·
check por fichero limpio · suite eidos sin rojos nuevos.
- README con «Talla y tema» y tab `Tokens` en la demo (6 claves).
Nota de proceso: el fichero de excepciones llegó a quedar con sintaxis TS
inválida por un apóstrofe sin escapar, y la comprobación que hice lo dio por
bueno porque el `$?` capturado era el del `grep` de la tubería, no el del
guard. Corregido, y re-verificados los ONCE componentes con ledger comprobando
el código de salida REAL: cero fallos.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
d3089e880c |
uix(link): temable — 0 % → 36 %, y ese techo bajo es la respuesta correcta
5 claves fusionadas en el bloque `link` de `recipes/base.ts` (donde ya vivían los dos forwards de paleta). Censo 0 % → 36 %. **Un enlace en línea hereda casi todo del texto que lo rodea**, así que su superficie de tema es pequeña por diseño. Sus dos escotillas por instancia (`--_link-font-size`, `--_link-line-height`) tienen como fallback `inherit`, y ese `inherit` es SEMÁNTICO: el enlace toma la tipografía del párrafo en el que vive. Convertirlo en token exigiría un público con valor `inherit`, que en `:root` no significa lo mismo — se quedan privadas. Con los dos forwards de paleta, ésos son los cuatro privados que forman el grueso del 64 % restante. Lo tokenizable es la GEOMETRÍA: radio del anillo, hueco del glifo externo, tamaño del glifo (`0.85em` en las dos dimensiones → UN knob) y el grosor y desplazamiento del subrayado, cada uno declarado en las DOS reglas que lo dibujan (`always` y `hover`) con el mismo valor. Las tres opacidades son sistema; el `fill: currentColor` del glifo es identidad, sigue a la tinta del enlace a propósito. **La cascada no se toca.** El CSS lleva dos correcciones de especificidad ya medidas y explicadas en su sitio (el `inherit` condicional, para que un `color` pedido por el consumidor no se descarte en silencio; y el `:active` al final, porque una pulsación es siempre también un hover). El diff de computed confirma que tokenizar no las altera. Artefactos y gates: - Sonda antes/después = 0 diffs en 203 valores × 7 estados. Determinismo verificado. - R-5.4: 2/5, los tres mudos adjudicados con su medición. Ninguno es deuda: el glifo externo no se monta en la demo (0 nodos, contados) y el enlace arranca en `data-underline='hover'` sin puntero encima, así que NO HAY subrayado que mover (`text-decoration-line: none`, `thickness: auto`). Forzando el estado, los tres alcanzan. - En el mismo pase, `text-decoration-thickness` y `text-underline-offset` entran en la lista de propiedades del guard, que no las miraba — verificado que los otros DIECISÉIS componentes con ledger no cambian. - censo --only 36 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio · README con «Talla y tema» y tab `Tokens` (5 claves). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
adb77863cd |
uix(kbd): temable — 0 % → 86 %, y 13/13 en el guard sin una sola excepción
13 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → 86 %. 1. **`font-family` NO se acuña**: lee `var(--style-code-font-family)`, la capa tipográfica, y un consumidor no re-declara el vocabulario de su capa — precedente inmediato, `code-block`. El `font-size` SÍ entra, y la diferencia está medida: su fallback era un PRIMITIVO, no la capa. `--_kbd-font-size` es la escotilla por instancia que el wrapper escribe desde la prop `size` (`kbd.svelte:37`), y el fallback pasa a ser el público. 2. **El padding y el min-width son em-relativos a propósito** — una tecla crece con su letra —, así que son knobs con valor `em`, no literales pendientes de corregir. El `line-height: 1` sí es identidad: una tecla no tiene interlineado. 3. **El relieve de tecla física es de la variante `surface`**: borde inferior más grueso + luz interior. Dos knobs propios, no adorno del borde general; outline y ghost son planas por identidad. Artefactos y gates: - Sonda antes/después = 0 diffs en 522 valores × 7 estados. Determinismo verificado. - R-5.4: **13/13**, sin una sola entrada en el ledger — el primero de la tanda que no necesita adjudicar nada. - censo --only 86 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con su «Talla y tema» y tab `Tokens` en la demo (13 claves, en vivo). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
650d76aa0e |
uix(drag-drop): temable — 0 % → 89 %, casi todo en el fantasma del arrastre
10 claves en el bloque `drag-drop` de `recipes/base.ts` (fusionadas con `preview-z`, que ya estaba, y los dos forwards de paleta). Censo 0 % → 89 %, cero globales. **Siete de sus dieciséis knobs YA eran sistema** y no entran al ratio (las opacidades de fantasma y deshabilitado, los dos anillos de foco y el anillo `inset` de los droppables), así que los puntuables eran nueve — seis de ellos en el PREVIEW, el fantasma que sigue al puntero. 1. Los dos forwards de paleta siguen privados (THM-2): el fondo del `[data-dragover]` los lee a pelo y no admite un público sin duplicar la regla — es el 11 % que falta. En cambio el `border` y el `box-shadow` del preview los COMBINAN con una anchura y una sombra que sí son knobs propios, así que esas dos declaraciones entran al alcance. 2. El `--ring-inset-*` de los droppables no se toca: es vocabulario del anillo del SISTEMA y la receta se limita a alimentarlo con su acento. Acuñar un `droppable-ring-*` sería vocabulario paralelo sobre un transversal. 3. El `padding` del preview es un shorthand de dos valores → dos knobs lógicos. Artefactos y gates: - Sonda antes/después = 0 diffs en 1.827 valores × 7 estados. Determinismo verificado. - R-5.4: 0/10 en vivo, y los DIEZ adjudicados con su medición. No es un instrumento roto ni tokens muertos: el preview se crea sólo mientras hay un arrastre en curso (0 nodos en reposo, contados), y forzando el nodo los diez mueven su propiedad — padding 8→1234px, radio 6→1236px, borde 1→9px, fondo, tinta, familia, tamaño 14→99px, sombra y z 100→4321. - censo --only 89 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos (el conocido skin-media-player) · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con su «Talla y tema» y tab `Tokens` en la demo (10 claves, en vivo). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |