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 }
42 Commits (b8eccc1c4f8b44178badfbe418219af73afce1a9)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
2498010a21 |
docs(theming): el handoff recoge la segunda tanda del 24 — ocho componentes, seis al 100 %
chat-message, chat-typing, fab, image-adjustments, separator y collapsible al 100 %; toolbar cerrado en 94 % y tags-input en 90 %, los dos por doctrina y no por deuda. Global 68 %, y los componentes al 100 % pasan de 36 a 42. Esta vez ningún commit se llevó trabajo ajeno: la ley del índice compartido ya iba en el brief. EL HALLAZGO QUE MÁS VALE Ceder el cromo al componente compuesto SALE GRATIS. toolbar deja que [data-button] gane —misma especificidad, emitido después— y no pierde ni una clave, porque su receta ya no escribe reglas sobre el botón. Medido antes de tocar nada: 51/54, y ninguna silenciosa era del botón. Es el reverso exacto de form, que conserva 23 declaraciones muertas por la misma causa. La firma pendiente de §13 tiene una salida barata y ya probada: no escribir la regla. LO QUE LA SUPERVISIÓN ARREGLÓ La sonda no congelaba nada, y es la que mide el gate del protocolo. Con transition y animation congeladas, los 18 diffs fantasma de chat-typing pasan a 0 sobre 1.568 valores. Las 164 fichas regeneradas quedaron clasificadas una a una en vez de por la cifra. Y refutado un susto: una sesión avisó de que cuatro veredictos §5 podían estar vacíos en HEAD; comprobados los ocho, intactos. DOS DEFECTOS REALES ANOTADOS Y NO TOCADOS El chip de añadir reacción de chat-message lo pinta popover.css y se ve en la captura: los chips de reacción son píldoras redondas y el de añadir un cuadrado gris. Y el morfo de tags-input sella aria-selected='true' como literal en cada etiqueta, así que archetypes.css le fija la tinta en reposo y su token nunca ha pintado — con cara de defecto de a11y. Los dos esperan decisión. Quedan cuatro de la cola A: scroll-area, tabs, slider y toast. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
bf6cd201cf |
docs(theming): el handoff recoge la deuda B saldada — quince de dieciocho
Quedan tres, y los tres por una razón concreta: audio-player no tiene README de eidos donde escribir la sección, y palabras y proof-of-human son carriles propios. Y queda anotada la deuda hermana que destapó hacerlo: ninguno de los quince tiene pestaña Tokens en su demo, porque el paso 11 del protocolo llegó después de que cerraran. Hasta que la tengan, la tabla del README es la fuente — está escrito en los quince README, no sólo aquí. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
9bbc58502f |
docs(theming): la cola eran TREINTA Y CUATRO, no once — y dos huecos más del instrumento
Ejecuta P3, P4 y P5 del plan de la revisión del 24.
P4 — LA COLA DEL HANDOFF ESTABA MAL, Y ERA MI ERROR
La bala que escribí al cerrar la tanda listaba once pendientes. Contados contra
el censo y el registro §8 son treinta y cuatro, y la lista sin separar tampoco
servía, porque mezcla dos cosas distintas:
- 16 que NUNCA han pasado por el eje (sin entrada §8 ni README): field-langs,
chronos, mockup, sidebar, image-adjustments, separator, chat-message, fab,
tags-input, chat-typing, collapsible, toolbar, scroll-area, tabs, slider,
toast. Ésa es la cola de verdad.
- 18 que SÍ pasaron y sólo les falta el README «Talla y tema»: el paso se
volvió obligatorio después de que cerraran y
|
2 months ago |
|
|
c05349c3ff |
docs(theming): el handoff recoge la tanda de DOCE y lo que encontró supervisarla
Doce componentes cerrados por cinco sesiones en paralelo — cinco al 100 % (chat-log, chat-composer, rating-group, toggle) y card cerrado en su 78 %, que ES su techo. Global 66 % -> 68 %. Y la parte que importa: los doce se supervisaron uno a uno, y la supervisión encontró cinco cosas que la ejecución no vio. Cuatro salieron del §7.7. Las dos primeras son de la rama, no del eje: el índice de git es COMPARTIDO —verificar el árbol indexado no basta, porque otra sesión puede reescribirlo entre que lo miras y confirmas— y un árbol de trabajo rancio hace mentir al instrumento sin tocar un solo commit (el guard de card daba 0/98 por un fichero sucio; desde HEAD limpio, 49/98 verde). Las otras tres son del eje: la cascada de paleta se lleva también el tono por defecto, el canal inline filtrado al contrato son cuatro claves y no dos, y la sonda y el guard mueren con --import tsx/esm. Queda escrito además el gate del diff cero con su matiz: dos componentes no cerraron a cero y los dos lo declararon; los dos son ruido reproducido sobre código idéntico. Un diff no cero no es automáticamente una regresión, pero sólo se declara ruido reproduciéndolo. Y dicho sin esconderlo: la demo de chat-log se tocó como instrumento. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
0c29c544b1 |
docs(theming): la revisión adversarial §7.7 de los 26 commits — 5 hipótesis, 5 refutadas
Cierra el punto P5 del plan de la revisión: lo ejecutado desde el 22 (33 componentes, dos bloques) por fin tiene su pasada escéptica, con medición propia y no leída de los commits. LA BASE, ANTES DE COMPARAR NADA Worktree en |
2 months ago |
|
|
233ef989b3 |
fix(theming): float-panel tenía DOCE rojos sin medir — el guard R-5.4 vuelve a verde
El barrido del centinela sobre TODO el ledger (59 componentes) destapó que `float-panel` fallaba: 17/40 con doce tokens públicos sin adjudicar. No es regresión —la bisección de las NUEVE versiones del guard desde `cd6a9f4e3` da siempre 17/40 con los mismos doce— sino un rojo que su propio commit del 22 dejó escrito («lo rojo que queda son 12 tokens anteriores») y que nadie midió. Y la frase del handoff «desde el 23 no queda ningún rojo del bloque viejo» era FALSA: se adjudicaron drawer, metrics y color-picker; éste no. Corregida, con la lección: un componente cuyo commit dice «lo que queda» NO está cerrado, y la única forma de saberlo es correr el guard sobre el ledger ENTERO. LOS DOCE, MEDIDOS UNO A UNO SEIS son el plano de profundidad, y la predicción del 22 era exacta: el contenido lleva data-depth=overlay y [data-depth=overlay] declara background, border, box-shadow, font-family y line-height a la MISMA especificidad (0,1,0) y más tarde en la cascada. Verificado moviendo los tokens del propio plano sobre el nodo (superficie, borde, fuente y leading lo repintan) y enumerando las reglas que casan. border-width cae con border (el plano escribe el shorthand). Misma adjudicación que tooltip, misma decisión abierta (§12.9). ⚠ Y una corrección a mi propio diagnóstico: primero atribuí la sombra a [data-topmost] porque el panel de la demo arranca frontal. Falso — quitando el atributo sigue muerta: es el plano también. Lo que sí depende de topmost es su compañero shadow-topmost, que SÍ alcanza (→ rgb(4,5,6)) porque su regla es (0,2,0) y le gana al plano: la prueba de que la causa es la cascada y no un token roto. TRES son estados o partes que la demo no monta: active-shadow (forzado data-dragging → alcanza), resize-size (lo consumen las asas de ESQUINA se/ne/sw/nw y la demo monta sólo las de borde, e y s) y button-size (lo consumen [data-float-panel-action] y [data-float-panel-stage-trigger], ninguno montado — el único control es el cierre, un <Button> compuesto que se dimensiona solo: el mismo grupo que las tres action-* ya adjudicadas). UNO es el PUENTE DE PALETA: el contenido lleva data-color, así que --_float-panel-accent viene del forward THM-2 (--_float-panel-palette-border → rgb(7,8,9)); sin data-color la clave alcanza (→ rgb(1,2,3)). DOS son la ley del congelado: transition-duration / -ease no pueden moverse bajo un guard que congela `transition`. Pasada aparte: 0.12s → 11.5s y cubic-bezier(0.4,0,0.2,1) → steps(7). DE PASO, DOS ARREGLOS DE LA MISMA REVISIÓN - `background.parallax-travel` estaba MAL CLASIFICADO como estructural («el escenario no tiene scroll timeline»): lo tiene (animation-timeline: view()). Forzando data-parallax + speed 1, el translate sigue al token (14,6 → 60,5 px al mismo scrollY). La causa real es que el guard NO fotografía translate ni transform — registrado en §13 junto al hueco de mask-image, para entrar en PROPS en un pase con re-verificación del ledger entero. - `cropper`: el hueco de composición que el README daba por «anotado» y no lo estaba, ahora es fila de §Gaps con su disposición. Y las tablas de tokens de `cropper` y `waveform` pasan a la sección «Talla y tema», el molde del resto. La nueva constante PLANE_SUPERSEDED se iza sobre el objeto (un `const` usado antes de su declaración reventaba el guard, y el fallo se veía sólo mirando el exit REAL: tras la tubería, `$?` es el del grep). Verificación: R-5.4 float-panel 17/40 con 23 adjudicaciones, cero STALE, exit 0 · docs:check 0 · el ledger vuelve a sus 63 hunks de prettier preexistentes (mis entradas se reformatearon a mano, sin tocar las ajenas). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
0e01649f79 |
docs(theming): el handoff y el PLAN recogen la tanda de SIETE — 66 %, y cinco leyes del instrumento
navigation-menu 100 % · background 95 % · cropper 94 % · color-field 93 % · badge 75 % · waveform 86 % · s-text-virtual-list 70 %. Los siete con diff 0 y su guard limpio. La sección de arriba del handoff se reescribe con lo que enseñaron, porque las cinco cosas se repiten en toda la cola que queda: 1. El instrumento tiene TRES caras del mismo punto ciego (HTML crudo · partes que compone el CONSUMIDOR · partes de un componente COMPUESTO) más una cuarta: las capas OPT-IN. Cuenta los nodos SIEMPRE. 2. Un guard puede CERRAR lo que mide (nav-menu abre por pointerenter y el aparcado del puntero lo cierra) y montar MÁS puede medir MENOS (background: 17 → 9 al encender capas que tapan). Nace prepareWith, con su regla. 3. Subir un privado al contrato lo somete a reglas que en el CSS no se le aplicaban: dos veces en una tarde, el bundle contra el primitivo crudo. 4. Lo que el componente escribe INLINE no es tema, nunca. 5. La mitad del trabajo que queda es ADJUDICAR, no acuñar — con dos atajos legítimos: la excepción POR PATRÓN y la clase «sólo el paso en vigor pinta». Más las dos trampas de medición: congela `transition` en toda medición a mano, y mide el nodo que PINTA, no el primero que casa el selector. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
129e11fa75 |
docs(theming): el handoff y el PLAN recogen navigation-menu — 100 %, y tres cegueras del instrumento
Registro §8 del PLAN y sección propia en el handoff, delante de «Lo primero al entrar», porque las tres lecciones se repiten en la cola de B1: - las partes que compone el CONSUMIDOR (los <a> desnudos de un mega-menú) no las ve ningún instrumento: 10 nodos y ninguno era el panel; - un panel de HOVER lo cierra el propio guard al aparcar el puntero, y eso da falso negativo Y falso positivo a la vez; - una propiedad en TRANSICIÓN devuelve el valor viejo si la lees en el acto: toda medición a mano congela `transition`. Más la nota de contabilidad: el censo decide el eje `size` grepeando data-size en el CSS, y el protocolo §7.4 ordena retirar esos bloques — todo componente que lo aplique bien aparece «sin eje». Ya le pasa a sidebar y nav-tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
b2a3ac8d27 |
docs(theming): el handoff recoge la sesión entera del 23 — 65 %, 16 componentes
Cabecera al día (65 % global, 25 componentes al 100 %, <20 % baja de 14 a 12) y una sección nueva con la tabla de los dieciséis, las CINCO LEYES que salieron y todo lo que aprendió el instrumento. Las leyes, que es lo que hay que leer antes de seguir la cola: 1. El portal es una frontera de cascada — un privado de la raíz no la cruza. 2. El plano `overlay` gana donde el componente habla, y en `tooltip` se queda también el fondo, el borde y la sombra: sus tres variantes computan lo mismo. 3. La cascada de paleta anula los tonos del componente — 419 claves, 49 recetas. 4. Un respaldo escrito a mano envejece contra su token. 5. Donde hay un par, el defecto viene en par. Firmas actualizadas: la 1 (§12.9) deja de ser sólo tipografía y suma la superficie del tooltip; la 7 pasa de UN canónico sin demo a CUATRO (picker-shell, mockup, surface, audio-player) con la nota de que el guard sobre una página vacía miente en verde-rojo; y entra la 11, las dos reglas con `:global()` que el navegador descarta. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
04c946a71f |
docs(theming): el handoff pasa a 64 % y la firma más gorda entra en la lista
Cinco componentes el 2026-08-23 (menubar · field · onion-menu · button · callout). Y la firma 10: la cascada de paleta anula los tonos del componente — 419 claves públicas, 49 recetas, medido en tres. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
99dcf29c8e |
docs(theming): el handoff pasa a 63 % y la firma 1 gana su mecanismo
menubar 15 % → 88 % dentro. Y §12.9 deja de ser «el plano impone tipografía» para ser algo operativo: el plano GANA donde el componente habla (misma especificidad, más tarde en la cascada), así que hasta la firma no se acuña `font-family` ni `line-height` en ninguna superficie `overlay`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
af0c6d9bdf |
docs(theming): el handoff registra que ya no queda rojo del bloque viejo
Cabecera: `drawer` (24), `metrics` (18) y `color-picker` (25) están medidos uno a uno y adjudicados por escrito — el guard R-5.4 pasa en los tres. Los tres hallazgos reales que salieron esperan firma en §13. Firma nueva (9): el eje `size` del `color-picker` muere en el portal. Dos lecciones del instrumento, con su fecha: los tokens que SON la transición no se miden congelando, y una lectura inmediata de una propiedad en transición devuelve el valor viejo — ni `!important` en línea la mueve. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
001b1cdbd0 |
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5638d67fde |
tooling(theming): el censo aprende a leer la válvula del canon — clase `exception`
Global 58 % → **59 %** sin tocar una línea de CSS: 54 knobs que eran deuda resultan ser desviaciones que el canon ya había firmado. `recipe-contract` §3 dice que una desviación anotada `/* literal: <razón> */` EN SU PROPIA DECLARACIÓN es válida, y `component-audit` la honra desde siempre (`declarationWindow` + `/literal:/i` en R-2.1, R-2.6 y R-2.7). El censo era el único instrumento que no: su `strip()` blanquea los comentarios ANTES de clasificar, así que las **81 anotaciones del catálogo** contaban como literales sin excusa. Dos instrumentos, un canon, dos respuestas — y la que mandaba era la del que no sabía leerlo. Ahora un literal anotado cae en la clase **`exception`, fuera del ratio** como `system`, y por la misma razón: no es que un tema no lo alcance, es que el canon ya aceptó por escrito que ahí no va un token. **54 knobs en 12 componentes**: `prose` 21 (su escala editorial em-relativa, que su README documenta como decisión — «No 5× duplicated scale»), `proof-of-human` 16 (la escena de tono fijo), `palabras` 3, `timeline` 2 (73 % → **77 %**), `result` 1 (86 % → **90 %**), y siete más con una cada uno. Detalles que costaron medición: - **La anotación vale para la DECLARACIÓN entera**, no sólo para su primera línea: un valor partido en varias líneas lleva la nota al final. Se comprueban todas las líneas que abarca la declaración. - **`strip()` blanquea en el sitio** (sustituye por espacios, conserva los saltos), así que el cuerpo despojado y el crudo quedan alineados línea a línea y basta con guardar el crudo al lado. - Muta-prueba: retirar una anotación de `prose` mueve el knob de `exception` a `literal` (21 → 20) y el conteo vuelve al restaurarla. Efecto colateral bueno: cada ficha gana una **§1.4 «Excepciones firmadas»** que las LISTA con su razón. Estaban escritas en el CSS y no se leían desde ninguna parte; ahora la ficha del componente las enseña, que es donde se decide si una sigue siendo cierta. Las 163 fichas cambian porque la plantilla cambia (sección nueva + la línea de reparto); el README de la auditoría gana la fila de la clase y la nota de que `system` y `exception` quedan fuera del denominador. Guards: `--names` 4.105 claves, DESVIADAS 0 · component-audit PASS · docs:check 0 · `check` con 72 errores globales y 0 en los ficheros tocados. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
1c4f9518bb |
uix(theming): tres techos que no son deuda — el PUENTE DE PALETA no se acuña
Sin cambios de código: los veredictos §5 de `tag-group` (65 %), `stepper` (79 %)
y `timeline` (73 %), y la clase registrada.
Los tres tienen `global` a CERO. Lo único fuera de alcance son sus privados
`--_{c}-palette-*`: el puente THM-2 que la capa compartida alimenta POR
INSTANCIA desde `[data-color]`. **Un público encima del puente
(`--tag-group-selected-bg: var(--_tag-group-palette-surface)`) dejaría que un
tema lo fijara y matara en silencio el `color=` de cada instancia** — la misma
clase de daño que «declarar un público de facto mata una escala» (`knob`). Y no
hace falta: los componentes ya exponen sus nueve roles × variante como claves
públicas (91 en `tag-group`). Ésa ES su superficie de color, y está completa.
`timeline` suma una segunda razón, también firmada: sus `--_timeline-hue-*` son
un CONMUTADOR —cada `data-intent` los re-apunta a las ranuras de rol y el
intent por defecto al puente—, y aplanarlo obligaría a duplicar cada regla por
intent (doctrina F2-B, cinco precedentes).
MEDIDO, para no adjudicar de oído: de las **687** declaraciones del catálogo que
leen un privado, **130 leen un `--_{c}-palette-*`**, y son las que dominan la
columna `private` de todo componente con paleta — tag-group 14/14, stepper
11/11, radio-group 10, checkbox 8, file-upload 8, calendar / editable / los tres
grids 7 cada uno.
Consecuencia que queda escrita en §13: **el techo de un componente con paleta no
es el 100 %**, y su cifra no compara con la de uno sin ella, porque el
denominador incluye un puente que por diseño no se acuña. Si algún día se quiere
comparabilidad, la salida es una clase `bridge` en el censo — no acuñar los
tokens. Los otros seis heredan la razón cuando les toque, pero ojo: ésos tienen
ADEMÁS knobs `global` y sí les toca trabajo real.
Los cuatro literales de los tres son identidad anotada: el `line-height: 1` del
botón de quitar y el del glifo del marcador, el `100%` de layout del stepper y
los dos `1em` que hacen que título y descripción del timeline hereden el tamaño
escalado del item en vez del tamaño UA del encabezado.
docs:check 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
643179de0f |
uix(chart): la COSTURA del texto — 49 % → 89 %, y `global` a cero
Seis claves. El valor sigue siendo el del canon; lo que faltaba era el knob.
CORRIGE MI LECTURA DE HACE DOS HORAS. Al tokenizar chart di por doctrina que
«el texto no recibe tokens del componente» porque su valor viene de la capa de
estilos con nombre, y dejé el CSS leyendo `var(--style-caption-font-size)` y
`var(--color-content-*)` A PELO. Eso es media doctrina: PLAN §2-A pide que TODO
knob de apariencia lea `--{c}-{slot}`. Sin la costura, un tema no puede aclarar
las anotaciones de un gráfico denso sin mover `caption` en toda la app, y
`getRecipeTokens()` / `/temas` no ven esa superficie.
El molde ya estaba escrito en la vertebración tipográfica
(`--accordion-trigger-font-family: var(--style-label-font-family)`), y D-TH.2
aclara que sólo los SEIS primitivos quedan fuera: «un componente que sólo LEE un
named style para un eje no es un primitivo y no está en el conjunto».
POR ROL, NO POR PARTE — y se decidió midiendo:
--chart-caption-font-size var(--style-caption-font-size)
--chart-caption-fg var(--style-caption-color)
--chart-label-font-size var(--style-label-font-size)
--chart-label-fg var(--style-label-color)
--chart-label-font-weight var(--style-label-font-weight)
--chart-gauge-label-font-size var(--size-xl-font-size)
Dos roles × tres ejes = 6 claves para 19 nodos de texto; nombrarlo por parte
habrían sido ~30 claves con dos valores. **Tamaño y tinta son ortogonales a
propósito**: `empty` y `bar-list-value` son tamaño `label` con tinta `caption`, y
el CSS lo dice. El readout del gauge no tiene rol en el canon —un `h2` es un
encabezado, no un dato— así que su costura toma el bundle de talla; con eso se
cierra la escotilla que dejé abierta en el commit anterior.
Tres nombres de mi primera propuesta no aguantaron la revisión y no entran:
`label-font-size` a secas chocaba con las seis partes `*-label` del componente
(se acepta el choque, pero nombrando por el ROL del canon, que dice la verdad:
las etiquetas de eje SON captions), `emphasis-*` inventaba vocabulario fuera de
§1/§6.7, y `fg-muted` se apoyaba en un único precedente. La tinta lee el color
DEL ROL (`var(--style-caption-color)`), no la ranura a pelo.
Y RETIRA UNA NOTA EQUIVOCADA DE §13: escribí que el censo penalizaba consumir la
capa tipográfica cuando no eres un primitivo. El censo medía bien; faltaba la
costura. Con ella, `global` cae a CERO y el alcance a 89 % — el techo, porque lo
que queda son los diez literales de identidad (nueve `100%` + el `max-content`
del tooltip). La lección queda escrita: cuando la métrica y la doctrina
discrepan, sospecha de la lectura antes que del instrumento. `listbox` (68 %,
ritmo de fila prestado de `list-surface`) es la misma pregunta un piso más
arriba y queda pendiente de revisar con este molde.
Gates: sonda antes/después **0 diffs en 161.850 valores computados** (16 rutas ×
7 estados) · centinela **43/45**, las dos de transición adjudicadas · censo
--only **89 %** con `global` 36 → 0 · --names 45/45 conformes · component-audit
PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check
0 · docs:check 0 · `check` con 72 errores globales y 0 en los ficheros tocados.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
0b3382fe67 |
uix(result): temable — 14 % → 23 %, la receta posee su CAJA y nada más
Cuatro claves nuevas (8 → 12). Censo result 14 % → **23 %**; global 57 %;
alcance <20 % 18 → 17.
Aplicación directa de la doctrina que cerró `chart`: lo que la receta posee es
su **caja** —el inset de página (`padding-block`/`-inline`) y el ritmo entre
bloques (`actions-margin-block-start`, `extra-margin-block-start`)—, más los
cuatro acentos de estado que ya tenía. Ni una clave más.
LO QUE NO SE ACUÑA, Y POR QUÉ:
Su tipo ya leía el BUNDLE DE TALLA (`var(--size-{xl,md,sm}-font-size)`), que es
literalmente lo que recipe-contract §1 prescribe; la tinta lee las ranuras de
contenido, el peso y el interlineado sus escalas, y el código grande la familia
mono del tema. Acuñar `--result-title-font-size` habría sido tipografía por
componente, prohibida hoy. El censo cuenta esas trece lecturas de canon como
`global`: es la nota de `listbox` y `chart` (next-features §13), **tercera
ocurrencia**, no deuda de este componente.
Los cuatro literales son identidad documentada: el `calc(var(--size-xl-font-size)
* 3)` del glifo de estado (el display es TRES veces el paso xl), el `1em` del
código grande que hereda esa escala a propósito, su `0.04em` de tracking óptico
y el `100%` del extra.
Higiene de paso: el privado `--_result-media-color` pasa a `--_result-media-fg`
— la gramática firmada (D-TH.6) dice `fg` y R-5.3 no mira los privados.
CINCO ADJUDICACIONES, TODAS SOBRE NODOS REALES:
El guard da 7/12. Las cinco que callan se midieron con los CONTROLES DE LA DEMO,
no fabricando nodos (la lección de `drag-drop`): los tres acentos sólo pintan
bajo su `data-status` —se pulsó su chip: oklch → rgb(1,2,3) en los tres— y el
bloque `extra` es opcional —se marcó su casilla: 16px → 1234px y 559,44px →
1234px—. Las cinco alcanzan.
Gates: sonda antes/después **0 diffs en 990 valores** (5 nodos × 7 estados) ·
censo --only 23 % · --names 12/12 conformes · component-audit PASS · eidos-lint
0 invalid · suite eidos con el único rojo conocido · rtl:check 0 · docs:check 0 ·
`check` con 72 errores globales y 0 en los ficheros tocados.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
15eb9c56c9 |
uix(chart): temable — 9 % → 49 %, y la ficha pedía 71 claves de las que 20 llevaban el mismo valor
22 claves nuevas fusionadas en el bloque existente (17 → 39). Censo chart 9 % → **49 %**; global **56 % → 57 %** (2.638 → 2.675 públicos; <20 % 19 → 18). LO QUE DECIDIÓ LA MEDICIÓN, no la ficha: Las 84 filas fuera de alcance colapsaban a **26 valores distintos** — 9× `content-secondary`, 9× `content-primary`, 9× `100%`, 6× `font-size-sm`, 6× `font-size-xs`, 6× `font-weight-medium`, 5× `surface-default`, 4× `radius-sm`. Nombrar por parte habría dado cinco claves para el pelo que separa marcas y nueve para la tinta de anotación: la inflación de `spinner` con otra cara. **El texto no recibe tokens de chart.** Toma su ROL DE TAMAÑO de los estilos con nombre del canon —`caption` (xs) para las anotaciones, `label` (sm) para el texto de cromo— y su tinta y su peso de las ranuras del sistema. Acuñar `--chart-label-font-size` sería tipografía por componente, prohibido el mismo día para text-effects. Precedente de consumir la capa: `code-block`, `kbd`, `announce`. Doce declaraciones cambian de `var(--font-size-xs|sm)` a `var(--style-caption|label-font-size)`, mismo valor. **La receta sólo posee la tinta de lo que NO es texto**, cinco claves y cada una un concepto que el CSS repite: `axis-fg` (eje + rejilla smith + conector del funnel), `grid-fg` (rejilla + radar), `separator-fg` (el pelo de superficie entre marcas contiguas: porción, punto activo, punto smith, pétalo, segmento), `smith-boundary-fg` y `track-bg` (raíl del bar-list y del gauge). Más 17 de geometría de cromo (gap, los pares row/column-gap, swatch, track, bar-segment). **Incumplimiento heredado, corregido**: el CSS leía la coordenada CRUDA `var(--control-height-sm, var(--space-7))` —lo que `recipe-css-contract` prohíbe— con un respaldo muerto. El contrato guarda el bundle `var(--size-sm-control-height)`, 1:1 con él. **Identidad fuera de contrato**: los nueve `100%` («ocupa a tu padre») y el `min-inline-size: max-content` del tooltip, misma clase ya adjudicada en `date-picker`. Por eso el techo es 49 %, y está escrito en el veredicto §5. EL INSTRUMENTO ESTABA CIEGO DE TRES MANERAS, arregladas ANTES de medir: 1. **La superficie de chart vive en DIECISÉIS rutas de demo**, una por tipo: `/chart` monta 58 nodos de los 302 de la página y el resto vive en rutas hermanas. El guard gana `urls`: un token está VIVO si ALGUNA superficie del componente lo sigue, y cada URL sólo re-prueba lo pendiente (el caso de una sola ruta cuesta exactamente lo que costaba). De paso `picker-shell` recibe la suya: su ruta propia es un 404 y se mide dentro del date-picker — pasa de 0/31 con seis sin adjudicar a 6/31 sin tener que saberlo. 2. **El guard no leía NINGUNA propiedad SVG.** Sin `fill` / `stroke` / `strokeWidth` / `fillOpacity` / `r` / `rx`, doce de las 39 claves de un componente que dibuja en SVG leían muertas estando vivas. Misma clase que el hueco de `filter` / `backdrop-filter` de ayer. 3. **El valor centinela se elegía por SUBCADENA**: `slice-stroke-width` recibía `rgb(1, 2, 3)` por contener «stroke» —inválido para una longitud— y leía muerta. La dimensión se decide ahora por el FINAL del nombre. Los 28 componentes con ledger re-verificados tras los tres cambios: cero regresiones, cero STALE. (Ojo: doce a la vez contra el mismo dev server dan falsos exit=1 por timeout; repetir a solas antes de creerse una regresión.) Gates: sonda **0 diffs en 161.850 valores computados** (16 rutas × 7 estados, 892 nodos en reposo) · centinela **37/39**, con `transition-duration` y `-ease` adjudicadas midiéndolas sin la congelación (0,12s → 11,5s · cubic-bezier → steps(4)) · censo --only 49 % · --names 39/39 conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido (`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con 72 errores globales y 0 en los ficheros tocados. Abre (→ next-features §13): el censo **penaliza consumir la capa tipográfica** si no eres un primitivo —las doce declaraciones correctas siguen contando `global`—, que es la nota de `listbox` con una segunda ocurrencia; y el número del gauge no tiene estilo con nombre que lo represente (un readout de dato no es un `h2`), así que sigue leyendo `--font-size-xl`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
5e7462a3ff |
uix(theming): text-scramble no tiene contrato que escribir — y el barrido de fantasmas, hecho
Sin cambios de código: su veredicto §5 y el registro.
Su 50 % no es ni deuda ni logro, es la suma de dos cosas que no son knobs:
- **Los dos literales son la técnica sr-only** (`width`/`height: 1px` en
`[data-text-scramble-sr]`), idéntica a `text-blur` y al resto del catálogo:
existe para que el lector de pantalla lea el texto entero mientras la versión
animada se parte en caracteres. Moverlos rompe la técnica.
- **Los dos «públicos» son tipografía que el componente no debería acuñar**
(`--text-scramble-font` / `-size`, con fallback y sin declarar): es la firma
1.bis pendiente. Escribirles contrato ahora sería acuñar exactamente lo que
esa firma propone retirar. Con esto, 1.bis son **7 claves en 4 de los 5**
componentes de la familia; `text-blur` es el único limpio: hereda.
Y el `font` apunta a un FANTASMA, medido en navegador: `var(--font-mono, …)` no
existe —el canónico es `--font-family-mono`— así que pinta `ui-monospace` e
**ignora la mono del tema** (`Azeret Mono`, que está ahí al lado).
EL BARRIDO MECÁNICO QUE PEDÍAN `--radius-xs` Y `--font-size-4xl`, HECHO:
5.793 custom properties declaradas en todo `src/uix/eidos` (fundación + capas +
recetas + `generated/`) contra los `var(--x, fallback)` de las recetas cuyo `--x`
sea vocabulario de SISTEMA → **9 referencias fantasma**. (Las que van sin
fallback ya las guarda `recipe-css-contract`; el hueco eran justo las que
«funcionan por accidente».) Tabla completa en next-features §13:
- `--color-content-tertiary` ×3 (float-panel, proof-of-human clock y
rotate-align) — **es el caso histórico** que `recipe-contract` §1 cita como
origen de su propia regla, y sigue vivo en tres recetas.
- `--style-{body,prose,label,caption}-font-variation-settings` ×4 (`text.css`) —
los estilos con nombre emiten 6 claves y ésta no está: **el eje de fuente
variable no llega nunca al primitivo `Text`**.
- `--font-family-sans` (palabras, track WIP) y `--font-mono` (text-scramble).
Ninguna se arregla aquí. El barrido debería ser un guard: misma lógica que el
test de fantasmas sin fallback que ya existe, con el filtro de vocabulario de
sistema encima.
Guards: censo `--only` sin cambio (50 %, es el veredicto lo que cambia) ·
component-audit PASS · docs:check 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5b10005ef7 |
docs(theming): apuntar para después — text-effects acuña tipografía propia contra el canon
Pregunta del autor (2026-08-22): «¿qué sentido tiene que text-effects introduzca diferentes nombres de tipografía cuando ya hay un canon establecido?». Ninguno. Queda apuntado como FIRMA PENDIENTE (CONTINUE §5 1.bis · PLAN §8 · next-features §13) para resolverlo después: Cinco claves del contrato acuñan tipografía: `text-focus.word-size` (3rem vía el fantasma `--font-size-4xl`) y `word-weight` (900) · `text-circular.weight` (900) y `font-size` (1.5rem) · `text-gradient.font-weight` (500, subida hoy). Son opiniones del seed react-bits que el protocolo «valor verbatim» convirtió en contrato sin la pregunta previa. La doctrina del propio eje (F2-B regla 2, cinco precedentes) dice que una receta CONSUME la capa tipográfica (`--style-*`) o HEREDA (`link` → `inherit`): un TextGradient dentro de un `h1` ES un h1. Resolución propuesta: retirar las cinco claves y heredar del contexto. Mueve defaults → firma. Con ello muere el fantasma `4xl` sin tocar el módulo de tipografía (canon, prohibido modificar). docs:check 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
652c3411ab |
docs(theming): las demos quedan FUERA del eje — sólo los componentes
Decisión del autor (2026-08-22): «las demos de los componentes no son importantes y no deben formar parte del plan, solo los componentes». Y sobre la escala: «las escalas tipográficas son las que están definidas en el módulo tipografía, esos son los valores canónicos» — prohibido tocar sus valores. Se retira del registro del eje (PLAN §8 · CONTINUE §3.bis · next-features §13) todo lo que hablaba de demos o del harness del sitio: los escenarios de text-gradient/text-blur, la tabla de tokens a mano de la pestaña API, las pestañas Tokens que faltan, las 37 referencias `--uix-font-size-*`. Nada de eso es trabajo del eje: la demo se toca sólo como INSTRUMENTO para que la sonda vea los nodos, y lo mínimo. Queda lo que sí es del componente: `text-focus.word-size` referencia `--font-size-4xl`, un paso que la escala canónica (`xxs..xxxl`, `lib/primitives/typography.ts`) no tiene y que entró como idioma Tailwind con el import de julio. El módulo de tipografía no se toca; el fix va en el consumidor, a un paso o estilo EXISTENTE, y espera firma porque `3rem` cae entre `xxl` y `xxxl` y mueve el default. docs:check 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
97a6f03d76 |
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %** (10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos. Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres literales. Sin eje `size` ni privados propios, así que declarar no puede matar una escala. LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO, no contra el CSS de partida: - **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight` contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya pintaba: `500` ES `var(--font-weight-medium)`. - **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo del marco asomando a cada lado. El knob es `border-width` —con `var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de la escala— y el hueco DERIVA de él. - **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje `scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es `calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110. Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter. Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el 2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro. FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y `--_text-gradient-play-direction` los escribe el wrapper INLINE desde `animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`. INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B aplicada por adelantado, no después): - La demo arranca con `showBorder=false`, así que sonda y centinela veían **2 nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa `DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una vez por talla) y el centinela una entrada `openWith` que no abre un panel sino que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica. - La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el centinela ya leía: un token de fondo podía moverse entre las dos corridas sin que el diff lo viera. Con la propiedad y la variante: **4 nodos**. Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el único efecto de hover es `animation-play-state`, que no es knob. LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene `2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token `text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y `--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit. Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y este renombrado la dejaba obsoleta al instante. Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) · centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7 conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 · docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**. Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene 2.392), no se reformatean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
e7219bb909 |
fix(theming): el slot de tinta es `fg` — R-5.3 me cazó tres claves, y el handoff de mañana
Los guards globales, corridos antes de cerrar la sesión, encontraron una regresión MÍA: `--names` daba **3 desviadas en 2 componentes** y `component:audit` había pasado de 4 a **6 NEEDS-WORK**. La causa: en `text-circular` y `text-focus` nombré tres claves con el slot `color` (`color`, `border-color`, `glow-color`) cuando la gramática firmada el 2026-08-20 dice que **el slot de tinta es `fg` y `color` como slot MUERE**. R-5.3 existe justamente para eso y funcionó — pero después de que yo lo escribiera, porque el guard es de catálogo y yo verificaba `--only`. Renombradas a `fg`, `border-fg` y `glow-fg`, con los destinos que el propio censo indica en su salida `--names`. Value-preserving verificado: **0 diffs** en text-circular (5.916 valores) y en text-focus (1.769), guards 5/6 y 8/8, `--names` **DESVIADAS 0**, audit de vuelta a **162 PASS / 4 NEEDS-WORK** (los cuatro preexistentes y ajenos al eje). La lección para el protocolo, y va al handoff: **la propuesta §4 generada usa el slot `color`**, así que es la cuarta manera en que falla — y como el paso 7 corre los guards con `--only`, la desviación de gramática sólo aparece al correr `--names` GLOBAL. Ese comando ya estaba en el paso 1 del handoff; ahora también se explica por qué no basta con el audit. Y el HANDOFF para mañana: cifras nuevas (56 %, sin contrato 25, al 100 % 16), la lista de los 24 componentes de F2-B con su alcance, las tres cosas que el bloque enseñó y hay que tener delante al seguir (las cuatro maneras en que falla la propuesta · declarar un público «de facto» puede MATAR una escala si detrás hay un privado por talla · cuenta los nodos que ve la sonda antes de creerte un gate verde), y la cola actualizada — con `mockup` marcado como SIN DEMO (404) y `text-scramble` como «0 % estructural, escribe el veredicto, no tokens». Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
a9acf8d0c4 |
uix(theming): el censo aprende que un privado DERIVADO sí alcanza — 50 % → 56 %
Seis puntos de alcance sin tocar una línea de componente: **la medición estaba mal, no el código**. EL DEFECTO. F0 encargaba «detección "privado que deriva de público" (leer `--_c-x: var(--c-y)` en la misma receta y reclasificar)». Se implementó a medias: el censo CALCULA `derives` y lo imprime en la columna «¿deriva de un público?» de la §3 de cada ficha, pero **el contador nunca lo usó** — esos knobs seguían puntuando como deuda. Medido: **240 privados en 59 componentes** estaban en ese estado, es decir, haciendo exactamente lo que la doctrina prescribe («privados sólo si derivan de públicos») y penalizados por ello. Lo destapó tokenizar `avatar`: sus 17 privados YA leían públicos (`--_avatar-size: var(--avatar-size-md)`), así que no había nada que tokenizar — había que arreglar el instrumento. LA CORRECCIÓN. Segunda pasada tras recoger privados y knobs: un knob que lee `var(--_c-x)` pasa a `public` si ese privado alcanza un público. El cierre es **TRANSITIVO** (`--_a: calc(var(--_b) * .3)` alcanza si `--_b` alcanza) con conjunto de visitados para que un ciclo no lo cuelgue. **Muta-prueba** (obligatoria, memoria `a-guard-that-inspects-nothing-passes`): apuntar `--_avatar-radius` al primitivo crudo baja avatar de 75 % a 72 % y el knob vuelve a `private`; revertirlo lo devuelve a 75 % y deja el árbol idéntico. EFECTO MEDIDO: - Global **50 % → 56 %** · privados 625 → 341 · al 100 % 10 → 14 · <20 % 22 → 20. - `avatar` 36 % → **75 %**, `picker-shell` 76 % → **95 %**, `menu-dial` 25 % → 38 %, y otras 51 fichas con cifras nuevas — **ninguna por cambio de código**. - Los READMEs de `picker-shell` y `menu-dial` se actualizan con la cifra nueva y con la razón, para que nadie crea que el componente cambió. ⚠ **Cualquier cifra anterior a este commit no es comparable con las de ahora.** Queda escrito en el handoff. Y un hueco de F0 que sale al hacerlo, registrado en §13: **el test del SUELO que el plan pedía NO EXISTE** («alcance global ≥ el de hoy y literales ≤ 614 — el número sube o el test falla»). Hoy nada impide que el alcance BAJE entre sesiones: sólo se vería mirando la cifra a mano. Con el censo ya endurecido, es el momento de escribirlo. Gates: `component:audit` 162 PASS / 4 NEEDS-WORK (preexistentes) · `--names` DESVIADAS 0 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · el censo compila. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
a0fc8f4f1e |
uix(theming): revisión adversarial de F2-B — 4 hipótesis, 3 refutadas, 1 token que mentía
El plan (§7.7) exige una revisión escéptica antes de cerrar un bloque, y F2-B
no la tenía. Molde F2-A: worktree en la base del bloque (`8400e5bdd`) con su
propio dev server, medición independiente.
**REFUTADA \u2014 «el default cambió en algún sitio que la demo no mira».** 77 casos
FORZADOS (variantes, formas, tallas y estados que las demos NO montan, en los
21 componentes) comparados base vs HEAD: **0 diferencias**. Era la sospecha más
fuerte, porque cuatro componentes miden UN nodo (`link`, `code`, `skeleton`,
`link-preview`) y sus tokens viven justo en las variantes que la demo no
renderiza.
**REFUTADA \u2014 «hay tokens huérfanos».** 339 públicos de los 21 bloques, 0 sin
consumo. El primer extractor daba «SIN BLOQUE» en los 21 \u2014 el mismo antipatrón
que audita este eje \u2014 y se rehízo contando llaves; muta-prueba: un token falso
inyectado sale detectado y el árbol se restaura.
**REFUTADA \u2014 «el gate de 0 diffs pasó sobre casi nada».** Contados los nodos que
ve cada sonda; los cuatro de un nodo se cubrieron forzando sus variantes arriba.
**HALLAZGO REAL \u2014 `drag-drop.preview-z` mentía, y lo escondía una adjudicación
mía sobre un nodo SINTÉTICO.** El ledger lo daba por vivo («forzado → alcanza,
100 → 4321»), pero ese nodo lo había creado yo con JS. El preview REAL que soma
monta durante un arrastre lleva `z-index: 9999` **INLINE**
(`drag-drop-provider.svelte.ts:663,671`): el token resuelve a 4321 y el nodo
computa 9999. Ninguna cascada puede ganarle. **Retirado con 0 diffs** contra el
snapshot original (1.827 valores × 7 estados), misma clase que el `item-gap*`
de carousel que retiró la revisión de F2-A. Era el único público que drag-drop
tenía antes del eje; su alcance se mantiene en 89 %.
**La lección que generaliza, y va al protocolo**: una adjudicación «forzado →
alcanza» vale lo que valga el nodo que se forzó \u2014 si lo creaste tú, no lleva lo
que soma le pone. Re-verificado el resto de la misma clase contra nodos reales:
`clipboard` (indicador tras un clic real) y `picker-shell` (pie real) coinciden
con lo adjudicado y no llevan inline; el inline de `skeleton-line` es de
`inline-size`, no del eje tokenizado.
DOS HALLAZGOS DE INSTRUMENTO en la propia revisión (→ §13):
- **El orden de carga NO es el mismo en dev que en producción.** Medido con
`npm run build` + preview y CDP: en dev la receta de `link-preview` va ANTES
del plano `overlay`; en producción queda EN MEDIO de sus dos reglas. El
ganador coincide por casualidad. La fragilidad de §12.9 queda medida en los
dos entornos, y confirma que restaurar el par fue lo correcto.
- **Un worktree cuyo `node_modules` es una junction fuera del root NO HIDRATA**:
Vite responde 403 a `@fs/…` y SvelteKit no arranca, así que la página SSR se
ve pero ningún componente monta. La primera pasada de esta revisión comparó
contra una base MUERTA y devolvió «77 casos, 1 diferencia» sin que nada lo
delatara. Se arregla con `server: { fs: { allow: [...] } }`; queda escrito en
el handoff junto a la regla: **comprueba que un componente monta antes de
comparar**.
Gates: censo global 50 % · `--names` DESVIADAS 0 · drag-drop 89 % ·
component:audit PASS · eidos-lint 0 invalid · R-5.4 verde · suite eidos sin
rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio.
Worktree eliminado quitando la junction ANTES del `remove --force`, con el
`node_modules` real verificado intacto (memoria
`git-worktree-remove-recurses-into-junctions`).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
43b3e8a501 |
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca código y es la que importa. 1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré como «declaraciones muertas» apoyándome en los precedentes de `table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es neutral — **fija el empate a favor del plano** y con él su 1.25 donde la receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9 tiene pendiente para VEINTE componentes. Un empate por orden de carga se registra, no se resuelve dentro de un commit de tokenización. Y la medición era más débil de lo que el commit daba a entender: estable en cinco recargas **en DEV**, sin verificar en un bundle de producción. Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5 tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa razón. §12.9 y el README dicen ahora que el par se deja declarado A PROPÓSITO. 2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al 100 % o excepción escrita», y la válvula que `component-audit` lee es esa marca (`readmeException`), no la prosa. Tenía la razón documentada en veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2, los 16 habrían dado error. Una marca por clase medida — forward de paleta THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan. 3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el protocolo lo pide por componente: una sesión nueva habría arrancado con el mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8 firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus seis lecciones, y actualizada la memoria del eje. 4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el bloque, cada una nombrando la forma en que el instrumento mentía, más la lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso — `picker-shell` medía CERO y reportaba éxito. 5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`, `virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md (md→sm); los valores eran correctos (0 diffs), el texto no. Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la medición de quien los escribió, y el plan la exige antes de cerrar un bloque. El handoff nombra las dos hipótesis concretas que hay que atacar. Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves · `component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno con un commit de esta sesión en su código) · R-5.4 verde en los 22 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
07a99679d7 |
docs(theming): el plan del eje theme-reach — medir qué alcanza un tema, y corregir componente a componente
El autor, al ver que el radio del trigger del nav vivía en un privado clavado a
--radius-default: «¿los componentes son themables? si no lo son, es un error
como framework». Lo es. La doctrina ya exige que cada receta declare sus knobs
en recipes/base.ts (recipe-contract §1, theming §6), pero R-1…R-4 sólo
comprueban «sin literales», no «alcanzable por un tema»: una receta con todo en
var(--radius-md) y privados pasa component:audit en PASS y sólo se puede temar
moviendo el sistema entero.
Medido, no opinado — scripts/theming-census.ts (instrumento, NO guard): de 5.205
knobs de apariencia en 162 recetas, 1.621 (33 %) pasan por un token público del
componente; 1.880 atan directo a un primitivo global, 856 a privados, 614 son
literales; 62 componentes no tienen una sola entrada en el contrato; 59 tienen
alcance < 20 %; 6 al 100 %. navigation-menu, tras todo el día de hoy, 44 %.
El plan (PLAN-theming.md): §1 el censo por familia y por componente (tabla
regenerable, no editable) · §2 los cuatro ejes de «personalizable» (tokens ·
talla · color/variante · estados) · §3 la regla R-5 «alcance de tema» para
component-audit, con su válvula de excepción · §4 ocho decisiones D-TH para el
autor (R-5 dura · perímetro de knob · WIP · orden · DEFAULT IDÉNTICO · normalizar
nombres de slot, que hoy incumplen tabs y el propio nav · cuándo gradúa a error ·
panel de temas) · §5 fases F0–F4 con gates · §6 deuda transversal · §7 el
PROTOCOLO DE VERIFICACIÓN por componente, porque «lo ejecutará Opus, y Opus falla
mucho»: cinco preguntas, medir ANTES (computed por parte/estado/talla, sonda
headless desde la raíz, fuera de callbacks de MutationObserver), editar sólo la
forma firmada, medir DESPUÉS (diff de computed = 0, prueba de CENTINELA por cada
token nuevo, desde el píxel hacia arriba, registro de animationstart/end),
guards por fichero, un componente = un commit con sus artefactos, y revisión
adversarial por bloque. Cada paso tiene un artefacto; sin artefacto no está hecho.
El instrumento se probó por mutación antes de creerle, y falló la primera vez:
no contaba una regla de una sola línea (`[x] { padding-inline: 8px; }`), así que
meter un literal no movía la cifra. Regex endurecido; ahora 6→7→8 con una y dos
mutaciones. Las cifras del plan son las del instrumento final, y el handoff
(CONTINUE-theming.md) obliga a reproducirlas antes de seguir.
Nada firmado, nada construido. Gates del commit: docs:check 0/642 · prettier del
script limpio · tsc del script sin errores · el plan cita ficheros que existen
(los once, comprobados).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |