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 }
195 Commits (b7f5a7d75a5491b9447cea7077417399589e74cc)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
0c06d42aac |
uix(file-upload): temable — 76 % → 83 %, y una clave suya NO PINTABA en ninguno de sus tres botones
Una clave acuñada, UNA RETIRADA con su declaración muerta, cuatro literales firmados y cuarenta y cuatro adjudicaciones medidas. El default no se mueve: diff de computed 0 sobre 11.448 valores en 17 estados y capturas 2x idénticas byte a byte. Censo: 76 % → 83 % (público 45, global 1 → 0, literal 4 → 0, excepción 0 → 4; knobs 61 → 56). Contrato 98 claves (una entra, otra sale). Global no baja. QUÉ ENTRA (1 clave) invalid-dropzone-border (var(--color-risk-border)). Era el único knob de apariencia que iba a un primitivo global a pelo. Lleva la PARTE en el nombre y no el `invalid-border` desnudo que el catálogo repite seis veces (checkbox, listbox, grid-list, radio-cards…): aquí hay TRES partes con borde —dropzone, botón e ítem— y el nombre desnudo no diría cuál tiñe. La forma modificador + parte + ranura ya está en el catálogo (invalid-input-border, invalid-control-border). Su estado no lo alcanza esta ruta: isInvalid sale de un Field envolvente y la demo no monta ninguno. Forzado: oklch(0.8059 0.1123 59.96) -> rgb(1,2,3). QUÉ SALE (1 clave, y su declaración) button-bg NO PINTABA. La regla compartida de los tres botones declaraba `background: var(--file-upload-button-bg)` y los tres la pisan después: el trigger con el sólido de la paleta, ItemRemove y ClearTrigger con transparent. Medido sobre los tres nodos, uno a uno: el centinela no mueve NADA en ninguno. Con UNA clave la respuesta de F2-A es retirar, no adjudicar — y retirarla da diff 0, que es la prueba de que estaba muerta. La clave sale con ella: un público sin consumidor es un huérfano. CUATRO LITERALES FIRMADOS (fuera del ratio) Los tres 100% de identidad —el campo ocupa el ancho que le dan, la miniatura llena la caja en la que se recorta, la barra ocupa la fila del grid— más el block-size de la miniatura. Cada uno con su anotación en la declaración (válvula de recipe-contract §3). CUARENTA CLAVES DE TONO NO PINTAN 8 tonos x 5 ranuras (solid, solid-hover, track, border, text), 40 de sus 98. Es la cascada de paleta: el forward emite AL FINAL un bloque genérico [data-file-upload][data-color] que resuelve desde el --palette-* global, misma especificidad (0,2,0), gana el último. Medido para los ocho tonos sobre las dos superficies que las consumen —el trigger (solid) y el dropzone en hover (track)—: ninguna se mueve, mientras --palette-solid sobre el nodo repinta. Adjudicadas POR PATRÓN; incidencia de fondo en next-features §13. FUERA POR DOCTRINA (los 9 privados) Ocho son el puente de paleta THM-2 y el noveno es EL CANAL DE VALOR (--_file-upload-progress-value, que el envoltorio escribe inline por fila). Lo que el componente escribe inline no es tema, y un público sobre el puente dejaría que un tema fijara el tono y matara el color= de cada instancia. Su techo honesto NO es el 100 %. VERIFICACIÓN Sonda estándar antes/después 0 diffs (4.608 valores · 8 estados · 19 nodos: la demo arranca con dos ficheros sembrados, así que monta la superficie entera) + barrido de los estados que la ruta no arranca (3 variantes x 3 tallas, invalid, disabled, dragging) 0 diffs sobre 6.840 valores · capturas 2x idénticas byte a byte · R-5.4 54/98, exit 0, sin STALE · censo --only 83 % · component:audit PASS · eidos-lint 29 morfo-backed / 0 invalid · vitest src/uix/eidos 35/36 (el rojo conocido es skin-media-player) · rtl:check 0 · docs:check 0 · prettier limpio · npm run check sin errores en ficheros del componente · pestaña Tokens verificada en el navegador (98 filas, 0 errores de consola). ⚠ Truco de medición nuevo: el «antes» del barrido de estados se reconstruye INYECTANDO el CSS de HEAD en la página (gana por orden a igual especificidad), sin tocar un árbol que otras tres sesiones están usando. Con muta-prueba: 19 diffs al alterar el control, 1 si sólo se altera el borde inválido. Índice construido a mano desde HEAD sobre los tres ficheros compartidos (recipes/base.ts, generated/base.css, theming-sentinel-exceptions.ts). Fuera del commit, como en el de `form`, docs/audit/theming/README.md — es un agregado global que mezcla trabajo en vuelo de otras sesiones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
ebfa1ce5ef |
fix(theming): el guard da por VIVO lo que un tema no alcanza — y dos bloques del ledger se descartaban en silencio
Dos defectos del instrumental, los dos medidos, ninguno arreglado en el guard
todavía (el arreglo toca a todos los componentes y pide su re-verificación).
EL GUARD TIENE FALSOS POSITIVOS: ESCRIBE EL CENTINELA EN EL style INLINE
`staticPass` escribe el token en documentElement Y en todos los nodos del
componente — y ahí es donde vive el canal inline de los wrappers. Si un wrapper
escribe un token PÚBLICO en el `style` del nodo, el guard lo pisa, ve el cambio
y lo da por VIVO, aunque un tema (que sólo puede escribir en :root o en una
hoja) no lo alcance jamás. Es la cara opuesta de drag-drop.preview-z.
Censo: siete wrappers escriben un --{c}-* público inline y DOS están en el
contrato — dialog.overlay-opacity y drawer.overlay-opacity. Medido en dialog con
el diálogo abierto y las animaciones congeladas: desde :root el fondo del velo NO
se mueve (color(srgb 0.1098 0.098 0.0902 / 0.2518) idéntico), desde el inline SÍ.
Su token MIENTE y el guard lo bendice. Los otros cinco no están en ningún
contrato: son sólo canal.
El arreglo propuesto va en §13: escribir en todos los nodos MENOS en los cuyo
`style` ya declara ese mismo token, y avisar cuando ocurra — no basta con
escribir sólo en :root, porque eso es justo lo que hace medibles los paneles
portalados. Con re-verificación del ledger entero, así que no entra aquí.
El veredicto de dialog (commiteado hoy) queda corregido con la medición.
DOS BLOQUES DEL LEDGER SE DESCARTABAN EN SILENCIO
`metrics` y `color-picker` aparecían DOS VECES en el mismo literal de objeto, así
que el primero de cada par no existía para el guard — la trampa que el handoff
documenta para base.ts, un piso más abajo. Comprobado antes de tocar nada: en los
dos casos el bloque que gana es SUPERCONJUNTO del muerto, así que no se perdía
ninguna adjudicación; era deuda con riesgo futuro, no un rojo. Retirados los dos
bloques muertos: 69 → 67 entradas, cero duplicados, y `metrics` (54/72) y
`color-picker` (46/71) siguen en verde. De paso, el fichero baja de 63 a 61 hunks
de prettier preexistentes.
Lo destapó la sesión de `progress` al leer el fichero para añadir su bloque.
Rama con varias sesiones en paralelo: índice construido desde HEAD + sólo mis
hunks, verificado con git diff --cached.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
f24abdb60e |
uix(search-field): temable — 71 % → 100 %, y sus 10 tokens sin medir NO mienten
Cero claves nuevas. Su 29 % de deuda eran CUATRO literales que son identidad, y ahora van firmados. Diff de computed 0 sobre 1.216 valores en 8 estados y 5 nodos; R-5.4 de 7/17 a 17/17 SIN una sola adjudicación, dos corridas de acuerdo; capturas 2× antes/después idénticas byte a byte. LOS CUATRO LITERALES SON IDENTIDAD, NO KNOBS El line-height: 1 del icono —un glifo solo no tiene interlineado, la misma anotación que su hermana field.css—, el 100 % doble del ::before —el anillo ES la caja del indicador, que ya mide por --_search-field-loading-size— y el border-radius: 50 %. Ese último la §4 pedía acuñarlo como loading-indicator-radius: sería un knob que SÓLO puede romper el componente. El arco es un BORDE que gira; con cualquier otro valor la ruleta deja de leerse como una. Es la clase 4 de F2-B, «el 50 % de un círculo», al pie de la letra. DIEZ DE SUS DIECISIETE TOKENS NO SE HABÍAN MEDIDO NUNCA El centinela leía 7/17 porque la demo no monta dos estados: el indicador de carga sólo existe con loading (ocho tokens) y la X sólo se desvanece con el campo VACÍO, y el escenario arranca con valor (clear-hidden-opacity). Los dos interruptores entran como prepareWith, y EL ORDEN IMPORTA: el clic en la X tiene que ir PRIMERO, porque la propia regla que enciende le quita después el pointer-events al botón que la disparó. La sonda necesita el de loading por lo mismo: 4 → 5 nodos, sin perder ninguno. LOS DOS PRIVADOS NO SON DEUDA --_search-field-icon-size y --_search-field-loading-size son el conmutador por talla y sus cinco fuentes son, cada una, una clave pública. Se quedan: 58 de las 162 recetas resuelven así su eje size —incluidas las cerradas al 100 % este mes, empty-state y banner—, y convertirlas al ámbito size: del TSC cambiaría la especificidad de la emisión sin ganar un punto de alcance. ⚠ UN DEFAULT MEDIDO, ANOTADO, NO CAMBIADO Las dos escalas del mismo renglón divergen en los dos últimos peldaños. Medido en Chrome con transiciones y animación congeladas, forzando data-size sobre el nodo real, icono → indicador: xs 14→14, sm 16→16, md 18→18, lg 20→18, xl 32→20. El contrato lo declara de frente (loading-indicator-size-lg apunta a --size-md-icon-size y -xl a --size-lg-icon-size), así que en xl la ruleta es DOCE píxeles menor que la lupa que tiene al lado. No es deuda de alcance —las diez claves alcanzan—, es diseño que huele a copia a medias. Mueve píxel: D-TH.5 lo saca de este eje. Escrito en el veredicto §5 y en el README. CIFRAS Y GUARDS Censo 71 % → 100 % (15 knobs → 11: público 10, literal 4 → 0, excepción firmada 0 → 4; sistema 1, fuera del ratio). Contrato 17 claves, intacto — no hay cambio en base.ts ni en generated/. component-audit PASS · eidos-lint invalid 0 (9 morfo-backed, 4 eidos-only) · vitest src/uix/eidos 35/36 (único rojo skin-media-player, preexistente) · rtl:check 0 · docs:check 0 · npm run check sin errores en ficheros de este componente. README con su sección «Talla y tema» y pestaña Tokens en la demo (17 claves, verificada con clic de Playwright tras networkidle). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
f68bac4a66 |
uix(avatar): temable — 75 % → 90 %, y su contrato era INVISIBLE para los dos instrumentos
Protocolo PLAN-theming §7 sobre `avatar` (incluye `AvatarGroup`, que comparte
receta y fichero). Censo 75 % → **90 %**, contrato 84 → 88 claves, centinela
**83/88** con 5 adjudicadas. El default NO se mueve.
## Lo primero: el instrumento no veía el contrato
La entrada `avatar` de `recipes/base.ts` es la ÚNICA construida por una IIFE (un
helper local genera sus 24 ámbitos compuestos), así que su mapa vive en el
`return {`, un tabulador más adentro. Consecuencia medida:
- el censo la leía como «sin entrada en base.ts» — 84 claves invisibles;
- el centinela **moría** con `no recipe block for avatar`: el componente no se
podía medir, y su gate no significaba nada.
Los dos lectores leen ya la IIFE (dedentan el `return`). Sin este arreglo, todo
lo demás de este commit habría sido humo.
## Lo que entra al contrato (6 claves)
`group-overlap-{xs,sm,md,lg,xl,xxl}` — la escala de solape de `AvatarGroup`.
Había UNA clave, `--avatar-group-overlap`, y la receta la RE-DECLARABA en seis
bloques `[data-size]`: sentada en el elemento, ganaba siempre al `:root` donde
escribe un tema. Medido: `37px` desde el asiento del tema no movía el margen; el
mismo valor escrito sobre el nodo, sí. Ahora el paso viaja por
`--_avatar-group-overlap` y los seis alcanzan desde `:root` (−8,4 · −11,2 · −14 ·
−16,8 · −22,4 · −33,6 px → 37 px, uno a uno).
## Lo que se retira (2 declaraciones muertas, diff 0 las dos)
- `group-max`: el envoltorio escribía `--avatar-group-max` INLINE y la receta
declaraba su default `99`. **No lo leía nadie** — el tope se aplica con
`data-has-max` + `:nth-child(n + M)` porque una variable no entra en
`:nth-child()`, y lo dice el propio comentario del CSS. Retirado de los dos
sitios; el `+3` del grupo sigue exactamente donde estaba.
- el respaldo `, white` de `--_avatar-badge-fg`: el contrato ya declara
`--avatar-badge-color-custom-contrast: white`, así que era inalcanzable y sólo
podía envejecer contra su token. Comprobado en la rama custom: la tinta sigue
computando `rgb(255, 255, 255)`.
## Seis literales firmados (salen del ratio)
Los cuatro `100 %` de Image y Fallback son IDENTIDAD — la parte ES la superficie
del avatar, no una talla propia — y los dos `line-height: 1` mantienen el glifo
centrado por la caja flex.
## Lo que se queda privado (el techo real es 90 %)
`--_avatar-bg`, `--_avatar-fg` y `--_avatar-badge-bg` son un CONMUTADOR: cambian
de fuente con la variante (solid · soft · outline) y su valor sale del forward de
paleta THM-2 que la capa de color alimenta por instancia desde `[data-color]`.
Un público encima dejaría que un tema los fijara y matara el `color=` de cada
avatar.
## Artefactos
- Sonda: **0 diffs** en TRES bases — demo de avatar con insignia y anillo (576
valores), la misma en modo fallback (384) y demo de AvatarGroup (3.072).
- Capturas 2× antes/después de las dos demos: **idénticas al byte**.
- Centinela R-5.4: 83/88, 5 adjudicadas con su medida en el ledger (`size-xxl` y
`font-size-xxl` viven en el paso `xxl`, que el barrido del guard no alcanza —
el límite que `metrics` ya registró; `radius-none` y `ring-width-sm` son «sólo
el paso en vigor pinta»; `group-overlap-xxl` junta las dos cosas).
- El guard aprende `avatar`: la insignia y el anillo son OPT-IN, el barrido de
`data-variant` destapa las 16 claves `*-outline-*`, y `AvatarGroup` se mide en
su propia ruta (21 muertos → 5).
- `eidos-lint` 0 invalid · `vitest src/uix/eidos` sin rojos nuevos (el conocido
`skin-media-player`) · `rtl:check` 0 · `docs:check` 0 · `npm run check`
COMPLETED sin un solo error en `avatar`.
- README «Talla y tema» + pestaña `Tokens` (88 filas, verificada en el navegador
con `networkidle` y clic real).
## Lo que NO se arregla aquí (anotado)
- **R-5.3 preexistente**: cuatro claves `*-color-custom*` donde la gramática
exige `fg`. Son escotillas que el envoltorio escribe INLINE, así que
renombrarlas cambia el contrato público de tres canales: se lista, el audit
sigue en NEEDS-WORK por esto y sólo por esto.
- **Falso POSITIVO nuevo del centinela** (next-features §13): escribe el token
en `:root` y también sobre cada nodo, y para una propiedad personalizada que
la receta re-declara en el ELEMENTO ese inline gana justo lo que un tema
pierde. Es lo que hacía que `--avatar-group-overlap` leyera vivo.
- **El barrido de tallas del guard para en `xl`**: añadir `xxl` dejaría STALE
las seis excepciones de `metrics`, así que se hace con la re-verificación del
ledger entero.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
bbdc77c07b |
uix(switch): temable — 76 % → 81 %, y su tono NEUTRAL cae con los otros once
Una clave nueva (51 → 52) y veinticinco adjudicaciones medidas: trece propias y doce por patrón. El default no se mueve: diff de computed 0 sobre 1.344 valores en 36 estados y capturas 2x idénticas. Censo: 76 % → 81 % (público 16 → 17, global 1 → 0; 22 knobs, 4 privados y 1 sistema fuera). Global 67 % (no baja). QUÉ ENTRA (1 clave) invalid-track-border (var(--color-threat-element)). Era el ÚNICO knob de apariencia que iba a un primitivo global a pelo. El nombre NO es el `invalid-border` que el catálogo repite seis veces (checkbox, listbox, grid-list, radio-cards, date-range-field…): esta receta tiene DOS partes con borde y las nombra — su hermana de estado es `disabled-track-border` y el pulgar lleva `thumb-border`, así que un nombre desnudo no diría cuál de las dos tiñe. La forma modificador + parte + ranura ya está en el catálogo (`invalid-input-border`, `invalid-control-border`). DOCE CLAVES DE TONO NO PINTAN — Y AQUÍ CAE TAMBIÉN «NEUTRAL» Es la cascada de paleta ya medida en button / badge / callout: el forward emite al FINAL un bloque genérico [data-switch][data-color] que resuelve desde el --palette-* global, misma especificidad (0,2,0), gana el último. Lo propio de este componente es que el fallback no salva ni al tono por defecto: soma estampa data-color SIEMPRE (es el color RESUELTO, neutral por defecto), así que el bloque genérico casa en toda instancia. Medido en checked: --switch-neutral-solid no mueve nada, --palette-solid sobre el nodo repinta (oklch(0.5556 …) -> rgb(4,5,6)). En button el neutral sobrevive; aquí no. Adjudicadas POR PATRÓN, con esa diferencia escrita. LAS OTRAS TRECE SON ESTADO O INSTRUMENTO Cinco disabled-* y el invalid-track-border nuevo sólo existen bajo su atributo, que ningún trigger alcanza (forzados: alcanzan, con su par medido). Los cinco size-*-thumb-translate son DOS huecos a la vez: pintan sobre `transform`, que el guard no fotografía, y valen 0px hasta que el interruptor está encendido (forzado checked: 12/14/16/18/20px -> 1234px). El par de transición ES la transición que el guard congela (sin congelar: 0,12s -> 11,5s en las cuatro propiedades). FUERA POR DOCTRINA (los 4 privados que quedan) --_switch-track-bg y --_switch-track-border-hover son CONMUTADORES: dos fuentes cada uno (la clave pública del estado apagado, el forward de paleta del encendido), y aplanarlos obligaría a duplicar cada regla por color. Las dos lecturas directas de --_switch-palette-solid* (el fondo del track en hover, la tinta del check dentro del pulgar) son el puente THM-2: un público encima dejaría que un tema fijara el tono y matara el color= de cada instancia. El techo honesto de este componente NO es el 100 %. DEFECTO ANOTADO, NO ARREGLADO El tinte inválido es --color-threat-element, el paso `element` de la escala: oklch(0.9555 0.0207 13.86), casi blanco sobre superficie clara. Y en cuanto entra el puntero, la regla de hover (0,4,0) lo tapa con el borde neutro fuerte. Es el MISMO valor en checkbox, radio-group y toggle para el mismo estado, así que es una decisión de escala del sistema (element contra border), no de esta receta: cambiarlo mueve píxel en cuatro componentes y D-TH.5 lo deja fuera. VERIFICACIÓN Sonda estándar antes/después 0 diffs (416 valores · 7 estados) + sonda de estados propia 0 diffs (928 valores · 29 estados: checked, invalid, readonly, disabled, RTL y las cinco tallas, cada uno con hover y foco) · capturas 2x antes/después idénticas · R-5.4 27/52, exit 0, sin STALE · censo --only 81 % · component:audit PASS · eidos-lint 13 morfo-backed / 0 invalid · vitest src/uix/eidos 35/36 (el rojo conocido es skin-media-player) · rtl:check 0 · docs:check 0 · npm run check sin errores en ficheros del componente · pestaña Tokens verificada en el navegador (52 filas, 0 errores de consola). Índice construido a mano desde HEAD sobre los cuatro ficheros compartidos (recipes/base.ts, generated/base.css, theming-sentinel-exceptions.ts): hay tres sesiones más en vuelo sobre ellos. Fuera del commit, como en el de `form`, docs/audit/theming/README.md — es un agregado global que mezcla ese trabajo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
1a41312b68 |
uix(image-picker): temable — 71 % → 100 %, y el instrumento medía UN nodo
Una clave nueva (13 → 14), cuatro literales firmados y el interruptor que hace
medible el componente. Diff de computed 0 sobre 1.344 valores en 7 estados y 6
nodos; R-5.4 de 13/13 a 14/14 SIN una sola adjudicación; capturas 2×
antes/después idénticas.
EL PICKER ARRANCA VACÍO Y LA SONDA VEÍA UN NODO
Todo lo que la receta pinta —preview, canvas, toolbar y los dos botones de
icono— sólo existe en el estado ready, al que no llega ningún trigger: hay que
cargar un fichero. Con el chip «Load sample image» de la demo la sonda pasa de 1
a 6 nodos. La sonda lo enciende por DEMO_VARIANTS y el centinela por
prepareWith; éste necesita además openMarker, porque su re-apertura por token
volvería a pulsar el chip y remontaría la vista previa a mitad de corrida.
LA CLAVE ES hover-button-bg, Y EL NOMBRE LO DECIDIÓ EL CATÁLOGO
Era el único knob que iba a un primitivo global a pelo. La §4 lo nombraba
hover-rotate-bg por el PRIMER selector de la regla, y miente dos veces: pinta
rotate Y remove, y el contrato de este componente ya llama button-* a ese par
desde que nació. hover-{parte}-{slot} es la forma de las 60 claves hover-* de
base.ts.
NO ES EL VELO DEL SISTEMA — MEDIDO DESDE EL PÍXEL HACIA ARRIBA
Los dos botones flotan SOBRE la foto: su relleno de reposo es translúcido
(color-mix 88 %) y el hover lo vuelve OPACO. Es un cambio de RELLENO, no una
capa encima. Con las transiciones congeladas, elementsFromPoint sobre el centro
del botón: el cambio cae en el <button> —el nodo con forma, radio 6 px, de
srgb .988/.88 a oklch(.9911 0 0)— y NINGÚN ancestro recibe background-image,
porque el arquetipo action no trae velo (archetypes.css sólo vela trigger, item
y option). No se bendice un duplicado, que es lo que paró el hover-* de listbox.
LOS CUATRO LITERALES SE FIRMAN, NO SE ACUÑAN
El 100 % doble del hijo del canvas es identidad (la <Image> ES la caja del
canvas, ya con inset: 0), el line-height: 1 es un botón de un solo glifo, y el
Highlight de forced-colors es la paleta del sistema operativo: un valor de tema
ahí lo sustituiría el UA. Válvula de recipe-contract §3 — salen del ratio como
ausencia ESCRITA.
DEFECTO REAL, ANOTADO, NO ARREGLADO
Ese hover neutro es una invención por componente y §38 / R-4.3 mandan que el
hover neutro sea la capa --state-*. Migrarlo cambia el default (velo translúcido
en vez de relleno opaco) y D-TH.5 lo prohíbe aquí. Y no basta con cambiar la
receta: el arquetipo del par es action, que HOY no recibe velo — o action gana
velo en archetypes.css (mueve píxel en todo el catálogo) o el par cambia de
arquetipo, que es morfo. Escrito en el veredicto §5 y en el README.
CIFRAS Y GUARDS
Censo 71 % → 100 % (20 knobs → 16: público 12 → 13, global 1 → 0, literal 4 → 0,
excepción firmada 0 → 4; sistema 3, fuera del ratio). Contrato 13 → 14 claves.
component-audit PASS · eidos-lint invalid 0 (12 morfo-backed, 5 eidos-only) ·
vitest src/uix/eidos 35/36 (único rojo skin-media-player, preexistente) ·
rtl:check 0 · docs:check 0 · npm run check sin errores en ficheros de este
componente. README con su sección «Talla y tema» y pestaña Tokens en la demo
(14 claves, verificada con clic de Playwright tras networkidle).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
9c3f17fa60 |
uix(form): temable — 71 % → 86 %, y 24 claves suyas NO PINTAN por una cascada
Diez claves nuevas (54 → 64), un literal firmado, veinte adjudicaciones medidas
y un hallazgo que espera firma. Diff de computed 0 sobre 832 valores en 7
estados; capturas 2× antes/después.
LAS DIEZ IBAN A LOS PRIMITIVOS A PELO
El resumen de errores (error-summary-{bg,fg,border}) —es el señalizador de nivel
de página y su superficie, su tinta y su borde SON el tono risk—, el acento de
formulario inválido (invalid-accent, un privado con UNA sola fuente, no un
conmutador), las tres superficies del árbol de AutoFields, las dos del widget y
el subrayado a media tinta de los enlaces del resumen (link-underline-fg, el par
del -offset que ya existía).
⚠ R-5.3 CAZÓ MI NOMBRE EN EL ACTO: lo acuñé como link-underline-color y la tinta
es `fg` (theming §6.7 r7, firmado el 20). Renombrado antes de commitear. El
guard de nombres funciona — es el vocabulario DIMENSIONAL el que no cubre (ver
badge, hoy mismo).
⚠⚠ VEINTICUATRO CLAVES DEL CONTRATO NO PINTAN, Y ES UNA CASCADA
[data-form-submit], [data-form-reset] y los dos botones del array llevan también
data-button porque COMPONEN el Button canónico, y [data-button] casa con la
MISMA especificidad (0,1,0) pero carga DESPUÉS: gana button.css. Medido
propiedad a propiedad sobre el nodo real —altura, padding-inline, tamaño y peso
de letra, interlineado, hueco, radio, grosor de borde, el par de transición y la
opacidad deshabilitada—: NINGUNA se mueve.
Es el defecto que gradient-picker documentó (36 de sus 45 claves) y que
emoji-picker encontró hoy en su trigger. Allí la respuesta fue RETIRAR las
declaraciones muertas; aquí son 24 claves públicas, y eso es una decisión del
autor, no del que ejecuta. Quedan adjudicadas POR PATRÓN (una razón
arquitectónica escrita una vez) y anotadas en §13 con la pregunta de fondo, que
es la misma de §12.9 con el plano overlay: qué manda, el componente compuesto o
la receta que lo compone. Si mandan las recetas, se sube la especificidad y no
se retira nada; si mandan los compuestos, hay ~63 claves públicas que retirar en
tres componentes.
LAS DEMÁS ADJUDICACIONES SON RAMAS QUE LA DEMO NO MONTA
El layout grid (forzado alcanza — y ojo: su grid-template-columns sólo CAMBIA si
el valor altera el número de columnas; con 90px pasa de una columna de 502px a
cuatro de 110,5), el resumen de errores VACÍO (sin <ul> que indentar ni <a> que
subrayar) y toda la rama de ARRAY de AutoFields: el modo `auto` de la demo monta
group y field, nunca array, item ni widget.
Fuera por doctrina: los tres privados del panel son un CONMUTADOR (variante
plain contra panel) y los cuatro --_form-action-* leen el forward de paleta
THM-2.
VERIFICACIÓN
Sonda antes/después 0 diffs (832 valores · 7 estados) · R-5.4 22/64 con las 20 +
el patrón adjudicados, exit 0 · component:audit PASS (tras el renombrado) ·
--names 0 desviadas · censo --only 86 % · eidos-lint 36 morfo-backed / 0 invalid
/ 0 class-hooks · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo
conocido) · el ledger sigue en sus 63 hunks de prettier previos.
Rama con cuatro sesiones en paralelo: índice construido desde HEAD + sólo mis
hunks (base.ts por bloque), verificado con `git diff --cached`. No entra
docs/audit/theming/README.md — es un agregado global que ahora mismo mezcla
trabajo en vuelo de otras sesiones.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
ebe3fe6ed7 |
uix(skip-link): temable — 71 % → 100 %, y el guard aprende a abrir por FOCO
Cero claves nuevas: su 29 % de deuda eran DOS literales que son la técnica, y ahora van firmados. Diff de computed 0 sobre 192 valores en 7 estados más los 52 del estado enfocado —el único que se ve— medidos aparte; capturas 2× idénticas byte a byte; R-5.4 de 0/8 a 8/8 SIN una sola adjudicación. LA §4 PEDÍA `width` Y `height`, Y LAS DOS SON LA TÉCNICA El `1px × 1px` no es un tamaño: es la mitad del sr-only canónico (la otra mitad es el par clip / clip-path). Un tema que lo mueva no cambia una apariencia, rompe el mecanismo — y a 0×0 algunos motores sacan el enlace del árbol de accesibilidad, que es exactamente lo único que este componente no puede permitirse; su propia cabecera ya razona eso mismo para display:none, visibility y el tabindex negativo. Firmados con /* literal: */, la válvula de recipe-contract §3: salen del ratio como ausencia ESCRITA, no como deuda. Misma clase que text-blur y text-scramble. LOS OTROS 5 KNOBS YA ESTABAN BIEN, Y LAS DOS AUSENCIAS SON DOCTRINA La tipografía se HEREDA (no hay font-* declarado; acuñarla fijaría el default, D-TH.5) y el anillo de foco es del SISTEMA (--focus-ring-*, recipe-contract §2). El `background:` en shorthand no mata ninguna capa de estado: su parte lleva archetype 'provider', que no recibe velo. EL INSTRUMENTO LEÍA 0 DE 8 — LA OCTAVA CLASE DE PUNTO CIEGO Toda su superficie existe SÓLO bajo :focus: sr-only mientras no lo tiene, píldora cuando sí. El guard no lo enfocaba nunca, y el blur que hace tras abrir lo habría deshecho igual. Clicarlo tampoco vale: su handler manda el foco a la región de destino, así que la píldora se va por el camino de entrada. Nace `openBy: 'focus'`, y con él `openingIsFragile` — el conjunto de aperturas que el blur y el aparcado del puntero NO deben deshacer, hasta hoy sólo 'hover'. Es aditivo: las cuatro condiciones que decían `openBy !== 'hover'` pasan a consultarlo y ninguna configuración existente cambia de rama. Re-verificado sobre tres del ledger: dialog 37/44 (la cifra exacta de su commit), tooltip 15/23, context-menu 27/28 — cero regresiones. ARTEFACTOS Sonda antes/después → 0 diffs, 0 nodos perdidos (192 valores, 7 estados) · estado ENFOCADO medido aparte con un script propio (la sonda estándar mide reposo, tallas, abierto y hover: nunca foco) → 52 valores, 0 diffs · capturas 2× idénticas byte a byte · R-5.4 8/8, exit 0 · censo --only 71 % → 100 % (knobs 8 → 6: los dos literales pasan a la clase excepción, fuera del ratio) · component:audit PASS · eidos-lint 2 morfo-backed / 0 invalid · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo conocido, skin-media-player) · npm run check COMPLETED sin errores en ficheros tocados · pestaña Tokens añadida a su demo y VERIFICADA en el navegador: 8 filas, 0 errores de consola. LO QUE NO ENTRA Y POR QUÉ docs/audit/theming/README.md es un agregado global y otra sesión tiene `form` en vuelo en el mismo árbol; se regenerará con su commit. Por lo mismo, de theming-sentinel.ts sólo entran mis hunks (verificado con git diff --cached). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
2e708adae8 |
uix(progress): temable — 69 % → 87 %, y el instrumento medía UNA de sesenta caras
Dos claves acuñadas, seis literales FIRMADOS y cuatro knobs adjudicados por escrito. El default no se mueve: diff de computed 0 sobre 60 configuraciones y capturas 2x idénticas byte a byte. Censo: 69 % → 87 % (35 knobs → 30; público 24 → 26, global 3 → 2, literal 6 → 0, excepción firmada 0 → 6). Contrato 41 → 43 claves. Global 67 % (no baja). QUÉ ENTRA (2 claves) row-gap (--space-2) + column-gap (--space-3). Era el ÚNICO knob de apariencia que iba a un primitivo a pelo, y se parte en dos porque el atajo llevaba DOS valores distintos: el hueco de fila separa la línea de texto de la barra, el de columna separa el rótulo del valor. Un gap único habría nombrado un knob para dos. El catálogo tiene las dos palabras (row-gap x10, column-gap x4) y el molde exacto es chart.legend-row-gap / -column-gap. QUÉ SE FIRMA EN VEZ DE ACUÑARSE (6 literales, fuera del ratio) Cuatro 100 % y dos max-content: la geometría de la barra, no una decisión de tema — llena la fila que le dan, o se encoge a su propio grosor / diámetro. Cada uno con su anotación en la declaración (válvula de recipe-contract §3). QUÉ SE RECHAZA DE LA PROPUESTA §4 (dos de sus tres filas) indicator-radius — el --radius-full del anillo. Su GEMELO meter ya dejó el veredicto escrito EN EL CSS: es lo que hace circular a shape='circular', y un token dejaría que un tema des-redondease una forma que el consumidor pidió por su nombre. Identidad, no knob; se copia el comentario del gemelo. Son los dos únicos global que quedan, y el censo no puede sacarlos del ratio: la válvula de la anotación sólo reclasifica la clase literal, nunca un global (mismo techo que meter). width: max-content — la §4 fundía en UN nombre dos nodos distintos (la raíz vertical y la raíz circular) y los nombraba por el primer selector. Es el literal de identidad de arriba. EL TECHO HONESTO ES 87 %, NO 100 % Los dos knobs private que quedan son el CANAL DE VALOR: --_progress-value-pct lo escribe soma en el estilo inline del provider en cada render (0-100 saturado) y la receta lo lee para el ancho del relleno lineal y el alto del vertical. Un público encima mentiría — un tema no puede fijar el progreso de una tarea. Misma clase que el z-index inline de drag-drop. GUARD R-5.4: 40/43, TRES ADJUDICADOS CON SU MEDIDA indicator-bg-loaded — sólo pinta bajo [data-state='loaded'], y la corrida mantiene indeterminate encendido para alcanzar los tokens del barrido; forzado sobre el nodo real: oklch(0.6406 0.1329 157.68) -> rgb(1,2,3). transition-duration / -ease — los congela el guard por diseño; pasada sin congelar: 0.18s -> 11.5s y cubic-bezier(0.4, 0, 0.2, 1) -> steps(7). EL INSTRUMENTO MEDÍA UNA DE SESENTA CARAS La sonda estándar ve 4 nodos — que son TODAS las partes del morfo — pero una sola configuración: lineal, horizontal, loading, md. Medio contrato (el anillo, el eje vertical, el barrido indeterminado, la tinta de completado) queda fuera del diff, y el gate pasa en verde sin haberlo mirado. El guard lo dijo antes: 22 de 41 en la página por defecto. Con sweepAttr data-shape — el interruptor que su gemelo meter YA tenía — sube a 34; con el interruptor indeterminate de la demo, a 37; con el chip vertical, a 38. Cada control se comprobó por separado, antes y después, porque montar más puede medir menos: aquí ninguno tapó nada. Y una trampa NUEVA, medida aquí: una sonda que CACHEA los nodos y luego mide en bucle da 8.352 falsos diffs si el HMR reemplaza el subárbol a mitad de corrida. getComputedStyle sobre un nodo DESACOPLADO devuelve la cadena vacía en TODAS las propiedades, y el diff lee cada vacío como un cambio. Se arregla re-consultando los nodos en cada instantánea, y se detecta haciendo fallar la sonda ante un computed vacío. Pariente de hmr-stale-tab-phantom-findings. ARTEFACTOS Sonda estándar: 4 nodos, 800 valores x 7 estados -> 0 diffs. Sonda de variantes (2 formas x 2 orientaciones x 3 estados x 5 tallas, elemento y ::before): 17.280 valores -> 0 diffs. Capturas 2x antes/después, lineal y circular: idénticas byte a byte. Censo --only progress 87 % · component:audit PASS 1/1 · eidos-lint 0 invalid (13 morfo-backed, 12 eidos-only) · vitest src/uix/eidos 439/440 (el único rojo es el conocido skin-media-player en lint.test.ts) · rtl:check 0 · docs:check 0 · npm run check sin errores atribuibles a progress · prettier limpio en lo tocado (progress.css estaba limpio en HEAD y sigue limpio; los dos ficheros del centinela ya venían sucios de antes y mis líneas no añaden nada). README de eidos con su sección «Talla y tema» y pestaña Tokens en la demo, verificada en el navegador: 43 filas resueltas en vivo, 0 errores de consola. NOTA DE ÁRBOL COMPARTIDO Otra sesión trabaja sobre form en los mismos ficheros (base.ts, generated/base.css, los dos del centinela y el índice de fichas). Lo indexado se construyó a mano desde HEAD + sólo mis hunks, así que el commit no arrastra su trabajo en curso; docs/audit/theming/README.md lleva sólo el delta de progress y conserva la fila de form tal como está en HEAD. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
4c5cfd8ba7 |
uix(color-swatch): temable — 70 % → 100 %, y el color del chip NO es un knob
Cuatro claves nuevas por una retirada (12 → 14 en el contrato), dos adjudicaciones
medidas. Diff de computed 0 sobre 832 valores en 15 estados y DOS rutas; capturas
2× byte a byte idénticas.
LA §4 PEDÍA UN NOMBRE Y LO QUE FALTABA ERA UNA ESCALA
La ficha marcaba `radius` con ⚠ y tres valores en colisión. No es una colisión: es
el eje `rounded` con cuatro pasos, y la clave que ya estaba en el contrato ERA el
paso `sm` bajo un nombre que no lo dice. Contado en base.ts: siete recetas
escriben `radius-{k}`, y una es `badge` — el gemelo que lee ESTE MISMO
`data-rounded` con el mismo conmutador privado. Así que entra la escala entera
(radius-sm/md/lg/full) más `--_color-swatch-radius`, exactamente la forma que su
propio eje `size` usaba dos líneas más arriba. Dejar `radius` al lado de
`radius-md` habría dejado el paso `sm` llamándose `radius`: un nombre que miente.
`fill` SALE DEL CONTRATO: ES UN CANAL DE VALOR, NO UN KNOB DE TEMA
El wrapper escribe `--color-swatch-fill: {color}` INLINE en cada render desde una
prop obligatoria. Medido sobre un chip real con transiciones congeladas: escribir
el token en :root deja el ::before en rgb(124, 58, 237) — la declaración inline
gana siempre. Un público encima sólo podía mentir. La forma correcta ya estaba
escrita en el guard de la capa: recipe-css-contract sanciona `var(--x, default)`
para las vars que el runtime escribe («el respaldo ES el default»), que es justo
lo que la receta tenía. Por eso el respaldo NO se retira: al salir del contrato
deja de ser código muerto y pasa a ser el default.
⚠ EL CENTINELA DABA `fill` POR VIVO — ES UN FALSO POSITIVO SUYO
El guard escribe el token en :root Y en el `style` inline de cada nodo del
componente, que es exactamente donde vive el canal de valor: lo pisa y lee
«mueve». Es la cara opuesta de drag-drop.preview-z, donde la adjudicación se
había medido sobre un nodo fabricado. Regla: un token que el componente escribe
INLINE no se puede juzgar con el guard — se mide a mano escribiendo sólo en :root.
EL INSTRUMENTO ESTABA CIEGO, DOS VECES
1. color-swatch NO TIENE RUTA DE DEMO (404): es el QUINTO canónico en ese estado,
tras picker-shell, mockup, surface y audio-player. La sonda medía 1 nodo. Se
mide donde de verdad se renderiza — gradient-builder (3 chips en el stage) y
color-picker (el del trigger).
2. El eje `rounded` no lo monta NADIE: ningún consumidor del repo pasa la prop, así
que los tres pasos que no son el default no tenían nodo que pintar. El guard los
barre con sweepAttr: data-rounded, como meter hace con su shape.
LAS DOS ADJUDICACIONES SON EL ANILLO OPT-IN
border-width y border-fg: `bordered` nace apagado y ningún consumidor lo enciende,
así que su ::after no existe en ninguna página. Forzado data-bordered sobre un chip
real, los dos llegan (inset 0 0 0 1px → 1234px; oklch(0.931 0 0) → rgb(1, 2, 3)).
ARTEFACTOS
Sonda antes/después en dos rutas (256 valores × 8 estados en color-picker, 576 × 7
en gradient-builder) → 0 diffs, 0 nodos perdidos · el eje `rounded` medido a mano
forzando el atributo: 4 / 4 / 6 / 10 / 9999 px antes y después · capturas 2×
idénticas byte a byte · R-5.4 12/14 con las dos adjudicadas, exit 0 · censo --only
70 % → 100 % (knobs 10 → 7: los tres border-radius por variante pasan a declarar
el privado) · component:audit PASS · eidos-lint 2 morfo-backed / 8 eidos-only / 0
invalid · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo conocido,
skin-media-player) · npm run check COMPLETED sin errores en ficheros tocados.
LO QUE NO ENTRA Y POR QUÉ
- Paso 9 del protocolo (pestaña Tokens en la demo): no hay demo que tocar.
- docs/audit/theming/README.md: es un agregado global y otra sesión tiene form y
progress en vuelo en el mismo árbol; se regenerará con su commit. Por lo mismo,
de base.ts, generated/base.css, theming-sentinel.ts y el ledger sólo entran mis
hunks (verificado con git diff --cached).
Defectos anotados, no arreglados (mueven documentación ajena a este cambio): la
cabecera del CSS, el docblock del .svelte y types.ts siguen diciendo que la talla
sale de `--icon-size-*`, cuando desde la extracción tiene escala propia.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
bb89174a8b |
uix(dialog): temable — 67 % → 89 %, y el borde dice CÓMO se cerró
Siete claves nuevas (37 → 44), un literal firmado, siete adjudicaciones medidas.
Diff de computed 0 sobre 480 valores en 8 estados.
LAS SIETE SON LAS DOS TINTAS SEMÁNTICAS QUE LE FALTABAN
Cuatro para los tonos EVALUATIVOS (risk-border, risk-title-fg, threat-border,
threat-title-fg): dialog no tiene forward de paleta THM-2 y su trato de tono es
deliberadamente estrecho —el borde y la tinta del TÍTULO, nunca la superficie
del cuerpo, para que el texto largo no compita con la señal—, pero iban a
--color-risk-* a pelo.
Tres para el tinte de SALIDA (saved-border, failed-border, dismissed-border): el
morfo escribe data-last-action antes de que data-state pase a closed, así que el
borde superior dice CÓMO se cerró mientras se va. El tercero cubre cancelled /
dismissed / dismissed-outside, que comparten valor: todo cierre sin resultado.
{tono}-border es el nombre del catálogo (48 claves) y failed-border el de
proof-of-human.
EL 11 % QUE QUEDA SON CUATRO ESCOTILLAS, NO DEUDA
Los --_dialog-content-*-override los escribe el wrapper INLINE desde las props
width / minWidth / maxWidth / height / minHeight. Un público encima lo pisaría el
inline y mentiría — la clase de --_background-gradient-image y del triple de
s-text-virtual-list. El nombre del privado ya lo dice: -override.
⚠ NO se acuñó tipografía de superficie, por §12.9: el contenido lleva
data-depth='modal' y un plano declara font-family / line-height a la misma
especificidad y más tarde en la cascada. Las claves de título y descripción que
ya existían son de PARTES internas, no de la superficie del plano.
SIETE ADJUDICACIONES, DOS DE ELLAS CON SEGUNDA PASADA
Estados que la demo no monta: la hoja inferior, el tamaño full, las ocho celdas
no centradas de la rejilla de posición, el data-position del botón de cierre y
los tres tintes de salida (que sólo existen mientras data-state='closed' y
data-last-action COEXISTEN). Y dos costaron una segunda pasada por el VALOR del
atributo: la rejilla usa top-left / top-right (físicos), no top-start; y el botón
de cierre NO lleva data-position en esta demo aunque todas las reglas que leen
close-inset lo exigen.
VERIFICACIÓN
Sonda antes/después 0 diffs (480 valores · 8 estados · 8 nodos con el diálogo
abierto) · R-5.4 37/44 con las siete adjudicadas, exit 0 · component:audit PASS ·
censo --only 89 % · eidos-lint 15 morfo-backed / 0 invalid / 0 class-hooks ·
rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo conocido) · capturas 2×
· el ledger sigue en sus 63 hunks previos.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
4b9354bba2 |
uix(pin-input): temable — 65 % → 100 %, y un respaldo que mentía por 0,15
Dos claves nuevas (20 → 22), cuatro privados renombrados, VEINTIDÓS respaldos retirados y seis adjudicaciones medidas. Diff de computed 0 sobre 1.856 valores en 8 estados. SU 35 % DE DEUDA ERAN TRES DEFECTOS, NINGUNO DE DISEÑO 1. Un prefijo ABREVIADO: los privados se llamaban --_pin-cell-* dentro de un componente llamado pin-input, así que el censo no podía reconocerlos como suyos y los cuatro knobs que los leen contaban como deuda aunque DERIVAN de públicos. Renombrados a --_pin-input-cell-* — el cuarto caso de esta clase tras color-picker, metrics y time-picker. 2. Un respaldo A SÍ MISMO: font-family leía var(--style-label-font-family, var(--style-label-font-family)), que es un no-op con forma de defecto. Ahora es la costura. 3. La tinta del dígito iba a --color-content-primary a pelo → cell-fg. Y LOS VEINTIDÓS RESPALDOS ESCRITOS A MANO Cada var(--pin-input-x, <valor>) duplicaba lo que el contrato ya declara en :root: código muerto, y retirarlos dio 0 diffs, que es la prueba. Pero UNO MENTÍA: disabled-opacity respaldaba 0.55 cuando --opacity-disabled vale 0.4. Es la ley de los `, 1.4` contra un --font-line-height-sm de 1.45 que este mes ya salió en dos componentes, aquí con más deriva. Un respaldo no es una red de seguridad: es una segunda fuente que nadie actualiza. SEIS ADJUDICACIONES, Y DÓNDE VIVE CADA ESTADO La demo muestra un pin vacío, editable y válido, así que los seis tokens de estado no tenían nodo. Forzados sobre los nodos reales alcanzan los seis — con un detalle que costó una pasada: `filled` y `active` son atributos de la CELDA, pero `invalid` y `readonly` se estampan en el CONTENEDOR y cascadean (soma los OR-fusiona con el Field que las envuelve). Forzarlos en la celda no hace nada. VERIFICACIÓN Sonda antes/después 0 diffs (1.856 valores · 8 estados · 8 nodos) · R-5.4 16/22 con las seis adjudicadas, exit 0 · component:audit PASS · censo --only 100 % · eidos-lint 8 morfo-backed / 0 invalid / 0 class-hooks · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo conocido) · capturas 2× antes y después · el ledger sigue en sus 63 hunks previos. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
2ebeb9b16c |
uix(spin-field): ADJUDICADO — 67 % es su techo, y lo dice la cabecera de su propio CSS
CERO claves nuevas, un literal firmado, siete adjudicaciones medidas. Diff de computed 0 sobre 2.400 valores en 8 estados. EL TECHO ESTABA ESCRITO, Y ES DOCTRINA Ocho de sus knobs leen los privados RESUELTOS del Field (--_field-control-height, --_field-control-padding-inline, --_field-control-gap) porque los steppers y el scrubber IGUALAN la fila del input a cualquier talla. La cabecera del CSS lo dice con estas palabras: «never a parallel --spin-field-* chrome that would alias the Field base». Acuñar ahí sería el antipatrón que el fichero prohíbe por su nombre. Préstamo con dueño —se tema en la ficha de field— y el censo lo puntúa como deuda porque no sabe distinguirlo: el mismo artefacto que listbox (68 %) y radio-cards (61 %) ya registraron. Los dos factores del apilado (* 0.62 para el ancho del botón, * 0.34 para el glifo) tampoco se acuñan: viven dentro de un calc() sobre ese mismo privado de Field, así que un token propio no cambiaría quién manda. SIETE ADJUDICACIONES, Y UNA SORPRESA Los tres active-control-* no responden a :active NI forzando el pseudo por CDP: su estado es el [data-scrubbing] que soma pone en el SCRUBBER mientras se arrastra. Forzado el atributo sobre el nodo real, los tres alcanzan. Más focus-control-bg (pseudo forzado por CDP), control-disabled-opacity (0.48 → 0.137) y el par de transición sin congelar (0,12s → 11,5s). ES UNA CAPA, NO UN COMPONENTE No tiene wrapper ni ruta propia, así que el guard lo mide dentro de number-field — declarado ahora en `urls`, para que nadie tenga que saberlo. ⚠ Y una corrida de sonda dio 5 «nodos ausentes» que no eran nada: una recarga que no montó la talla xl. Repetida, 0 diffs y 0 ausentes contra el mismo ANTES. Un «missing node» tampoco se cree a la primera. VERIFICACIÓN Sonda antes/después 0 diffs · R-5.4 13/20 con las siete adjudicadas, exit 0 · component:audit sin hallazgos · censo 67 % con las ocho filas de préstamo explicadas · docs:check 0 · el ledger sigue en sus 63 hunks previos. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
4da40c63a2 |
style(theming): el bloque meter del ledger, como prettier lo quiere
El commit anterior dejó el fichero en 64 hunks (base 63): mi entrada añadía uno. Es justo lo que la revisión de hoy señalaba como E4, así que se corrige en el acto — reformateando SÓLO mi bloque, sin tocar los 63 ajenos que el fichero arrastra desde antes. Guard re-verificado: meter 24/28, exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
d6871eb103 |
uix(meter): ADJUDICADO — 64 % → 75 %, su techo, y el guard medía la MITAD
CERO claves nuevas: su contrato de 28 ya cubría todo lo que es suyo. Dos literales firmados, cuatro adjudicaciones medidas y tres filas que se quedan fuera A PROPÓSITO. Diff de computed 0 (416 valores, 7 estados), capturas antes/después idénticas. EL GUARD MEDÍA LA MITAD DEL COMPONENTE La demo arranca en shape='linear', así que los CATORCE tokens del anillo —doce pasos de tamaño y grosor, más su pista y su centro— no tenían nodo que pintar: 12 de 28. Con el barrido de data-shape sube a 24/28. LOS DOS border-radius DEL CÍRCULO NO SE ACUÑAN Son lo que hace circular a shape="circular": el exterior del anillo y el agujero del centro. Un --meter-circular-radius dejaría que un tema descirculara una forma que el consumidor pidió POR NOMBRE — identidad, no knob, la misma lectura que los dos 50 % de cropper. Nota de coherencia con badge, donde SÍ acuñé dot-radius para un --radius-full: allí el punto es un adorno cuya forma es estética (y knob.indicator-radius vale --radius-sm, que lo prueba); aquí el redondeo ES el valor del atributo. La prueba sigue siendo qué DECIDE el token, no qué valor tiene. --_meter-value-pct es CANAL DE VALOR: el wrapper lo escribe inline con el porcentaje, y de él salen la anchura de la barra y la parada del conic-gradient. Y los dos 100 % son identidad (la barra lineal ES el ancho de su contenedor; el indicador llena el alto de la pista), firmados en su declaración. Adjudicado con medida: las dos tintas de zona fuera de `optimum` (forzadas alcanzan) y el par de transición (sin congelar: 0,18s → 11,5s). VERIFICACIÓN Sonda antes/después 0 diffs · R-5.4 24/28, exit 0 · component:audit PASS · censo 75 % con las tres filas explicadas · eidos-lint 4 morfo-backed / 0 invalid / 0 class-hooks · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo conocido) · capturas 2× miradas · el ledger sigue en sus 63 hunks previos. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
863c6993c8 |
uix(emoji-picker): temable — 61 % → 100 %, y el cromo del trigger NO era suyo
Siete claves nuevas, TRES RETIRADAS por muertas, tres literales firmados y cinco
adjudicaciones medidas. Contrato 17 → 21. Diff de computed 0 sobre 6.080 valores
en 8 estados (176 nodos con el panel abierto), capturas 2× idénticas.
LOS NOMBRES LOS DIO EL CATÁLOGO
`open-trigger-fg` (accordion lo nombra igual), grid-padding-inline +
grid-padding-block-end (el eje lógico completo, como card-group / combobox /
command) y las tres del marcador de tono, la familia
timeline.marker-{size,radius,bg}. Se llama tone-marker-* y no marker-* porque el
pie lleva además un selector de TONO: dentro del propio componente, `marker` a
secas sería ambiguo.
TRES CLAVES RETIRADAS — EL CROMO DE REPOSO DEL TRIGGER NO ES SUYO
El trigger lleva también data-popover-trigger, y
[data-popover-trigger]:not([data-archetype='field-trigger']) es (0,2,0) contra
el (0,1,0) de esta receta: el radio, la tinta y el tamaño de letra los pinta
popover.css. Medido: mover --emoji-picker-trigger-{fg,radius,font-size} no
cambiaba NADA. Retiradas con sus declaraciones, 0 diffs — la prueba de que
estaban muertas. Es el defecto que gradient-picker documentó (36 de sus 45
tokens) y la misma respuesta. Sobreviven dos por razones distintas:
trigger-size, porque popover dimensiona con `height` y no con el par lógico, y
open-trigger-fg, porque su selector añade [data-state='open'] y gana por orden.
trigger-fg no llegó a existir: se acuñó y se midió muerta en el mismo pase.
CINCO ADJUDICACIONES, TODAS SOBRE NODOS REALES
Las tres del marcador de tono (la demo monta CERO celdas data-tone-capable;
forzado el atributo sobre una celda real, el ::after alcanza: 4px → 37px,
9999px → 37px, y el fondo), preview-name-fg (los hijos de la vista previa son
<span> desnudos, sin atributo del componente, fuera del conjunto medido) y
open-trigger-fg.
⚠ open-trigger-fg OSCILA ENTRE CORRIDAS: 17/21, 16/21, 16/21 con el mismo
código. Medido vivo CUATRO veces —la última replicando paso a paso el staticPass
del propio guard, que movió a la primera talla—, así que el token no miente: lo
que falla es el instrumento. La causa: el panel se cierra en algún punto de la
pasada y, durante la animación de SALIDA, el content sigue en el DOM mientras el
trigger ya perdió data-state='open', que es lo que la regla selecciona;
reopen() mira el CONTENT, cree que está abierto y no reabre. Probé un openMarker
sobre el trigger y NO basta (el clic de reapertura cae en esa misma ventana), así
que lo retiré en vez de dejar un override que no arregla. El arreglo real es que
reopen() espere a la CONDICIÓN en vez de dormir un número fijo — §13. Su entrada
de ledger saldrá STALE en las corridas donde alcanza, y está escrito en la razón
para que nadie la borre por eso.
Y EL INSTRUMENTO DE CAPTURA ESTABA ROTO DESDE SIEMPRE
__shot.ts tenía el puerto 5173 CABLEADO, así que cualquier sesión en otro puerto
moría con ERR_EMPTY_RESPONSE. Es probablemente por lo que los pasos 6 y 13 del
protocolo se saltaron en 33 componentes sin que nadie lo notara. Ahora toma la
URL como argumento —como la sonda y el guard— y un --open opcional para los
componentes cuya superficie sólo existe abierta. Estrenado aquí: capturas antes
y después, miradas y idénticas.
VERIFICACIÓN
Sonda antes/después 0 diffs (6.080 valores · 8 estados) · R-5.4 17/21 con las
cinco adjudicadas, exit 0 · component:audit PASS · censo --only 100 % ·
eidos-lint 17 morfo-backed / 0 invalid / 0 class-hooks · rtl:check 0 ·
docs:check 0 · suite eidos 439/440 (el rojo es skin-media-player, el conocido) ·
el ledger sigue en sus 63 hunks de prettier preexistentes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
233ef989b3 |
fix(theming): float-panel tenía DOCE rojos sin medir — el guard R-5.4 vuelve a verde
El barrido del centinela sobre TODO el ledger (59 componentes) destapó que `float-panel` fallaba: 17/40 con doce tokens públicos sin adjudicar. No es regresión —la bisección de las NUEVE versiones del guard desde `cd6a9f4e3` da siempre 17/40 con los mismos doce— sino un rojo que su propio commit del 22 dejó escrito («lo rojo que queda son 12 tokens anteriores») y que nadie midió. Y la frase del handoff «desde el 23 no queda ningún rojo del bloque viejo» era FALSA: se adjudicaron drawer, metrics y color-picker; éste no. Corregida, con la lección: un componente cuyo commit dice «lo que queda» NO está cerrado, y la única forma de saberlo es correr el guard sobre el ledger ENTERO. LOS DOCE, MEDIDOS UNO A UNO SEIS son el plano de profundidad, y la predicción del 22 era exacta: el contenido lleva data-depth=overlay y [data-depth=overlay] declara background, border, box-shadow, font-family y line-height a la MISMA especificidad (0,1,0) y más tarde en la cascada. Verificado moviendo los tokens del propio plano sobre el nodo (superficie, borde, fuente y leading lo repintan) y enumerando las reglas que casan. border-width cae con border (el plano escribe el shorthand). Misma adjudicación que tooltip, misma decisión abierta (§12.9). ⚠ Y una corrección a mi propio diagnóstico: primero atribuí la sombra a [data-topmost] porque el panel de la demo arranca frontal. Falso — quitando el atributo sigue muerta: es el plano también. Lo que sí depende de topmost es su compañero shadow-topmost, que SÍ alcanza (→ rgb(4,5,6)) porque su regla es (0,2,0) y le gana al plano: la prueba de que la causa es la cascada y no un token roto. TRES son estados o partes que la demo no monta: active-shadow (forzado data-dragging → alcanza), resize-size (lo consumen las asas de ESQUINA se/ne/sw/nw y la demo monta sólo las de borde, e y s) y button-size (lo consumen [data-float-panel-action] y [data-float-panel-stage-trigger], ninguno montado — el único control es el cierre, un <Button> compuesto que se dimensiona solo: el mismo grupo que las tres action-* ya adjudicadas). UNO es el PUENTE DE PALETA: el contenido lleva data-color, así que --_float-panel-accent viene del forward THM-2 (--_float-panel-palette-border → rgb(7,8,9)); sin data-color la clave alcanza (→ rgb(1,2,3)). DOS son la ley del congelado: transition-duration / -ease no pueden moverse bajo un guard que congela `transition`. Pasada aparte: 0.12s → 11.5s y cubic-bezier(0.4,0,0.2,1) → steps(7). DE PASO, DOS ARREGLOS DE LA MISMA REVISIÓN - `background.parallax-travel` estaba MAL CLASIFICADO como estructural («el escenario no tiene scroll timeline»): lo tiene (animation-timeline: view()). Forzando data-parallax + speed 1, el translate sigue al token (14,6 → 60,5 px al mismo scrollY). La causa real es que el guard NO fotografía translate ni transform — registrado en §13 junto al hueco de mask-image, para entrar en PROPS en un pase con re-verificación del ledger entero. - `cropper`: el hueco de composición que el README daba por «anotado» y no lo estaba, ahora es fila de §Gaps con su disposición. Y las tablas de tokens de `cropper` y `waveform` pasan a la sección «Talla y tema», el molde del resto. La nueva constante PLANE_SUPERSEDED se iza sobre el objeto (un `const` usado antes de su declaración reventaba el guard, y el fallo se veía sólo mirando el exit REAL: tras la tubería, `$?` es el del grep). Verificación: R-5.4 float-panel 17/40 con 23 adjudicaciones, cero STALE, exit 0 · docs:check 0 · el ledger vuelve a sus 63 hunks de prettier preexistentes (mis entradas se reformatearon a mano, sin tocar las ajenas). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
271fcd4df8 |
uix(badge): temable — 59 % → 75 %, y subir un privado al contrato lo somete a reglas nuevas
Seis claves nuevas (65 → 71), dos literales firmados, cinco privados
adjudicados. Diff de computed 0 sobre 992 valores en 7 estados.
LA ALTURA DEL CHIP ERA EL HUECO
Badge monta su altura en la escala de CONTROL a propósito —para que `md`
signifique lo mismo lleve o no un control dentro (el ✕ removible es un
IconButton: medido, el mismo badge md daba 30px sin él y 46px con él)— pero lo
hacía desde un privado con cuatro fuentes por talla que leía --control-height-*
A PELO. Eso es una ESCALA, no un conmutador: sube al TSC como
min-block-size-{xs,sm,md,lg} + el resuelto, el molde que sus vecinas
padding-inline / gap / font-size ya tenían.
Y AL ENTRAR EN EL CONTRATO, LA SUITE LO CORRIGIÓ
El valor verbatim del CSS era el primitivo CRUDO (--control-height-{k}) y
recipe-css-contract exige la coordenada del BUNDLE (--size-{k}-control-height,
theming §5). Es la trampa que el handoff nombra —«la propuesta hereda el
incumplimiento del CSS de partida»— y que ya mordió a code-block: SUBIR UN
PRIVADO AL CONTRATO SOMETE SU VALOR A REGLAS QUE EN EL CSS NO SE LE APLICABAN.
Corregido; el diff sigue en 0.
dot-radius ES EL PAR QUE FALTABA
Redondo es el DEFECTO, no la definición: knob.indicator-radius vale
--radius-sm, así que el catálogo ya trata el radio de un marcador como knob.
Los dos 100% del glifo son identidad (el icono ES su ranura), firmados.
LOS CINCO PRIVADOS SON LAS TRES CLASES DE F2-B EN UN SOLO COMPONENTE
--_badge-bg / --_badge-fg son un CONMUTADOR (cambian de fuente con la variante:
track · solid · transparent, y aplanarlos obligaría a duplicar cada regla);
--_badge-fill-finish es el canal que el generador de degradados deriva de la
paleta de ESTA instancia; y --_badge-palette-* son forwards THM-2 que la capa de
color alimenta por instancia — un público encima dejaría que un tema los fijara
y matara el color= de cada chip.
LAS 40 CLAVES DE TONO NO MUEVEN NADA, Y YA SABÍAMOS POR QUÉ
El bloque genérico [data-badge][data-color] del forward de paleta se emite EL
ÚLTIMO y gana por orden a igual especificidad: la pintura sale del --palette-*
global. Es el hallazgo de cascada de paleta medido en button, badge y callout el
mismo día (§13, pendiente de firma) y entra como EXCEPCIÓN POR PATRÓN — una
razón arquitectónica escrita UNA vez, no cuarenta accidentes. Con ella y los dos
pasos de radius adjudicados (forzando data-rounded: 4px → 37px y 10px → 37px),
el guard queda en 29/71 y limpio.
EL INSTRUMENTO NO VEÍA TRES DE SUS CINCO PARTES
Dot, icon y remove son interruptores OPT-IN apagados por defecto: la sonda medía
2 nodos —raíz y etiqueta— y ninguna de las partes que la receta pinta.
Encendidos, 5. Misma clase que las capas opt-in de background.
⚠ component:audit da NEEDS-WORK y es PREEXISTENTE: R-1.5, sin tratamiento de
foco en la receta (grep focus-visible = 0 tanto en HEAD como después). El ✕ trae
el suyo del IconButton que compone; el chip no es focalizable. No se toca aquí:
darle foco mueve píxel y es decisión de diseño.
VERIFICACIÓN
Sonda antes/después 0 diffs (992 valores · 7 estados · 5 nodos con las tres
partes encendidas) · R-5.4 29/71 con el resto adjudicado (dos entradas propias +
una excepción por patrón), cero STALE · censo 75 % · eidos-lint 5 morfo-backed /
14 eidos-only / 0 invalid / 0 class-hooks · rtl:check 0 · docs:check 0 · suite
eidos 439/440 (el rojo es skin-media-player, el conocido).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
9bdc5a5d5d |
uix(background): temable — 57 % → 95 %, y montar MÁS capas hacía medir MENOS
Seis claves nuevas (31 → 37), tres literales firmados, un privado adjudicado y
19 tokens preexistentes medidos uno a uno: no había pasado por R-5.4.
LAS SEIS CLAVES SON LA MISMA COSTURA, DOS VECES
El patrón mesh leía var(--gradient-aurora) y los cinco pasos de escarcha leían
var(--blur-*), los dos A PELO: el VALOR es del sistema, el KNOB es del
componente. Con scrim-blur-* hay además una razón dura — `blur` es familia
MÉTRICA del eje `scaling` (theming §23), así que un literal ahí sería ciego al
zoom global.
TRES LITERALES FIRMADOS, Y EL GRANO NO SE ACUÑA
El 100% de img/video es identidad (una capa de medio ES la caja de su capa). El
grano del ruido es un feTurbulence en un data-URI: la textura ES la técnica —el
único patrón que el UA no elimina bajo forced-colors— y re-escaparlo para
meterlo en el contrato cambiaría el valor serializado sin cambiar la imagen. Su
mando sigue siendo pattern-noise-opacity.
EL 5 % QUE QUEDA ES CANAL DE VALOR
--_background-gradient-image lo escribe background-gradient.svelte EN LÍNEA
desde la prop `colors`. Un público encima no lo alcanzaría —el inline gana— y
mentiría: el caso de --gp-current-gradient y del preview-z que F2-B retiró.
UNA SOSPECHA MÍA, REFUTADA MIDIENDO
La línea del mesh hace lo que un apunte da por roto: un gradiente MESH por el
longhand background-image (su color base final no es capa de imagen válida →
computa `none`). Medido aquí: --gradient-aurora PINTA, porque su serialización
empieza por un radial-gradient. No hay defecto. La nota vale para un mesh
serializado con color base final, no para este token.
EL GUARD: DE 3/37 A 18/37, Y UNA LECCIÓN AL REVÉS
Las partes de este componente son CAPAS OPT-IN independientes (velo, foco,
pausa…), cada una tras su control, y sólo un patrón se renderiza a la vez: sobre
el escenario por defecto casi todo el contrato no tiene nodo que pintar. Nace
`prepareWith` — enciende TODOS los controles que se le den, al contrario que
`openWith`, que para en el primero — y con el barrido de data-pattern sube a 18.
Y la lección: MONTAR MÁS PUEDE MEDIR MENOS. Encender además el foco puntual, la
velocidad de paralaje y la profundidad bajó la corrida de 17 a 9: los tres
repintan el background-image y el translate de la MISMA capa donde se miden los
patrones. prepareWith se dejó en lo que no tapa.
LAS 19 ADJUDICACIONES, FORZANDO SOBRE LA CAPA REAL
Nunca sobre un nodo fabricado. Las dos del mask (fade-*, que el guard no puede
ver porque no fotografía mask-image — hueco de instrumento, §13), las dos del
contexto de tinta (on=dark/light), los ocho pasos de las dos escalas (blur 4→33,
8→33, 12→33, 24→33 px; strength alpha 0.08 · 0.13 · 0.4 · 0.7 → 0.9), el
gradient-drift-duration (24s → 42s, en una capa gradient que EXCLUYE a la de
patrón), los tres del foco puntual (40% → 42px…, y spotlight-fg sólo cuando la
capa NO lleva data-color: con él manda --palette-solid, por diseño), el
parallax-travel (sólo entra por las keyframes ligadas al scroll) y los dos de la
pausa (la demo no monta ese control: cero nodos).
AVISO: LOS CHIPS DE ESTA DEMO SE APLICAN CON RETRASO
Una comparación por chips capturó cada estado con el patrón ANTERIOR —el estado
«mesh» guardaba el glow— y dio 0 diffs por estar desfasada IGUAL en las dos
corridas: un gate verde sobre dos medidas equivocadas. La prueba buena fue la de
EQUIVALENCIA, determinista: cada token nuevo resuelve al mismo valor que el
primitivo que sustituyó (pattern-mesh-image = --gradient-aurora; scrim-blur-{k}
= --blur-{k} = 4/8/12/16/24 px) y lo pintado al forzar el atributo es idéntico
(el mesh pinta el aurora, el ruido pinta su data-URI intacto).
VERIFICACIÓN
Sonda estándar antes/después 0 diffs (384 valores · 7 estados) · equivalencia
token↔primitivo exacta en las seis · R-5.4 18/37 con las 19 restantes
adjudicadas y medidas, cero STALE · component:audit PASS · censo 95 % ·
eidos-lint 3 morfo-backed / 63 eidos-only / 0 invalid / 0 class-hooks ·
rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo es skin-media-player,
el conocido). Tras el cambio del guard, command, table, tooltip,
navigation-menu y waveform re-verificados sin regresión ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
3c6742b9c5 |
uix(color-field): temable — 56 % → 93 %, y sus TRECE tokens nunca se habían medido
Cuatro claves nuevas (22 → 26), un literal firmado, un préstamo adjudicado y
trece tokens PREEXISTENTES medidos uno a uno: el componente nunca había pasado
por R-5.4. Diff de computed 0 sobre 2.336 valores en 8 estados.
LAS CUATRO CLAVES
color-field IS-A Field y no realiasa nada suyo, así que lo que faltaba era
pequeño y concreto:
- separator-bg + separator-thickness — los separadores de canal («,», « / ») se
pintan como líneas verticales de un pelo, y ni su tinta (--color-border-default)
ni su grosor (1px) eran alcanzables. El 1px ES --border-width: es un filete, y
dropdown-menu.separator-thickness lee la misma familia. El MISMO nodo
renderizado como glifo («#», «%») ya tenía su literal-fg — una parte, dos
tratamientos, ahora los dos con mando.
- segment-min-width (3ch) + hex-segment-min-width (6ch) — el ancho fijo por
número de caracteres, el que impide el reflujo al teclear (99 → 100). Los
gemelos date-field y time-field cargan el mismo hecho DENTRO de un
calc(2ch + 2 * var(--…-segment-padding-inline)), así que el suyo ya viajaba con
un token; aquí iba a pelo. Precedentes de `ch` en el catálogo:
editable.area-min-inline-size (12ch) y tags-input.input-min-inline-size (8ch).
EL 7 % QUE QUEDA ES UNA FILA, Y ES DOCTRINA
El chip lee var(--field-control-radius) porque IGUALA el radio del control —el
comentario del CSS lo dice: «so the chip tracks the control»—. Qué DECIDE ese
token: el radio del control de campo. Un swatch-radius propio daría un segundo
mando para una decisión ajena y permitiría desincronizar el chip del campo que
lo contiene. Préstamo con dueño: se tema en la ficha de field — misma lectura
que el --slider-disabled-opacity de waveform, hoy mismo.
TRECE ADJUDICACIONES, TODAS PROBADAS SOBRE NODOS REALES
La demo arranca con valor, en md, editable y con tres formatos: cada estado y
cada paso de talla que no monta no tiene nodo que pintar. Seis de estado
(placeholder, invalid, los tres de readonly, disabled), cuatro de la escala del
chip (14→77, 16→77, 20→77, 32→77 px), la etiqueta del formato BLOQUEADO —que
sólo existe con un único formato permitido, medida desmarcando rgb y hsl CON LOS
CHIPS DE LA PROPIA DEMO, no fabricando el nodo— y las dos de transición.
LAS DOS DE TRANSICIÓN, DOS DIAGNÓSTICOS FALSOS Y EL SEGUNDO ES NUEVO
El primero es la ley ya escrita: el guard congela `transition` para hacer
medible todo lo demás, así que los tokens que SON la transición no se mueven
bajo él. El segundo fue mío: midiéndolas a mano leí 0s y sospeché del
@media (prefers-reduced-motion: reduce) del final del fichero — lo comprobé
corriendo con reducedMotion: 'no-preference' y SEGUÍA dando 0s, porque el nodo
que había cogido (querySelector('[data-color-field-segment]')) es el PRIMER
segmento, que es un `literal` y declara transition: none de su propia cosecha.
Sobre un segmento editable: 0.12s → 11.5s y cubic-bezier(0.4,0,0.2,1) →
steps(7). Mide el nodo que PINTA, no el primero que casa el selector.
VERIFICACIÓN
Sonda antes/después 0 diffs (2.336 valores · 8 estados · 10 nodos) · R-5.4 13/26
con las trece restantes adjudicadas y medidas, cero STALE · component:audit PASS
· censo 93 % · eidos-lint 14 morfo-backed / 14 eidos-only / 0 invalid / 0
class-hooks · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo es
skin-media-player, el conocido) · Chrome: los dos glifos con tinta y sin fondo,
el divisor a 1px con el fondo del borde, hex 64.4px (6ch), chip 18px.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
11b92ded6f |
uix(waveform): temable — 55 % → 86 %, y el playhead era el ÚNICO primitivo crudo
UNA clave nueva, cuatro literales firmados, un préstamo adjudicado. Diff de computed 0 sobre 1.600 valores en 7 estados; R-5.4 11/11, CERO adjudicaciones. LA CLAVE NUEVA NO LA PIDIÓ EL CENSO, LA PIDIÓ EL FICHERO `playhead-bg`. Todas las demás líneas del re-tinte del Slider embebido leen ya un token propio (--slider-secondary-bg: var(--waveform-buffered-fg)) o una identidad (transparent / none / 0px / 1); el thumb era la ÚNICA que pasaba un primitivo CRUDO (--color-content-primary) a un componente compuesto. Con eso, repintar el playhead exigía mover --slider-thumb-bg (todos los sliders de la app) o --color-content-primary (todo). Ahora es el par natural de `playhead-width`, que ya existía. El molde es el re-tinte de media-player, que reenvía --media-player-* en cada línea. El censo no lo veía: una custom property reenviada a un componente compuesto no entra en KNOB_PROPS (D-TH.2). La clase entera queda anotada en §13 — toda receta que re-tinta un embebido puede pasarle primitivos crudos sin que nada lo vea. EL 14 % QUE QUEDA ES UNA FILA, Y ES DOCTRINA La onda deshabilitada lee var(--slider-disabled-opacity). La prueba de si un token es tuyo no es qué valor tiene sino QUÉ DECIDE: aquí decide cuánto se apaga un control deshabilitado, y eso es del Slider — la onda vive fuera de su caja pero es la misma superficie a la vista. Un --waveform-disabled-opacity daría un segundo mando para UNA decisión y permitiría desincronizar cromo y pintura. Préstamo con dueño: se tema en la ficha de slider, como el 82 % de time-picker se tema en la de field. LOS CUATRO LITERALES SON IDENTIDAD, Y AHORA LO DICEN La pintura ES la caja del provider (100% sobre un position:absolute; inset:0), el área de arrastre ES la caja entera («scrubbing means grabbing anywhere on it»), y un playhead abarca todo el alto por definición. Anotación /* literal: */ en su declaración: desviación firmada, fuera del ratio. EL INSTRUMENTO, CIEGO POR UNA CAUSA NUEVA: EL COMPONENTE COMPUESTO La sonda medía 4 nodos —provider, svg y los dos paths— y NINGUNO era el playhead: el cromo entero es un Slider embebido cuyos nodos llevan data-slider*. Con extraNodes, 8. Es la TERCERA cara del mismo agujero: HTML crudo (prose), partes que compone el consumidor (navigation-menu) y partes de un componente compuesto (waveform). En §13, con la pregunta de fondo: hoy hay que sospecharlo y contar los nodos, el instrumento no lo detecta solo. VERIFICACIÓN Sonda antes/después 0 diffs (1.600 valores · 7 estados · 8 nodos) · R-5.4 11/11 sin adjudicaciones · component:audit PASS · censo 86 % con la única fila restante explicada · eidos-lint 4 morfo-backed / 16 eidos-only / 0 invalid / 0 class-hooks · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo es skin-media-player, el conocido) · Chrome: playhead 2px × 40px, onda 544 × 40, trazo 0.6 — idénticos. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
85988785d4 |
uix(navigation-menu): temable — 44 % → 100 %, y el guard cerraba el panel que medía
Bloque B1 de D-TH.4. Contrato 26 → 44 claves: 19 nuevas y UNA retirada.
Diff de computed 0 sobre 2.752 valores en 8 estados; R-5.4 43/44 con una
adjudicación escrita. Global 65 % (al 100 % 25 → 26).
LOS NOMBRES LOS DIO EL CATÁLOGO, NO YO
Ninguno se inventó. Los gemelos cerrados el mismo día (dropdown-menu 96 %,
context-menu 87 %) dan content-{min-width,padding,radius,fg} y
chevron-{size,stroke}; accordion da trigger-font-family y disabled-trigger-fg.
Las cuatro recetas que declaran un chevron lo dimensionan con un LITERAL
(0.42em · 0.5em · 0.625rem): un glifo no es un paso de la escala de espacio.
Al revés con el subrayado del indicador: su 2px ES --border-width-medium, y
dropdown-menu.separator-thickness dice que un grosor decorativo se nombra por
esa familia.
LA §4 GENERADA FALLA DE CINCO MANERAS, UNA NUEVA
Llamaba trigger-width / trigger-height al CHEVRON — nombrando por el primer
selector de la regla ([…-trigger]::after) y colisionando con trigger-height,
que YA EXISTE y es la altura del control. Fundía en content-radius dos nodos
con dos valores. Cruzaba los nombres: content-padding-* para lo que es de la
FILA, y el padding real del panel a «sin nombre mecánico». Llamaba
content-width a un min-inline-size. Y la nueva: abría exigiendo «consume la
capa compartida menu-indicator» — HOMONIMIA, esa capa es el check de los
CheckboxItem de dropdown/context-menu y no toca el subrayado de esta barra
(LAYER_VOCABULARY sólo registra calendar-surface).
LAS FILAS DEL PANEL NO SON item- NI link-
En los gemelos, `item` ES la fila. Aquí `item` es el <li> de la barra (parte
del morfo) y el Link de barra viste el cromo del trigger: --…-item-radius o
--…-link-radius prometerían a un tema un nodo que no alcanzan. Se acuñan
content-link-*, que nombra el nodo por donde vive. Su tinta sigue leyendo
trigger-fg, como venía.
EL PRIVADO ERA UNA ESCALA, NO UN CONMUTADOR
--_navigation-menu-list-gap tenía tres fuentes (0 / --space-1 / --space-2) por
data-size: sube al TSC como list-gap-{sm,md,lg} + el resuelto, el molde que el
bundle del trigger ya tenía al lado. Los dos bloques [data-size] del CSS se
retiran — los emite el TSC, y dejarlos vivos da un diff de 0 por la ruta vieja.
indicator-x ERA DECLARACIÓN MUERTA
Soma escribe las cuatro coordenadas del rect INLINE sobre el indicador
(-x, -y, -w, -h) y la receta lee sólo -w y -h; su propio comentario registra
que sumar translateX(var(--…-x)) DUPLICABA el desplazamiento. No la leía
nadie. Retirada, 0 diffs — la prueba de que estaba muerta (precedente: el
re-point de --command-radius, el trío item-gap* de carousel). -w se queda:
vive, y es canal de valor, no superficie de tema.
EL PANEL NO ACUÑA TIPOGRAFÍA, A PROPÓSITO
Lleva [data-depth='overlay'], y ese plano declara font-family / line-height a
la misma especificidad (0,1,0) y más tarde en la cascada: un token ahí leería
muerto. Es §12.9, pendiente de firma — la misma que hizo retirar claves en
menubar, dropdown-menu, context-menu y tooltip. Sí se acuña la familia de la
BARRA (trigger-font-family), que no es overlay y alcanza.
TRES COSAS QUE APRENDIÓ EL INSTRUMENTO (registradas en next-features §13)
1. Sonda y centinela eran CIEGOS A LA MITAD DEL COMPONENTE. Las filas del
mega-menú son los <a> DESNUDOS del consumidor, estilados por descendencia:
el filtro data-{c}-* veía 10 nodos y NINGUNO era el panel ni una fila — 9
de los 19 knobs fuera del diff. Con EXTRA_NODES / extraNodes la sonda pasa
a 16 nodos abiertos. Y el paso `open` de la sonda no honraba EXTRA_NODES.
2. EL GUARD CERRABA EL PANEL QUE MEDÍA. Este mega-menú abre con pointerenter
y pointerleave programa el cierre; el guard abría con clic y luego aparcaba
el puntero en (0,0) — justo el gesto que lo cierra. Dos corridas del mismo
código discrepaban. Y daba las DOS caras del error: falso negativo en los
tokens de la fila, falso positivo en content-link-padding-inline, que leía
«vivo» por ensanchar el panel que sí se medía. Con openBy: 'hover', dos
corridas idénticas.
3. `color` está EN TRANSICIÓN en esta parte: forzar data-disabled y leer en el
acto devuelve el valor VIEJO — tres diagnósticos falsos («ni el inline lo
mueve») hasta congelar. La trampa del cuentagotas del color-picker, en otro
componente. Congelado: reposo oklch(0.2435 0 0) → disabled oklch(0.61 0 0).
Y una de contabilidad, del instrumento y no del componente: el censo decide el
eje `size` grepeando data-size en el CSS, y el protocolo §7.4 ORDENA retirar
esos bloques. Todo componente que lo aplique bien aparece «sin eje». Ya le
pasa a sidebar y nav-tree. En §13.
VERIFICACIÓN
Sonda antes/después 0 diffs (2.752 valores · 8 estados · 16 nodos con el panel
abierto) · R-5.4 43/44 en dos corridas idénticas, adjudicación única
(disabled-trigger-fg: la demo no monta el estado; forzado alcanza en trigger Y
link, rgb(1,2,3)) · component:audit PASS · censo --only 100 % · eidos-lint 30
morfo-backed / 3 eidos-only / 0 invalid / 0 class-hooks · rtl:check 0 ·
docs:check 0 · suite eidos 439/440 (el rojo es skin-media-player, el conocido)
· check sin error nuevo en los ficheros tocados · Chrome con el panel abierto:
panel 8/10px/224px, fila 8/12/6px, trigger 36px/6px/gap 4px, indicador 2px.
Tras tocar el guard, command, table y tooltip re-verificados sin regresión ni
STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
83a897b925 |
uix(audio-player): temable — 37 % → 56 %, y el instrumento medía CERO nodos
3 claves nuevas (5 → 8) y un literal anotado. El 44 % restante es PRÉSTAMO CON DUEÑO, no deuda: ocho filas que leen `--media-player-*` porque este componente ES la piel de audio de ese chasis, y una ficha nunca propone duplicar un token prestado con prefijo propio (§5.3-3). Acuñado lo único que ESTE reproductor añade sobre el chasis: el peso del título y la insignia LIVE en versalitas espaciadas (peso + tracking). Los dos `600` pasan a `var(--font-weight-semibold)`: el mismo valor, con nombre. Y EL INSTRUMENTO ESTABA CIEGO DEL TODO: MEDÍA 0 NODOS. Tres razones encadenadas: 1. `/uix/components/audio-player` es un 404 — el CUARTO canónico sin ruta propia (picker-shell, mockup, surface y éste). Se mide en la demo del chasis. 2. Sus partes no llevan `data-audio-player-*`: son `data-media-player-*`. Con `extraNodes`, la sonda pasa de 0 a 48 NODOS. 3. Sólo existe tras el chip `media: audio` de esa demo: sonda (`DEMO_VARIANTS`) y guard (`openWith` + `openMarker`) lo pulsan ahora, y el guard barre además las cuatro variantes (card/row/bar/inline). Con eso, 0/8 → 6/8. Las dos que quedan son la insignia LIVE, que sólo existe mientras el proveedor refleja un directo: montada con `[data-live]`, alcanza (600 → 333 y 1,28px → 7px). Gates: sonda con 48 nodos (antes 0) · centinela 6/8 con las dos adjudicadas · censo 56 % · suite eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0 · equivalencia comprobada en el computado (título 600, tracking 1,28px). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
0c362cedd5 |
uix(theming): cola pequeña — seis componentes, y una receta que TAPABA sus claves
`section` (cuatro claves resucitadas), `sticky` 0 → 100 %, `button-group` 40 →
100 %, `qr-code` 43 → 100 %, `toggle-group` 33 → 50 % (su techo) y `split-button`
adjudicado en 50 % (el suyo). Cero claves nuevas. Global 65 %, 25 componentes al
100 %, y los de alcance <20 % bajan de 14 a 12.
EL HALLAZGO ESTÁ EN `section`: LA RECETA TAPABA SUS PROPIAS CLAVES PÚBLICAS.
Declaraba los cuatro pasos de relleno en el host
(`[data-box][data-section] { --section-padding-block-sm: … }`), y esa declaración
gana a la que el contrato emite en `:root`: un tema que escribiera
`--section-padding-block-lg` perdía contra la receta. Borrado el bloque —mismos
valores, una sola fuente—, computado idéntico (48px antes y después), y las
cuatro claves alcanzan.
Lo demás es IDENTIDAD: once `100 %` entre las seis recetas y el centinela de 2px
del sticky —el hilo invisible que el observador vigila—, todos con su razón
escrita. Más un respaldo muerto retirado en `toggle-group`, sobre un token
PRESTADO de `toggle`: el velo de un grupo deshabilitado ES el del toggle, y se
tema en su ficha (§5.3-3).
Y UNA CLASE DE ADJUDICACIÓN NUEVA, QUE SE REPETIRÁ: UN PASO POR INSTANCIA.
`section` y `qr-code` mapean su prop de talla a `var(--{c}-{eje}-{k})` y la
escriben INLINE, así que sólo el paso ACTIVO alcanza; los otros leen muertos
hasta que la prop cambia. No es deuda ni ceguera del instrumento: es cómo
funciona una escala resuelta por prop.
Gates: los seis guards en verde · censo 65 % · `component:audit` PASS · suite
eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
6d199133c7 |
uix(tooltip): temable — 52 % → 75 %, y el plano ANULA SUS TRES VARIANTES
3 claves nuevas y 4 literales anotados. Subiría más, pero medir destapó que cinco de sus claves no pintan: el plano `overlay` le gana la superficie ENTERA. Acuñados el desenfoque del velo `ghost` y las dos tintas de la flecha `outline`, que se pintan por selector HERMANO desde el contenido. ⚠⚠ EL PLANO NO SÓLO SE QUEDA LA TIPOGRAFÍA: SE QUEDA EL FONDO, EL BORDE Y LA SOMBRA. `[data-depth='overlay']` declara las tres con la misma especificidad que `[data-tooltip-content]` y más tarde en la cascada. Medido: escribir `--tooltip-bg`, `--tooltip-border` o `--tooltip-shadow` no mueve NADA, mientras `--depth-overlay-surface` / `-border` / `-shadow` repintan el panel. Con `font-family` y `line-height`, son cinco públicos que no alcanzan. Y LA CONSECUENCIA VISUAL ES PEOR QUE LA CONTABLE: LAS TRES VARIANTES SON LA MISMA. Medidas `solid`, `outline` y `ghost` con el panel abierto: fondo, borde y sombra IDÉNTICOS en las tres. `outline` es indistinguible de `solid`; `ghost` sólo se diferencia por un `backdrop-filter` que no se ve porque la superficie que tiene delante es opaca. La máquina de variantes existe, alimenta privados, y el plano la anula entera. → §13. Por eso no se acuñó `ghost-bg`: lo intenté, el centinela lo delató y se retiró antes de commitear. Las cinco que ya estaban quedan ADJUDICADAS, no retiradas: son la FUENTE de esa máquina de variantes, y borrarlas dejaría inválidos los privados sin arreglar nada. La corrección de fondo es la precedencia del plano — la misma firma §12.9 que arrastran menubar, dropdown-menu y combobox. `content-z` sí está vivo, pero en otro nodo: aterriza en el ENVOLTORIO flotante (90 → 4321), que no lleva ningún `data-tooltip-*` y queda fuera del conjunto medido. Instrumento: un tooltip abre por HOVER, no por clic (`openBy: 'hover'`, como link-preview) — con eso pasó de 0/24 a 14/24. El resto se midió con el interruptor `open` de la demo: un panel abierto por puntero exige el ratón quieto sobre el disparador toda la pasada, y no es medida fiable. Gates: sonda 0 diffs en 256 valores × 8 estados · centinela 15/23 con las ocho adjudicadas · censo 75 % · suite eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
694fcb99dc |
uix(surface): ADJUDICADO — el 25 % es su techo, y su ruta de demo es un 404
Cero claves nuevas: sus cuatro knobs son, uno a uno, doctrina bien aplicada. Surface es la cara de PINTURA de Box, y lo que pinta no es suyo: `bg` y `fg` salen del PUENTE DE PALETA (THM-2) —que es exactamente cómo un tema llega a ellos, por el color— y `--_surface-fill-finish` es el CANAL DE VALOR del acabado de degradado, que el generador deriva por instancia (§39). La rama `inherit` del `fg` suave es intencionada: la tinta del contenido se queda en la global porque el tinte del track es discreto, y está escrito en la receta. PERO NO TIENE RUTA PROPIA: `/uix/components/surface` es un 404, como `picker-shell` y `mockup`. El guard medía una página VACÍA y reportaba 0/25 — incluido `radius`, que está vivísimo—. Apuntado a `/temas/gradientes` (cuatro surfaces, dos variantes, tres colores) y a `/blocks/cta`: 1/25, y el que mueve es el radio (10px → 1234px). Ya son TRES los componentes del canon sin demo → §13. Sus 24 claves de tono son la SUPERSESIÓN de la cascada de paleta medida hoy en `button`: el bloque genérico va el último y gana por orden. Adjudicadas con el patrón compartido. Gates: centinela 1/25 con las 24 adjudicadas · censo 25 %, que es el techo · `docs:check` 0 · sin cambios de código. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
c751b3fb45 |
uix(banner): temable — 30 % → 100 %, y el guard pasa de 4/42 a 53/53
11 claves nuevas (42 → 53). Su contrato ya era grande —40 claves de intención— pero su CROMO estaba a pelo: la densidad por talla, la interlínea y el trazo del anillo de `outline`, que era la última fila que impedía al privado del borde derivar de un público. Dos ausencias firmadas: los `transparent` de `outline` y `ghost` y los tres `border-width: 0`. La variante ES la ausencia de cromo — mismo criterio que button, y por la misma razón: diez claves de `transparent` no son un contrato, son ruido. EL INSTRUMENTO NO VEÍA 38 DE SUS 42 CLAVES, Y NINGUNA ESTABA MUERTA. Dos cegueras a la vez: 1. Su paleta resuelve por `data-intent`, NO por `data-color`. El barrido de tono del guard —añadido esta mañana para button— estampaba sólo `data-color`. Ahora estampa los DOS nombres: un componente selecciona por uno y el otro queda inerte. 2. Y luego por VARIANTE: las ranuras `solid`/`contrast` sólo pintan en `solid`, la de borde sólo en `outline`, y la demo monta una de cada. Con `sweepAttr` sobre `data-variant`, el guard las recorre. Con las dos, 4/42 → 53/53. Es la diferencia entre «38 tokens que mienten» y «38 tokens que nadie había mirado con el atributo puesto»: exactamente lo que R-5.4 existe para distinguir. Gates: sonda 0 diffs en 192 valores × 7 estados (la demo monta UNA franja) · centinela 53/53 sin una sola adjudicación · censo 100 % · `component:audit` PASS · suite eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0 · captura de las cuatro variantes con cuatro intenciones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
7fabee1972 |
uix(anchor-nav): temable — 20 % → 100 %, y el censo aprende los bordes POR LADO
11 claves nuevas (2 → 13). Tenía dos knobs y todo lo demás a pelo: la escala del
índice (que ahora lee el bundle, no `--font-size-sm` suelto), el relleno y el
radio del enlace, sus tres tintas —reposo, hover y activo—, el peso del activo y
LAS DOS TINTAS DEL RAÍL, que es lo que da nombre al componente.
EL RAÍL ACTIVO ESTABA INVISIBLE PARA EL CENSO. Su color vive en un
`border-inline-start-color`, y `KNOB_PROPS` sólo conocía `border-color` y los
shorthands: los ocho longhands por lado (`border-{top,bottom,left,right,
block-start,block-end,inline-start,inline-end}-{color,width}`) no eran knobs para
la medida. El centinela los mira desde el 2026-08-22 —los añadió cuando prose y
nav-tree leyeron muertos—; el censo, no. Corregido: +30 FILAS EN EL CATÁLOGO
(5.101 → 5.131 knobs), y esta ficha baja de 20 % a 18 % antes de coserse, que es
lo honesto: el censo promete sobre-reportar, nunca infra-reportar.
La tinta de reposo del raíl estaba escondida de otra manera: dentro del shorthand
`border-inline-start: var(--anchor-nav-rail-width) solid var(--color-border-subtle)`,
que el censo clasifica por el PRIMER token que casa —el trazo, ya público— y da
la fila por alcanzable. No hizo falta partir el shorthand: basta con nombrar el
color dentro.
Un susto útil: una coma que faltaba en el contrato rompió el build de tokens, y
lo que lo delató fue la SONDA midiendo 0 nodos — la página no renderizaba. El
recuento de nodos es el canario, tal como dice el handoff.
Gates: sonda 0 diffs en 1.760 valores × 7 estados (8 nodos) · centinela 11/12 con
el radio del foco adjudicado (el guard desenfoca a propósito) · censo 100 % ·
`component:audit` PASS · suite eidos con el rojo conocido ajeno · `rtl:check` 0 ·
`docs:check` 0 · captura del raíl.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
c08e88598d |
uix(image): temable — 60 % → 96 %, y dos instrumentos que morían en esta página
Una clave nueva y 12 literales anotados. La fila que queda fuera es el puente de paleta del placeholder de color, que no es deuda. Su «deuda» era casi toda IDENTIDAD: once `100 %` —la imagen, el fallback, el error y sus dos `<img>` llenan su caja— y un `opacity: 1`, porque una imagen CARGADA es opaca. Ninguno es una perilla, y ahora los doce llevan su razón. Lo acuñado es la barra del esqueleto (`skeleton-bg`): leía `--gradient-shimmer` a pelo, y es lo único de ese placeholder que un tema querría retocar sin tocar todas las recetas que brillan. LA PÁGINA NO ALCANZA `networkidle` NUNCA: monta un `src` roto a propósito para su estado de error y el navegador reintenta, así que sonda y guard morían con un `TimeoutError` antes de medir un solo nodo. Las dos caen ahora al evento `load` si la espera de red se agota — la ociosidad era una comodidad, no una garantía. UN TOKEN BAJO `@media (prefers-reduced-motion: reduce)` LEE MUERTO: `placeholder-base` sólo existe ahí, donde el brillo se sustituye por un plano. Emulando la preferencia alcanza, y vale para cualquier token detrás de una media query de preferencia. Y una lectura fantasma cazada por repetición: el primer diff acusó `opacity: 0.925793 → 1` en la imagen cargada. Era el fade EN VUELO —el mismo falso positivo que el rim animado de `onion-menu` esta mañana—. Repetida la medida: 0 diffs. Un comentario CSS no puede mover un computado. Gates: sonda 0 diffs en 544 valores × 7 estados (medida repetida) · comprobación aparte del esqueleto y del base de movimiento reducido · centinela 20/23 con las tres adjudicadas · censo 96 % · `component:audit` PASS · suite eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
0aa0e8997d |
uix(checkbox): temable — 59 % → 72 %, y un HUÉRFANO que el test no puede ver
3 claves nuevas, 3 literales anotados y un token del contrato CABLEADO. El 28 % que queda es el puente de paleta (`--_checkbox-palette-*`, THM-2): ocho filas que no son deuda. EL HALLAZGO: `indicator-fg` ERA UN HUÉRFANO QUE EL TEST DE HUÉRFANOS NO PUEDE VER. La clave llevaba en el contrato desde siempre, pero la receta pintaba la tinta de la casilla marcada leyendo `--color-content-on-solid` DIRECTAMENTE, sin nombrarla nunca — y el test busca el NOMBRE en los ficheros del componente, así que un token que nadie menciona pasa por vivo. Cableado (`--_checkbox-palette-text: var(--checkbox-indicator-fg)`), computado idéntico, y el propio guard lo confirmó marcando su adjudicación como STALE: ahora mueve. Es la clase inversa del `--popover-bg` que vivía de un COMENTARIO. Acuñado el estado INVALID, que gana a todas las variantes y leía el primitivo: el borde y el DOBLE ANILLO DE FOCO (hueco + anillo), que era una sombra con dos colores cableados. La geometría (2px/4px) se queda dentro de la declaración: es la forma del anillo, no una perilla. Tres literales pasan a excepción por identidad: el glifo llena su caja (`100 %` × 2) y la etiqueta de grupo es su texto (`fit-content`). Los 26 rojos del guard, medidos — y dos son trampas de ALCANCE del instrumento: - El glifo SÓLO existe dentro de una casilla MARCADA, y la primera de la demo está vacía: medir el trazo por talla sobre «el primer indicador del documento» mide otro nodo. Con el path dentro de la misma casilla, los cinco pasos alcanzan. - La etiqueta de grupo lleva su PROPIO `[data-disabled]`: no lo hereda del grupo, así que forzar el grupo no pinta nada. El resto es lo esperable (invalid, disabled, los cuatro de transición que el guard congela) y los ocho de TONO, que son la supersesión de la cascada de paleta medida hoy en `button`: adjudicados con el patrón compartido. Gates: sonda 0 diffs en 2.688 valores × 7 estados (13 nodos) · centinela 22/47 con todo lo demás adjudicado · censo 72 % · `component:audit` PASS · suite eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0 · captura de marcada, invalid, disabled, xl y tono affirm. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
e276bb0cce |
uix(dropdown-menu): temable — 57 % → 96 %, y la tipografía del gemelo se RETIRA
9 claves nuevas (20 → 28) y 18 respaldos muertos retirados. Y una corrección a la baja, a propósito: `context-menu` 90 % → 87 %. Es el GEMELO de `context-menu`: mismos nombres, misma doctrina, mismas dos limpiezas de paso —el `font-family` era respaldo de SÍ MISMO y el peso del encabezado llevaba un `500` muerto detrás del token que ya vale 500—. Cosidos la tinta del panel y de la fila, su interlínea, el encabezado entero (tinta, peso y tracking) y el galón del submenú, que ahora tiene sus dos knobs: trazo y caja. EL FILO DEL SEPARADOR DEJA DE SER UN `1px` SUELTO y pasa a ser el trazo fino del sistema (`--border-width`, idéntico hoy): un tema que engorde el hairline lo engorda también aquí. Los 18 respaldos: cada `var(--dropdown-menu-x, …)` llevaba detrás un valor que NO puede ocurrir —las 18 claves están en el contrato— y sólo servía para envejecer contra él. Ninguno movía un píxel; dos ya discrepaban del contrato en la FUENTE. ⚠ `content-font-family` NO SE ACUÑA, Y LA DEL GEMELO SE RETIRA. El panel lleva `data-depth='overlay'` y el PLANO declara la familia con la misma especificidad y más tarde en la cascada: gana él. Quinta prueba de §12.9. `context-menu` la tenía acuñada desde esta misma sesión CON una adjudicación escrita, y eso era media doctrina: un público que no alcanza es un token que miente (R-5.4). Las dos recetas vuelven a su fuente literal con la razón encima. Un tercer caso —`combobox`, misma clave, mismo plano— queda medido y registrado en §13; no se toca aquí porque no es el componente en curso, y cuando §12.9 se firme la decisión será la misma para las cuatro. Gates: sonda 0 diffs en 928 valores × 8 estados (22 nodos con el panel abierto) · centinela 27/28 con la deshabilitada adjudicada · censo 96 % · `component:audit` PASS · suite eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0 · captura del panel abierto. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
c15873be2e |
uix(callout): temable — 27 % → 79 %, y la base óptica deja de copiar el sistema
7 claves nuevas (28 → 35) y un literal anotado. El 21 % que falta es el PUENTE DE PALETA (THM-2), que no es deuda: es la vía por la que `data-color` resuelve los 8 roles y las 33 escalas donantes sin una línea de CSS extra. Global 64 %. Cosido lo que la receta consumía a pelo: el hueco de fila, la tipografía del cuerpo (`font-size` + `line-height` — así se lee una admonición), la tinta, el tamaño del icono y el peso del título. Los tres pasos leen el BUNDLE (`--size-md-font-size`, `--size-md-font-line-height`, `--size-md-icon-size`). LA LÍNEA BASE ÓPTICA DEL ICONO DEJA DE REPETIR LAS MÉTRICAS DEL SISTEMA: era `calc(var(--size-md-font-size) * var(--font-line-height-md, 1.5))` y ahora es `calc(var(--callout-font-size) * var(--callout-line-height))` — la misma derivación, sobre los tokens del propio callout, así que un tema que agrande la copia mueve la caja del glifo con ella. Cinco respaldos muertos retirados: `var(--callout-gap, var(--space-3))`, `padding`, `accent-width`, `radius` —las cuatro claves están en el contrato— y el `, 1.5` de `--font-line-height-md`, que además MENTÍA: el token existe y vale 1.45. Los 24 rojos del guard son los TONOS, y no son de este componente: es la supersesión de la cascada de paleta que `button` destapó hoy (el bloque genérico va el último y gana por orden). Adjudicados con el patrón compartido, que ahora nombra su razón una sola vez para los dos componentes. Gates: sonda 0 diffs en 896 valores × 7 estados · centinela 10/34 con los tonos adjudicados · censo 79 % · `component:audit` PASS · suite eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0 · `check` sin errores propios · captura de cuatro tonos. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
e68b01f840 |
uix(button): temable — 55 % → 91 %, y la cascada de paleta ANULA 419 claves
Una clave nueva y 17 declaraciones anotadas. Al medirlo salió lo más gordo del
eje hasta hoy: 56 de las 106 claves públicas de este componente no pintan nada,
y no por deuda suya.
Acuñado lo único que faltaba: EL PASO `full` DE LA ESCALA DE RADIO —
`[data-rounded='full']` leía el primitivo global a pelo, así que la forma que
más se retoca (la píldora) era el único escalón fuera del contrato.
Diecisiete declaraciones pasan a excepción firmada, de dos clases: IDENTIDAD
(`fit-content` × 2 —un botón ES su contenido—, el `100 %` de `[data-block]` y
los cuatro `1px` de las cajas sr-only) y AUSENCIA (los `transparent` de `soft`,
`outline`, `ghost` y `plain`: la variante ES la ausencia de cromo, y ponerle
fondo a un `ghost` es pedir un `soft`). Diez claves de `transparent` habrían
sido justo el antipatrón que la doctrina avisa: agrupa por VALOR.
Para que la ausencia cuente, EL CENSO APRENDE LA VÁLVULA UN PISO MÁS ABAJO: un
PRIVADO cuyo valor es un literal CON su razón escrita es una ausencia firmada,
no deuda. Sin eso, cuatro privados marcaban «no deriva» y seis knobs leían
inalcanzables mientras todas las demás ramas del mismo privado leen un público.
⚠⚠ EL HALLAZGO: LA CASCADA DE PALETA ANULA LOS TONOS DEL COMPONENTE.
El último bloque del forward, `[data-button][data-color]`, resuelve
`--button-palette-*` desde el `--palette-*` GLOBAL —que `[data-color='{tono}']`
llena desde `--color-{tono}-*`— y gana a las reglas por tono por ORDEN, con la
misma especificidad (0,2,0). Medido sobre `data-color='risk'`:
`--button-risk-solid` no mueve nada, ni en `:root` ni en el nodo, mientras
`--palette-solid` y `--color-risk-solid` en el nodo repintan. Las siete
`primary-*` son el RESPALDO de esa misma regla y sólo actúan SIN `data-color`.
No es de este componente: 49 recetas emiten el mismo forward genérico y el
contrato tiene 419 CLAVES DE TONO. Medido igual en `badge` y `callout`. El
arreglo cabe en el orden de emisión —el genérico ANTES de los de tono— y no
movería un píxel, porque el valor por defecto de `--button-risk-solid` ES
`var(--color-risk-solid)`; pero cambia el contrato de la jaula del color (un
ancestro que inyecte `--palette-*` dejaría de pisar un tono semántico). Es
firma. → §13.
El techo restante son dos filas de canal de valor: `--_button-fill-finish`, el
acabado de degradado que el generador deriva por instancia.
Un error de método, anotado porque casi cuela: anclé la clave nueva en la
primera línea `'radius-xl'` del fichero y aterrizó en `meter`. Lo delató el
navegador (`--button-radius-full` sin definir ⇒ radio 0). Una inserción se
ancla en el BLOQUE del componente, nunca en una línea de clave.
Instrumento: el guard aprende `sweepAttr` (barrer una variante mientras mide) y
a estampar el TONO que la clave nombra; y el fichero de excepciones gana
PATRONES, para que una razón arquitectónica se escriba una vez y no 56.
Gates: sonda 0 diffs (416 valores; la demo monta UN botón) · equivalencia del
paso `full` comprobada aparte · centinela 34/106 con todo lo demás adjudicado ·
censo 91 % · `component:audit` PASS · suite eidos con el rojo conocido ajeno ·
`rtl:check` 0 · `docs:check` 0 · `check` sin errores propios · captura de las
seis variantes + píldora + tono `risk`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
c679b1b449 |
uix(onion-menu): temable — 29 % → 84 %, y una regla que el navegador DESCARTA
7 claves nuevas (12 → 19) y 5 literales anotados. Lo que queda fuera son TRES filas y ninguna es deuda de tokenización: una es canal de valor y dos viven en una regla inválida. Acuñado el color del ANILLO DEL SECTOR —uno para los dos estados, porque el propio comentario del CSS dice que el hover usa «el mismo color que el anillo de selección, más claro» y lo que los separa es la opacidad, que ya tenía token—, la tipografía de la etiqueta, el radio y la tinta del disparador, y las dos piezas del glifo `+`→`×`. Dos limpiezas de paso: un `var(--style-label-font-family, var(--style-label-font-family))` —respaldo de sí mismo, el defecto que ya se cazó en context-menu— y dos `var(--radius-full, …)` con un respaldo que no puede ocurrir. Cinco literales pasan a excepción POR IDENTIDAD: dos `opacity: 1` que DESHACEN un atenuado (sin atenuar es 1 por definición) y la caja del icono. ⚠ `.onion-menu-icon :global(svg)` NO EXISTE. `:global()` es un envoltorio de SVELTE y esto es un CSS plano: el selector es inválido y el navegador descarta la regla entera. Medido: el glifo computa 14px —el tamaño propio del Icon— y el `70 %` que el fichero cree pintar no pinta. Acuñé un `icon-glyph-size`, el centinela lo delató y lo RETIRÉ; los literales se quedan con el defecto escrito encima, porque arreglar el selector empieza a pintar el 70 % y MUEVE PÍXEL. Mismo bug en `timeline.css:331`; `image-picker.css` ya documentaba la trampa —la lección estaba escrita y se repitió—. → §13. Canal de valor: el fondo del disparador lo escribe el componente INLINE desde el motor de color, como los rellenos de cada sector. No es superficie de tema. TRES CEGUERAS DEL INSTRUMENTO, dos nuevas y genéricas: 1. EL GUARD CERRABA LA SUPERFICIE. Este menú nace ABIERTO y el clic de «abrir» lo cerraba: 12 de 20 tokens leían muertos. Ahora, si hay `openMarker` y ya casa, no se pulsa nada (8 → 14 de golpe). 2. Sus tripas cuelgan de CLASES, no de `data-onion-*`: sonda y guard las miden con `extraNodes` — 37 nodos en reposo contra los 5 con atributo. 3. Congelar las transiciones NO BASTA cuando el nodo está ANIMADO: `rim-glow-opacity` leía 0,482956 —el valor animado— y parecía muerto; con la animación congelada computa 0,45 y sigue al token. → §13. Los cuatro tokens del rim son del look `luminous`, que la demo del componente no renderiza (es una prop de Svelte que emite OTRO marcado, así que no hay atributo que forzar): medidos en `/active/docs/agnt`, que sí lo usa. Gates: sonda 0 diffs en 7.328 valores × 8 estados (37 nodos) · centinela 14/19 con las cinco adjudicadas · censo 84 % · `component:audit` PASS · suite eidos con el rojo conocido ajeno · `rtl:check` 0 · `docs:check` 0 · `check` sin errores propios · capturas de reposo, sector en hover y disparador. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
b7888f7a05 |
uix(field): temable — 73 % → 98 %, y sus 18 rojos estaban VIVOS
8 claves nuevas (60 → 68) y 8 literales ANOTADOS. Lo que falta es el PUENTE DE PALETA (`_palette-text`, THM-2), que no es deuda. Global 63 %. Field es el componente más COMPUESTO del sistema: lo que otras fichas llaman «préstamo con dueño» se cobra aquí, así que su techo pesa más que el de nadie. Acuñados el DISPARADOR DE CONTROL —el icono que abre el calendario, el reloj o la muestra, y revela la contraseña: `size`, `radius`, `fg` y sus dos estados—, el indicador `optional` (gemelo del `required`, que ya tenía token) y el lateral de la etiqueta flotante, que es lo que CORTA el borde bajo el texto. La caja del disparador se mide en `em` a propósito, así que el token guarda la RAZÓN (`1.75em`) y no un píxel por talla. OCHO LITERALES PASAN A EXCEPCIÓN FIRMADA POR IDENTIDAD, no para inflar el ratio: cuatro `inline-size: 100%` (el campo, el control, el input y el control flotante llenan su fila), dos `line-height: 1` (un glifo suelto no tiene interlínea) y dos `1em` del icono dentro del disparador (el glifo ES el tamaño del texto). LOS 20 ROJOS DEL GUARD ESTABAN VIVOS, uno por uno, y tres enseñan algo: - `disabled-opacity` vive en el CONTROL, no en la raíz: el guard leía el nodo equivocado. - `control-placeholder-fg` no leía porque el input de la demo NO TIENE `placeholder`: sin el atributo no existe la caja `::placeholder`, y `getComputedStyle(nd, '::placeholder')` devuelve entonces el estilo del ELEMENTO. Con un placeholder puesto, alcanza. Es genérico → §13. - `segment-height` es un token de FAMILIA que field posee y los pickers consumen —en las rutas de field no lo lee nadie— y además es RESUELTO (declarado por `[data-field][data-size]`), así que escribirlo en `:root` pierde POR DISEÑO: el tema mueve la coordenada. Medido en `/time-picker`: desde `:root` nada, desde el host del campo 28px → 1234px, y moviendo `--field-control-height-md` 28px → 992px. El resto son estado (invalid, disabled, readonly, foco), variante ghost, orientación horizontal, la franja de segmentos, el texto de error —que sólo se RENDERIZA con el interruptor de la demo: forzar el atributo no hace que Svelte monte el nodo— y los dos de transición, que el guard congela. Instrumento: el disparador de control no lo monta NINGUNA demo de field, así que el guard mide ahora `field` sobre DOS rutas (`/field` + `/date-picker`). Gates: sonda 0 diffs en 2.280 valores × 8 estados · equivalencia del disparador comprobada aparte en `/date-picker` (28px = 1.75em con fuente 16px · 4px = `--radius-sm` · misma tinta) · centinela 48/68 con las 20 adjudicadas · censo 98 % · `--names` 0 · `component:audit` PASS · `rtl:check` 0 · `docs:check` 0 · suite eidos con el rojo conocido ajeno · `check` sin errores propios · capturas de reposo, invalid, disabled, etiqueta flotante y disparador. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
df3c8d760e |
uix(menubar): temable — 15 % → 88 %, y el plano `overlay` GANA a la receta
30 claves nuevas (5 → 35): la barra (superficie, marco, radio —uno solo, la
receta lo desacopla de la talla a propósito y el motor de forma deriva el del
disparador de él— y las tres escalas `gap`/`padding`/`height`), el disparador
(tinta, tipografía, escala de `font-size` y de `padding-inline`, el par de la
entrada ABIERTA y la tinta deshabilitada) y el Panel `role=dialog` (tinta +
escala). Global 62 % → 63 %.
Los pasos leen el BUNDLE (`--size-{k}-control-height` / `--size-{k}-font-size`),
no el primitivo crudo que el CSS venía consumiendo; y el
`calc(var(--space-1) * 0.5)` del paso `sm` es `var(--space-0-5)` exacto.
EL HUECO DEL PANEL DEJA DE REPETIR EL VALOR DEL PADDING. Las tres reglas de
`--floating-gap` compensan el sangrado del disparador dentro de la barra con lo
que era una COPIA del padding; ahora leen `--menubar-padding-{k}`, su fuente —
si un tema ensancha el padding, el panel deja de quedar a ras de la barra. No
pueden leer el privado `--_menubar-padding`: esas superficies viajan POR PORTAL
y un privado declarado en la raíz no cruza esa frontera.
⚠ EL PLANO `overlay` GANA A LA RECETA — cuarta prueba de §12.9 y la primera con
MECANISMO. Acuñé `panel-font-family` y `panel-line-height` sobre declaraciones
que la receta YA tenía, y el centinela las dio muertas. Medido:
`[data-depth='overlay']` declara las dos con la MISMA especificidad (0,1,0) y
más tarde en la cascada, así que gana; del mismo bloque, `color` y `font-size`
—que el plano no declara— sí alcanzan. Retiradas del contrato y devueltas a su
fuente literal, con la razón escrita en el CSS. Mientras §12.9 no se firme, un
token de tipografía en CUALQUIER superficie `overlay` miente, y son veinte.
EL HOVER NO SE ACUÑA: ES DEL EJE navigation-menu. `background:
var(--color-surface-overlay)` sobre el disparador mata la capa del sistema
—medido: `background-image` computa `none` en hover con `--state-hover` vivo—,
por las dos razones que `navigation-menu.css` ya documenta al retirar esta
MISMA regla: el shorthand resetea `background-image`, y la regla del arquetipo
va en `:where()`, especificidad CERO. Acuñar un `hover-trigger-bg` habría
fosilizado la invención.
Instrumento: la barra suelta DOS superficies y el Panel —el que lleva sus
knobs— cuelga de la entrada «Format», no de la primera; sonda (`OPEN_TRIGGER`)
y guard (`openWith`) aprenden a abrir la que toca. Y el guard necesitó
`openMarker`: su comprobación de «ya está abierto» busca `[data-{c}-content]`,
que aquí no existe, así que volvía a pulsar el disparador antes de cada token y
CERRABA el panel — media corrida contra una superficie cerrada.
Gates: sonda 0 diffs en 1.470 valores × 8 estados · centinela 34/35 (la
deshabilitada, adjudicada) · censo 88 % · `--names` 0 desviadas ·
`component:audit` PASS · `rtl:check` 0 · `docs:check` 0 · suite eidos con el
rojo conocido ajeno (`skin-media-player`) · `check` sin errores propios ·
capturas de barra, tallas sm/lg, menú abierto y panel.
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 |