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 }
2042 Commits (d3089e880c9df14d258d4560f6a1660cf0b106c7)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
d3089e880c |
uix(link): temable — 0 % → 36 %, y ese techo bajo es la respuesta correcta
5 claves fusionadas en el bloque `link` de `recipes/base.ts` (donde ya vivían los dos forwards de paleta). Censo 0 % → 36 %. **Un enlace en línea hereda casi todo del texto que lo rodea**, así que su superficie de tema es pequeña por diseño. Sus dos escotillas por instancia (`--_link-font-size`, `--_link-line-height`) tienen como fallback `inherit`, y ese `inherit` es SEMÁNTICO: el enlace toma la tipografía del párrafo en el que vive. Convertirlo en token exigiría un público con valor `inherit`, que en `:root` no significa lo mismo — se quedan privadas. Con los dos forwards de paleta, ésos son los cuatro privados que forman el grueso del 64 % restante. Lo tokenizable es la GEOMETRÍA: radio del anillo, hueco del glifo externo, tamaño del glifo (`0.85em` en las dos dimensiones → UN knob) y el grosor y desplazamiento del subrayado, cada uno declarado en las DOS reglas que lo dibujan (`always` y `hover`) con el mismo valor. Las tres opacidades son sistema; el `fill: currentColor` del glifo es identidad, sigue a la tinta del enlace a propósito. **La cascada no se toca.** El CSS lleva dos correcciones de especificidad ya medidas y explicadas en su sitio (el `inherit` condicional, para que un `color` pedido por el consumidor no se descarte en silencio; y el `:active` al final, porque una pulsación es siempre también un hover). El diff de computed confirma que tokenizar no las altera. Artefactos y gates: - Sonda antes/después = 0 diffs en 203 valores × 7 estados. Determinismo verificado. - R-5.4: 2/5, los tres mudos adjudicados con su medición. Ninguno es deuda: el glifo externo no se monta en la demo (0 nodos, contados) y el enlace arranca en `data-underline='hover'` sin puntero encima, así que NO HAY subrayado que mover (`text-decoration-line: none`, `thickness: auto`). Forzando el estado, los tres alcanzan. - En el mismo pase, `text-decoration-thickness` y `text-underline-offset` entran en la lista de propiedades del guard, que no las miraba — verificado que los otros DIECISÉIS componentes con ledger no cambian. - censo --only 36 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio · README con «Talla y tema» y tab `Tokens` (5 claves). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
adb77863cd |
uix(kbd): temable — 0 % → 86 %, y 13/13 en el guard sin una sola excepción
13 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → 86 %. 1. **`font-family` NO se acuña**: lee `var(--style-code-font-family)`, la capa tipográfica, y un consumidor no re-declara el vocabulario de su capa — precedente inmediato, `code-block`. El `font-size` SÍ entra, y la diferencia está medida: su fallback era un PRIMITIVO, no la capa. `--_kbd-font-size` es la escotilla por instancia que el wrapper escribe desde la prop `size` (`kbd.svelte:37`), y el fallback pasa a ser el público. 2. **El padding y el min-width son em-relativos a propósito** — una tecla crece con su letra —, así que son knobs con valor `em`, no literales pendientes de corregir. El `line-height: 1` sí es identidad: una tecla no tiene interlineado. 3. **El relieve de tecla física es de la variante `surface`**: borde inferior más grueso + luz interior. Dos knobs propios, no adorno del borde general; outline y ghost son planas por identidad. Artefactos y gates: - Sonda antes/después = 0 diffs en 522 valores × 7 estados. Determinismo verificado. - R-5.4: **13/13**, sin una sola entrada en el ledger — el primero de la tanda que no necesita adjudicar nada. - censo --only 86 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con su «Talla y tema» y tab `Tokens` en la demo (13 claves, en vivo). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
650d76aa0e |
uix(drag-drop): temable — 0 % → 89 %, casi todo en el fantasma del arrastre
10 claves en el bloque `drag-drop` de `recipes/base.ts` (fusionadas con `preview-z`, que ya estaba, y los dos forwards de paleta). Censo 0 % → 89 %, cero globales. **Siete de sus dieciséis knobs YA eran sistema** y no entran al ratio (las opacidades de fantasma y deshabilitado, los dos anillos de foco y el anillo `inset` de los droppables), así que los puntuables eran nueve — seis de ellos en el PREVIEW, el fantasma que sigue al puntero. 1. Los dos forwards de paleta siguen privados (THM-2): el fondo del `[data-dragover]` los lee a pelo y no admite un público sin duplicar la regla — es el 11 % que falta. En cambio el `border` y el `box-shadow` del preview los COMBINAN con una anchura y una sombra que sí son knobs propios, así que esas dos declaraciones entran al alcance. 2. El `--ring-inset-*` de los droppables no se toca: es vocabulario del anillo del SISTEMA y la receta se limita a alimentarlo con su acento. Acuñar un `droppable-ring-*` sería vocabulario paralelo sobre un transversal. 3. El `padding` del preview es un shorthand de dos valores → dos knobs lógicos. Artefactos y gates: - Sonda antes/después = 0 diffs en 1.827 valores × 7 estados. Determinismo verificado. - R-5.4: 0/10 en vivo, y los DIEZ adjudicados con su medición. No es un instrumento roto ni tokens muertos: el preview se crea sólo mientras hay un arrastre en curso (0 nodos en reposo, contados), y forzando el nodo los diez mueven su propiedad — padding 8→1234px, radio 6→1236px, borde 1→9px, fondo, tinta, familia, tamaño 14→99px, sombra y z 100→4321. - censo --only 89 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos (el conocido skin-media-player) · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con su «Talla y tema» y tab `Tokens` en la demo (10 claves, en vivo). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
7a0fc2eadb |
uix(link-preview): temable — 0 % → 100 %, y el plano overlay que traía tipografía
33 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → **100 %**: no queda un knob de apariencia fuera del contrato (los tres restantes son sistema — anillo de foco y los dos del plano de profundidad que pintan la flecha). Global 48 %, sin contrato 42 → 41, al 100 % 7 → 8. 1. **Los per-talla llevan `parts: ['content']`**, no el host: el panel está PORTALADO y su `data-size` vive en el content, así que una cascada colgada del host no lo alcanza nunca. La talla mueve sólo dimensiones físicas (padding, min-width, tipo); familia, peso e interlineado son constantes a propósito, como ya decía la receta. 2. **La flecha no se tokeniza**: su fill y su stroke consumen el plano `overlay` para casar siempre con el panel; acuñar `arrow-fg` rompería justo esa garantía. El subrayado del trigger es un `color-mix` sobre `currentColor` — la mezcla ES el aspecto, así que el knob es la declaración entera, no el 35 %. Y el fallback encadenado del color del trigger viaja verbatim: la coma es parte del valor, no un segundo knob. EL HALLAZGO — el plano `overlay` impone TIPOGRAFÍA (→ next-features §12.9): `[data-depth='overlay']` (`generated/base.css:7088`) no declara sólo fondo, borde y sombra: también `font-family` y `line-height`. El panel estampa ese plano para su elevación, así que la declaración del plano empata a (0,1,0) con la de la receta y **gana por orden de carga** (la hoja generada va después del chunk de la receta). Medido con CDP `getMatchedStylesForNode`: el par `font-family` / `line-height` de esta receta **no había pintado nunca**. Retirado con **0 diffs**, que es la prueba. Afecta a los **veinte** componentes que estampan el plano. Lo que hay que decidir —aparte, mueve píxel— es si un plano de profundidad tiene competencia sobre la tipografía o sólo sobre la superficie. Cuarta ocurrencia de la clase «empate resuelto por orden de carga». CÓMO SE MIDIÓ, porque el instrumento estándar tampoco servía aquí: El panel abre en HOVER con retardo y está portalado → la sonda genérica ve **1 nodo**, y una sonda que compara un nodo pasa en falso. Sonda dirigida (abre por hover, captura los cinco nodos reales en las cinco tallas): determinismo verificado y **gate antes/después = 0 diffs sobre 550 valores**, repetido tras la retirada. El guard R-5.4 pasó de **3/35 a 31/33** con dos extensiones: `openBy: 'hover'` para este componente (un hover card no se abre con clic — clicar su `<a>` navega) y `text-decoration-color` en la lista de propiedades, que faltaba pese a estar en `KNOB_PROPS` del censo. Verificado que los otros QUINCE componentes con ledger no se mueven ni una cifra. Los dos tokens que siguen mudos son un conflicto ESTRUCTURAL, no un hueco de demo: para abrir el panel hay que tener el puntero en el trigger, y el hover es justo el estado cuya regla pisa la tinta y el subrayado de reposo — el token de hover lee vivo en la misma corrida. Adjudicados con esa razón. Gates: censo --only 100 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos (el conocido skin-media-player) · rtl:check 0 · docs:check 0 · check por fichero limpio · README con «Talla y tema» y tab `Tokens` en la demo (33 claves, en vivo). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
67b4c810c7 |
uix(picker-shell): temable — 0 % → 76 %, y el componente que el instrumento no veía
31 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → 76 %. Global
48 %, sin contrato 43 → 42.
La cola avisaba «es CAPA de los pickers: mirar antes qué posee y qué presta».
Mirarlo cambió tres cosas del encargo:
1. **NO es una capa compartida: es un COMPONENTE.** A diferencia de
list-surface o calendar-surface no hay hook de capa ni vocabulario prestado
— color-picker, date-picker y chronos importan sus `.svelte` directamente.
No toca `LAYER_VOCABULARY` y el censo ya lo puntuaba bien.
2. **Su eje de talla no es `data-size`, es `data-picker-size` sobre
`[data-popover-content]`**, un ancestro PORTALADO. El TSC no puede emitir esa
cascada (`scope: 'size:xs'` generaría `[data-picker-shell][data-size='xs']`,
que no casa nunca), así que las coordenadas por talla quedan como públicos
PLANOS y la receta las consume desde sus propios selectores. Es el único
componente del eje donde el patrón de nombres resueltos no aplica; la regla
base es el default `sm` y `md` sólo re-declara lo que cambia. La fila de
tiempo lleva un TERCER eje, `data-size` sobre su propia clase.
3. **El instrumental del eje estaba CIEGO aquí, y la sonda genérica devolvió 0
nodos** — el antipatrón de comparar cero valores y pasar. Dos causas a la
vez: `picker-shell` no tiene demo propia (404, se mide dentro de un picker
anfitrión y detrás de su popover), y sus partes se llaman
`data-picker-header` / `-body` / `-footer` en vez de
`data-picker-shell-{parte}` — genéricas A PROPÓSITO, dice la receta, «so
every picker gets the same visual contract for free» —, así que todo filtro
por prefijo del componente ve sólo la raíz.
CÓMO SE VERIFICÓ, ya que el instrumento estándar no servía:
- Sonda DIRIGIDA (abre el popover del date-picker, captura los seis nodos
reales en las cuatro picker-sizes): determinismo comprobado (576 valores, 0
diffs entre dos corridas del mismo código) y **gate antes/después = 0 diffs**.
- Los knobs que la demo no monta —el header entero y la fila de tiempo— se
midieron FORZANDO el nodo: los quince mueven su propiedad, y el font-size del
header se comprobó talla a talla (12/14/16/16px → 102px, cada uno en su
picker-size).
- El guard R-5.4 pasó de **0/31 a 6/31** al ganar un `COMPONENT_OVERRIDES`
(prefijo de atributo + selector de apertura) acotado a este componente.
Verificado que los otros CATORCE con ledger no se mueven ni una cifra.
Adjudicar 31 excepciones sin ese arreglo habría sido escribir una mentira en
el ledger; los 25 que siguen mudos llevan cada uno su razón medida.
Header y footer comparten la regla que los separa del cuerpo → UN par de knobs
(`border-width` + `border`), no dos.
Sin tab `Tokens`: este componente no tiene página donde ponerlo. Registrado en
next-features §13 junto con la pregunta de fondo — si el precio de los nombres
genéricos (un contrato visual común para todos los pickers) compensa la ceguera
del instrumental — y con el eje portalado como caso de prueba si el TSC llega a
ganar un scope configurable.
Gates: censo --only 76 % · suite eidos sin rojos nuevos (el conocido
skin-media-player) · rtl:check 0 · docs:check 0 · check por fichero limpio ·
`component:audit` no lo cubre (eidos-only, sin morfo) y `eidos-lint` tampoco.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
42a3e74136 |
uix(spinner): temable — 0 % → 70 %, y 71 tokens propuestos que eran 18
18 claves en el bloque `spinner` de `recipes/base.ts` (fusionadas con los dos forwards de paleta). Censo 0 % → 70 %, cero globales. Global 48 %, sin contrato 44 → 43. **La §4 proponía 71 tokens para 23 knobs — la peor inflación que ha dado el generador en todo el eje.** El spinner tiene UNA coordenada de talla (`--spinner-size`) que gobierna el anillo, la pista de puntos y las barras, más el trazo (`--spinner-thickness`). La propuesta multiplicaba esa única coordenada por variante × parte × dimensión × talla y producía `ring-track-width-xs`, `dots-track-gap-xs`, `dots-dot-width-xs`, `bars-track-gap-xs`… todos con el mismo `0.75rem`, porque todos SON el tamaño en xs. Un tema habría necesitado veinte claves para cambiar un número. 1. Las proporciones son CONSTRUCCIÓN, no knobs: `calc(size * 0.3)` es el punto, `* 0.18` la barra, `* 0.2` y `* 0.12` los huecos. Definen la FORMA de cada variante y se quedan en la receta — mismo reparto que los gradientes de las guías de tree-grid o el damero de gradient-builder. 2. `fg` / `dots-dot-bg` / `bars-bar-bg` ⚠ no eran tres knobs con dos valores en pugna: son UNA variable (`--_spinner-color`) leída en tres sitios, con el conmutador `data-color='inherit'` que la cambia de forward de paleta a `currentColor`. Se queda privada, igual que `--_spinner-track`, que además envuelve su fuente en un color-mix distinto por rama (60 % / 25 %). Aplanarlas exigiría duplicar cada regla por color. 3. La escala es PROPIA, no la del bundle de iconos: medido, 12/16/20/28/40 px contra los 14/16/18/20/32 de `--icon-size-*`, y sólo coinciden en sm. Verbatim con la desviación anotada — forzar el bundle habría movido el default en cuatro tallas de cinco. 4. `duration` entra al contrato en vez de seguir en `0.9s` a pelo: el registro ya tenía abierta la incoherencia de que el spinner de feed ganó tokens de duración y el de media-player no (§13). Aquí se hace bien de entrada. El 30 % que falta son los dos privados conmutadores, los dos `border-radius: 50%` (identidad de forma) y los fotogramas de los @keyframes. Artefactos y gates: - Sonda antes/después = 0 diffs en 377 valores × 7 estados. Determinismo verificado. - R-5.4: 14/18. Los cuatro mudos, medidos uno a uno y adjudicados: la demo monta SÓLO la variante ring y sin etiqueta (0 barras, 0 puntos, 0 labels, contados), y `track-opacity` sólo se declara dentro de `prefers-reduced-motion` — forzando variante, etiqueta y contexto reduce, los cuatro alcanzan. - censo --only 70 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos (el conocido skin-media-player) · rtl:check 0 · docs:check 0 · check por fichero limpio. - README con su «Talla y tema» y tab `Tokens` en la demo (18 claves, en vivo). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
c56d6544e6 |
uix(card-group): temable — 0 % → 90 %, y dos privados abreviados que mueren
20 claves en una entrada NUEVA de `recipes/base.ts`. Censo 0 % → 90 %, cero
globales y cero privados. Global 47 %, sin contrato 45 → 44.
Es un CASCO de composición y su propia cabecera ya lo decía: compone
ToggleGroup, Collapsible, Card y Button, y la receta posee «ONLY the genuinely
CardGroup-level visual». Eso acota el contrato antes de nombrar nada — el cromo
de las tarjetas es de Card, el del título de disclosure es de Button.
1. **`--_cg-pad` y `--_cg-card-radius` eran privados ABREVIADOS** (§6 r5 los
prohíbe: `cg` por `card-group`), el mismo defecto que los `--_mp-*` de
media-player. Pasar a públicos con el nombre completo es a la vez el
renombrado que la regla pedía y la tokenización. La §3 de la ficha decía
«la receta no declara privados propios»: los declaraba en su bloque raíz
(`card-group.css:15-16`), y el escáner no los veía por buscarlos con el
prefijo completo del componente.
2. **`--shape-outer-radius` NO se acuña: se CALCULA.** La receta lo compone
como `card-radius + padding` para que las tarjetas aniden concéntricamente
(§30). Un tema mueve las dos coordenadas y el radio exterior se recompone
solo; el censo ya lo clasifica como sistema.
3. **El eje `size` es sm|md|lg, no las cinco tallas**
(`Extract<Size, 'sm' | 'md' | 'lg'>`): seis coordenadas por talla, no diez.
Escribir xs/xl habría sido vocabulario muerto.
4. Los tres `padding` son shorthand con una parte fija y otra variable; lo que
varía y no es el inset del grupo es el hueco inferior →
`title-padding-block-end` y `description-padding-block-end`.
5. El chevron es geometría propia (dos bordes girados 45°): `chevron-size`
cubre las dos dimensiones y `chevron-width` el trazo. Su `currentColor`
hereda del título a propósito y no es knob.
6. Los `font-size` van al BUNDLE (`--size-{k}-font-size`, alias 1:1) y no al
primitivo crudo — misma trampa que cayó en code-block: la propuesta copia el
CSS verbatim y hereda el incumplimiento cuando el valor de partida ya
violaba `recipe-css-contract`. Aquí se aplicó de entrada.
Artefactos y gates:
- Sonda antes/después = 0 diffs en 2.581 valores × 7 estados. Determinismo
verificado: dos corridas, 0 diffs.
- R-5.4: 15/20. Los cinco mudos son los del encabezado ESTÁTICO, que la demo no
monta (0 nodos `[data-static]` contra 1 `[data-button]`, CONTADOS); forzado
`data-static` alcanzan los cinco, y cada uno lleva su medición en el ledger.
El hueco de demo queda registrado en next-features §13, misma clase que el
`kind='month'|'year'` de date-range-picker.
- censo --only 90 % · component:audit PASS · eidos-lint invalid 0, class-hooks
0 · suite eidos sin rojos nuevos (el conocido skin-media-player) · rtl:check
0 · docs:check 0 · check por fichero limpio.
- README con su «Talla y tema» y tab `Tokens` en la demo (20 claves, en vivo).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
354d166df1 |
uix(code-block): temable — 0 % → 81 %, y la demo que no enseña el componente
20 claves en una entrada NUEVA de `recipes/base.ts` (no tenía). Censo 0 % →
81 %. Global 46 % → 47 %, sin contrato 46 → 45.
El handoff lo llamaba «el más mecánico de los que quedan». No lo es: sus 26
knobs se parten en dos grupos con doctrinas distintas.
1. **El nodo del código NO acuña nada, y la §4 pedía que lo hiciera.**
`[data-code-block-code]` consume la capa tipográfica `--style-code-*` en sus
cinco declaraciones, y las dos que pasan por privado usan la forma canónica
de la escotilla por instancia
(`var(--_code-block-font-size, var(--style-code-font-size))`, escrita por el
wrapper desde la prop `size` y sólo si llega). Es el patrón que D-TH.2-b
fijó para heading/text/code. Acuñar `code-font-family` y compañía sería el
vocabulario paralelo que la regla 2 de capas prohíbe. Todo lo que entra al
contrato es el CASCO alrededor.
2. **Los tres `font-size` iban al primitivo crudo, y lo cazó un guard.** La
propuesta copia el valor del CSS verbatim, y ese valor ya violaba
`recipe-css-contract` («recipes consume the size bundle, not the raw
size-coordinate primitives»): `title/lang/copy-font-size` corregidos a
`var(--size-{k}-font-size)`. Los alias son 1:1 → 0 diffs tras aplicarlo.
Aviso general: cuando el CSS de partida ya incumple el contrato, la
propuesta generada hereda el incumplimiento.
3. Shorthand partidos: los dos `border` y el `border-bottom` de la cabecera
comparten anchura y color → `border-width` + `border`; el `padding` del
`<pre>` → `pre-padding`. Los `transparent` de outline/ghost y el `border: 0`
de ghost son identidad de variante.
El 19 % que falta son esas cinco de la capa, que el censo cuenta como `global`
porque `code-block` no está en `TYPOGRAPHIC_PRIMITIVES` — es un compuesto que
CONTIENE un primitivo tipográfico, no uno de ellos. Extender la clase `system`
del censo a las capas sigue pendiente de tu firma; la métrica penaliza hacer lo
correcto y no se fuerza de oficio.
DOS HALLAZGOS QUE NO SE ARREGLAN AQUÍ (→ next-features §13):
- **La demo de `code-block` no enseña el `code-block`.** `[data-uix-docs] pre`
(`web/routes/uix/uix.css:801`) pesa (0,1,1) contra los (0,1,0) de
`[data-code-block-pre]`, y `[data-uix-docs]` es el shell de TODAS las
páginas. Siete propiedades del `<pre>` las pinta el harness y no la receta:
padding (16px 20px contra 12px), border (1px contra ninguno), radius (8px
contra 0), background (gris contra transparente), font-family, font-size
(13 contra 14) y line-height (18.2 contra 20.3). El fondo, el borde y el
radio que se ven ahí son del sitio. Por eso `pre-padding` lee muerto en el
guard, adjudicado con esa medición. Acotar la regla toca el CSS del SITIO,
que sirve a ~162 páginas: decisión aparte.
- **El guard de claves duplicadas del handoff inspeccionaba el VACÍO.** El
comando documentado usa `grep -oE "^\t…"`, y `grep -E` lee `\t` como una `t`
literal: 0 coincidencias sobre 130 bloques reales, así que salía «vacío = OK»
sin mirar nada — el antipatrón que el proyecto tiene registrado, dentro del
propio handoff. Comprobado con un contador fiable: cero duplicados en el
árbol, así que no hay daño en los commits que confiaron en él. CONTINUE
queda corregido con una versión que CUENTA los bloques y avisa de que «0
bloques» significa guard roto, no fichero limpio.
Artefactos y gates:
- Sonda antes/después = 0 diffs en 1.305 valores × 7 estados (dos veces: tras
la tokenización y tras la corrección del bundle). Determinismo verificado.
- R-5.4: 19/20; `pre-padding` adjudicado con las siete propiedades medidas.
- censo --only 81 % · component:audit PASS · eidos-lint invalid 0, class-hooks
0 · suite eidos de vuelta al único rojo conocido (skin-media-player) tras
corregir el bundle · rtl:check 0 · docs:check 0 · check por fichero limpio.
- README con su «Talla y tema» y tab `Tokens` en la demo (20 claves, en vivo).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
dd188f1255 |
uix(tree-view): temable — 0 % → 92 %, y el velo que tiñe la carpeta entera
46 claves en el bloque `tree-view` de `recipes/base.ts` (fusionadas con el
forward de paleta). Censo 0 % → 92 %, cero globales. Global 46 %, sin contrato
47 → 46. Molde del hermano `tree-grid` allí donde el problema es el mismo.
LA PROPUESTA GENERADA FALLABA EN EL NOMBRE DE CASI TODO LO QUE IMPORTA: el
clasificador toma el PRIMER selector de cada regla como si fuera la parte
pintada, y aquí ese primero es el root o el branch-control cuando el nodo real
es otro.
1. `root-width: 1px` / `root-bg` NO son del root: son la GUÍA de indentación
(el `::before` del branch, una línea vertical). → `guide-width` + `guide-fg`,
literalmente los nombres de tree-grid. Un `root-bg` que tiñe una línea es la
clase de nombre que miente.
2. `branch-control-padding-inline-{k}` ⚠ fundía DOS ejes que se SUMAN en el
mismo calc: el ritmo de la fila y el PASO DE PROFUNDIDAD
(`--tree-depth × indent + padding`). Fundidos, tematizar la sangría habría
movido el padding. → `row-padding-inline-{k}` + `indent-{k}`.
3. El prefijo `branch-control-` es erróneo: la regla reza
`[data-tree-view-branch-control], [data-tree-view-item]` — las DOS filas. El
CSS ya llamaba `row` a sus privados. → `row-*`, como tree-grid y como la
lección de table. Y fuera el prefijo `root-` del chasis: el wrapper ES el
componente.
4. `row-padding-block` ⚠ no eran dos valores en pugna sino cinco por talla: xs
colapsa a `0`, las otras cuatro `--space-1`.
5. `branch-indicator-width` + `-height` son UN knob (`1em`) →
`branch-indicator-size`.
Bundle: la altura de fila casa 1:1; padding e indent llevan ritmo propio; la
tipografía un paso por debajo desde lg — verbatim, como table y tree-grid. Los
resueltos con `parts: ['root']` (el `data-size` va en `[data-tree-view-root]`,
wrapper de eidos, no parte del morfo). Los `transparent` de outline/ghost y el
`padding: 0` de ghost son identidad de variante y siguen literales.
`hover-row-bg` SÍ se acuña, al revés que en grid-list, y por medición: la misma
regla pinta dos nodos con arquetipo distinto, y `branch-control` NO lleva
archetype — ahí el plano de la receta es la única pintura (velo medido ausente)
y el token es toda la superficie de tema del hover. Tener un consumidor
legítimo es lo que lo distingue del caso grid-list.
EL DEFECTO QUE LA MEDICIÓN DESTAPÓ (preexistente, NO se toca aquí →
next-features §12.8): al pasar el ratón por la fila de una carpeta abierta se
tiñe LA CARPETA ENTERA, hijos incluidos. `archetype: 'item'` está declarado en
el `<li>` branch (`morfo/components/tree-view.ts:103`), que contiene el control
Y todo el `branch-content`, mientras la fila que el usuario señala es el
`branch-control` de dentro: el nodo velado mide 336 px frente a los 36 px de la
fila — medido y capturado. Un branch anidado acumula además el velo de sus
ancestros, así que sus filas se ven más oscuras que las hermanas. Mover el
arquetipo es morfo y mueve píxel en toda la demo. Es la TERCERA variante de la
misma familia: table lo tiene en fila Y celda, grid-list en fila Y celda sobre
el mismo nodo, y tree-view en un ANCESTRO del nodo señalado.
Artefactos y gates:
- Sonda antes/después = 0 diffs en 8.062 valores × 7 estados.
- R-5.4: 45/46; `disabled-row-fg` adjudicado en el ledger (la demo monta CERO
filas deshabilitadas, contadas; forzada alcanza oklch(0.61 0 0) → rgb(1,2,3)).
- censo --only 92 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0
· suite eidos sin rojos nuevos (el conocido skin-media-player) · rtl:check 0
· docs:check 0 · check por fichero limpio (72 globales, ninguno mío).
- README con su «Talla y tema» y tab `Tokens` en la demo (46 claves, en vivo).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
893aeaf817 |
uix(textarea): temable — 0 % → 80 %, y el contador que casi pierde su 0.85
37 claves en el bloque `textarea` de `recipes/base.ts` (fusionadas con el
forward de paleta que ya estaba). Censo 0 % → 80 %, con **cero globales y cero
literales de valor**: los 16 privados leen ya su público. Global 46 %, sin
contrato 48 → 47.
LO QUE LA MEDICIÓN CAMBIÓ. La §4 generada proponía 35 tokens; cuatro eran
colisiones y uno habría movido el default:
1. `count-font-size-{k}` × 5 BORRABA el factor 0.85. El CSS calcula
`calc(var(--_textarea-font-size) * 0.85)` y la propuesta ponía el tipo del
input crudo en las cinco tallas: el contador habría crecido un 18 %.
D-TH.5 lo prohíbe. Queda en UN token con el `calc` sobre el público del
input — la escala se escribe una vez y la talla la resuelve el input. Pide
`scope: 'host'`: emitido en `:root` su dependencia no existe, y el contrato
de scope de la receta lo caza (lo cazó).
2. `input-fg` ⚠ eran DOS knobs (texto y placeholder) → `input-fg` +
`input-placeholder-fg`. Igual `count-fg` → `count-fg` + `overflow-count-fg`.
3. `input-border` ⚠ NO eran dos knobs sino UNA variable con su swap de paleta,
y el nombre estaba mal: es el borde de FOCO → `focus-input-border`. El de
reposo es otro token, que la propuesta ni listó por viajar en el atajo.
4. `ghost-input-border` se RETIRA: la regla ghost lee ese mismo conmutador —
sería un valor con dos nombres.
Bundle, medido: la tipografía casa 1:1 en las cinco (lee `--size-{k}-font-size`);
el spacing NO — `padding-inline` casa salvo en xs (8px vs 6px) y `padding-block`
sólo en xs. Verbatim y documentado: un campo multi-línea respira más, y el
spacing queda fuera del guard del bundle. Resueltos sin `parts` (el `data-size`
va en `[data-textarea]` y el input hereda); fuera los cuatro `[data-size]`.
DOS ARREGLOS DEL INSTRUMENTO, los dos por medición y no por sospecha:
- **El guard medía con el PUNTERO encima.** `reopen()` corre antes de CADA
token y hace clic en `[data-{c}-input]` cuando el componente no tiene parte
`content`; el `blur()` de la revisión adversarial quitaba el foco pero no el
puntero, así que `:hover` casaba toda la corrida y toda regla de hover pisaba
a sus vecinas. Costaba TRES falsos negativos aquí. Con `mouse.move(0,0)`
tras cada blur, `input-border` revive solo (31 → 32).
- **`::placeholder` SÍ se lee con `getComputedStyle`.** La nota de §13 que
decía lo contrario nunca se comprobó; medido, el color centinela vuelve tal
cual. Entra en el snapshot (32 → 33) y deja STALE la entrada
`command.input-placeholder-fg`, que el guard señaló y se ha borrado.
Corridos los DIEZ componentes con ledger tras los dos arreglos: ningún otro
cambia, un único STALE, el previsto.
Y un hallazgo de píxel que NO se toca aquí (→ next-features §13): el borde de
foco sólo se ve con Tab. Las tres reglas de `border-color` del input están
ordenadas al revés de lo que significan — hover (0,4,0) > foco (0,3,0) >
invalid (0,2,0) — y hacer clic deja el puntero encima por definición, así que
gana el hover; un campo inválido pierde su borde rojo al enfocarlo o al pasar
el ratón. El anillo de foco del sistema sí se ve siempre, así que no es fallo
de accesibilidad. Arreglarlo mueve píxel.
El 20 % que falta son las dos declaraciones que consumen
`--_textarea-border-focus`, privado a propósito: es el conmutador de una
variable con dos fuentes (el público y el forward THM-2), y aplanarlo exigiría
duplicar la regla por color. Mismo techo que `listbox` paga por consumir bien
su capa. Mi propio veredicto predecía ~100 % y la medición lo corrigió a 80 %.
Artefactos y gates:
- Sonda antes/después = 0 diffs en 1.247 valores × 8 estados (el 0.85 intacto,
que era el riesgo). Determinismo verificado: dos corridas, 0 diffs.
- R-5.4: 33/37; los 4 mudos adjudicados en el ledger con su medición (foco,
invalid y las dos del contador rebasado — estados que la demo no monta).
- censo --only 80 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0
· suite eidos sin rojos nuevos (el conocido skin-media-player) · rtl:check 0
· docs:check 0 · check por fichero limpio (72 globales, ninguno mío).
- README con su «Talla y tema» y tab `Tokens` en la demo (37 claves; el panel
muestra el contador computando `calc(calc(1rem * 1) * 0.85)`).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
60b5b98969 |
uix(grid-list): temable — 0 % → 85 %, y una selección que nunca pintó
38 claves nuevas en el bloque `grid-list` de `recipes/base.ts` (que ya existía
con los dos forwards de paleta: se FUSIONA, no se añade un segundo). Alcance
del censo 0 % → 85 % (22 de 26 puntuables); global 45 % → 46 %, sin contrato
49 → 48.
El eje `size` se estampa en el PROVIDER —el wrapper de eidos no tiene parte
`root`—, así que los tres nombres resueltos van SIN `parts`: molde `command`,
no `table`/`tree-grid`. Fuera los cuatro bloques `[data-size]` del CSS; los
emite el TSC. Altura de fila 1:1 con el bundle, `row-padding-inline` con ritmo
propio, y la tipografía un paso por debajo de md en adelante — verbatim, como
table y tree-grid.
LO QUE LA MEDICIÓN CAMBIÓ (la §4 generada tenía un error de doctrina y dos
defectos que sólo aparecieron midiendo; el §5 Veredicto se escribió con la
sonda delante, porque estaba vacío):
1. La selección de fila NUNCA HA PINTADO. La receta seleccionaba
`[data-grid-list-row][data-selected]`, un atributo que ni el morfo declara
ni soma estampa (estampa `data-state='selected'` + `aria-selected`): la
regla no casaba jamás y su acento `--_grid-list-palette-element` no llegó
nunca al píxel — una fila seleccionada muestra el velo NEUTRO del
arquetipo, indistinguible del hover (capturado). Retirada la declaración
muerta y su forward huérfano: 0 diffs, que es la prueba. Repararlo mueve
píxel y choca con §12.5 (el arquetipo fija también `color`) → §13, espera
firma. El acento del checkbox (`_palette-solid`) sí vive y se conserva.
2. NO se acuña `hover-row-bg` aunque la propuesta lo pedía. La fila es
`archetype: 'item'`: el velo del sistema la pinta a especificidad plena y
el plano de la receta pierde — medido, el hover pinta DOS VECES sobre el
MISMO nodo (a diferencia de table/tree-grid, donde velo y plano caen en
nodos distintos). Sería un token que no puede ganar; mismo criterio que
listbox.highlighted → §12.7. Y fila Y celda llevan ambas `item`, así que
bajo el puntero se apilan tres capas.
3. «Consume la capa compartida `menu-indicator`» es FALSO. Sale de
`SHARED_LAYERS` (`theming-census.ts:432`), pero esa capa no tiene un solo
selector de grid-list, la receta no la importa y soma no renderiza
indicator: el checkbox ESPEJA el visual pintándolo por su cuenta. Entrada
desviada del censo → §13 (listbox / menubar / navigation-menu están en la
misma entrada y tampoco aparecen en el fichero).
Nombres, sobre la propuesta: `selection-checkbox-{width,height}` son UN knob →
`selection-checkbox-size`; `on-selection-checkbox-bg` → `checked-selection-checkbox-fg`
(es la tinta del glifo, y `on-` es prefijo reservado); `border` partido en
`border-width` + color (molde `command.input-border*`), que el checkbox
comparte; `padding` uniforme se queda `padding` (precedente
`command.viewport-padding`); `max-block` entra al contrato (molde
`command.viewport-max-block`).
Artefactos y gates:
- Sonda antes/después = 0 diffs en 6.090 valores × 7 estados. Determinismo
verificado: dos corridas del mismo código, 0 diffs.
- R-5.4: 37/38 tokens mueven un computed. `invalid-border` adjudicado EN EL
LEDGER con su razón medida (la demo arranca con su control en off; activado
a mano alcanza: oklch(0.9555 0.0207 13.86) → rgb(1,2,3)).
- censo --only 85 % · component:audit PASS (R-5.3 incluida) · eidos-lint
invalid 0, class-hooks 0 · suite eidos sin rojos nuevos (el único es el
conocido skin-media-player) · rtl:check 0 · docs:check 0 · check por fichero
limpio (72 globales, ninguno mío).
- README con su «Talla y tema» y tab `Tokens` en la demo (38 claves, leídas en
vivo). El tab `Recipe` documentaba la regla retirada: corregido.
Las fichas de calendar / carousel / command / month-grid / range-calendar /
table / year-grid entran porque `--report` regenera el informe entero: sólo
actualizan NÚMEROS DE LÍNEA de commits ya hechos que no lo regeneraron. Cero
cambios de alcance. Las otras 161, que sólo cambiaban la fecha, se revirtieron.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
8400e5bdd4 |
feat(calendar-surface): la capa que ya existía, con nombre, casa y su agujero tapado
Firma 1 del acta, diseño presentado y firmado. **La medición desmontó el
encargo**: el handoff la vendía como una capa NUEVA de ~220 knobs, y la capa ya
existía de hecho, sin nombre. `--calendar-*` se emite en `:root` (76 claves) y
sus consumidores no acuñan NADA — medido: `range-calendar` 114 referencias
prestadas y 0 propias, `month-grid` 77/0, `year-grid` 77/0, y lo único ajeno
que leen es sistema puro (`--focus-ring-*`, `--state-hover`). Su 0 % era el
artefacto de `listbox` (§13), pero total.
**`lib/calendar-surface.css`** (hook `data-calendar-surface`):
- cuatro coordenadas por talla — `padding`, `control-size`, `day-size`,
`font-size` — xs..lg, porque la familia NO tiene xl, y con la celda DOS pasos
por debajo del bundle de control. Esa desviación estaba escondida en cuatro
bloques `[data-size]` idénticos, uno por receta, cada uno puenteando a un
privado con otro nombre; ahora se lee en un sitio.
- la FORMA del anillo de evento y de la marca de festivo.
**Capa HÍBRIDA, y es lo que la distingue de sus hermanas**: `list-surface` y
`viewport-placement` componen primitivos del sistema, así que declaran sus
públicos en el fichero y no tienen entrada de receta. Ésta no puede: su
vocabulario son 76 claves SEMÁNTICAS que un tema alcanza una a una por config,
así que la entrada `calendar` de `recipes/base.ts` pasa a ser la de la FAMILIA
y la capa posee sólo lo que una entrada de receta no sabe expresar.
**El defecto que la justificaba, medido**: `--calendar-event-shadow` y
`--calendar-day-holiday-shadow` se emitían con ámbito `[data-calendar]`
(audit B.2 los host-scopeó por buenas razones) mientras `range-calendar`,
`month-grid` y `year-grid` los leían desde hosts que nunca llevan ese atributo:
variable VACÍA, `box-shadow` inválido en computed, **el anillo sema de
`commit-select` / `commit-set` no pintaba jamás en tres componentes**. Un token
prestado cuyo ÁMBITO no te cubre no es un préstamo, es un agujero silencioso, y
ningún guard lo veía. Ahora la forma vive en la capa y el acento entra por
`--_calendar-surface-accent`, que cada superficie alimenta con su propio
forward de paleta THM-2.
**Siete wrappers estampan, no cuatro** — y esto casi se me cuela: `DatePicker`
y `DateRangePicker` renderizan la superficie soma por sus PROPIOS wrappers
(`date-picker-calendar`, `-month-view`, `-year-view`,
`date-range-picker-calendar`) y un panel portalado no hereda nada del root del
picker. Con sólo los cuatro standalone sellando, ambos quedaban con
`--calendar-padding` VACÍA y el panel a padding 0 (medido). La tentación era
enganchar la capa a las cuatro identidades de componente: eso viola la regla 1
de capas compartidas, y la respuesta correcta es un sello por wrapper.
computed 0 diffs en range-calendar (19.285 valores) · month-grid (3.451) ·
year-grid (3.451) · date-picker (464) · date-range-picker (406).
`calendar` da 12, y son del INSTRUMENTO: dos corridas del MISMO
código dan 24 en los mismos nodos y las mismas dos propiedades.
Los «missing node» son el propio sello entrando en la clave.
**Una incidencia nueva, medida y NO arreglada aquí** (§13): el font-size de los
selectores month/year es una moneda al aire —
`[data-calendar-month-select][data-button]` (0,2,0) empata con
`[data-popover-trigger]:not([data-archetype='field-trigger'])` (0,2,0), la
MISMA regla de popover que dejó muerto el cromo de `gradient-picker`, y gana la
hoja que cargue después: 16px o 14px según la recarga. Arreglarlo fija el píxel
en un lado ⇒ decisión.
De paso, `calendar-select.css` deja de puentear un privado que sólo
`[data-calendar]` declaraba: en range / date-range corría SIEMPRE por el
fallback, clavado a md fuera cual fuera la talla.
**El censo deja de penalizar hacer lo correcto**: `LAYER_VOCABULARY` en
`theming-census.ts`, mismo precedente que D-TH.2-b con `--style-*`. Global
43 % → **45 %**, `calendar` 75 % → **84 %**. `list-surface` NO se registra: sus
consumidores puentean por privados, otra forma, y mueve diez componentes de
golpe. Y aparece el techo de debajo, anotado: a los tres consumidores sólo les
quedan los forwards de paleta THM-2 —que el censo cuenta como `private` en TODO
el catálogo— así que siguen leyendo 0 %.
`recipe-css-contract` aprende que una CAPA también declara públicos (antes sólo
miraba la receta, y una capa que comparte prefijo con un componente la hacía
fallar). Sin debilitarla: un nombre que no declara nadie sigue en rojo.
eidos-lint 0 invalid (calendar 29/8 · range-calendar 41/12 · los grids 23/5) ·
audit --only calendar PASS · vitest eidos 434/435 (el rojo conocido) ·
rtl 0/181 · docs 0/813 · check 0 errores en tocados · prettier: revertido el
reformateo en masa que se coló en cuatro README, el test y el censo (churn
ajeno, no mío)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
df27351ffc |
fix(table): el striped cuenta filas de DATOS — la banda vuelve a existir
Firmado por el autor tras la revisión adversarial: el hallazgo 4 (
|
2 months ago |
|
|
679dfdb291 |
uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4
Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree
con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba
más dura que la del autor), sonda x2 por componente para fijar el suelo de
ruido. 34 hipótesis · 26 refutadas · 8 reales.
Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs;
command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 ·
listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen
idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens
huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano»
de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación;
eidos-lint 0 invalid.
Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command
8.091 y carousel 2.842 valores, 0 diffs):
1. command: el re-point de `--command-radius` dentro del Dialog era una
declaración muerta con comentario falso — la misma regla pone el radio a 0
y el input lee `--command-input-radius`, nunca este token (medido:
`--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px`
movía la paleta inline y no la del dialog). Retirado; comentarios y README
reescritos con lo medido.
2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo
mientras la horizontal leía `active-indicator-scale` — el token alcanzaba
media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora
lo leen las dos.
3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap`
INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por
CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y
las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es
la prueba. Canal de valor de soma, como --gp-current-gradient. Censo
carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto
(5.190 · 2.102).
4. table: `striped-row-bg` no alcanza NADA en la demo publicada —
`:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos
quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel →
PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`);
adjudicado en el ledger mientras tanto.
El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas
medidas, y la cuarta era de la sonda:
- el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input
de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el
token de reposo leía muerto (era el «falso negativo sin causa» de §13);
- el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de
`{c}-root` no lo recibían;
- `::before`/`::after` eran invisibles (el aro de buffering, el spinner);
- la no-determinación de feed no era una animación sin localizar: era la demo
aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma
`commit-settle` anima box-shadow sobre el nodo medido. Con la espera de
asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas.
Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y
que carousel convirtió en patrón — un estilo inline de otra capa es invisible
para todo análisis estático): `npm run theming:sentinel -- <c> <url>`
(scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en
todos los nodos del componente, pseudos, pase de hover, settle) + ledger
scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto
sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en
verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 ·
gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46
excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías
salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró;
y dos muertos nuevos los produjeron los propios arreglos (el blur apaga
focus-input-border; el settle desmonta el spinner de feed) — adjudicados con
su porqué. Doctrina en recipe-contract §4.
También: tres cifras de especificidad de next-features §12 recontadas (la
banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0);
y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el
velo en la celda), el comentario de listbox que mandaba pisar el privado
`--_listbox-max-height` apunta ahora al público, y quedan registrados en §13
los dos `header-z` con literal '2' y el spinner de media-player a 720ms
mientras el gemelo de feed lleva tokens.
Guards: censo global 43 % intacto · audit --only command+carousel PASS ·
eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest
eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs
0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier
limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en
HEAD y no se tocan).
Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el
arquetipo en fila+celda, y que soma lea el gap de un token.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
f5f2b5d225 |
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo. Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio encabezado. Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día: el veredicto orienta pero la medición decide (tres de ocho tenían un error de lectura) · un token que no mueve nada miente, y lo que procede es retirar la declaración muerta · un alias puro se borra, no se renombra · lo que la capa posee el consumidor no lo acuña · y la sonda miente de tres maneras distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo código antes de sospechar del cambio. El plan §8 gana la entrada de la sesión con las cifras y los commits, y su cabecera de estado pasa a 43 %. Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0 desviadas y guard en `error`. 29 commits, sin pushear. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
34a95a550c |
feat(feed): temable — 0 % → 94 %, y cierra el bloque F2-A
Octavo y último del bloque.
censo 0 % → 94 % · global 43 %
computed reposo y las CINCO tallas, idénticas al byte
**El título no escala por talla: escala por NIVEL DE ENCABEZADO.** El informe
leyó sus cuatro valores como una colisión de `size`, y son `aria-level` 3..6 —
un encabezado más profundo es más pequeño porque es más profundo. Sus tokens
son `article-title-font-size-{3,4,5,6}`, no coordenadas de talla. Tercera
corrección de este tipo a un veredicto en el bloque.
**El ⚠ del `sentinel` eran DOS medidas**, como sospechaba el veredicto: la
fila-sonda mantiene un alto mínimo para que el observador tenga algo que
intersecar, y el spinner que va dentro tiene su propio diámetro.
El feed tipa por debajo del 1:1 de md en adelante, como `table` y `tree-grid`;
la coordenada lo nombra en vez de esconderlo.
**Sobre la medición, que aquí hubo que trabajarla.** La sonda dio 7 diffs y
ninguno era un cambio:
- el `box-shadow` del nodo `[data-busy]` está ANIMADO, y la sonda congela
`transition` pero nunca `animation` —a propósito, porque congelarla impide
que Presence monte nada—, así que lo muestrea en una fase distinta cada vez:
dos corridas del MISMO código dan cinco diffs;
- y el estado `hover` se mide después de haber forzado las tallas, así que su
altura arrastra la última.
Lo que decide es que las SEIS medidas estables —reposo y las cinco tallas—
salieron idénticas al byte: 544,5 · 564,5 · 628,5 · 792,5 · 966,5 px. Queda
escrito en el README para que el siguiente no persiga el mismo fantasma.
audit PASS · eidos-lint 0 invalid · rtl 0 · docs 0 · check 0 en tocados ·
suite: sólo el rojo conocido
Demo con tab Tokens: 50 filas, 0 sin computar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
4cab776677 |
feat(carousel): temable — 0 % → 77 %
Séptimo del bloque F2-A. censo 0 % → 77 % · global 42 % computed 2.842 valores en 7 estados: 0 diffs **Los botones prev/next no se acuñan aquí** — componen `<IconButton>`, así que su cromo es el del Button y un tema los viste por ahí. Esta receta sólo decide DÓNDE se colocan (`trigger-offset`). El veredicto avisaba de comprobarlo antes de copiar filas de trigger, y estaba en lo cierto. **El ⚠ del informe eran DOS gaps distintos**, no un knob con dos valores: el `gap` en columna de la raíz y el `item-gap` ENTRE DIAPOSITIVAS. Y el segundo sólo se aparta del default en `xs`, así que su cascada declara UN override en vez de cinco coordenadas iguales — el TSC no necesita que se le repita lo que ya hereda. **Los puntos del paginador son geometría propia**: 0.375–0.75rem por talla, ni bundle ni desviación que marcar, porque el bundle no tiene coordenada que signifique «un punto». El punto activo se estira a pastilla con un factor que ahora es token (`active-indicator-scale`): es lo que lo hace leer como «estás aquí» y no como un punto más gordo. **El radio interior es concéntrico**, no un segundo radio: viewport y diapositivas redondean por dentro del marco, así que su esquina es la del marco menos el borde — el `2px` suelto pasa a `inner-radius-inset`. Las tres variantes (surface / outline / ghost) entran enteras: padding del marco, borde y superficie. Quedan 5 literales de layout (`block-size: 100%` ×3 para que el viewport vertical no colapse, `max-content` del raíl de puntos) y los 2 privados de paleta. audit PASS · eidos-lint 0 invalid · rtl 0 · docs 0 · check 0 en tocados · suite: sólo el rojo conocido Demo con tab Tokens: 30 filas, 0 sin computar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
3b325c4394 |
feat(listbox): temable hasta donde le toca — 0 % → 68 %
Sexto del bloque F2-A, y el primero cuyo techo es DELIBERADO. censo 0 % → 68 % · global 42 % computed 2.813 valores en 7 estados: 0 diffs **Este componente no puede acuñar su ritmo de fila, y esa es la regla de oro de las capas compartidas.** Altura, padding inline y block, gap y tamaño de letra los posee `lib/list-surface.css`, por talla, para TODAS las superficies de lista —select, combobox, command y los menús—. Acuñar `--listbox-item-height` sería el vocabulario paralelo que las reglas de esa capa prohíben, y encima ganaría a la capa para todas las demás. Los cinco privados ADOPTAN la capa y se quedan privados; un tema mueve ese ritmo por `--list-*`, que es donde vive. Consecuencia honesta: el censo cuenta esos cinco como privados y el alcance se queda en 68 % en vez de ~86 %. **La métrica penaliza hacer lo correcto** — el mismo defecto de medición que D-TH.2-b arregló para los primitivos tipográficos (`--style-*` pasó a `system`). Registrado en `next-features.md` §13; extenderlo a las capas compartidas es decisión, no corrección al paso. **Dos cosas medidas que NO se tocaron:** - El `highlighted` pinta DOS veces: la receta pone un `--color-surface-overlay` plano y encima el arquetipo `item` añade su velo del 8 %. El plano es el duplicado que §38 deprecó, así que se dejó SIN token — bendecir con un nombre público algo condenado a morir es el error que este eje ya evitó en el codemod. Retirarlo mueve píxel. - La tinta de la fila seleccionada era código MUERTO y se retiró: el arquetipo la fija a (0,4,0) contra los (0,3,0) de la receta. Mismo hallazgo que en `table`, verificado igual, 0 diffs al quitarlo. Lo que sí es suyo y ahora es público: la superficie que sostiene las filas (fondo, borde, radio, padding, gap, tipografía, alto máximo), la esquina y la tinta de la fila, el glifo de selección y el grupo con su etiqueta. audit PASS · eidos-lint 0 invalid · rtl 0 · docs 0 · check 0 en tocados · suite: sólo el rojo conocido Demo con tab Tokens: 21 filas, 0 sin computar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
d177ee331c |
feat(gradient-picker): temable — y su trigger resultó estar muerto entero
Quinto del bloque F2-A. censo 0 % → 88 % · global 42 % computed 609 valores en 8 estados: 0 diffs **El hallazgo llegó por el centinela: 36 de 45 tokens no movían nada.** Con esa cifra no se sigue adelante. El trigger es un POPOVER TRIGGER, y `popover.css` le pinta el cromo entero —altura, padding inline, tipografía, color, fondo, borde, radio, hover y foco— desde `[data-popover-trigger]:not([data-archetype='field-trigger'])`, que gana a `[data-gradient-picker-trigger]` en base (0,2,0 contra 0,1,0) y en los estados (0,3,0 contra 0,2,0). Esta receta re-declaraba TODO eso y nada pintaba: la altura, el padding, el tamaño de letra y el radio venían de popover, y con valores distintos —12px contra el `space-2-5` de la receta, 14px contra su `font-size-md`—. Llevaba así desde que el trigger se volvió trigger de popover. Así que no se tokeniza: **se retira**. Un token sobre una declaración muerta es un token que miente, y este eje ya retiró uno por lo mismo en `table`. Retirarlo dio **0 diffs**, que es la prueba de que estaba muerto. Un tema viste este trigger por el contrato de POPOVER, que es composición funcionando. Lo que sí es del picker se queda y alcanza (verificado a mano, porque el chip usa un hook de CLASE que el centinela no ve): el `gap` de la fila, el chip del degradado (tamaño por talla, radio, borde), las tres anchuras del panel, la lista de paradas y la rejilla de presets. **Correcciones al veredicto**, ambas medidas: `--gp-current-gradient` NO lo estampa el wrapper sino SOMA (`gradient-picker-provider.svelte.ts:197`), así que renombrarlo toca otra capa y no es de este commit; y no es un knob de tema sino un canal de valor —el degradado que eligió el usuario—, sobre el que un tema no tiene nada que decir. Las tres anchuras del panel se quedan como tokens planos leídos por tres reglas, no como cascada del TSC: el content va por PORTAL y dimensiona con `data-picker-size` (el atributo de picker-shell), y el vocabulario de scopes no tiene palabra para el atributo de otro componente. Al registro (`next-features.md` §13) van cuatro incidencias nuevas: que un componente compuesto pueda tener el cromo entero muerto sin que nada avise —merece guard, y el instrumento ya existe—, el nombre abreviado en soma, los dos hooks por CLASE que `eidos-lint` cuenta, y el foco opaco del trigger contra la mezcla suave del sistema. audit PASS · eidos-lint 0 invalid · rtl 0 · docs 0 · check 0 en tocados · suite: sólo el rojo conocido Demo con tab Tokens: 25 filas, 0 sin computar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
5596fc8707 |
docs(next-features): el registro de incidencias del eje theme-reach
Encargo del autor: anotar todas las incidencias de esta clase para resolverlas después. Van al registro canónico (`next-features.md`), no a un sitio nuevo, y con su MEDICIÓN — no como impresión. **§12 — El contrato de cascada del velo de estado.** Seis incidencias que resultaron ser la misma: nadie fijó nunca cómo compone el velo de `archetypes.css` con las reglas de una receta. Y la raíz explica por qué se manifiestan de formas tan distintas: el velo se pinta con DOS pesos según el arquetipo — `:where()` (0,0,0) para `trigger`, especificidad plena (0,5,0) para `item`/`option`. 131 declaraciones-atajo en 45 componentes cancelan el velo (66 BASE · 32 ACENTO · 23 HOVER · 10 OTRA; cero valores con gradiente, así que el paso a longhand no tiene riesgo técnico; 32 nodos velados que hoy no reaccionan al ratón pasarían a hacerlo) · la prop `hoverable` de table no suprime nada · en tree-grid el empate (0,5,0) lo decide el ORDEN DE CARGA y varía entre recargas · la banda de tree-grid mata el hover en las filas pares · un token de tinta no puede ganar al arquetipo (`selected-row-fg` se retiró por eso) · el thumb de scroll-area no tiene velo al que migrar. Esto explica de paso la adopción 21/135 que midió la auditoría del 2026-07-01: el velo estaba escrito y estructuralmente derrotado. **§13 — Huecos de instrumento y de demo.** Lo que hizo que una medición mintiera o no existiera, que importa porque el eje entero se apoya en ellas: falsos negativos del centinela sobre propiedades transicionadas, pseudo-elementos y componentes compuestos que no ve, la sonda que no pasa el ratón por un `<tr>`, y la lección general —**una sonda sobre una parte que la demo no monta compara CERO valores y pasa**—, con la lista de partes condicionales afectadas. El handoff gana la regla para las sesiones del eje: si una incidencia mueve píxel o toca morfo, se mide, se anota ahí y se sigue; no se arregla dentro del commit del componente. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
9748733adc |
feat(tree-grid): el árbol se vuelve temable — 0 % → 95 %
Cuarto del bloque F2-A. 42 knobs con 29 privados que no derivaban de nada; ahora 47 claves públicas y tres privados, los tres legítimos. censo 0 % → 95 % · global 41 % → 42 % computed 9.744 valores en 7 estados: 0 diffs **Las guías de indentación eran UN color, no un fondo.** Lo que la propuesta llamaba `root-bg-image` son las líneas verticales por `aria-level`: cinco gradientes apilados que dibujan una línea por ancestro. El knob es `guide-fg` (+ `guide-width`); la construcción se queda en la receta — el mismo reparto que el damero de gradient-builder, donde el color es el token y el patrón es de la receta. **Tres privados sobreviven, y por razones distintas**: `--_tree-grid-columns` no es un knob de tema sino un CANAL de layout que el wrapper escribe inline desde la definición de columnas del consumidor; `--_tree-grid-palette-element` es el forward THM-2; `--_tree-grid-stable-rows` es dato del consumidor. **El hover de fila es no determinista, y viene de antes de este eje.** Dos hallazgos medidos: 1. En filas CON BANDA el hover está muerto: la regla de `striped` pesa (0,7,0) contra los (0,5,0) del hover y usa el atajo, así que en las pares no ocurre nada al pasar el ratón. 2. En las demás, quién gana depende del ORDEN DE CARGA: el velo del arquetipo `item` y el hover de la receta empatan EXACTAMENTE a (0,5,0). Seis corridas de la misma configuración dieron cuatro veces «sin velo» y dos «con velo». Eso segundo obligó a parar y caracterizarlo: al ver 3 diffs tras un cambio trivial (un `border-width` a token) lo primero que hice fue sospechar de mi cambio; comparar dos corridas del MISMO código dio los mismos 3 diffs, así que no era el código sino un empate de especificidad resuelto por orden — la misma clase de fragilidad que el canon documenta para las bandas de z-index. No se toca aquí: decidir quién manda mueve píxel y es la decisión pendiente del velo. El guard de huérfanos cazó tres tokens que acuñé suponiendo (`font-family`, `fg`, `surface-bg`): existían en la receta pero leyendo el valor crudo. Ahora los leen, que es justo lo que el eje persigue. audit PASS · eidos-lint 0 invalid · rtl 0 · docs 0 · check 0 en tocados · suite: sólo el rojo conocido `skin-media-player` Demo con tab Tokens: 47 filas, 0 sin computar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
8324e2cedb |
docs(theming): partir recipes/base.ts, al terminar el eje entero
Pregunta del autor: por qué los tokens de 128 componentes viven en un fichero
de 6.223 líneas y no junto a su componente.
La respuesta medida: NO es un fichero de tokens, es el valor del campo
`recipes` de `EidosConfig` —serializable, que un tema hidrata—, y por eso los
valores no pueden mudarse a `components/{x}/`: ya se intentó y se retiró («The
old `tokens/components/*` were retired»). Lo que sí puede repartirse es la
AUTORÍA, con un fichero por componente que `base.ts` compone.
Verificado antes de proponerlo: el muro de tipos de `defineRecipes` sigue
disparando cuando las claves llegan por spread desde un fichero suelto —
probado con `trigger-color` y `padding-x`, ambas siguen sin compilar. Y el
único consumidor sensible a la forma (`eidos-purge`, que hace `Object.keys()`)
es indiferente.
Va al final de TODO el themeable, no al cerrar el bloque: mientras quede un
componente por tokenizar, ese fichero se toca en cada commit, y mover 6.000
líneas en medio garantiza conflicto con cualquier sesión que esté trabajando.
Los tres costes que justifican hacerlo se midieron hoy: casi entra un SEGUNDO
bloque `table` que el catálogo habría descartado en silencio, una coma perdida
rompió el catálogo entero dos veces, y es el punto de conflicto de todas las
sesiones concurrentes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
00cc9d76cf |
fix(media-player): el skin de audio SÍ se puede medir — y sale a cero
Corrección de una nota que escribí mal hace un commit. Dije que `audio-player` no tenía demo porque `/uix/components/audio-player` da 404. El autor lo corrigió: **la demo es la de `media-player`**, y el chip `media` conmuta a audio — ahí entra `<AudioPlayer variant>` sobre las mismas partes. El 404 es correcto; lo que estaba mal era mi lectura de él. Que la sonda encontrara 0 nodos no significaba «sin demo»: significaba que cargaba en modo VÍDEO. Y una comparación de 0 valores pasa siempre, así que ese «0 diffs» no valía nada — la clase de guard que este eje ya tiene anotada. `scripts/__probe-audio-skin.ts` pulsa el chip y recorre las cuatro variantes (card · row · bar · inline). Medido contra el commit anterior, revirtiendo los cuatro ficheros a HEAD~1 y restaurándolos: **1.008 valores, 0 diffs, 0 nodos ausentes**. El skin lee los públicos nuevos y pinta exactamente igual. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
b7a4cef08f |
feat(media-player): el proyector se vuelve temable — 0 % → 88 %
Tercero del bloque F2-A. 45 knobs sin contrato salvo el acento; ahora 61 claves públicas, **cero privados y cero globales**. censo 0 % → 88 % · global 40 % → 41 % computed 3.277 valores en 7 estados: **0 diffs** **El veredicto pedía renombrar `--_mp-*` → `--_media-player-*`; hacen falta menos pasos que eso.** El prefijo abreviado viola theming §6 r5, cierto, pero al leerlos uno a uno los dieciséis privados eran ALIAS PUROS de su fuente (`--_mp-fg: var(--color-content-primary)`, `--_mp-accent: var(--media-player-accent)`…). Un alias puro no se renombra: se borra. La capa privada entera desaparece y cada knob pasa a público. **El acento firmado NO se tocó**: `accent`/`accent-strong` siguen siendo `--scale-amber-9/10` — acento de proyector theme-stable, que debe leerse sobre cualquier vídeo en claro Y oscuro, con su doctrina escrita en el propio bloque. Verificado en vivo que sigue re-tintando el rango del Slider compuesto. **El scrim: UN color, dos gradientes.** La tira inferior de controles y el degradado del título salen del mismo `--media-player-scrim`; dos tokens dejarían que un tema rompiera la pareja sin querer. **`audio-player` viajaba en el mismo barco y no era obvio**: consume siete de esos tokens sin declarar ninguno. No es fuga entre componentes — es un SKIN sobre las mismas partes (`[data-media-player][data-variant]`), así que están en ámbito. Su receta se migró en el mismo pass. **Lo que no se pudo medir, y se dice**: `audio-player` no tiene página de demo (la ruta da 404), así que la sonda encontró 0 nodos — y una comparación de 0 valores pasa siempre, que es justo la clase de guard que no vale. Se verificó a mano estampando `data-variant` sobre el player vivo: el padding pasó a `6px 12px`, exactamente los tokens nuevos. Hueco de demo anotado en el README. Centinela 36/61. Los 25 restantes, adjudicados por clase: partes no montadas en la demo (captions, buffering, título de audio, paneles portalados), un pseudo-elemento (`::after` del scrim) y los que pintan DENTRO del Slider compuesto — verificado a mano que `--media-player-track` sí llega hasta `--slider-track-bg`. Los 6 knobs que quedan son literales de relleno (`100%`, `max-content`). audit PASS · eidos-lint 0 invalid · rtl 0 · docs 0 · check 0 en tocados · suite: sólo el rojo conocido `skin-media-player` Demo con tab Tokens: 61 filas, 0 sin computar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
564133b485 |
feat(table): la rejilla se vuelve temable — 0 % → 86 %
Segundo del bloque F2-A. 46 knobs sin una sola entrada de contrato; ahora 45
claves públicas.
censo 0 % → 86 % · global 39 % → 40 %
computed 13.050 valores en 7 estados: **0 diffs**
**Una trampa esquivada de milagro**: `table` YA tenía bloque en `base.ts` — los
forwards de paleta THM-2. Insertar uno nuevo habría creado un segundo bloque
`table:` y el catálogo lo habría descartado EN SILENCIO (gana el último). Las
claves se fusionan en el existente; el guard de duplicadas lo confirma.
**Dos nombres corregidos, como decía el veredicto**: lo que el privado llamaba
`root-height-{k}` es la altura de la FILA (`row-height-{k}`), y el prefijo
`root-` desaparece del resto — el envoltorio ES el componente y
recipe-contract §1 no repite la parte en ese caso.
**Qué casa con el bundle y qué no**, medido eje a eje: la altura de fila sí
(1:1); el padding NO (la rejilla empaqueta más denso en xs y más suelto de md
en adelante — forzar el bundle cambiaría el default); y la tipografía casa
DESPLAZADA: de md en adelante la tabla tipa un paso por debajo
(`font-size-md` = `var(--size-sm-font-size)`), que es deliberado y ahora se lee
en el propio nombre de la coordenada en vez de esconderse en un primitivo.
**Dos hallazgos del arquetipo `item`, y ninguno es mío** — la fila lo lleva, y
ese velo de `archetypes.css` está a especificidad PLENA (0,5,0), a propósito:
1. **La prop `hoverable` no suprime nada.** Una fila se ilumina al pasar el
ratón aunque el atributo no esté — medido con hover real, y ocurría ANTES de
tocar esta receta. El arquetipo y la prop no se ponen de acuerdo sobre quién
decide: es decisión de morfo, se presenta, no se toca de oficio.
2. **`selected-row-fg` era un token que mentía.** La misma regla fija el
`color` de la fila seleccionada y gana a la receta (0,5,0 contra 0,3,0), así
que el token no podía mover nada nunca. Lo cazó el centinela; retirado con su
declaración muerta. La tinta de la fila seleccionada es del arquetipo.
Y una corrección de rumbo a mitad de camino: al pasar todo a `background-color`
el velo apareció en 3 sort-triggers (su velo sí va en `:where()`, 0,0,0). Eso
es el barrido sistemático del velo, que NO está firmado — así que en los nodos
velados se mantiene el atajo a propósito, con el porqué escrito en la línea.
Primero lo diagnostiqué como regresión mía; la medición lo corrigió.
Los 6 knobs que quedan: 3 privados de paleta (patrón THM-2, capa compartida) y
3 literales de layout/identidad (`inline-size: 100%` ×2, `opacity: 1`).
El test `horizontal-escape` afirmaba el nombre del privado; ahora afirma el
público, que es justo lo que este eje persigue.
audit PASS · eidos-lint 0 invalid · rtl 0 · docs 0 · check 0 en tocados ·
suite: sólo el rojo conocido `skin-media-player`
Demo con tab Tokens: 46 filas, 0 sin computar. README con «Talla y tema» y los
dos hallazgos del arquetipo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
b43e7e2ec0 |
docs(theming): el tab Tokens entra en el protocolo del bloque
Cada componente que se tokenice engancha su tab en el mismo commit — una línea, porque el panel lee el contrato vivo y no hay tabla que mantener. `command` queda marcado como cerrado en la tabla del bloque. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
90aa6dc5f0 |
feat(demos): la demo enseña el contrato de tokens — `TokensPanel`
Hallazgo del autor mirando `command`: la demo no enseñaba su superficie de tema. Al ir a comprobarlo salió que **ninguna** demo lo hacía — ni las que este eje ya llevó de 0 % a 98 %. El tab `recipe` lista SELECTORES; los tokens no aparecían en ningún sitio, y lo más cerca era el tab `system` de 23 demos, que en `sidebar` enseña 3 de sus 40 claves. Un componente temable cuya demo esconde sus tokens está a medio entregar: la demo es el producto. `TokensPanel` es un panel COMPARTIDO (junto a SemaPanel / MotionPanel / SystemAxes), no una tabla a mano por demo: pregunta `eidos.getRecipeTokens(component)` — la misma entrada de `recipes/base.ts` que alimenta al generador — así que un token añadido, renombrado o retirado aparece aquí sin que nadie se acuerde de tocar la demo. Una lista escrita a mano sería una segunda fuente de verdad, y en este repo ya está medido lo que cuestan. Tres columnas: el nombre, el valor DECLARADO, y lo que COMPUTA sobre el escenario vivo. Esa tercera es la que convierte «es temable» en algo que se ve en vez de algo que el doc afirma. Un knob por talla o por ámbito se muestra como tal en vez de fingir un valor único. Verificado en el navegador con `command`: **57 filas, 0 sin computar** (`--command-input-padding-inline-sm` → `var(--size-sm-padding-inline)` → `calc(8px * 1 * 1)`). Entra en el protocolo del bloque F2-A: cada componente que se tokenice engancha su tab en el mismo commit. Para los 160 que aún no tienen contrato el panel dice justo eso — que todavía no son alcanzables por un tema. check 0 errores en ficheros tocados Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
4ddea7fe29 |
feat(command): la paleta se vuelve temable — 0 % → 98 %
Primer componente del bloque F2-A, y el peor del catálogo con veredicto
verificado: 52 knobs y NINGUNA entrada de contrato. Ahora tiene 57 claves y no
le queda un solo privado.
censo 0 % → 98 % · global 38 % → 39 %
computed 8.091 valores en 8 estados (reposo · 5 tallas · abierto · hover):
**0 diffs**. El default no se movió.
**El eje `size`** sigue el patrón firmado en Sidebar: coordenadas por talla en
`root` + nombre RESUELTO con `declarations` (default `host` = md, overrides
`size:sm`/`size:lg`), que es lo único que la receta lee. Los bloques
`[data-size]` del CSS se RETIRAN: dejarlos vivos pisaría los tokens nuevos con
los valores viejos y el diff daría 0 porque la ruta vieja seguiría mandando —
la trampa que este eje ya pagó una vez. Las cuatro coordenadas casan 1:1 con el
bundle, medido (`--size-{k}-padding-inline` / `--size-{k}-font-size`), así que
leen la coordenada y no el primitivo suelto — que es justo lo que
`recipe-css-contract` exige, y lo cazó: `group-heading-font-size` entró como
`var(--font-size-xs)` y salió como `var(--size-xs-font-size)`.
**El radio y el modo Dialog**, que el veredicto marcaba como ⚠ colisión y no lo
era: dentro de `<Command.Dialog>` el panel que el usuario ve ES el del dialog,
así que la regla de contexto reapunta el propio público a
`var(--dialog-content-radius)`. Leer el público de un hermano donde ese hermano
ES la superficie es composición correcta, no un segundo token — y de paso el
componente se queda sin privados (antes el radio vivía en `--_command-radius`).
**El hueco del scrollbar** se resuelve con el patrón de combobox:
`viewport-padding-inline` + `scrollbar-inset`, y la regla del overflow los
compone.
**Centinela: 50/57 tokens mueven un computed.** Los 7 restantes, adjudicados
uno a uno en el navegador, no por conjetura:
5 `loading-*`, `viewport-padding`, `empty-*` — sus partes NO están montadas
en la demo (el estado vacío, la barra de carga y el scroller interno son
condicionales). No se puede medir lo que no existe.
1 `input-placeholder-fg` — `::placeholder` es pseudo-elemento y
`getComputedStyle` sobre el nodo no lo ve. Límite del instrumento.
1 `input-border` — FALSO NEGATIVO del centinela: comprobado a mano tres
veces (con la misma congelación de transición que él usa) el token SÍ
alcanza, `oklch(0.3485)` → `rgb(1, 2, 3)`. No he encontrado por qué el
centinela lo pierde; queda anotado como defecto del instrumento.
`R-5.1 exception: inline-size: 100%` — el panel rellena su contenedor; es
mecánica de layout, no apariencia. Es el 2 % que falta.
audit PASS (R-5.3 incluida) · eidos-lint 0 invalid · rtl 0 · docs 0 ·
suite: el único rojo es el conocido `skin-media-player`
README con la sección «Talla y tema» (molde navigation-menu).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
bd032534be |
feat(census): los primitivos tipográficos se miden contra su capa — pieza 0 de F2-A
D-TH.2-b, la firma que va ANTES del bloque porque cambia el suelo del censo: medirla a mitad de camino falsearía todos los antes/después. `heading` marcaba «36 knobs, 0 % alcanzable» y eso no era deuda: era una lectura equivocada. Su receta resuelve cada eje como `var(--_heading-font-size, var(--style-h2-font-size))` — el privado es el escape POR INSTANCIA que el wrapper escribe desde una prop, y el named style es la superficie de tema, ya pública y viva. Acuñar `--heading-*` para espejarla sería un alias por eje × nivel: la clase que mató la purga del changelog §39. El criterio de qué ES un primitivo tipográfico se midió, no se supuso: o la receta SELECCIONA por `data-style` (`heading`, `text`, `s-text` — el named style es su API) o está atada entera a UN style (`code` → `--style-code-*`, `display` → `--style-hero-*`, `label` → `--style-label-*`). `code-block` queda FUERA a propósito: lee un par de tokens de style para su texto pero posee cromo de caja real, y eso sí es suyo. Detalle que costó una vuelta: la comprobación va ANTES de la de privado. Leer el privado primero puntúa el primitivo entero como inalcanzable cuando es completamente temable — por la capa que lo posee. antes 5.199 knobs · 1.837 públicos (37 %) · 894 privados · 232 sistema después 5.199 knobs · 1.837 públicos (38 %) · 788 privados · 338 sistema **Gate**: 106 knobs pasan de `private` a `system` en los SEIS primitivos y **cero** de los otros 156 se mueve — verificado componente a componente contra la versión en HEAD, no a ojo. Alcance `—` (nada que poseer) para heading, text y display; `s-text` al 100 %; `code` y `label` bajan a 7 y 2 knobs de deuda real. Informe regenerado (171 veredictos a mano intactos), veredicto de heading anotado como ejecutado, y recipe-contract §1 gana el párrafo que fija el criterio — incluida la frontera: un menú que lee `--style-label-font-family` para una etiqueta NO es un primitivo y no entra en el conjunto. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
5ee796fa98 |
docs(theming): el bloque F2-A preparado — ocho componentes, sus defectos y sus gates
La cola revisada se eleva a plan de bloque: pieza 0 de instrumento (D-TH.2-b: la familia tipográfica mide por --style-* — va primero porque cambia el suelo del censo), los ocho componentes con sus defectos MEDIDOS (censo) y la corrección que su veredicto §5 ya verificó contra el CSS, los gates de §7 por componente, y la revisión adversarial al cierre. 330 knobs hoy a 0 %; el bloque debe llevar el global de 37 % a ~42 %. Y al cerrarlo, el orden de lo que las firmas desbloquearon: el diseño de calendar-surface (220 knobs más), el mandato Field, y el resto de B1-B8. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
80b22fb60c |
docs(eidos): los README de componente hablan el idioma nuevo — claves sueltas
El codemod reescribe tokens COMPLETOS (`--{c}-clave`); un README que cita la
clave a pelo (`input-color`, `dot-color`) se le escapa. Barrido de los 180
README/CONTINUE contra los dos planes del codemod: 19 apariciones entre
backticks en 14 ficheros, de las que sólo 10 en 6 ficheros eran CLAVES — el
resto era la PROP `color` (los 9 roles), que está viva y no se toca. La
adjudicación fue con el contexto delante, no con un replace a ciegas: la línea
«Eidos añade `size`, `variant`, `color`» habla de la prop; la línea
«`gap`, `font-size`, `color`, `min-block-size`» lista claves.
Corregidos: chat-typing (2) · chat-composer (4) · chat-list (1) ·
password-field (1) · waveform (2, incluida la lista de contrato en su bloque
de código, anotada con el nombre viejo como crónica).
Re-barrido tras corregir: 0 restantes. `docs:check` 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
e20e8b8095 |
docs(theming): el informe habla el idioma nuevo — y el fleco del README, cerrado
Al rendir cuentas del repaso de los 7 salió un fleco: el README de gradient-builder mencionaba `checker-color` por su clave SUELTA, sin el prefijo `--gradient-builder-`, y el codemod busca tokens completos — quedó con el nombre muerto. Dos líneas corregidas, más las dos del §5 de su ficha. Y la causa de fondo: las 170 fichas del informe llevaban desde el codemod citando el contrato con los nombres viejos en sus secciones generadas. Regenerado entero (`--report`): 69 fichas cambian, los 171 veredictos §5 escritos a mano sobreviven (verificado), `docs:check` 0. El censo del informe registra 5.199 knobs · 1.837 públicos — cuatro menos que el suelo del codemod, que son EXACTAMENTE las cuatro declaraciones de hover bespoke que la firma 3 retiró (checkbox, splitter, switch, drp ×2 −1 nueva del checked). El alcance global sigue en 37 %. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
d27e2ac9fc |
docs(theming): la firma 3 al día — y el atajo que llevaba dos meses ganando
Cuatro componentes migrados con su medición, y el diagnóstico que cambió al ejecutar: el velo del sistema no llegaba a ninguno, y la culpa no era del hover propio sino de la regla base — el atajo `background:` pesa (0,1,0) contra el `:where()` (0,0,0) de archetypes.css y fija `background-image: none` para siempre. Queda escrito lo que NO he hecho y por qué: scroll-area pide decisión de morfo (su thumb no lleva arquetipo con velo), el barrido de las otras 141 declaraciones no entra en una firma que se dio sobre knobs concretos, y la demo del date-range-picker no monta `kind`, así que su overview no se puede medir. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
0c80a8efb8 |
fix(date-range-picker): el overview hereda el velo, y su demo no lo enseña
Firma 3, cuarto componente. Los cuatro nav del overview llevan `archetype: 'trigger'` y sus celdas `archetype: 'item'`: los dos reciben velo de `archetypes.css`. Y los dos lo tenían cancelado por la misma causa que el resto — `background: transparent` es el ATAJO y también fija `background-image: none`, con (0,1,0) contra el `:where()` (0,0,0). reglas base `background: transparent` → `background-color: transparent` reglas hover fuera las dos; el velo las sustituye contrato `hover-overview-nav-bg` y `hover-overview-cell-bg`, retiradas **La verificación aquí es más floja que en los tres anteriores, y conviene decirlo**: la demo monta UN picker sin `kind`, así que el overview de mes/año no se renderiza nunca y la sonda no puede medir el pintado (2 nodos vistos). El artefacto es la forma del CSS y el arquetipo leído del morfo, no un computed antes/después. El mecanismo sí está medido tres veces (checkbox, splitter, switch). Queda anotado un hueco de demo: `kind='month'` y `kind='year'` son la mitad de la API del picker (norma N-6) y la superficie de demo no los expone, así que esas partes no se pueden ver ni medir. La demo es el producto. audit PASS · censo 40 % · suite 434 (1 rojo conocido) · rtl 0 · docs 0 Nota aparte: las celdas conservan `background:` (atajo) en `[data-in-range]` y `[data-range-start/end]`. Son estado de rango con valencia, no hover neutro — fuera del alcance de esta firma, pero cancelan el velo igual. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
3219a19c3c |
fix(switch): el velo para el off, el swap de paleta para el checked
Firma 3, tercer componente, y el primero donde la regla servía DOS hovers a la
vez: `--_switch-track-bg-hover` resolvía al color neutro cuando el switch está
off y al `palette-solid-hover` cuando está checked. recipe-contract §2 los
separa —el neutro es la capa del sistema, el con valencia es el swap de la
receta— así que la regla se parte en dos:
`[data-switch]:hover` sólo el borde; el fondo lo pone
el velo de archetypes.css
`[data-switch][data-state=checked]:hover` `background-color:
var(--_switch-palette-solid-hover)`
Y la regla base pasa a `background-color:` por lo mismo de siempre: el atajo
fijaba `background-image: none` y ganaba al `:where()` del sistema.
Medido (377 valores, 7 estados): 2 diffs, los dos en el hover del track off —
el velo aparece y el fondo vuelve a su base. Verificado además en el navegador
que las DOS reglas viven y que el swap del checked sigue en pie.
`track-bg-off-hover` sale del contrato, y con él el privado que lo reenviaba.
censo switch 57 % · audit PASS · suite 434 (1 rojo conocido)
Nota de método: borrar la clave por línea partió una declaración multilínea
(clave y valor en líneas distintas) y dejó el valor huérfano — esbuild lo cazó
al regenerar. Un rename en sitio es seguro; un borrado necesita mirar si el
valor va debajo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
c66b738101 |
fix(splitter): el asa recupera el velo del sistema
Firma 3, segundo componente, y la misma pareja de causas que el checkbox: el asa lleva `archetype: 'trigger'`, así que `archetypes.css` le pinta el velo, pero la regla base declaraba el ATAJO `background:` (0,1,0) y lo cancelaba contra el `:where()` (0,0,0) del sistema. Encima había un hover propio con su propio color. regla base `background:` → `background-color:` regla hover fuera entera; el velo la sustituye Medido (812 valores, 7 estados): 2 diffs, ambos en el hover del asa — `bg oklch(0.8853) → oklch(0.931)` y `img none → linear-gradient(rgb(0 0 0 / 0.08))`. Reposo, tallas, dragging, disabled y foco: idénticos. El estado `dragging` conserva su acento (`--splitter-active-handle-bg`), que es un hover CON VALENCIA y no le toca la capa neutra. `handle-bg-hover` sale del contrato: sin consumidores. censo splitter 100 % · audit PASS · suite 434 (1 rojo conocido) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
b35855c20d |
fix(checkbox): el velo del sistema vuelve a pintar — y el atajo era el culpable
Firma 3, primer componente. El checkbox tenía un hover propio
(`bg-off-hover`, un `color-mix` del surface al 82 %) de los que §38 deprecó, y
al quitarlo apareció que el velo del sistema no volvía. La causa no era el
hover: era la regla BASE.
`[data-checkbox] { background: var(--checkbox-bg-off) }` usa el ATAJO, que fija
`background-image: none`, y esa regla pesa (0,1,0) contra el `:where()` de
`archetypes.css`, que pesa (0,0,0). El velo perdía la cascada SIEMPRE — no en
hover, nunca. El hover bespoke no era un capricho: era la cicatriz de que el
velo del sistema no llegaba, y con él delante nadie lo notó.
Dos cambios, uno por causa:
regla base `background:` → `background-color:` (longhand), que deja libre
`background-image` para el velo
regla hover fuera el `background` propio; queda el `border-color`, que es
otro eje y otra decisión
Medido en el navegador (sonda de computed, 2.436 valores en 7 estados):
antes hover bg `srgb 0.974` · img `none` ← el velo, ausente
después hover bg `oklch(0.9911)` · img `linear-gradient(rgb(0 0 0 / 0.08))`
reposo intacto · tallas intactas · disabled intacto · foco intacto
8 diffs, todos en el hover y sólo en esas dos propiedades. El hover queda algo
MÁS visible que antes (0.911 efectivo contra 0.974): es la calibración del
sistema, que es justamente lo que la firma perseguía.
`bg-off-hover` sale del contrato: sin consumidores, y un alias público que
nadie consume rompe `recipe-css-contract`.
censo checkbox 47 % · audit PASS · eidos-lint 0 invalid · suite 434 (1 rojo
conocido) · rtl 0 · docs 0
No adjunto captura: el panel del navegador no está visible en esta sesión y el
screenshot expira. La evidencia es la medición de computed sobre Chromium real.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
476da2dd23 |
feat(eidos): el tercer muro — `color` como slot deja de compilar
Cierra el triple muro de D-TH.6, con el mismo molde que la normalización px/py del 2026-07-06: el codemod vacía la deuda, R-5.3 la vigila al correr el audit, y el tipo la impide mientras escribes. El muro de tipos es el único que no necesita que nadie ejecute nada. Ayer no podía entrar: disparaba sobre 17 claves de hover neutro que todavía decían `color`. El commit anterior las renombró al descubrir que no eran capa de estado, así que ahora el catálogo compila limpio y el muro sube. Las tres exenciones firmadas van DELETREADAS, no encajadas en un patrón laxo —una exención que no se puede leer es una que nadie puede auditar—: `*-focus-ring-color` (espeja la familia del sistema), `orb-color-*` (color como sustantivo) y `stop-color-*` (una parte de gradient-builder). Muta-prueba: `mutant-trigger-color` → NO COMPILA, con el mensaje que enseña la regla las tres exenciones → compilan catálogo actual → 0 errores en recipes Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
93017975ca |
fix(eidos): la capa de estado es un VELO — 38 hovers que no lo eran, al idioma
El codemod de ayer apartó 47 knobs «en cola de migración a la capa de estado».
Al empezar esa migración se ve que sólo SEIS lo estaban: el velo de §38 es
`background-image: linear-gradient(var(--state-hover), var(--state-hover))` y
no alcanza nada más. De los otros 41, veintidós mueven un BORDE y diecinueve
mueven la TINTA — ninguno es la capa de estado por muy neutro que sea su valor.
Eran deuda de nombre, y yo los había excluido del renombrado.
El clasificador tenía media prueba: miraba el VALOR (¿neutro o con valencia?) y
no la PROPIEDAD. Ahora exige las dos, siguiendo un salto por privado
(`--_switch-track-bg-hover`) y entre componentes (la familia calendar presta
`--calendar-control-*` a month-grid, range-calendar y year-grid, y por eso
esos cuatro no aparecían consumidos en su propia receta).
renombres 38 en 22 componentes · 113 referencias en 30 ficheros
cola real 6 (checkbox · date-range-picker ×2 · scroll-area · splitter ·
switch) — los únicos que pintan fondo
censo 162 · 5.203 · 1.841 (37 %) · 56 — IDÉNTICO
--names 38 → 0 desviadas
diff generated 38 renombres 1:1 · 0 cambios de valor
computed field · tabs contra la línea base ORIGINAL (anterior a las dos
pasadas): 4.031 valores, 16 estados, 0 diffs
huérfanos 0 · formato sin regresión · audit 163 PASS · rtl 0 · docs 0 ·
suite 434 pasan (1 rojo conocido) · check 0 errores en ficheros tocados
La muta-prueba se reescribió contra el catálogo vivo — asertaba nombres que el
codemod ya había renombrado — y gana los casos que faltaban: un knob de borde
neutro es `modifier`, uno de tinta neutro es `both`, y sólo los de fondo son
`state-layer`.
Queda una pregunta que §38 no contesta y que NO he decidido: si un hover de
borde o de tinta POR COMPONENTE debe existir siquiera. R-4.3 guarda
`background*` en `:hover`, nada más. Ahora al menos se llaman como deben
mientras se decide.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
e154b23fb9 |
docs(theming): el handoff al día — el bloque del vocabulario, cerrado
Los cuatro pasos hechos, con sus commits, y lo único que queda del bloque: el tercer muro (el tipo de `defineRecipes`) espera a que la migración a la capa de estado vacíe las 17 claves de hover neutro que todavía dicen `color`. Y las cuatro cosas que el bloque enseñó a base de costar vueltas: el plan se escribe antes de tocar nada o el verificador mide el vacío; un valor puede cambiar de texto sin cambiar de significado; prettier en masa reformatea deriva ajena (88 de 101 ficheros ya salían sucios por el CRLF del checkout); y un hover se clasifica por su VALOR, nunca por su nombre — cosa que este mismo handoff tenía mal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
7781d6e4c8 |
feat(audit): R-5.3 — la gramática de los nombres deja de ser prosa
El canon de nombres llevaba meses documentado y sin guard, y la medición del
2026-07-01 ya decía qué le pasa a un canon así: deriva entre el 30 y el 85 %.
Había derivado. El codemod de ayer lo normalizó; esto es lo que impide que
vuelva.
R-5.3 valida una FORMA, no una lista — ahí se separa del guard de eventos, que
comprueba pertenencia a un vocabulario cerrado. La forma es: tinta = `fg`,
modificador interactivo DELANTE, y detrás lo dimensional y contextual.
No reimplementa la gramática: la consume de `theming-census --names`, que es
la misma fuente sobre la que corrió el codemod. Dos implementaciones de una
gramática son dos gramáticas que acaban discrepando — y este repo ya pagó esa
factura con `commit-resize`, un hook muerto tres meses en una receta con todos
los tests en verde.
Entra en `error` directo, sin rampa `warn`, porque su deuda murió en el mismo
pass (precedente R-4.4). Las claves en cola de migración a la capa de estado se
reportan APARTE: no son deuda de nombre, son knobs que van a desaparecer, y
renombrar lo condenado es churn.
Muta-prueba de tres caras, que es lo único que distingue un guard de un guard
que pasa sobre el vacío:
`-bg-hover` con valor de acento → ROJO
`trigger-color` → ROJO
`primary-solid-hover` → VERDE (canónica: COLOR_ROLE_SLOTS pone
el modificador detrás por construcción)
La tercera es la que importa: es el fallo que un codemod ingenuo habría
cometido sobre las 47 claves de rol, `button` entero incluido.
Doctrina en el mismo pass: recipe-contract §1 gana las dos filas que le
faltaban (tinta y estado) más la frase que las gobierna y las dos familias con
gramática propia; §4 gana la fila R-5.3; theming §6.7 una nota fechada que
acota el principio de plataforma del px/py a los ejes dimensionales. El
checklist de cierre declara la regla — lo cazó `docs:check` con su propio
guard I5, que exige que toda regla del audit esté declarada allí.
Lo que NO entra, y por qué: el tercer muro (el tipo en `defineRecipes`, molde
`PhysicalAxisKey`) está escrito y probado, y dispara sobre 17 claves — los
hovers neutros que la firma 3 manda migrar. Meterlo hoy rompería `npm run
check` a todo el mundo por una deuda que ya tiene dueño y fecha. Entra cuando
la migración a la capa de estado las vacíe; son dos líneas entonces.
component:audit 163 PASS · 3 NEEDS-WORK (badge, mockup, motion — los tres
sin tocar por esto, R-5.3 pasa en los 166)
docs:check 0
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
bd916ef3fb |
refactor(eidos): el catálogo habla un idioma — 269 claves al vocabulario firmado
D-TH.6, ejecutada. El slot de tinta pasa a `fg` y el modificador interactivo
se pone delante, que es lo que theming §6.7 r7 documentaba sin guard desde
que se escribió. Value-preserving: renombra la clave en `recipes/base.ts` y
sus 793 referencias en 101 ficheros; no toca un solo valor.
claves renombradas 269 en 66 componentes
referencias 793 en 101 ficheros
censo antes/después 162 recetas · 5.203 knobs · 1.841 públicos (37 %) · 56
sin contrato — IDÉNTICO, como debe ser un rename
--names antes/después 269 desviadas → 0
Qué NO entra, y por qué:
47 `{rol}-{slot-de-rol}` canónicas: COLOR_ROLE_SLOTS pone el modificador
detrás POR CONSTRUCCIÓN (`primary-solid-hover`)
13 exentas firmadas `--focus-ring-*` es familia del sistema; el color
de `aura` es un sustantivo; `stop-color` ES una
parte de gradient-builder
47 hovers neutros por VALOR: migran a la capa de estado
(§38 + R-4.3), no se renombran — firma 3
6 ocurrencias en historia changelog, errores-toxico, PLAN-affix/background:
reescribir un registro fechado lo vuelve mentira
El clasificador vive en el censo (`--names`), no en un script suelto, para que
el guard R-5.3 consuma la MISMA gramática que el codemod. Su muta-prueba
(`__names-mutatest.ts`, 27 casos) es lo que hizo el trabajo: cazó que yo
promovía al frente CUALQUIER valor declarado por el morfo, y así
`--sidebar-width-icon` (la anchura del raíl colapsado) se convertía en
`--sidebar-icon-width` (la anchura de un icono), que es otra cosa. La firma
dice «delante lo interactivo, detrás lo dimensional y contextual»: ahora sólo
promociona el vocabulario interactivo cerrado, y lo contextual —`below`,
`loaded`, `vertical`, `icon`— se queda donde estaba. Los cinco casos de
regresión están en la muta-prueba.
También cazó que `dropdown-menu.item-bg-hover` lee `var(--color-primary-element)`:
es un hover CON VALENCIA (el palette swap de recipe-contract §2), no el hover
bespoke que §38 deprecó. Clasificar por el nombre lo habría metido en una
migración que no le toca; se clasifica por el VALOR.
Verificación (§7.4, artefacto por paso):
diff de generated/ 269 renombres 1:1 · 0 cambios de valor · 22 privados
reapuntados a los nombres nuevos (`__names-verify-diff`)
computed tag-group · field · tabs: 6.467 valores en 23 estados,
0 diffs — y comprobado en el navegador que sirve el CSS
nuevo, para que ese 0 no sea el de una copia cacheada
huérfanos 0 en código
suite eidos 434 pasan · 1 rojo, el conocido (`skin-media-player`).
`recipe-css-contract` verde: es el guard que caza el
`var()` sin fallback a un nombre que ya no se emite,
o sea el fallo exacto de un rename a medias
component:audit 163 PASS · 3 NEEDS-WORK, los tres SIN TOCAR por esto
check 0 errores en ficheros tocados (los 73 globales son de
otras sesiones de la rama; se atribuye por fichero)
rtl:check 0 · docs:check 0
formato el renombrado no alarga ninguna línea: ningún fichero
tiene más líneas de 100 chars que antes, así que no se
pasa prettier — hacerlo reformateaba 300 ficheros de
deriva ajena
Entra aquí la corrección del repaso de los 7 ya hechos:
`gradient-builder.checker-color` → `checker-fg` (el damero de transparencia;
ahí `color` era slot). Sus `stop-color-*` no se tocan.
Queda para el paso siguiente: R-5.3 no puede graduar a `error` directo
mientras los 47 hovers neutros sigan hablando el idioma viejo — o migran
antes (firma 3, ya firmada), o el guard necesita una exención greppable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
f09e04fab1 |
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
51122efa32 |
docs(theming): mañana lo primero — el vocabulario de tokens: D-TH.6 (codemod) y R-5.3 (guard de gramática)
La conversación de hoy destapó que el backfill está escribiendo canon sobre un catálogo que habla al revés: el vocabulario de nombres existe (theming §6.7 + recipe-contract §1) pero no tiene guard, y la medición fundacional del 2026-07-01 ya dijo lo que le pasa a un canon defendido por prosa. Medido ahora con `scripts/__names-inventory.ts` (semilla del `--names` del censo): sobre 3.333 claves públicas hay 370 desviadas en 68 componentes — 125 con el modificador detrás, 215 con `color` como slot o segmento, 30 con ambas. Y dos falsos amigos que NO se renombran de oficio: `*-focus-ring-color` espeja la familia del sistema, y los `orb-color-*` de aura usan color como sustantivo. El handoff pone el bloque como primera tarea, con el orden que evita el error clásico: primero la FIRMA (D-TH.6, una decisión con el inventario delante), luego el codemod value-preserving con el triple muro del precedente px/py (renombres 1:1 en generated, censo idéntico, computed intacto en tres sondas), y sólo entonces el guard — R-5.3 como gramática y no como lista, porque el vocabulario de tokens es compositivo donde el de eventos era cerrado: la talla contra las siete canónicas, el modificador cerrado y delante, el slot contra sus tres fuentes, y la parte contra el morfo compilado como ya hace eidos-lint. En `error` directo: tras el codemod no hay deuda que tolerar, y la rampa warn es como estos guards mueren. Con muta-prueba antes de darlo por bueno. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
6e501f4fdf |
docs(blocks): handoff del día — cinco filas cerradas, y el eje que cambió el método
Deja escrito por dónde entrar mañana, en este orden: §0 EL EJE VIVO — el chasis de sección, que es lo que hay que retomar. Con la frase del autor que lo abrió («lo estás convirtiendo en una mierda a base de parches, ninguna es profesional ni de alcance») y su pregunta, que es la que tenía razón: si no debería haber un componente del que se basen todos los bloques. El censo que la confirmó (16 · 15 · 9 · 8 copias del Header), la firma (que CREZCA Section, no que nazca un hermano), por qué el nombre Block se descartó (ya significa «a todo el ancho» en el canon), los tres commits, las dos trampas que costaron —el Background que se capa dentro de la medida, y la raíz que extiende SectionProps y no HTMLAttributes— y las tres cosas que quedan: los 19 README describen el nido viejo, el contrato del tier no dice todavía que la raíz de un block ES un Section, y nada más. §1 LA COLA, REENCUADRADA — con el aviso de que más de la mitad de lo que sigue archivado bajo un block tiene la causa en el canon (A-48, A-53, A-60, A-62, A-65), así que bajarlas dentro de la frontera del tier fabrica parches. Y el trabajo honesto que sí queda dentro: A-74, A-96 y A-71. A-11 replanteada en su ficha por la misma razón: su arreglo profesional es que el canon publique el CATÁLOGO en runtime de sus escalas —como ya hace EIDOS_VARIANTS— y no siete líneas de exhaustividad repartidas por las demos. Queda medido lo que hoy está derivado: ContainerSize sin xxl, Breakpoint con 3 de 6, Decor con 5 de 8. docs:check 0/0 (813). Los avisos de prettier de los dos ficheros son preexistentes (CRLF), comprobado contra HEAD. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
cc98444343 |
uix(blocks): las diecisiete raíces que quedaban dejan de reescribir el chasis de sección
Cada block abría con el mismo nido escrito a mano: un <section {...rest}> sólo
para poder nombrarse, dentro Section para el aire, dentro Container para la
medida, y a veces un Background para la banda. Con Section ya crecido, la raíz
es una línea y el <section> duplicado desaparece: medido en las previews, el
documento pasa de 3 elementos <section> a 2 en cada block migrado.
Trece van al patrón entero (size + containerSize + decor):
article-grid, contact, faq, pricing, team, testimonials, feature-split,
logo-cloud, newsletter, más los dos de la primera tanda. Cuatro conservan algo
propio y sólo pierden el envoltorio:
- cta mantiene su Container, porque su medida lleva un paddingX condicional
(`full` significa EDGE TO EDGE y el gutter hay que quitarlo) que no es del
chasis.
- content-section no usa Container: su medida es una rejilla de cinco pistas.
- site-footer usa `as="footer"` — la sección de cierre de la página ES una
sección, con el mismo aire, la misma medida y la misma banda; lo que cambia
es el elemento, que es lo que la hace landmark `contentinfo`.
- hero conserva su Container en la variante `background`, y esto lo destapó la
MEDIDA, no la lectura: al pasarle `containerSize` su backdrop quedó atrapado
dentro de la medida y el hero salió con 128px de blanco a cada lado en vez de
a sangre. El `decor` del chasis se pinta FUERA del container justo por eso,
pero el de hero no es un patrón de tokens sino la media de la app bajo un
scrim, así que llega como hijo — y un hijo se capa con la copia. Queda escrito
en el sitio donde volvería a morder. Verificado después: fondo 1280 a sangre,
hijo directo de la sección, medida 1024 dentro, en hero y en stats-band.
Los tipos siguen la regla que ya estaba escrita en el types.ts de stats-band y
que la primera tanda confirmó: la raíz extiende los props del componente del
canon que envuelve —SectionProps— y nunca HTMLAttributes, cuya superficie
laxa choca con el style/class refinado del canon al esparcirse.
Gates: svelte-check 72/62 antes y después · vitest eidos+blocks 470/471 (el rojo
es skin-media-player, ajeno) · blocks:check 0/19 · docs:check 0/0. Medido en
navegador block a block: tag SECTION, aire, medida y patrón en su sitio, y el
hero en sus tres layouts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
35216b591c |
fix(natural-time-picker): la anotación del literal volvió a su línea — prettier la había separado del valor
Regresión mía de ayer, cazada por el guard al preguntar si los nombres pasan por el canon. Al renombrar los privados abreviados a su nombre completo, tres declaraciones cruzaron el ancho de línea y prettier las partió en varias; la anotación que las justifica quedó en otra línea, y R-2.1 la exige en LA MISMA. Resultado: un componente que estaba en PASS pasó a NEEDS-WORK con tres colores crudos donde en realidad hay tres excepciones anotadas de tono fijo. Se arregla con `prettier-ignore` sobre cada declaración, que es lo único que no toca lo que importa: ni se acorta el comentario que documenta por qué el color es fijo, ni se cambia el valor. El diff de computed sigue vacío (6.438 valores, ocho estados) y el componente vuelve a PASS. La lección va al handoff, porque el error no fue el rename sino el ORDEN de la verificación: correr `component:audit` antes del formateo final deja pasar exactamente esta clase de regresión. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
a9b9711657 |
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y no por la memoria de nadie. `CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia calendar, mandato de Field, el perímetro del knob para la familia tipográfica, el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes → después. El plan gana su §8 con el registro completo y corrige su cabecera, que seguía diciendo que no había nada construido. Y se commitea el instrumental, porque sin él el protocolo §7 es una intención: la sonda de computed antes/después, el diff que es el gate (vacío o se para), el centinela que pregunta si cada token alcanza de verdad, y la captura del stage. Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev server. Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el `animationend` para montar el panel, y si lo congelas mides un popup que no existe); un token resuelto no se mueve desde `:root` por diseño; un panel portalado no ve el ámbito del componente; la demo puede tapar el componente que mides; y un valor centinela igual al real se lee como «no efecto». Igual las cuatro trampas que costaron un commit cada una, con su guard al lado: la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el encabezado que un Edit se come al insertar una sección. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
3bfe0d4130 |
docs(theming): revisadas las fichas 11-20 — veredicto verificado y corregido en cada una
Segunda tanda de revisión del eje theme-reach: command, table, media-player, tree-grid, field-langs, gradient-picker, listbox, carousel, heading y feed. Cifras reproducidas en las diez; la corrección va escrita en el bloque de veredicto de cada ficha, que sobrevive a la regeneración. Lo que la verificación cambió del plan mecánico: - Tres «colisiones» no eran colisiones: el radio de command es ADAPTACIÓN al Dialog que lo hospeda (lee un público de dialog, legítimo); el ancho del panel de gradient-picker es POR TALLA (20/18/22rem); y el título de feed son las redeclaraciones por talla de su propio privado. - Dos nombres mecánicos estaban mal: el `root-height` de table es la FILA (row-height, al bundle), y el `root-bg-image` de tree-grid son las GUÍAS de indentación — el knob es un color (`guide-color`), los cinco gradientes son de la receta. - Dos prefijos más de la misma plaga: media-player declara `--_mp-*` (el censo lo cuenta global) y field-langs `--_fls-*` — que además lee un privado DE FIELD con la fórmula del label un paso por debajo, sólo resoluble anidado: eso va al mandato field-composition, no se copia congelado. Y gradient-picker estampa `--gp-current-gradient` inline: mismo renombrado que gb. - Una regla de capa a punto de romperse: la propuesta de listbox acuñaba `font-size = var(--list-font-size)`, que es un público DE LA CAPA list-surface — duplicarlo es el vocabulario paralelo que la propia nota prohíbe. Retirada. - Y una lectura equivocada del 0 %: heading NO tiene deuda — es el primitivo tipográfico consumiendo la capa de named styles, que ES su superficie de tema (applyTypeScale la retunea en vivo). Acuñar --heading-* sería el alias por eje×nivel que la purga del §39 mató. Disposición propuesta: medir --style-* como sistema transversal para los primitivos tipográficos — decisión D-TH.2, y aplica a toda la familia B5. media-player trae además contexto que la propuesta ignoraba: su acento ya está firmado en el propio bloque de recetas como theme-stable (una escala cruda a propósito, para leerse sobre cualquier vídeo) — no se «corrige» a un rol. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
07778b597a |
uix(date-range-picker): la vista de década es suya y pasa a tokens; el calendario y el campo esperan su firma
Séptimo del eje theme-reach. Este componente es un híbrido de tres familias y el contrato lo dice ahora explícitamente: la vista de década/mes es invención suya y pasa a contrato público — separación, ancho, cabecera, navegación, rejilla y celdas, con los estados del rango separados por nombre en vez de amontonados en uno solo. Más el acento. Lo que NO se toca tiene dueño y esperando firma: la mitad de calendario lee `--calendar-*` y su corrección es la decisión de familia calendar que la auditoría del sistema dejó registrada; la entrada segmentada lee `--field-*` y le toca el mandato de composición de Field. Duplicar cualquiera de las dos bajo prefijo propio habría sido justo el alias que la purga de 2026-07 mató. Y el mismo defecto de prefijo que sus hermanos, aquí por partida doble: 44 referencias `--_date-field-*` y 9 `--_calendar-font-size` declaradas en ESTE CSS con el nombre de otro componente. Con un DateField o un Calendar anidados se habrían pisado. Renombradas, con el diff de computed en cero. Verificación: diff de computed vacío sobre 493 valores en ocho estados · component:audit PASS · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |