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 }
2167 Commits (2370fe5378dfc6c25c26e3ba19c45b93a77696d0)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
2370fe5378 |
docs(theming): FIRMADO — completar una demo que no monta su propio componente es instrumento, no diseño
Cierra P2, lo último del plan de la revisión del 24, y con él la revisión entera. LA TENSIÓN, Y DÓNDE CAE Dos doctrinas chocaban en el commit de chat-log: «las demos quedan FUERA del plan de theming» contra «la demo ES el producto, un testbed interactivo con profundidad canónica». La primera se escribió para dos cosas concretas —que un hallazgo de demo no se registre ni se mida, y que nadie rediseñe una demo «ya que estamos»—, y las dos siguen en pie. Lo que no cubría: una demo que sólo menciona en PROSA partes que la receta viste y el morfo declara no es un testbed, es una página. En chat-log eran tres de sus seis partes sin montar y ONCE claves vivas sin un nodo donde probarse. LA EXCEPCIÓN, CON CUATRO CONDICIONES VERIFICABLES 1. Sólo partes o estados del PROPIO componente, declarados en su morfo. 2. Contenido mínimo canónico: el ejemplo más corto que hace existir la parte. 3. El diff de computed sobre lo que YA estaba montado sigue siendo CERO. 4. Declarado en el mensaje de commit, con las claves que pasan a medibles. Y la mitad que no se toca: lo aprendido mirando una demo sigue sin entrar en el ratio ni en el registro. La excepción abre la mano para MEDIR, no para contabilizar. chat-log cumple las cuatro —comprobado: separator-day, event y divider-unread están los tres en su morfo—, así que su commit queda validado retroactivamente. LAS TRES DESCARTADAS, Y POR QUÉ Revertir el montaje habría convertido once claves VIVAS en verdes-por-excusa, que es lo contrario de lo que R-5.4 significa. Una ruta de sonda aparte duplica superficie por componente y contradice «la demo ES el producto» por el otro lado. Y los nodos sintéticos chocan de frente con verify-with-real-components, ya firmado. Con esto la revisión del 24 queda CERRADA: plan §6 ejecutado entero. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
9130070bd5 |
docs(theming): la revisión del 24 entra al repo con su plan EJECUTADO — y las ocho entradas §8 que faltaban
REVIEW-theming-2026-08-24.md: 2 errores (los dos de la concurrencia, ya
corregidos), 4 desviaciones, 1 incoherencia real de gramática (las cuatro
claves de avatar, preexistentes y ahora VISIBLES), 9 refutaciones con su
medición, y el barrido del centinela sobre el LEDGER ENTERO: 59 + 23
componentes, cero sin adjudicar, cero STALE. P7 vacío.
Las OCHO entradas §8 que faltaban (emoji-picker, spin-field, pin-input,
dialog, form, skip-link, image-picker, search-field) entran redactadas desde
sus commits y VERIFICADAS por un pase escéptico independiente contra el censo,
el contrato en HEAD y en {sha}^, y los artefactos. El escéptico corrigió tres
antes de entrar — form (el patrón casa 23 claves, no 24; §13 corregido de ~63
a ~62), search-field (nueve tokens del indicador, no ocho) e image-picker (una
cifra no reproducible, reescrita) — que es exactamente para lo que existe el
pase.
Queda UNA cosa del plan, y es firma: P2, la demo como instrumento (el
precedente de chat-log). Presentada aparte con recomendación.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
df839849a4 |
docs(theming): trece entradas del registro decían (COMMIT) donde va el sha
El §8 existe para que cualquiera pueda ir del número al cambio que lo produjo. Trece entradas —las doce de la tanda del 23/24 más progress— llevaban el marcador (COMMIT) sin resolver, así que daban la cifra y no el camino. Resueltos los trece contra el log. toggle lleva los dos, porque su trabajo quedó partido en dos commits por la carrera del índice compartido. Mismo defecto que las ocho entradas que faltan del todo (D1 de la revisión del 24): un registro a medias no es un registro. 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 |
|
|
2e0f4b6504 |
fix(theming): el guard aprende a decir OSCILANTE, y deja de dar falsas alarmas
Un token puede leerse vivo unas corridas y muerto otras sobre el MISMO HEAD, sin mentir: la culpa es de la apertura del guard, no del contrato. Hasta hoy eso rompía el ledger por los dos lados. - Si el token está adjudicado y la corrida lo lee VIVO, el guard gritaba STALE y la sesión siguiente borraba una adjudicación correcta. - Si NO está adjudicado y la corrida lo lee muerto, el guard fallaba R-5.4 con un token que alcanza perfectamente. Una razón que empiece por OSCILLATES: describe justo eso. El guard la respeta en los dos sentidos: adjudica cuando lee muerto y, cuando lee vivo, imprime «oscillating — read ALIVE this run; the entry stays» en vez de STALE. Marcadas las dos carreras ya medidas: - emoji-picker.open-trigger-fg (17/21 vs 16/21 en el mismo código; vivo cuatro veces, una de ellas replicando el staticPass paso a paso). Tres corridas: vivo, vivo, muerto — exit 0 las tres, ninguna falsa alarma. - editable.submit-fg (vivo 3 de 4, 42/56 vs 41/56). Salir del modo edición es lo que hace un blur y el guard abre por foco + prepareWith, así que la superficie que mide no es determinista. Cuatro corridas: exit 0 las cuatro. Sale del plan de la revisión del 24 (P6). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
764a28088f |
docs(theming): dos fichas se quedaron con la cifra VIEJA en la cabecera, y el agregado al día
Supervisando la tanda: `select` y `calendar` commitearon su veredicto §5 con las cifras correctas (83 -> 92 y 84 -> 89) pero la CABECERA de la ficha seguía diciendo el número de antes. Un lector ve la cabecera primero. El árbol de trabajo tenía la regeneración del script de auditoría, con las cifras buenas — y BORRANDO la prosa medida de las fichas: las razones de cada literal y de cada retirada colapsadas a «Ninguno.». Ni una versión ni otra estaban bien, así que van cosidas: el cuerpo de HEAD (la prosa) con las líneas de cabecera regeneradas (las cifras). Cinco líneas en total, ningún párrafo perdido. Y el agregado `docs/audit/theming/README.md`, que es dato generado sin prosa, entra tal cual: alcance global 67 % -> 68 %, componentes al 100 % 28 -> 36. Lo demás que quedaba sucio en el árbol era ruido de fin de línea (PLAN §8, next-features) y se restauró desde HEAD. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
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 |
|
|
5be7dabf49 |
docs(theming): el índice de git es COMPARTIDO — verificar el árbol indexado no basta
Ocho sesiones sobre el mismo worktree y un solo .git/index. La técnica que esta rama daba por segura —construir el índice desde HEAD con sólo tus hunks y comprobarlo con git diff --cached— protege del árbol de trabajo ajeno, no de la ventana entre MIRAR y CONFIRMAR: si otra sesión hace su reset + add en ese hueco, tu commit fotografía SU índice. Ocurrido dos veces en una tarde. |
2 months ago |
|
|
88a2086441 |
fix(theming): HEAD lleva cuatro commits con el ledger del centinela ROTO por una coma
`scripts/theming-sentinel-exceptions.ts` tiene `},,` en la costura entre el bloque de `rating-group` y el de `toggle`: un literal de objeto con una coma de más, o sea que el fichero NO PARSEA. Lo introdujo |
2 months ago |
|
|
b139b4280b |
docs(theming): el §8 salió con la entrada de rating-group y radio-group DUPLICADA
Mismo error que la sesión anterior, en otro fichero y por la misma causa: para construir el índice desde HEAD recorté MI entrada del árbol de trabajo entre dos marcas —«desde la mía hasta la de chat-composer»— y entre medias otra sesión había insertado las suyas. El recorte se las llevó, y HEAD acabó con `rating-group` y `radio-group` dos veces (507/517 y 560/570). Se borran las DOS copias inyectadas; las originales, con su sitio en el orden, se quedan. Ningún otro cambio. **La lección, para la próxima**: en una rama con sesiones concurrentes, recortar del árbol de trabajo «desde X hasta Y» sólo es seguro si NADA puede aparecer entre X e Y. Cuando lo que separa a X de Y es un fichero compartido, el recorte tiene que terminar en el FIN de lo mío, no en el principio de lo siguiente — que es exactamente lo que ya había fallado con el override del guard una hora antes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
f3189a05ac |
uix(card): temable — 78 % → 78 %, y el número CERRADO es el resultado
Card es un primitivo con paleta, y su columna `private` no es deuda: es el puente THM-2. Clasificados uno a uno sus ocho knobs fuera de alcance ANTES de tocar una línea —que es la mitad del trabajo—: - cuatro leen `--_card-palette-*` DIRECTO: el velo de hover de `ghost` y `outline`, la descripción en `solid` y el filete del pie en `solid`; - los otros cuatro leen el conmutador por VARIANTE (`--_card-bg`, 4 fuentes; `--_card-fg`, 2) en la raíz, el título y el cuerpo, y sus ramas son ese mismo puente. Un público encima de cualquiera dejaría que un tema lo fijara y matara en silencio el `color=` de cada instancia (CONTINUE-theming §3.pre). El techo de card **no es el 100 %**, y forzar la cifra habría sido romper la jaula del color. Lo único que faltaba era **la costura**: la rama `outline` del conmutador leía `var(--color-surface-default)` a pelo — el valor es del sistema, el knob es de la card. Entra **`outline-bg`** con ese valor verbatim, y el centinela lo confirma vivo. Ni `ghost` ni el borde transparente se acuñan: son identidad. Censo: 37 knobs · 28 públicos · **78 %** (idéntico, y así queda escrito en la ficha). Contrato 97 → **98** claves. Global del catálogo sin bajar (68 %). Diff de computed: **VACÍO**. 1.216 valores en 7 estados (sonda estándar, 6 nodos = la card y sus cinco ranuras) más 2.484 valores en 18 celdas de variante / tono / rounded / selected / disabled / lift, con `transition` y `animation` congeladas — porque el escenario monta UNA card `soft` y la sonda no barre variantes. Capturas 2× antes y después, miradas. Centinela R-5.4: **49/98, 49 adjudicadas**, verde. 40 por PATRÓN (la cascada de paleta, medida aquí: con `data-color=primary` `--card-primary-track` no mueve nada, `--palette-track` sobre el mismo nodo repinta, y sin `data-color` `--card-neutral-track` vuelve a pintar) y 9 forzadas sobre el nodo real. Dos merecen leerse: - **el trío `emerge-*` no pinta en la demo, y no es culpa de la demo**: el montaje CEDE al sistema de motion (`:not([data-animation-style])`) y el escenario arranca con el preset `select-pop`. Quitado el atributo, los tres alcanzan — y `emerge-distance` tiene ADEMÁS una segunda causa: alimenta `--motion-distance-md` y la animación acaba en `translate 0` con `fill-mode: both`, así que `transform` en reposo no puede enseñarlo nunca (se mide leyendo el hook, 8px → 1234px); - **`hover-lift` y `press-scale` mueven `transform`, que el guard no fotografía** — mismo hueco que `rating-group.item-hover-offset` (§13). Hallazgo de composición, MEDIDO y no forzado: dentro de un `CardGroup` el eje `radius` de la card está muerto — `[data-card-group] [data-card]` es (0,2,0) contra la (0,1,0) de la receta, así que manda `--card-group-card-radius` (`--card-radius-md: 1234px` no mueve nada; el del grupo mueve las dos cards). Es la anidación concéntrica de §30, deliberada y documentada en `card-group.css`; se registra porque significa que el token de la card no tiene efecto en ese contexto. Guards: censo `--only card` 78 % · `component-audit --only card` PASS · `eidos-lint card` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 · `docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin desviaciones NUEVAS sobre el árbol indexado. Anotado, fuera del eje: la raíz declara `background:` en ATAJO, lo que fija `background-image: none` y cancela el velo del sistema — card es uno de los 45 componentes de la incidencia §12 de next-features. Arreglarlo mueve píxel. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
c242616eea |
docs(theming): la viñeta de radio-group se pegó a la línea anterior
El commit `f5d252443` construyó su índice desde HEAD insertando la viñeta ANTES del ancla `\n**Deps**: ninguna…`, y ese ancla empieza por el salto de línea: el texto quedó `…ninguna superficie la monta.- **La escala del punto…` en una sola línea, y la lista de §13 perdió un ítem de vista. Sólo el salto de línea. Ni una palabra cambia. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
007c2af52c |
uix(toggle): el ledger y el guard del commit anterior, que un índice COMPARTIDO se llevó
Reparación, no trabajo nuevo. `edc019515` salió con la mitad del componente: la receta, el CSS, el README, la demo y la ficha entraron; el ledger R-5.4, el guard y la entrada del §8 se quedaron fuera, y en su lugar viajaron fragmentos de OTRA sesión (rating-group). Causa medida: en esta rama el ÍNDICE de git es un recurso compartido — entre el `git add` verificado y el `git commit` otra sesión hizo su propio `reset` + `add`, y el commit fotografió su índice, no el mío. Verificar el árbol indexado no basta si alguien puede reescribirlo DESPUÉS de mirarlo; la verificación y el commit tienen que ir en la misma invocación. Sin esto `npm run theming:sentinel -- toggle` falla: el contrato tiene 126 claves y el ledger no tenía ninguna. Lo que entra: - **Ledger** (`theming-sentinel-exceptions.ts`): las 8 adjudicaciones medidas de toggle (los cinco pasos de `rounded` que la demo no expone, `disabled-opacity`, y el par de transición que ES lo que el guard congela) y la excepción POR PATRÓN de sus 48 claves de tono — la cascada de paleta, medida aquí: con `data-color=primary` `--toggle-primary-solid` no mueve nada y `--palette-solid` sobre el mismo nodo repinta; quita `data-color` y `--toggle-neutral-solid` pinta otra vez. - **Guard** (`theming-sentinel.ts`): el barrido de VARIOS ejes como producto cartesiano (un solo eje da la misma secuencia de siempre), el valor `null` que QUITA el atributo, el mismo barrido en el pase de HOVER, y el override de toggle. 36/126 → 70/126 sin adjudicar nada. Los 12 componentes con `sweepAttr` re-verificados uno a uno: cero regresiones, cero STALE. - **`PLAN-theming.md` §8**: la entrada de toggle. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
f6a618328a |
uix(rating-group): temable — 80 % → 100 %, y su ÚNICO hover mueve lo que el guard no fotografía
Cuatro claves acuñadas, tres privados jubilados, dos literales firmados y seis
adjudicaciones medidas. El default no se mueve: diff de computed 0 sobre 5.624
valores en 27 estados y capturas 2x idénticas.
Censo: 80 % → 100 % (público 12 → 13, global 1 → 0, literal 2 → 0 —los dos pasan
a `exception`, fuera del ratio—, privado 0, sistema 1). Contrato 25 → 29 claves.
Global no baja (68 %).
QUÉ ENTRA (4 claves)
gap · item-size · font-size — los tres ejes RESUELTOS por talla en el TSC, con
`scope: 'size:{k}'` sobre el proveedor, que es quien lleva `data-size`. Con
ellos se van los tres privados `--_rating-group-*` y los cuatro bloques
`[data-size]` que los conmutaban: eran «privado con fuentes por TALLA», o sea
una ESCALA, y una escala sube al contrato. Un tema alcanza ahora la coordenada
resuelta además de los cinco pasos que ya alcanzaba.
invalid-item-fg — la costura: el tinte de validación leía
`--color-threat-element` a pelo, igual que en sus hermanos de formulario
(checkbox, radio-group, pin-input). El valor es del sistema; el knob es del
componente.
DOS LITERALES FIRMADOS (fuera del ratio)
`inline-size: 100%` / `block-size: 100%` sobre el glifo son IDENTIDAD: el SVG
llena la caja del ítem, y la caja ES el eje de talla. Llevan su anotación
`/* literal: … */` con la razón en la misma línea, más un
`/* prettier-ignore */` sobre la regla para que el formateo no separe la
anotación de su valor (la regresión que costó un día en natural-time-picker).
Nota honesta: la demo pinta las estrellas con TEXTO (★/☆), así que esa regla
no tiene nodo en esta ruta — su razón es estructural, no medida en pantalla.
CENTINELA 23/29, 6 adjudicadas, ninguna es deuda
partial-item-fg necesita `allowHalf` y medio valor · invalid-item-fg necesita
[data-invalid], y encenderlo en la demo taparía item-fg, active-item-fg y
partial-item-fg durante toda la corrida (su regla es (0,3,0)) · focus-radius
necesita :focus-visible, que el guard quita a propósito · el par de transición
ES la transición que el guard congela.
Y la sexta es un HUECO DE INSTRUMENTO nuevo: **item-hover-offset mueve un
`transform`**, propiedad que el guard no fotografía. Es el único knob de esta
receta que mueve uno, así que leía muerto estando vivo — medido a mano sobre
el ítem realmente hovereado: matrix(1, 0, 0, 1, 0, -1) → matrix(1, 0, 0, 1, 0,
-40). Añadir `transform` a la lista obliga a re-verificar los componentes con
ledger, así que queda anotado en next-features §13.
El guard gana además un `prepareWith` con el interruptor `disabled` de la
demo: `disabled-opacity` era el único knob tras un estado, esta demo no tiene
switch por URL, y encenderlo no tapa nada (el único hover de la receta ya
estaba fuera del alcance del instrumento).
CARRERA DE ÍNDICE — dónde está el resto de este trabajo
El commit `edc019515` (`toggle`, otra sesión) se llevó cuatro fragmentos míos
que estaban en el índice compartido cuando confirmó: el `prepareWith` de
rating-group en `theming-sentinel.ts`, su bloque de seis adjudicaciones en
`theming-sentinel-exceptions.ts`, su entrada del §8 del PLAN y su viñeta de
next-features §13. El contenido es correcto y ya vive en HEAD; se anota aquí
para que la trazabilidad no se pierda. Lección: en esta rama el índice es
compartido, así que entre construirlo y confirmar no puede mediar NADA.
GUARDS
censo --only rating-group 100 % · global 68 % (no baja) · component-audit PASS
· eidos-lint 0 invalid (12 morfo-backed, 0 eidos-only) · vitest src/uix/eidos
sin rojos nuevos (el único es `skin-media-player`, conocido) · rtl:check 0 ·
docs:check 0 · prettier OK sobre el contenido normalizado a LF · check sin
errores en ficheros del componente.
README con su sección «Talla y tema» y la demo con su pestaña Tokens (29
claves, verificada en navegador).
Índice construido a mano desde HEAD sobre los dos ficheros compartidos que
quedaban (recipes/base.ts, generated/base.css). Fuera del commit,
docs/audit/theming/README.md — es un agregado global que mezcla trabajo en
vuelo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
edc0195156 |
uix(toggle): temable — 81 % → 100 %, y el guard sólo sabía barrer UN eje
Tres knobs fuera de alcance, ninguno por doctrina.
- **El radio** (1 knob, 6 fuentes). La receta leía `--radius-default` y la
escala global `--radius-*` A PELO, así que la única forma de redondear un
toggle era mover el radio de todo el sistema — el agujero que tenía
`navigation-menu`, y el único de los CINCO componentes con escala `rounded`
que no tenía la suya (button, badge, image y color-swatch la declaran).
Entran `radius` (el reposo, default `var(--radius-default)`: sigue siguiendo
el default del arquetipo) y `radius-{sm,md,lg,xl,full}`. El desacople de
`size` se conserva intacto: son pasos de `rounded`, no de talla.
- **El tinte inválido**: `var(--color-threat-element)` a pelo →
`invalid-border` con ese valor (la costura, PLAN §2-A).
- **Los tres literales quedan FIRMADOS** con su anotación y salen del ratio:
el `100%` de `data-block` es identidad y el par `1px` del cuerpo ES la
técnica sr-only.
Censo: 28 knobs · 22 públicos · 81 % → 25 knobs · 24 públicos · **100 %**
(3 excepciones firmadas fuera del ratio). Contrato 119 → 126 claves. Global
del catálogo sin bajar (68 %).
Diff de computed: **VACÍO**. 416 valores en 7 estados (sonda estándar, 2
nodos) más 1.150 valores en 25 celdas de variante / rounded / on / invalid /
disabled / block / icon-only / tono, con `transition` y `animation`
congeladas — porque el escenario de la demo monta UN toggle solid, apagado y
válido, y la sonda no barre esos ejes. Capturas 2× antes y después, miradas.
Centinela R-5.4: **70/126, 56 adjudicadas**, verde. Empezó en 36/126 y la
diferencia NO es adjudicación, es instrumento: las claves `{variante}-*` y
`{variante}-on-*` son las mismas tres variantes en dos ESTADOS, y forzar el
estado con `prepareWith` cambiaba una mitad por la otra (36 → 46, y murieron
las de reposo) — «montar más puede medir menos», esta vez dentro de un
componente. El guard aprende tres cosas, cada una nacida de una medición:
- barrer el **producto cartesiano** de varios ejes (un solo eje da la misma
secuencia de siempre, así que nada de lo que ya tenía `sweepAttr` cambia);
- **quitar** un atributo con `null`, porque sellar `data-invalid` toda la
corrida hacía que el borde inválido ganase a los otros seis bordes;
- aplicar el barrido también en el **pase de hover**, que no barría nada —
que es literalmente la razón escrita en el ledger de
`radio-group.hover-segmented-segment-fg`.
Con eso, 58 y luego 70. Los **12 componentes con `sweepAttr` re-verificados
uno a uno**: cero regresiones, cero STALE (tres dieron exit=1 falso corriendo
doce seguidos contra el mismo dev server; a solas, verdes).
De las 56 adjudicadas, 48 son la cascada de paleta POR PATRÓN, medida aquí:
con `data-color=primary`, `--toggle-primary-solid` no mueve nada y
`--palette-solid` sobre el mismo nodo repinta; quita `data-color` y
`--toggle-neutral-solid` pinta otra vez. Las ocho `neutral-*` caen con las
demás por una razón que conviene escribir: el propio guard ESTAMPA
`data-color=neutral` para probarlas, que es justo lo que enciende el bloque
genérico. Las otras 8 están medidas una a una sobre el nodo real (los cinco
pasos de `rounded`, que la demo no expone; `disabled-opacity`; y el par de
transición, que ES lo que el guard congela).
Guards: censo `--only toggle` 100 % · `component-audit --only toggle` PASS ·
`eidos-lint toggle` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos
(el conocido `skin-media-player` en `lint.test.ts`) · `rtl:check` 0 ·
`docs:check` 0 · `check` sin errores en ningún fichero tocado · prettier sin
desviaciones NUEVAS sobre el árbol indexado.
Anotado y FUERA por D-TH.5: `[data-toggle]:hover` y
`[data-toggle][data-invalid]` pesan lo mismo (0,2,0) y el hover se declara
antes, así que un toggle inválido bajo el puntero pierde su tinte. Arreglarlo
mueve píxel y es una decisión de escala del sistema — los cuatro controles de
formulario comparten el patrón.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
f5d252443c |
uix(radio-group): temable — 77 % → 81 %, y su punto NUNCA ha pintado su escala
Ocho claves acuñadas, diecisiete bloques `[data-size]` retirados y veinticuatro
adjudicaciones medidas. El default no se mueve: diff de computed 0 sobre 25.263
valores en 47 estados (20 combinaciones de variante x estado x talla con su
pasada de hover, más las 7 de la sonda estándar) y capturas 2x idénticas.
Censo: 77 % → 81 % (knobs 75 → 59, público 56 → 46, global 7 → 1, privado 10
invariante, sistema 2). Contrato 61 → 69 claves. Global no baja (68 %).
QUÉ ENTRA (8 claves)
item-size · dot-size · font-size — los tres ejes RESUELTOS por talla en el
TSC, con `scope: 'size:{k}'` sobre el proveedor, que es quien lleva
`data-size`. Con ellos se van los DIECISIETE bloques `[data-size]` del CSS
(§7.4-4: dejarlos vivos hace que el diff dé 0 por la ruta vieja) y el privado
`--_radio-item-size`, que llevaba el nombre del componente ABREVIADO —
theming §6 r5 lo prohíbe, es la clase de `--_mp-*` y `--gp-*` — y por eso el
censo contaba el ancho y el alto del ítem como deuda.
invalid-indicator-border · invalid-ring · invalid-ring-gap ·
invalid-item-label-fg — el tinte de validación leía `--color-threat-element`
y `--color-threat-text` a pelo. El trío del anillo toma el vocabulario del
gemelo `checkbox`, que ya lo tenía; el borde se llama `indicator-*` porque en
ESTE componente «indicator» es el círculo exterior y `dot-*` el punto.
segmented-segment-padding-block — el hermano que le faltaba a
`-padding-inline`.
UNA CLAVE ACUÑADA Y RETIRADA EN EL ACTO
`row-min-height-touch: var(--touch-target)` para el suelo táctil de la fila.
La suite `recipe-css-contract` la rechazó como referencia FANTASMA: nadie
emite `--touch-target`, es una constante ergonómica escrita a mano en
`archetypes.css` («a hard ergonomic constant — the fingertip, NOT a theme
value»). Y recipe-contract §2 ya lista el touch-target entre los sistemas
transversales que una receta CONSUME y nunca acuña, así que la lectura cruda
es el contrato cumpliéndose. El censo la cuenta `global` sólo porque su lista
`system` aún no conoce el token — el pendiente de firma «extender la clase
system a las capas compartidas».
POR QUÉ 81 % ES EL TECHO
Los diez knobs que quedan fuera leen `--_radio-group-palette-*`: el puente
THM-2 que la capa compartida alimenta por instancia desde `[data-color]`. Un
público encima dejaría que un tema lo fijara y matara el `color=` de cada
instancia. No es deuda; es el componente cerrado en su número.
TRES DECLARACIONES QUE NO PINTAN (medidas, y las tres mueven píxel → firma)
1. La escala del punto NUNCA ha pintado. `<SvgDot>` escribe
`style="width: 1em; height: 1em"` y un inline gana a cualquier regla: el
punto computa 13,3281px en las CINCO tallas mientras el token dice
5/6/7/9/11px, el valor centinela no lo mueve, y quitando el estilo inline
el MISMO token pinta 1234px. Clase «canal de valor inline» del trío
`carousel.item-gap*`, pero con arreglo posible: la forma `!important` que
recipe-contract §3 autoriza justo para saltarse un estilo inline.
2. `[data-radio-group-label][data-disabled]` no casa jamás. Con el grupo
entero deshabilitado la etiqueta lleva `[id, data-radio-group-label,
data-archetype]` y nada más: soma no estampa `data-disabled` en la parte
`Label` (el morfo declara `data: []`). Forzado a mano el token alcanza, o
sea que falta el ATRIBUTO, no la clave — decisión de MORFO.
3. El fondo de un radio marcado Y deshabilitado no llega: la regla de
variante es (0,4,0) y `[data-radio-group-item][data-disabled][data-state=
'checked']` sólo (0,3,0). Medido con el centinela escrito: solid da el
acento a plena intensidad, outline y segmented transparente, ghost la
mezcla al 18 %. Quitar `data-variant` no ayuda: el gemelo
`:not([data-variant])` también es (0,4,0).
Y una cuarta, de escala del SISTEMA y por tanto fuera de este eje (D-TH.5):
el `:hover` del círculo es (0,4,0) y el tinte inválido (0,3,0), así que pasar
el ratón por encima TAPA el borde de error. Las cuatro, en next-features §13.
EL INSTRUMENTO MEDÍA 27 DE 61
No veía el punto (es un `<svg data-svg='dot'>` sin atributo del componente),
ni la variante `segmented` (doce claves), ni los estados disabled / invalid.
El guard lleva ahora `extraNodes` para el punto, el barrido de `data-variant`
y DOS URL más — `?perm.disabled=true` y `?perm.invalid=true`, que esta demo
honra: once adjudicaciones sustituidas por medición real.
CENTINELA 45/69, 24 adjudicadas: 6 del punto (estilo inline), 8 tonos por la
cascada de paleta (mismo patrón que su gemelo checkbox, medido aquí: la clave
no mueve nada, `--palette-solid` en el nodo repinta), 4 del par de transición
congelado, 2 del anillo inválido (necesita `:focus-visible` con modalidad de
teclado), `gap-horizontal` (el par de gap, sólo pinta la mitad en vigor),
`segmented-pill-shadow` (la píldora sólo la renderiza el envoltorio bajo la
variante real), `disabled-item-label-fg` y `checked-disabled-indicator-bg` (las
dos declaraciones muertas de arriba).
GUARDS
censo --only radio-group 81 % · global 68 % (no baja) · component-audit PASS ·
eidos-lint 0 invalid (13 morfo-backed, 24 eidos-only) · vitest src/uix/eidos
sin rojos nuevos (el único es `skin-media-player`, conocido) · rtl:check 0 ·
docs:check 0 · prettier OK sobre el contenido normalizado a LF · check sin
errores en ficheros del componente.
README con su sección «Talla y tema» y la demo con su pestaña Tokens (69
claves, verificada en navegador).
Índice construido a mano desde HEAD sobre los seis ficheros compartidos
(recipes/base.ts, generated/base.css, theming-sentinel.ts,
theming-sentinel-exceptions.ts, PLAN-theming.md, next-features.md): otras
cuatro sesiones los escriben a la vez. Fuera del commit, docs/audit/theming/
README.md — es un agregado global que mezcla trabajo en vuelo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
bc9b9016bb |
docs(theming): file-upload barre DESCENDIENTES y se come el token de sus huéspedes
Lo destapó la sesión de chat-composer y lo dejó sin registrar a propósito (este fichero estaba en manos de otra sesión); la medición de aquí es propia. file-upload declara `[data-file-upload] [data-disabled]` — un selector de DESCENDIENTE, (0,2,0), el mismo peso que `[data-chat-composer-send][data-disabled]`, y se emite más tarde. Dentro de un FileUpload, que es donde la composición documentada pone al composer, el token del composer muere. Medido desde los dos asientos sobre el mismo nodo deshabilitado: suelto y envuelto computa 0.4 en los dos casos —los defaults coinciden, así que el VALOR no delata nada—, pero envuelto la clave del composer desde :root no lo mueve y la de file-upload sí (0.4 -> 0.321). Es invisible hasta que un tema mueva uno de los dos, y entonces el huésped no responde a su propia clave. file-upload es HOY el único componente del catálogo con un barrido así: una sola ocurrencia en las 162 recetas. No es una clase, es una regla concreta que se puede acotar — pero acotarla mueve el píxel de cualquier huésped deshabilitado que hoy hereda, así que es firma, no commit de theming. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
71a097ddca |
uix(chat-composer): temable — 79 % → 100 %, y file-upload le gana el disabled desde FUERA
Protocolo PLAN-theming §7 sobre `chat-composer`. Censo 79 % → **100 %**,
contrato 31 → **33** claves, centinela **29/33** con 4 adjudicadas. El default
no se mueve.
## La mitad de su contrato no la montaba la demo
El guard leía 14 muertas de 31, y once eran la barra de contexto (`context-*`,
opt-in tras un chip) más la bandeja de adjuntos (`attachments-gap`, opt-in tras
un botón). Con las dos encendidas por `prepareWith`: **29/33 antes de tocar el
código**. La sonda mide ya 9 nodos, con los dos glifos.
## Lo que entra: DOS claves donde el generador pedía cuatro
`context-close-size` y `context-close-radius`. El chip de descarte es un
control CUADRADO, así que es UNA clave para los dos ejes — la forma que
`send-size` ya usa en esta misma receta. El aviso del generador ("`var(--size-
xs-control-height)` / `1em`, dos valores") era un falso conflicto: metía en el
mismo saco la CAJA (26 px) y su GLIFO.
## Lo que SALE: cuatro declaraciones que no han pintado nunca
`[data-chat-composer-context-close] > svg` (`1em`) y
`[data-chat-composer-send] > svg` (`1.1em`). Los dos glifos son `Icon`
compuestos y el `Icon` emite `style="width: var(--icon-size-{k}); height: ..."`
INLINE: ningún selector gana a un estilo en línea. Medido — el cierre pinta
14 px (`--icon-size-xs`) contra los 13,3 px que daría `1em`, y el envío 16 px
(`--icon-size-sm`) contra los 14,7 px de `1.1em`. Retiradas: **0 diffs**.
Misma lección que `chat-log` esta misma tarde, con dos glifos en vez de uno.
## Y una colisión ENTRE RECETAS, que no es del instrumento
`--chat-composer-disabled-opacity` no alcanza, y no por un hábito del guard:
`file-upload` barre DESCENDIENTES. `[data-file-upload] [data-disabled]` pesa
(0,2,0) — lo mismo que `[data-chat-composer-send][data-disabled]` — y su receta
se emite MÁS TARDE, así que gana sobre cualquier nodo deshabilitado dentro de
un FileUpload. Que es exactamente donde vive el composer en su composición
DOCUMENTADA (su propio README y su demo lo envuelven en uno).
Medido sobre los nodos REALES quitando el atributo del ancestro: fuera del
envoltorio alcanza (0.4 → 0.123 en el send Y en el shell). Los dos defaults son
`--opacity-disabled`, así que la colisión es INVISIBLE hasta que un tema mueva
uno de los dos. **No se arregla aquí** —tocar `file-upload` es cascadear—: se
adjudica con su medida.
Las otras tres adjudicaciones son hábitos conocidos del guard: `focus-border`
(sólo bajo `:focus-within`, y el guard blurea tras abrir; enfocado el textarea
real, `color(srgb 0.745 0.577 0.894 / 0.48)` → `rgb(1, 2, 3)`) y el par
`transition-duration` / `-ease`, que ES la transición que el guard congela para
poder medir todo lo demás (0,12 s → 4,321 s sin congelar).
## Identidad firmada (1)
El `inline-size: 100%` del textarea, que ocupa su celda de la rejilla.
## El diff de computed y su residuo, medido
2.208 valores, 8 estados, 9 nodos. Idénticos salvo 2-4 de
`[data-chat-composer-attach]` `blockSize`, que flota entre 30 px y 36 px —
**y flota igual corriendo dos veces el MISMO código** (control after vs after2:
2 diffs, mismo nodo, misma propiedad). La causa, medida: en una recarga de cada
ocho el `Button size="sm" variant="ghost"` que la demo compone en esa ranura
computa 36 px **y fondo `oklch(0.5556 0.1829 305.86)`** —el sólido primario—
con sus `data-size` y `data-variant` puestos: las reglas de talla y variante de
`button` llegan tarde en el servidor de desarrollo. Un nodo que esta receta no
dimensiona, y una carrera de CSS del dev server. Es también lo que salió en la
captura "antes" (el clip sujetapapeles relleno), y por eso la de "después" se
tomó cuatro veces: las cuatro idénticas entre sí.
## Guards
censo `--only chat-composer` 100 % (global 68 %, no baja) · `component-audit`
PASS · `eidos-lint` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (el
único vivo es el conocido `skin-media-player`) · `rtl:check` 0 · `docs:check` 0
· `check` sin un solo error del componente · prettier limpio sobre el contenido
normalizado a LF.
README con su sección «Talla y tema», demo con pestaña `Tokens` verificada en
navegador, ficha con su veredicto §5 y registro en PLAN §8.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
b4e4fe1fe8 |
docs(theming): la sonda y el guard no se pueden lanzar con --import tsx/esm
Medido supervisando calendar. Cualquier script del eje que use page.evaluate muere con «ReferenceError: __name is not defined» DENTRO del navegador: el transform de esbuild que trae tsx envuelve las funciones con su ayudante keepNames, el cuerpo de la evaluación viaja serializado a la página y llega sin él. Reproducido en __theming-probe.ts y en theming-sentinel.ts. Se lanzan con node a secas — Node 24 desnuda los tipos de forma nativa, que es justo lo que hace npm run theming:sentinel. Sólo los scripts SIN page.evaluate (censo, component-audit, eidos-lint) toleran el --import tsx/esm. Vale una sesión entera si se confunde, porque el error no nombra ni a tsx ni a la sonda: nombra una variable que nadie ha escrito. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
509d1144ff |
uix(calendar): temable — 84 % → 89 %, y una entrada de FAMILIA no se juzga en la ruta de UN componente
CERO claves acuñadas: el censo no tenía nada que coser. Su columna `global` ya
era 0 desde la capa calendar-surface (2026-08-21), así que lo único fuera de
alcance eran cuatro literales de IDENTIDAD. Todo el trabajo fue MEDIR, y ahí
estaba el hallazgo.
Qué entra:
- Cuatro literales firmados con su razón (recipe-contract §3), fuera del
ratio: el inline-size: max-content del panel y de la tabla (su anchura ES
day-size × 7 más el espaciado — precedente progress), el min-inline-size:
max-content del panel de mes y el inline-size: 100% de la cabecera. La
propuesta §4 pedía acuñar width / month-panel-width / grid-width para ellos:
sería dar a un tema la anchura de una caja cuya anchura es su contenido.
- Ninguna línea de CSS nueva. Las 74 claves del contrato quedan como estaban.
Censo: 84 % → 89 % (71 knobs, 57 públicos, 4 literales → 67 knobs, 57
públicos, 0 literales, 4 excepciones). Los 7 que quedan fuera son los forwards
de paleta THM-2: no se acuñan. CERRADO en su 89 %. Global 68 %, no baja.
Centinela R-5.4: 45/74 → 68/74, 6 adjudicadas. Verde (exit 0).
Lo que enseñó:
1. Una entrada de receta de FAMILIA no se puede juzgar en la ruta de UN
componente. Esta entrada es el vocabulario de las cuatro superficies de
rejilla de fechas (lo dice lib/calendar-surface.css): range-calendar,
month-grid y year-grid consumen --calendar-* y no acuñan nada — de ahí su
0 % HONESTO. Sus partes llevan data-month-grid-* / data-range-calendar-*,
invisibles al filtro data-calendar: 23 de sus 29 «tokens muertos» eran eso.
Con urls a las tres rutas + extraNodes + barrido de variant, 45/74 → 68/74.
Los tres consumidores NO se han tocado y siguen en su 0 % honesto.
2. Y la propia demo tapa tres claves más: su cabecera monta SELECTORES de mes
y año donde iría el heading, así que heading-{fg,font-size,font-weight} no
tienen nodo aquí; los tiene month-grid.
3. HALLAZGO — el tamaño de letra de los selectores de mes / año es NO
DETERMINISTA. La sonda dio 36 diffs contra un cambio que era SÓLO
comentarios; corrida dos veces sobre el MISMO código dio 24, en los mismos
dos nodos y las mismas dos propiedades. Causa medida:
[data-calendar-month-select][data-button] (calendar-select.css, la regla
que existe precisamente para fijar la letra del Button a la del calendario)
y [data-popover-trigger]:not([data-archetype='field-trigger'])
(popover.css) empatan a (0,2,0), así que gana el módulo que Vite inyecte el
ÚLTIMO: cuatro cargas dieron 14 / 16 / 14 / 14 px, con el orden de las
hojas invertido en la que dio 16. Es la clase del empate por orden de carga
de tree-grid (§12); arreglarlo mueve píxel → next-features §13.
Regla que confirma: ante un diff inesperado, corre la sonda dos veces sobre
el mismo código ANTES de sospechar de tu cambio.
4. calendar.select-min-width no tiene nodo en NINGUNA página del repo: su
único consumidor es [data-range-calendar-month-select] / -year-select, y la
demo de range-calendar renderiza un heading de texto mientras
DateRangePicker importa los selectores del CALENDARIO. Hueco de demo → §13.
Diff de computed: sonda antes/después, 22.656 valores en 7 estados. Los 36
diffs son ÍNTEGRAMENTE el no-determinismo del punto 3 (misma corrida contra sí
misma: 24) y caen en dos nodos y dos propiedades; fuera de ellos, 0. Capturas
2× antes/después: IDÉNTICAS byte a byte.
Guards: censo --only calendar 89 % · component-audit PASS · eidos-lint 0
invalid · vitest src/uix/eidos sin rojos nuevos (los dos son ajenos:
skin-media-player, el conocido, y un fantasma de radio-group de otra sesión) ·
rtl:check 0 · docs:check 0 · npm run check COMPLETED con 0 errores en ficheros
de calendar · prettier limpio sobre el contenido normalizado a LF.
README «Talla y tema» actualizado y pestaña Tokens en la demo (74 claves,
verificada en navegador: 0 errores de consola).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
cc010f79aa |
uix(select): temable — 83 % → 92 %, y un token que ALCANZA y aun así no pinta
Dos claves de COSTURA (PLAN §2-A: el valor es del sistema, el knob es del componente) y tres literales de identidad firmados. Ni un píxel movido. Qué entra en el contrato (101 → 103 claves): - invalid-border — las TRES declaraciones del estado inválido (el borde en reposo, el borde con foco/abierto y el anillo box-shadow que lo dobla) leían --color-risk-border A PELO. Es UNA clave, no dos: la propuesta §4 pedía invalid-trigger-border + open-invalid-trigger-border, y las filas agrupadas por VALOR son una sola. Bare como sus vecinas disabled-* (las ranuras de estado de esta receta son las del trigger) y como las siete invalid-border del catálogo. - group-gap — el hueco entre filas de un grupo iba a var(--space-1) directo. Nombre CONTADO en base.ts antes de acuñarlo: toolbar.group-gap. Tres literales firmados con su razón (recipe-contract §3), fuera del ratio: los dos inline-size: 100% (identidad — el select ES la anchura de su contenedor, el trigger ES la caja del select) y el opacity: 1 del check revelado, que deshace el 0 de la regla base. Censo: 83 % → 92 % (72 knobs, 54 públicos, 3 globales, 3 literales → 69 knobs, 57 públicos, 0 globales, 0 literales, 3 excepciones). Los 5 que quedan fuera son los forwards de paleta THM-2 leídos a pelo: no se acuñan. CERRADO en su 92 %. Global 68 %, no baja. Diff de computed: sonda antes/después, 2.176 valores en 8 estados = 0 diffs. Capturas 2× antes/después (cerrado y abierto): IDÉNTICAS byte a byte. Centinela R-5.4: 69/103, 34 adjudicadas en el ledger, todas MEDIDAS sobre el nodo real con las transiciones congeladas. Verde (exit 0). Lo que enseñó, todo del PORTAL: 1. El guard tiene que mantener el panel ABIERTO para medir los ~30 tokens de dentro, y el estado abierto TAPA los de reposo: trigger-border y trigger-indicator-fg leen muertos abiertos y MUEVEN con el panel cerrado. El instrumento sólo puede estar en un estado a la vez. 2. Tres knobs viven en nodos SIN data-select-*: la z del panel está en el [data-floating-wrapper] que soma porta (el caso popover.content-z) y el ritmo del viewport lo pinta el ScrollArea compuesto. Con extraNodes, 65/101 → 69/103. Nodos: 4 en reposo, 42 con el panel abierto. 3. La cascada de paleta anula sus 24 tonos, aquí en su forma MULTI-PARTE (trigger + content, porque el panel se porta fuera). Medido sobre el trigger abierto: --select-primary-border no mueve nada, --palette-border sobre el mismo nodo repinta. 4. separator-size ALCANZA y aun así no pinta: flex-shrink 1 en la columna del ScrollArea y un panel que desborda (scrollHeight 670 vs clientHeight 310) aplastan su 1px a 0px; con flex-shrink 0 el token sigue (1px → 9px). Un token vivo sobre un nodo aplastado lee igual que uno muerto. Defecto de píxel → next-features §13, no se arregla en este eje. §12.9 respetado: el contenido lleva data-depth=overlay, así que no se acuñó font-family ni line-height para el panel. Guards: censo --only select 92 % · component-audit PASS · eidos-lint 0 invalid · vitest src/uix/eidos sin rojos nuevos (los dos rojos son ajenos: skin-media-player, el conocido, y un fantasma de radio-group de otra sesión) · rtl:check 0 · docs:check 0 · npm run check COMPLETED con 0 errores en ficheros de select · prettier limpio sobre el contenido normalizado a LF. README con su sección «Talla y tema» y pestaña Tokens en la demo (103 claves, verificada en navegador: 0 errores de consola). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
fd8f01bace |
uix(chat-log): temable — 77 % → 100 %, y el instrumento daba DIECISÉIS falsos muertos de 31
Protocolo PLAN-theming §7 sobre `chat-log`. Censo 77 % → **100 %**, contrato
31 → **35** claves, centinela **34/35** con 1 adjudicada. El default NO se
mueve: diff de computed VACÍO (1.920 valores · 7 estados · 9 nodos), capturas
2x antes/después idénticas.
## Lo caro no fue acuñar: fue VER
El guard leía **15/31** antes de tocar una línea de código, y las dieciséis
"muertas" estaban las dieciséis VIVAS. Tres cegueras, ninguna del componente:
1. **El viewport que scrollea es del componente COMPUESTO.** El log pinta su
`padding-inline` / `padding-block` sobre `[data-virtual-list-viewport]`, un
nodo sin un solo `data-chat-log-*`: fuera del filtro de la sonda y del
guard. Cuarta forma del mismo punto ciego (prose · navigation-menu ·
waveform).
2. **La demo no montaba TRES de las seis partes.** Separador de día y divisor
de no-leídos no existían en el escenario, y la fila de evento vivía en el
índice 0 de una lista virtualizada anclada al FINAL — fuera de la ventana.
Once claves sin nodo que pintar. La demo los monta ya cerca del final
(instrumento: lo que la demo no monta, nadie lo mide).
3. **La pastilla del separador es un `> span` sin atributo** — seis claves más.
Con las tres arregladas, **31/31 antes de acuñar nada**.
## Lo que entra (4 claves, la COSTURA de los cuatro globales)
`divider-padding-block` · `event-radius` · `pill-gap` · `to-latest-radius`.
El valor sigue siendo el del sistema; el knob pasa a ser del componente.
Los nombres salen del CATÁLOGO, no del generador: la ficha proponía
`divider-unread-padding-block` y `pill-new-gap` —nombra por el atributo de la
parte— cuando el contrato lleva `divider-fg` / `-line` / `-font-size` / `-gap`
y `pill-bg` / `-fg` / `-radius`. La familia manda.
## Lo que SALE: una regla que no ha pintado nunca
`[data-chat-log-to-latest] svg { block-size: 1em; inline-size: 1em }` no puede
ganar: el `Icon` compuesto emite `style="width: var(--icon-size-sm); height:
..."` EN LÍNEA, y un estilo en línea gana a todo selector. El glifo mide 16 px
(paso `sm` del icono), no los 14 px que `1em` daría sobre la fuente heredada
del botón. **Retirada: 0 diffs**, que es la prueba de que estaba muerta. Es la
clase `carousel.item-gap` / `drag-drop.preview-z`, con una vuelta más: aquí el
inline lo escribe un COMPONENTE COMPUESTO, no soma.
## Identidades firmadas (3, fuera del ratio)
`block-size: 100%` del shell y del viewport (el log ocupa la caja que la app le
da) e `inline-size: fit-content` de la pill (la dimensiona su contenido).
## Adjudicada (1)
`event-radius` — sólo pinta bajo `:focus-visible` y el guard hace blur tras
abrir. Medido enfocando con TECLADO la fila real, con `transition` congelada:
0 px en reposo, 4 px enfocada, 1234 px con el centinela.
## Guards
censo `--only chat-log` 100 % (global 67 %, no baja) · `component-audit` PASS ·
`eidos-lint` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (los dos
vivos son ajenos: `skin-media-player` y `radio-group.row-min-height-touch`) ·
`rtl:check` 0 · `docs:check` 0 · `check` sin un solo error del componente ·
prettier limpio sobre el contenido normalizado a LF.
README con su sección «Talla y tema», demo con pestaña `Tokens` verificada en
navegador, ficha con su veredicto §5 y registro en PLAN §8.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
bf90fc62b1 |
docs(theming): el guard tiene una carrera en editable — un rojo suyo se re-corre antes de creerlo
Supervisando el commit 2117d7422: sobre el MISMO HEAD, submit-fg leyó muerto en una corrida de cuatro (41/56, exit 1) y vivo en las otras tres (42/56, exit 0). El verde del commit era legítimo; lo intermitente es la apertura por foco + prepareWith del guard. Anotado en la ficha para que un barrido futuro del ledger no convierta la carrera en un falso rojo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
8a4bb8e0e8 |
docs(theming): el párrafo que faltaba de la corrección anterior
El commit
|
2 months ago |
|
|
009af3300d |
docs(theming): el canal inline filtrado al contrato son CUATRO claves, no dos
La entrada §13 del falso positivo inline decía que de los siete wrappers que
escriben un token público en el style, dos estaban en el contrato. Eran cuatro:
los dos de avatar parecían fuera porque su bloque de base.ts es una IIFE que el
censo no supo leer hasta
|
2 months ago |
|
|
2117d7422f |
uix(editable): temable — 75 % → 82 %, y el guard CERRABA la superficie que medía
Protocolo PLAN-theming §7 sobre `editable`. Censo 75 % → **82 %**, contrato 56
claves, centinela **42/56** con 14 adjudicadas. El default NO se mueve.
## Lo que costó medirlo: dos superficies y una apertura frágil al revés
- **Preview e input comparten celda de rejilla y se excluyen** (`display: none`),
igual que los triggers (Edit en reposo, Save/Cancel editando): una pasada deja
fuera la mitad de la receta. Todo se midió DOS veces.
- **Salir del modo edición es lo que hace un `blur`** —da igual lo que diga
`submitMode`, esa opción sólo decide si el valor se compromete— y el guard
blurea justo después de abrir. Abriendo con clic en el trigger, la superficie
ya estaba cerrada cuando se medía: `submit-fg` leía muerto y mueve
perfectamente abierta (`rgb(255,255,255)` → `rgb(1,2,3)`). Se abre por FOCO,
con la demo en `activationMode=focus`, que es la apertura que el guard no
deshace. Misma ley que `navigation-menu`, con el gesto invertido.
## Lo que entra al contrato (1 clave)
`disabled-fg` — la tinta apagada de TODO el componente: preview, input y los
tres triggers comparten UNA regla, así que el nombre desnudo del catálogo es el
que toca (`label` y `select` ya lo llevan con este mismo valor). Era el único
knob que iba a un primitivo a pelo, y encima con un respaldo escrito a mano
—`var(--color-content-disabled, var(--color-content-muted))`— que estaba MUERTO:
el token sí está declarado, así que el respaldo no podía pintar nunca. Retirado
con él.
## Lo que sale (1 clave huérfana)
`control-border`: ninguna regla lo consumía. El borde en reposo del control es
`transparent` por diseño y el del input es el acento
(`--_editable-palette-border`), así que esa clave pública prometía un knob que no
existe — la deuda INVERSA del eje. Diff 0, y el centinela lo confirmaba muerto.
## Dos literales de identidad firmados
El `fit-content` del preview (es tan ancho como el texto que enseña; la ficha
proponía acuñarlo como `preview-width`, que sería acuñar la definición de la
parte) y el `100 %` del input (llena la celda que comparte con el preview).
## Lo que se queda privado (el techo honesto es 82 %)
Los SIETE knobs por privado son el puente de paleta THM-2
(`--_editable-palette-{solid,border,solid-hover}`), que la capa compartida
alimenta por instancia desde `[data-color]`: un público encima dejaría que un
tema lo fijara y matara el `color=` de cada instancia. Otros cuatro son sistema
transversal (anillo de foco y velo de hover), ya fuera del ratio.
## Las catorce adjudicaciones, en dos razones — y una tercera que casi se cuela
- El par `transition-*` **ES** la transición que el guard congela; medido sin
congelar: `0.12s → 4.321s` y `cubic-bezier(0.4, 0, 0.2, 1) → steps(3)`.
- Las doce claves de tono son la cascada de paleta, por PATRÓN y con el mecanismo
a la vista: el nodo lleva `--palette-solid` de la capa por instancia, el bloque
genérico `[data-editable][data-color]` —emitido EL ÚLTIMO, misma
especificidad— lo lee, y el respaldo que nombra la clave del componente no
llega nunca. Quítale `data-color` a la misma instancia y
`--editable-primary-solid` vuelve a pintar (`rgb(1, 2, 3)`).
- ⚠ **`risk-border` NO cae en ese patrón**: las tres reglas de inválido la leen
DIRECTAMENTE, así que su silencio tiene otra causa —la demo es válida— y
entrada propia: forzando `data-invalid` alcanza en el input Y en el control.
Una excepción por patrón que engulle una clave con vida propia es una
adjudicación falsa.
## Artefactos
- Sonda: **0 diffs** en las dos caras — modo preview (1.696 valores, 7 estados) y
modo edición (2.528 valores, 8 estados).
- Captura 2× del reposo idéntica al byte. La de edición NO es comparable por
bytes: la traza de la demo imprime un TIMESTAMP, así que dos corridas del mismo
código difieren (comprobado antes de creerme el diff). Revisada a ojo.
- `component-audit --only editable`: **PASS** · `eidos-lint` 0 invalid ·
`vitest src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player`) ·
`rtl:check` 0 · `docs:check` 0 · `npm run check` COMPLETED, 0 errores en
`editable`.
- README «Talla y tema» + pestaña `Tokens` (56 filas, verificada en el navegador
con `networkidle` y clic real).
## Defecto anotado, NO arreglado
El tinte inválido ES la clave de tono (`--editable-risk-border`): dos knobs con
una sola llave — un tema que quiera otro color de error mueve también las
instancias `color="risk"`. El arreglo es una clave de estado por parte
(`invalid-input-border` / `invalid-control-border`, la forma que `switch` acuñó
el mismo día) y es contrato: se lista.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
b7f5a7d75a |
docs(theming): la cascada de paleta se lleva también el tono POR DEFECTO
El §13 decía que las claves `{c}-primary-*` son el respaldo de la regla
genérica y salvan a la instancia SIN `data-color`. Es cierto donde el atributo
puede faltar — y hay componentes donde no puede.
Cuando el proveedor de soma trata el color como un valor RESUELTO, estampa
`data-color` en toda instancia y `neutral` es su default, no su ausencia. Ahí
el bloque genérico casa siempre y no queda respaldo: medido en `switch` en
estado checked, `--switch-neutral-solid` no mueve nada mientras `--palette-solid`
sobre el nodo repinta.
Amplía el alcance de la firma pendiente: no es «los tonos no canónicos»,
son los tonos. Lo destapó la sesión de `switch` al adjudicar sus doce claves de
tono y encontrarse `neutral` cayendo con las otras once.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
0c06d42aac |
uix(file-upload): temable — 76 % → 83 %, y una clave suya NO PINTABA en ninguno de sus tres botones
Una clave acuñada, UNA RETIRADA con su declaración muerta, cuatro literales firmados y cuarenta y cuatro adjudicaciones medidas. El default no se mueve: diff de computed 0 sobre 11.448 valores en 17 estados y capturas 2x idénticas byte a byte. Censo: 76 % → 83 % (público 45, global 1 → 0, literal 4 → 0, excepción 0 → 4; knobs 61 → 56). Contrato 98 claves (una entra, otra sale). Global no baja. QUÉ ENTRA (1 clave) invalid-dropzone-border (var(--color-risk-border)). Era el único knob de apariencia que iba a un primitivo global a pelo. Lleva la PARTE en el nombre y no el `invalid-border` desnudo que el catálogo repite seis veces (checkbox, listbox, grid-list, radio-cards…): aquí hay TRES partes con borde —dropzone, botón e ítem— y el nombre desnudo no diría cuál tiñe. La forma modificador + parte + ranura ya está en el catálogo (invalid-input-border, invalid-control-border). Su estado no lo alcanza esta ruta: isInvalid sale de un Field envolvente y la demo no monta ninguno. Forzado: oklch(0.8059 0.1123 59.96) -> rgb(1,2,3). QUÉ SALE (1 clave, y su declaración) button-bg NO PINTABA. La regla compartida de los tres botones declaraba `background: var(--file-upload-button-bg)` y los tres la pisan después: el trigger con el sólido de la paleta, ItemRemove y ClearTrigger con transparent. Medido sobre los tres nodos, uno a uno: el centinela no mueve NADA en ninguno. Con UNA clave la respuesta de F2-A es retirar, no adjudicar — y retirarla da diff 0, que es la prueba de que estaba muerta. La clave sale con ella: un público sin consumidor es un huérfano. CUATRO LITERALES FIRMADOS (fuera del ratio) Los tres 100% de identidad —el campo ocupa el ancho que le dan, la miniatura llena la caja en la que se recorta, la barra ocupa la fila del grid— más el block-size de la miniatura. Cada uno con su anotación en la declaración (válvula de recipe-contract §3). CUARENTA CLAVES DE TONO NO PINTAN 8 tonos x 5 ranuras (solid, solid-hover, track, border, text), 40 de sus 98. Es la cascada de paleta: el forward emite AL FINAL un bloque genérico [data-file-upload][data-color] que resuelve desde el --palette-* global, misma especificidad (0,2,0), gana el último. Medido para los ocho tonos sobre las dos superficies que las consumen —el trigger (solid) y el dropzone en hover (track)—: ninguna se mueve, mientras --palette-solid sobre el nodo repinta. Adjudicadas POR PATRÓN; incidencia de fondo en next-features §13. FUERA POR DOCTRINA (los 9 privados) Ocho son el puente de paleta THM-2 y el noveno es EL CANAL DE VALOR (--_file-upload-progress-value, que el envoltorio escribe inline por fila). Lo que el componente escribe inline no es tema, y un público sobre el puente dejaría que un tema fijara el tono y matara el color= de cada instancia. Su techo honesto NO es el 100 %. VERIFICACIÓN Sonda estándar antes/después 0 diffs (4.608 valores · 8 estados · 19 nodos: la demo arranca con dos ficheros sembrados, así que monta la superficie entera) + barrido de los estados que la ruta no arranca (3 variantes x 3 tallas, invalid, disabled, dragging) 0 diffs sobre 6.840 valores · capturas 2x idénticas byte a byte · R-5.4 54/98, exit 0, sin STALE · censo --only 83 % · component:audit PASS · eidos-lint 29 morfo-backed / 0 invalid · vitest src/uix/eidos 35/36 (el rojo conocido es skin-media-player) · rtl:check 0 · docs:check 0 · prettier limpio · npm run check sin errores en ficheros del componente · pestaña Tokens verificada en el navegador (98 filas, 0 errores de consola). ⚠ Truco de medición nuevo: el «antes» del barrido de estados se reconstruye INYECTANDO el CSS de HEAD en la página (gana por orden a igual especificidad), sin tocar un árbol que otras tres sesiones están usando. Con muta-prueba: 19 diffs al alterar el control, 1 si sólo se altera el borde inválido. Índice construido a mano desde HEAD sobre los tres ficheros compartidos (recipes/base.ts, generated/base.css, theming-sentinel-exceptions.ts). Fuera del commit, como en el de `form`, docs/audit/theming/README.md — es un agregado global que mezcla trabajo en vuelo de otras sesiones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
ebfa1ce5ef |
fix(theming): el guard da por VIVO lo que un tema no alcanza — y dos bloques del ledger se descartaban en silencio
Dos defectos del instrumental, los dos medidos, ninguno arreglado en el guard
todavía (el arreglo toca a todos los componentes y pide su re-verificación).
EL GUARD TIENE FALSOS POSITIVOS: ESCRIBE EL CENTINELA EN EL style INLINE
`staticPass` escribe el token en documentElement Y en todos los nodos del
componente — y ahí es donde vive el canal inline de los wrappers. Si un wrapper
escribe un token PÚBLICO en el `style` del nodo, el guard lo pisa, ve el cambio
y lo da por VIVO, aunque un tema (que sólo puede escribir en :root o en una
hoja) no lo alcance jamás. Es la cara opuesta de drag-drop.preview-z.
Censo: siete wrappers escriben un --{c}-* público inline y DOS están en el
contrato — dialog.overlay-opacity y drawer.overlay-opacity. Medido en dialog con
el diálogo abierto y las animaciones congeladas: desde :root el fondo del velo NO
se mueve (color(srgb 0.1098 0.098 0.0902 / 0.2518) idéntico), desde el inline SÍ.
Su token MIENTE y el guard lo bendice. Los otros cinco no están en ningún
contrato: son sólo canal.
El arreglo propuesto va en §13: escribir en todos los nodos MENOS en los cuyo
`style` ya declara ese mismo token, y avisar cuando ocurra — no basta con
escribir sólo en :root, porque eso es justo lo que hace medibles los paneles
portalados. Con re-verificación del ledger entero, así que no entra aquí.
El veredicto de dialog (commiteado hoy) queda corregido con la medición.
DOS BLOQUES DEL LEDGER SE DESCARTABAN EN SILENCIO
`metrics` y `color-picker` aparecían DOS VECES en el mismo literal de objeto, así
que el primero de cada par no existía para el guard — la trampa que el handoff
documenta para base.ts, un piso más abajo. Comprobado antes de tocar nada: en los
dos casos el bloque que gana es SUPERCONJUNTO del muerto, así que no se perdía
ninguna adjudicación; era deuda con riesgo futuro, no un rojo. Retirados los dos
bloques muertos: 69 → 67 entradas, cero duplicados, y `metrics` (54/72) y
`color-picker` (46/71) siguen en verde. De paso, el fichero baja de 63 a 61 hunks
de prettier preexistentes.
Lo destapó la sesión de `progress` al leer el fichero para añadir su bloque.
Rama con varias sesiones en paralelo: índice construido desde HEAD + sólo mis
hunks, verificado con git diff --cached.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
f24abdb60e |
uix(search-field): temable — 71 % → 100 %, y sus 10 tokens sin medir NO mienten
Cero claves nuevas. Su 29 % de deuda eran CUATRO literales que son identidad, y ahora van firmados. Diff de computed 0 sobre 1.216 valores en 8 estados y 5 nodos; R-5.4 de 7/17 a 17/17 SIN una sola adjudicación, dos corridas de acuerdo; capturas 2× antes/después idénticas byte a byte. LOS CUATRO LITERALES SON IDENTIDAD, NO KNOBS El line-height: 1 del icono —un glifo solo no tiene interlineado, la misma anotación que su hermana field.css—, el 100 % doble del ::before —el anillo ES la caja del indicador, que ya mide por --_search-field-loading-size— y el border-radius: 50 %. Ese último la §4 pedía acuñarlo como loading-indicator-radius: sería un knob que SÓLO puede romper el componente. El arco es un BORDE que gira; con cualquier otro valor la ruleta deja de leerse como una. Es la clase 4 de F2-B, «el 50 % de un círculo», al pie de la letra. DIEZ DE SUS DIECISIETE TOKENS NO SE HABÍAN MEDIDO NUNCA El centinela leía 7/17 porque la demo no monta dos estados: el indicador de carga sólo existe con loading (ocho tokens) y la X sólo se desvanece con el campo VACÍO, y el escenario arranca con valor (clear-hidden-opacity). Los dos interruptores entran como prepareWith, y EL ORDEN IMPORTA: el clic en la X tiene que ir PRIMERO, porque la propia regla que enciende le quita después el pointer-events al botón que la disparó. La sonda necesita el de loading por lo mismo: 4 → 5 nodos, sin perder ninguno. LOS DOS PRIVADOS NO SON DEUDA --_search-field-icon-size y --_search-field-loading-size son el conmutador por talla y sus cinco fuentes son, cada una, una clave pública. Se quedan: 58 de las 162 recetas resuelven así su eje size —incluidas las cerradas al 100 % este mes, empty-state y banner—, y convertirlas al ámbito size: del TSC cambiaría la especificidad de la emisión sin ganar un punto de alcance. ⚠ UN DEFAULT MEDIDO, ANOTADO, NO CAMBIADO Las dos escalas del mismo renglón divergen en los dos últimos peldaños. Medido en Chrome con transiciones y animación congeladas, forzando data-size sobre el nodo real, icono → indicador: xs 14→14, sm 16→16, md 18→18, lg 20→18, xl 32→20. El contrato lo declara de frente (loading-indicator-size-lg apunta a --size-md-icon-size y -xl a --size-lg-icon-size), así que en xl la ruleta es DOCE píxeles menor que la lupa que tiene al lado. No es deuda de alcance —las diez claves alcanzan—, es diseño que huele a copia a medias. Mueve píxel: D-TH.5 lo saca de este eje. Escrito en el veredicto §5 y en el README. CIFRAS Y GUARDS Censo 71 % → 100 % (15 knobs → 11: público 10, literal 4 → 0, excepción firmada 0 → 4; sistema 1, fuera del ratio). Contrato 17 claves, intacto — no hay cambio en base.ts ni en generated/. component-audit PASS · eidos-lint invalid 0 (9 morfo-backed, 4 eidos-only) · vitest src/uix/eidos 35/36 (único rojo skin-media-player, preexistente) · rtl:check 0 · docs:check 0 · npm run check sin errores en ficheros de este componente. README con su sección «Talla y tema» y pestaña Tokens en la demo (17 claves, verificada con clic de Playwright tras networkidle). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
f68bac4a66 |
uix(avatar): temable — 75 % → 90 %, y su contrato era INVISIBLE para los dos instrumentos
Protocolo PLAN-theming §7 sobre `avatar` (incluye `AvatarGroup`, que comparte
receta y fichero). Censo 75 % → **90 %**, contrato 84 → 88 claves, centinela
**83/88** con 5 adjudicadas. El default NO se mueve.
## Lo primero: el instrumento no veía el contrato
La entrada `avatar` de `recipes/base.ts` es la ÚNICA construida por una IIFE (un
helper local genera sus 24 ámbitos compuestos), así que su mapa vive en el
`return {`, un tabulador más adentro. Consecuencia medida:
- el censo la leía como «sin entrada en base.ts» — 84 claves invisibles;
- el centinela **moría** con `no recipe block for avatar`: el componente no se
podía medir, y su gate no significaba nada.
Los dos lectores leen ya la IIFE (dedentan el `return`). Sin este arreglo, todo
lo demás de este commit habría sido humo.
## Lo que entra al contrato (6 claves)
`group-overlap-{xs,sm,md,lg,xl,xxl}` — la escala de solape de `AvatarGroup`.
Había UNA clave, `--avatar-group-overlap`, y la receta la RE-DECLARABA en seis
bloques `[data-size]`: sentada en el elemento, ganaba siempre al `:root` donde
escribe un tema. Medido: `37px` desde el asiento del tema no movía el margen; el
mismo valor escrito sobre el nodo, sí. Ahora el paso viaja por
`--_avatar-group-overlap` y los seis alcanzan desde `:root` (−8,4 · −11,2 · −14 ·
−16,8 · −22,4 · −33,6 px → 37 px, uno a uno).
## Lo que se retira (2 declaraciones muertas, diff 0 las dos)
- `group-max`: el envoltorio escribía `--avatar-group-max` INLINE y la receta
declaraba su default `99`. **No lo leía nadie** — el tope se aplica con
`data-has-max` + `:nth-child(n + M)` porque una variable no entra en
`:nth-child()`, y lo dice el propio comentario del CSS. Retirado de los dos
sitios; el `+3` del grupo sigue exactamente donde estaba.
- el respaldo `, white` de `--_avatar-badge-fg`: el contrato ya declara
`--avatar-badge-color-custom-contrast: white`, así que era inalcanzable y sólo
podía envejecer contra su token. Comprobado en la rama custom: la tinta sigue
computando `rgb(255, 255, 255)`.
## Seis literales firmados (salen del ratio)
Los cuatro `100 %` de Image y Fallback son IDENTIDAD — la parte ES la superficie
del avatar, no una talla propia — y los dos `line-height: 1` mantienen el glifo
centrado por la caja flex.
## Lo que se queda privado (el techo real es 90 %)
`--_avatar-bg`, `--_avatar-fg` y `--_avatar-badge-bg` son un CONMUTADOR: cambian
de fuente con la variante (solid · soft · outline) y su valor sale del forward de
paleta THM-2 que la capa de color alimenta por instancia desde `[data-color]`.
Un público encima dejaría que un tema los fijara y matara el `color=` de cada
avatar.
## Artefactos
- Sonda: **0 diffs** en TRES bases — demo de avatar con insignia y anillo (576
valores), la misma en modo fallback (384) y demo de AvatarGroup (3.072).
- Capturas 2× antes/después de las dos demos: **idénticas al byte**.
- Centinela R-5.4: 83/88, 5 adjudicadas con su medida en el ledger (`size-xxl` y
`font-size-xxl` viven en el paso `xxl`, que el barrido del guard no alcanza —
el límite que `metrics` ya registró; `radius-none` y `ring-width-sm` son «sólo
el paso en vigor pinta»; `group-overlap-xxl` junta las dos cosas).
- El guard aprende `avatar`: la insignia y el anillo son OPT-IN, el barrido de
`data-variant` destapa las 16 claves `*-outline-*`, y `AvatarGroup` se mide en
su propia ruta (21 muertos → 5).
- `eidos-lint` 0 invalid · `vitest src/uix/eidos` sin rojos nuevos (el conocido
`skin-media-player`) · `rtl:check` 0 · `docs:check` 0 · `npm run check`
COMPLETED sin un solo error en `avatar`.
- README «Talla y tema» + pestaña `Tokens` (88 filas, verificada en el navegador
con `networkidle` y clic real).
## Lo que NO se arregla aquí (anotado)
- **R-5.3 preexistente**: cuatro claves `*-color-custom*` donde la gramática
exige `fg`. Son escotillas que el envoltorio escribe INLINE, así que
renombrarlas cambia el contrato público de tres canales: se lista, el audit
sigue en NEEDS-WORK por esto y sólo por esto.
- **Falso POSITIVO nuevo del centinela** (next-features §13): escribe el token
en `:root` y también sobre cada nodo, y para una propiedad personalizada que
la receta re-declara en el ELEMENTO ese inline gana justo lo que un tema
pierde. Es lo que hacía que `--avatar-group-overlap` leyera vivo.
- **El barrido de tallas del guard para en `xl`**: añadir `xxl` dejaría STALE
las seis excepciones de `metrics`, así que se hace con la re-verificación del
ledger entero.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
bbdc77c07b |
uix(switch): temable — 76 % → 81 %, y su tono NEUTRAL cae con los otros once
Una clave nueva (51 → 52) y veinticinco adjudicaciones medidas: trece propias y doce por patrón. El default no se mueve: diff de computed 0 sobre 1.344 valores en 36 estados y capturas 2x idénticas. Censo: 76 % → 81 % (público 16 → 17, global 1 → 0; 22 knobs, 4 privados y 1 sistema fuera). Global 67 % (no baja). QUÉ ENTRA (1 clave) invalid-track-border (var(--color-threat-element)). Era el ÚNICO knob de apariencia que iba a un primitivo global a pelo. El nombre NO es el `invalid-border` que el catálogo repite seis veces (checkbox, listbox, grid-list, radio-cards, date-range-field…): esta receta tiene DOS partes con borde y las nombra — su hermana de estado es `disabled-track-border` y el pulgar lleva `thumb-border`, así que un nombre desnudo no diría cuál de las dos tiñe. La forma modificador + parte + ranura ya está en el catálogo (`invalid-input-border`, `invalid-control-border`). DOCE CLAVES DE TONO NO PINTAN — Y AQUÍ CAE TAMBIÉN «NEUTRAL» Es la cascada de paleta ya medida en button / badge / callout: el forward emite al FINAL un bloque genérico [data-switch][data-color] que resuelve desde el --palette-* global, misma especificidad (0,2,0), gana el último. Lo propio de este componente es que el fallback no salva ni al tono por defecto: soma estampa data-color SIEMPRE (es el color RESUELTO, neutral por defecto), así que el bloque genérico casa en toda instancia. Medido en checked: --switch-neutral-solid no mueve nada, --palette-solid sobre el nodo repinta (oklch(0.5556 …) -> rgb(4,5,6)). En button el neutral sobrevive; aquí no. Adjudicadas POR PATRÓN, con esa diferencia escrita. LAS OTRAS TRECE SON ESTADO O INSTRUMENTO Cinco disabled-* y el invalid-track-border nuevo sólo existen bajo su atributo, que ningún trigger alcanza (forzados: alcanzan, con su par medido). Los cinco size-*-thumb-translate son DOS huecos a la vez: pintan sobre `transform`, que el guard no fotografía, y valen 0px hasta que el interruptor está encendido (forzado checked: 12/14/16/18/20px -> 1234px). El par de transición ES la transición que el guard congela (sin congelar: 0,12s -> 11,5s en las cuatro propiedades). FUERA POR DOCTRINA (los 4 privados que quedan) --_switch-track-bg y --_switch-track-border-hover son CONMUTADORES: dos fuentes cada uno (la clave pública del estado apagado, el forward de paleta del encendido), y aplanarlos obligaría a duplicar cada regla por color. Las dos lecturas directas de --_switch-palette-solid* (el fondo del track en hover, la tinta del check dentro del pulgar) son el puente THM-2: un público encima dejaría que un tema fijara el tono y matara el color= de cada instancia. El techo honesto de este componente NO es el 100 %. DEFECTO ANOTADO, NO ARREGLADO El tinte inválido es --color-threat-element, el paso `element` de la escala: oklch(0.9555 0.0207 13.86), casi blanco sobre superficie clara. Y en cuanto entra el puntero, la regla de hover (0,4,0) lo tapa con el borde neutro fuerte. Es el MISMO valor en checkbox, radio-group y toggle para el mismo estado, así que es una decisión de escala del sistema (element contra border), no de esta receta: cambiarlo mueve píxel en cuatro componentes y D-TH.5 lo deja fuera. VERIFICACIÓN Sonda estándar antes/después 0 diffs (416 valores · 7 estados) + sonda de estados propia 0 diffs (928 valores · 29 estados: checked, invalid, readonly, disabled, RTL y las cinco tallas, cada uno con hover y foco) · capturas 2x antes/después idénticas · R-5.4 27/52, exit 0, sin STALE · censo --only 81 % · component:audit PASS · eidos-lint 13 morfo-backed / 0 invalid · vitest src/uix/eidos 35/36 (el rojo conocido es skin-media-player) · rtl:check 0 · docs:check 0 · npm run check sin errores en ficheros del componente · pestaña Tokens verificada en el navegador (52 filas, 0 errores de consola). Índice construido a mano desde HEAD sobre los cuatro ficheros compartidos (recipes/base.ts, generated/base.css, theming-sentinel-exceptions.ts): hay tres sesiones más en vuelo sobre ellos. Fuera del commit, como en el de `form`, docs/audit/theming/README.md — es un agregado global que mezcla ese trabajo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
1a41312b68 |
uix(image-picker): temable — 71 % → 100 %, y el instrumento medía UN nodo
Una clave nueva (13 → 14), cuatro literales firmados y el interruptor que hace
medible el componente. Diff de computed 0 sobre 1.344 valores en 7 estados y 6
nodos; R-5.4 de 13/13 a 14/14 SIN una sola adjudicación; capturas 2×
antes/después idénticas.
EL PICKER ARRANCA VACÍO Y LA SONDA VEÍA UN NODO
Todo lo que la receta pinta —preview, canvas, toolbar y los dos botones de
icono— sólo existe en el estado ready, al que no llega ningún trigger: hay que
cargar un fichero. Con el chip «Load sample image» de la demo la sonda pasa de 1
a 6 nodos. La sonda lo enciende por DEMO_VARIANTS y el centinela por
prepareWith; éste necesita además openMarker, porque su re-apertura por token
volvería a pulsar el chip y remontaría la vista previa a mitad de corrida.
LA CLAVE ES hover-button-bg, Y EL NOMBRE LO DECIDIÓ EL CATÁLOGO
Era el único knob que iba a un primitivo global a pelo. La §4 lo nombraba
hover-rotate-bg por el PRIMER selector de la regla, y miente dos veces: pinta
rotate Y remove, y el contrato de este componente ya llama button-* a ese par
desde que nació. hover-{parte}-{slot} es la forma de las 60 claves hover-* de
base.ts.
NO ES EL VELO DEL SISTEMA — MEDIDO DESDE EL PÍXEL HACIA ARRIBA
Los dos botones flotan SOBRE la foto: su relleno de reposo es translúcido
(color-mix 88 %) y el hover lo vuelve OPACO. Es un cambio de RELLENO, no una
capa encima. Con las transiciones congeladas, elementsFromPoint sobre el centro
del botón: el cambio cae en el <button> —el nodo con forma, radio 6 px, de
srgb .988/.88 a oklch(.9911 0 0)— y NINGÚN ancestro recibe background-image,
porque el arquetipo action no trae velo (archetypes.css sólo vela trigger, item
y option). No se bendice un duplicado, que es lo que paró el hover-* de listbox.
LOS CUATRO LITERALES SE FIRMAN, NO SE ACUÑAN
El 100 % doble del hijo del canvas es identidad (la <Image> ES la caja del
canvas, ya con inset: 0), el line-height: 1 es un botón de un solo glifo, y el
Highlight de forced-colors es la paleta del sistema operativo: un valor de tema
ahí lo sustituiría el UA. Válvula de recipe-contract §3 — salen del ratio como
ausencia ESCRITA.
DEFECTO REAL, ANOTADO, NO ARREGLADO
Ese hover neutro es una invención por componente y §38 / R-4.3 mandan que el
hover neutro sea la capa --state-*. Migrarlo cambia el default (velo translúcido
en vez de relleno opaco) y D-TH.5 lo prohíbe aquí. Y no basta con cambiar la
receta: el arquetipo del par es action, que HOY no recibe velo — o action gana
velo en archetypes.css (mueve píxel en todo el catálogo) o el par cambia de
arquetipo, que es morfo. Escrito en el veredicto §5 y en el README.
CIFRAS Y GUARDS
Censo 71 % → 100 % (20 knobs → 16: público 12 → 13, global 1 → 0, literal 4 → 0,
excepción firmada 0 → 4; sistema 3, fuera del ratio). Contrato 13 → 14 claves.
component-audit PASS · eidos-lint invalid 0 (12 morfo-backed, 5 eidos-only) ·
vitest src/uix/eidos 35/36 (único rojo skin-media-player, preexistente) ·
rtl:check 0 · docs:check 0 · npm run check sin errores en ficheros de este
componente. README con su sección «Talla y tema» y pestaña Tokens en la demo
(14 claves, verificada con clic de Playwright tras networkidle).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
9c3f17fa60 |
uix(form): temable — 71 % → 86 %, y 24 claves suyas NO PINTAN por una cascada
Diez claves nuevas (54 → 64), un literal firmado, veinte adjudicaciones medidas
y un hallazgo que espera firma. Diff de computed 0 sobre 832 valores en 7
estados; capturas 2× antes/después.
LAS DIEZ IBAN A LOS PRIMITIVOS A PELO
El resumen de errores (error-summary-{bg,fg,border}) —es el señalizador de nivel
de página y su superficie, su tinta y su borde SON el tono risk—, el acento de
formulario inválido (invalid-accent, un privado con UNA sola fuente, no un
conmutador), las tres superficies del árbol de AutoFields, las dos del widget y
el subrayado a media tinta de los enlaces del resumen (link-underline-fg, el par
del -offset que ya existía).
⚠ R-5.3 CAZÓ MI NOMBRE EN EL ACTO: lo acuñé como link-underline-color y la tinta
es `fg` (theming §6.7 r7, firmado el 20). Renombrado antes de commitear. El
guard de nombres funciona — es el vocabulario DIMENSIONAL el que no cubre (ver
badge, hoy mismo).
⚠⚠ VEINTICUATRO CLAVES DEL CONTRATO NO PINTAN, Y ES UNA CASCADA
[data-form-submit], [data-form-reset] y los dos botones del array llevan también
data-button porque COMPONEN el Button canónico, y [data-button] casa con la
MISMA especificidad (0,1,0) pero carga DESPUÉS: gana button.css. Medido
propiedad a propiedad sobre el nodo real —altura, padding-inline, tamaño y peso
de letra, interlineado, hueco, radio, grosor de borde, el par de transición y la
opacidad deshabilitada—: NINGUNA se mueve.
Es el defecto que gradient-picker documentó (36 de sus 45 claves) y que
emoji-picker encontró hoy en su trigger. Allí la respuesta fue RETIRAR las
declaraciones muertas; aquí son 24 claves públicas, y eso es una decisión del
autor, no del que ejecuta. Quedan adjudicadas POR PATRÓN (una razón
arquitectónica escrita una vez) y anotadas en §13 con la pregunta de fondo, que
es la misma de §12.9 con el plano overlay: qué manda, el componente compuesto o
la receta que lo compone. Si mandan las recetas, se sube la especificidad y no
se retira nada; si mandan los compuestos, hay ~63 claves públicas que retirar en
tres componentes.
LAS DEMÁS ADJUDICACIONES SON RAMAS QUE LA DEMO NO MONTA
El layout grid (forzado alcanza — y ojo: su grid-template-columns sólo CAMBIA si
el valor altera el número de columnas; con 90px pasa de una columna de 502px a
cuatro de 110,5), el resumen de errores VACÍO (sin <ul> que indentar ni <a> que
subrayar) y toda la rama de ARRAY de AutoFields: el modo `auto` de la demo monta
group y field, nunca array, item ni widget.
Fuera por doctrina: los tres privados del panel son un CONMUTADOR (variante
plain contra panel) y los cuatro --_form-action-* leen el forward de paleta
THM-2.
VERIFICACIÓN
Sonda antes/después 0 diffs (832 valores · 7 estados) · R-5.4 22/64 con las 20 +
el patrón adjudicados, exit 0 · component:audit PASS (tras el renombrado) ·
--names 0 desviadas · censo --only 86 % · eidos-lint 36 morfo-backed / 0 invalid
/ 0 class-hooks · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo
conocido) · el ledger sigue en sus 63 hunks de prettier previos.
Rama con cuatro sesiones en paralelo: índice construido desde HEAD + sólo mis
hunks (base.ts por bloque), verificado con `git diff --cached`. No entra
docs/audit/theming/README.md — es un agregado global que ahora mismo mezcla
trabajo en vuelo de otras sesiones.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
ebe3fe6ed7 |
uix(skip-link): temable — 71 % → 100 %, y el guard aprende a abrir por FOCO
Cero claves nuevas: su 29 % de deuda eran DOS literales que son la técnica, y ahora van firmados. Diff de computed 0 sobre 192 valores en 7 estados más los 52 del estado enfocado —el único que se ve— medidos aparte; capturas 2× idénticas byte a byte; R-5.4 de 0/8 a 8/8 SIN una sola adjudicación. LA §4 PEDÍA `width` Y `height`, Y LAS DOS SON LA TÉCNICA El `1px × 1px` no es un tamaño: es la mitad del sr-only canónico (la otra mitad es el par clip / clip-path). Un tema que lo mueva no cambia una apariencia, rompe el mecanismo — y a 0×0 algunos motores sacan el enlace del árbol de accesibilidad, que es exactamente lo único que este componente no puede permitirse; su propia cabecera ya razona eso mismo para display:none, visibility y el tabindex negativo. Firmados con /* literal: */, la válvula de recipe-contract §3: salen del ratio como ausencia ESCRITA, no como deuda. Misma clase que text-blur y text-scramble. LOS OTROS 5 KNOBS YA ESTABAN BIEN, Y LAS DOS AUSENCIAS SON DOCTRINA La tipografía se HEREDA (no hay font-* declarado; acuñarla fijaría el default, D-TH.5) y el anillo de foco es del SISTEMA (--focus-ring-*, recipe-contract §2). El `background:` en shorthand no mata ninguna capa de estado: su parte lleva archetype 'provider', que no recibe velo. EL INSTRUMENTO LEÍA 0 DE 8 — LA OCTAVA CLASE DE PUNTO CIEGO Toda su superficie existe SÓLO bajo :focus: sr-only mientras no lo tiene, píldora cuando sí. El guard no lo enfocaba nunca, y el blur que hace tras abrir lo habría deshecho igual. Clicarlo tampoco vale: su handler manda el foco a la región de destino, así que la píldora se va por el camino de entrada. Nace `openBy: 'focus'`, y con él `openingIsFragile` — el conjunto de aperturas que el blur y el aparcado del puntero NO deben deshacer, hasta hoy sólo 'hover'. Es aditivo: las cuatro condiciones que decían `openBy !== 'hover'` pasan a consultarlo y ninguna configuración existente cambia de rama. Re-verificado sobre tres del ledger: dialog 37/44 (la cifra exacta de su commit), tooltip 15/23, context-menu 27/28 — cero regresiones. ARTEFACTOS Sonda antes/después → 0 diffs, 0 nodos perdidos (192 valores, 7 estados) · estado ENFOCADO medido aparte con un script propio (la sonda estándar mide reposo, tallas, abierto y hover: nunca foco) → 52 valores, 0 diffs · capturas 2× idénticas byte a byte · R-5.4 8/8, exit 0 · censo --only 71 % → 100 % (knobs 8 → 6: los dos literales pasan a la clase excepción, fuera del ratio) · component:audit PASS · eidos-lint 2 morfo-backed / 0 invalid · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo conocido, skin-media-player) · npm run check COMPLETED sin errores en ficheros tocados · pestaña Tokens añadida a su demo y VERIFICADA en el navegador: 8 filas, 0 errores de consola. LO QUE NO ENTRA Y POR QUÉ docs/audit/theming/README.md es un agregado global y otra sesión tiene `form` en vuelo en el mismo árbol; se regenerará con su commit. Por lo mismo, de theming-sentinel.ts sólo entran mis hunks (verificado con git diff --cached). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
2e708adae8 |
uix(progress): temable — 69 % → 87 %, y el instrumento medía UNA de sesenta caras
Dos claves acuñadas, seis literales FIRMADOS y cuatro knobs adjudicados por escrito. El default no se mueve: diff de computed 0 sobre 60 configuraciones y capturas 2x idénticas byte a byte. Censo: 69 % → 87 % (35 knobs → 30; público 24 → 26, global 3 → 2, literal 6 → 0, excepción firmada 0 → 6). Contrato 41 → 43 claves. Global 67 % (no baja). QUÉ ENTRA (2 claves) row-gap (--space-2) + column-gap (--space-3). Era el ÚNICO knob de apariencia que iba a un primitivo a pelo, y se parte en dos porque el atajo llevaba DOS valores distintos: el hueco de fila separa la línea de texto de la barra, el de columna separa el rótulo del valor. Un gap único habría nombrado un knob para dos. El catálogo tiene las dos palabras (row-gap x10, column-gap x4) y el molde exacto es chart.legend-row-gap / -column-gap. QUÉ SE FIRMA EN VEZ DE ACUÑARSE (6 literales, fuera del ratio) Cuatro 100 % y dos max-content: la geometría de la barra, no una decisión de tema — llena la fila que le dan, o se encoge a su propio grosor / diámetro. Cada uno con su anotación en la declaración (válvula de recipe-contract §3). QUÉ SE RECHAZA DE LA PROPUESTA §4 (dos de sus tres filas) indicator-radius — el --radius-full del anillo. Su GEMELO meter ya dejó el veredicto escrito EN EL CSS: es lo que hace circular a shape='circular', y un token dejaría que un tema des-redondease una forma que el consumidor pidió por su nombre. Identidad, no knob; se copia el comentario del gemelo. Son los dos únicos global que quedan, y el censo no puede sacarlos del ratio: la válvula de la anotación sólo reclasifica la clase literal, nunca un global (mismo techo que meter). width: max-content — la §4 fundía en UN nombre dos nodos distintos (la raíz vertical y la raíz circular) y los nombraba por el primer selector. Es el literal de identidad de arriba. EL TECHO HONESTO ES 87 %, NO 100 % Los dos knobs private que quedan son el CANAL DE VALOR: --_progress-value-pct lo escribe soma en el estilo inline del provider en cada render (0-100 saturado) y la receta lo lee para el ancho del relleno lineal y el alto del vertical. Un público encima mentiría — un tema no puede fijar el progreso de una tarea. Misma clase que el z-index inline de drag-drop. GUARD R-5.4: 40/43, TRES ADJUDICADOS CON SU MEDIDA indicator-bg-loaded — sólo pinta bajo [data-state='loaded'], y la corrida mantiene indeterminate encendido para alcanzar los tokens del barrido; forzado sobre el nodo real: oklch(0.6406 0.1329 157.68) -> rgb(1,2,3). transition-duration / -ease — los congela el guard por diseño; pasada sin congelar: 0.18s -> 11.5s y cubic-bezier(0.4, 0, 0.2, 1) -> steps(7). EL INSTRUMENTO MEDÍA UNA DE SESENTA CARAS La sonda estándar ve 4 nodos — que son TODAS las partes del morfo — pero una sola configuración: lineal, horizontal, loading, md. Medio contrato (el anillo, el eje vertical, el barrido indeterminado, la tinta de completado) queda fuera del diff, y el gate pasa en verde sin haberlo mirado. El guard lo dijo antes: 22 de 41 en la página por defecto. Con sweepAttr data-shape — el interruptor que su gemelo meter YA tenía — sube a 34; con el interruptor indeterminate de la demo, a 37; con el chip vertical, a 38. Cada control se comprobó por separado, antes y después, porque montar más puede medir menos: aquí ninguno tapó nada. Y una trampa NUEVA, medida aquí: una sonda que CACHEA los nodos y luego mide en bucle da 8.352 falsos diffs si el HMR reemplaza el subárbol a mitad de corrida. getComputedStyle sobre un nodo DESACOPLADO devuelve la cadena vacía en TODAS las propiedades, y el diff lee cada vacío como un cambio. Se arregla re-consultando los nodos en cada instantánea, y se detecta haciendo fallar la sonda ante un computed vacío. Pariente de hmr-stale-tab-phantom-findings. ARTEFACTOS Sonda estándar: 4 nodos, 800 valores x 7 estados -> 0 diffs. Sonda de variantes (2 formas x 2 orientaciones x 3 estados x 5 tallas, elemento y ::before): 17.280 valores -> 0 diffs. Capturas 2x antes/después, lineal y circular: idénticas byte a byte. Censo --only progress 87 % · component:audit PASS 1/1 · eidos-lint 0 invalid (13 morfo-backed, 12 eidos-only) · vitest src/uix/eidos 439/440 (el único rojo es el conocido skin-media-player en lint.test.ts) · rtl:check 0 · docs:check 0 · npm run check sin errores atribuibles a progress · prettier limpio en lo tocado (progress.css estaba limpio en HEAD y sigue limpio; los dos ficheros del centinela ya venían sucios de antes y mis líneas no añaden nada). README de eidos con su sección «Talla y tema» y pestaña Tokens en la demo, verificada en el navegador: 43 filas resueltas en vivo, 0 errores de consola. NOTA DE ÁRBOL COMPARTIDO Otra sesión trabaja sobre form en los mismos ficheros (base.ts, generated/base.css, los dos del centinela y el índice de fichas). Lo indexado se construyó a mano desde HEAD + sólo mis hunks, así que el commit no arrastra su trabajo en curso; docs/audit/theming/README.md lleva sólo el delta de progress y conserva la fila de form tal como está en HEAD. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
4c5cfd8ba7 |
uix(color-swatch): temable — 70 % → 100 %, y el color del chip NO es un knob
Cuatro claves nuevas por una retirada (12 → 14 en el contrato), dos adjudicaciones
medidas. Diff de computed 0 sobre 832 valores en 15 estados y DOS rutas; capturas
2× byte a byte idénticas.
LA §4 PEDÍA UN NOMBRE Y LO QUE FALTABA ERA UNA ESCALA
La ficha marcaba `radius` con ⚠ y tres valores en colisión. No es una colisión: es
el eje `rounded` con cuatro pasos, y la clave que ya estaba en el contrato ERA el
paso `sm` bajo un nombre que no lo dice. Contado en base.ts: siete recetas
escriben `radius-{k}`, y una es `badge` — el gemelo que lee ESTE MISMO
`data-rounded` con el mismo conmutador privado. Así que entra la escala entera
(radius-sm/md/lg/full) más `--_color-swatch-radius`, exactamente la forma que su
propio eje `size` usaba dos líneas más arriba. Dejar `radius` al lado de
`radius-md` habría dejado el paso `sm` llamándose `radius`: un nombre que miente.
`fill` SALE DEL CONTRATO: ES UN CANAL DE VALOR, NO UN KNOB DE TEMA
El wrapper escribe `--color-swatch-fill: {color}` INLINE en cada render desde una
prop obligatoria. Medido sobre un chip real con transiciones congeladas: escribir
el token en :root deja el ::before en rgb(124, 58, 237) — la declaración inline
gana siempre. Un público encima sólo podía mentir. La forma correcta ya estaba
escrita en el guard de la capa: recipe-css-contract sanciona `var(--x, default)`
para las vars que el runtime escribe («el respaldo ES el default»), que es justo
lo que la receta tenía. Por eso el respaldo NO se retira: al salir del contrato
deja de ser código muerto y pasa a ser el default.
⚠ EL CENTINELA DABA `fill` POR VIVO — ES UN FALSO POSITIVO SUYO
El guard escribe el token en :root Y en el `style` inline de cada nodo del
componente, que es exactamente donde vive el canal de valor: lo pisa y lee
«mueve». Es la cara opuesta de drag-drop.preview-z, donde la adjudicación se
había medido sobre un nodo fabricado. Regla: un token que el componente escribe
INLINE no se puede juzgar con el guard — se mide a mano escribiendo sólo en :root.
EL INSTRUMENTO ESTABA CIEGO, DOS VECES
1. color-swatch NO TIENE RUTA DE DEMO (404): es el QUINTO canónico en ese estado,
tras picker-shell, mockup, surface y audio-player. La sonda medía 1 nodo. Se
mide donde de verdad se renderiza — gradient-builder (3 chips en el stage) y
color-picker (el del trigger).
2. El eje `rounded` no lo monta NADIE: ningún consumidor del repo pasa la prop, así
que los tres pasos que no son el default no tenían nodo que pintar. El guard los
barre con sweepAttr: data-rounded, como meter hace con su shape.
LAS DOS ADJUDICACIONES SON EL ANILLO OPT-IN
border-width y border-fg: `bordered` nace apagado y ningún consumidor lo enciende,
así que su ::after no existe en ninguna página. Forzado data-bordered sobre un chip
real, los dos llegan (inset 0 0 0 1px → 1234px; oklch(0.931 0 0) → rgb(1, 2, 3)).
ARTEFACTOS
Sonda antes/después en dos rutas (256 valores × 8 estados en color-picker, 576 × 7
en gradient-builder) → 0 diffs, 0 nodos perdidos · el eje `rounded` medido a mano
forzando el atributo: 4 / 4 / 6 / 10 / 9999 px antes y después · capturas 2×
idénticas byte a byte · R-5.4 12/14 con las dos adjudicadas, exit 0 · censo --only
70 % → 100 % (knobs 10 → 7: los tres border-radius por variante pasan a declarar
el privado) · component:audit PASS · eidos-lint 2 morfo-backed / 8 eidos-only / 0
invalid · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo conocido,
skin-media-player) · npm run check COMPLETED sin errores en ficheros tocados.
LO QUE NO ENTRA Y POR QUÉ
- Paso 9 del protocolo (pestaña Tokens en la demo): no hay demo que tocar.
- docs/audit/theming/README.md: es un agregado global y otra sesión tiene form y
progress en vuelo en el mismo árbol; se regenerará con su commit. Por lo mismo,
de base.ts, generated/base.css, theming-sentinel.ts y el ledger sólo entran mis
hunks (verificado con git diff --cached).
Defectos anotados, no arreglados (mueven documentación ajena a este cambio): la
cabecera del CSS, el docblock del .svelte y types.ts siguen diciendo que la talla
sale de `--icon-size-*`, cuando desde la extracción tiene escala propia.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
bb89174a8b |
uix(dialog): temable — 67 % → 89 %, y el borde dice CÓMO se cerró
Siete claves nuevas (37 → 44), un literal firmado, siete adjudicaciones medidas.
Diff de computed 0 sobre 480 valores en 8 estados.
LAS SIETE SON LAS DOS TINTAS SEMÁNTICAS QUE LE FALTABAN
Cuatro para los tonos EVALUATIVOS (risk-border, risk-title-fg, threat-border,
threat-title-fg): dialog no tiene forward de paleta THM-2 y su trato de tono es
deliberadamente estrecho —el borde y la tinta del TÍTULO, nunca la superficie
del cuerpo, para que el texto largo no compita con la señal—, pero iban a
--color-risk-* a pelo.
Tres para el tinte de SALIDA (saved-border, failed-border, dismissed-border): el
morfo escribe data-last-action antes de que data-state pase a closed, así que el
borde superior dice CÓMO se cerró mientras se va. El tercero cubre cancelled /
dismissed / dismissed-outside, que comparten valor: todo cierre sin resultado.
{tono}-border es el nombre del catálogo (48 claves) y failed-border el de
proof-of-human.
EL 11 % QUE QUEDA SON CUATRO ESCOTILLAS, NO DEUDA
Los --_dialog-content-*-override los escribe el wrapper INLINE desde las props
width / minWidth / maxWidth / height / minHeight. Un público encima lo pisaría el
inline y mentiría — la clase de --_background-gradient-image y del triple de
s-text-virtual-list. El nombre del privado ya lo dice: -override.
⚠ NO se acuñó tipografía de superficie, por §12.9: el contenido lleva
data-depth='modal' y un plano declara font-family / line-height a la misma
especificidad y más tarde en la cascada. Las claves de título y descripción que
ya existían son de PARTES internas, no de la superficie del plano.
SIETE ADJUDICACIONES, DOS DE ELLAS CON SEGUNDA PASADA
Estados que la demo no monta: la hoja inferior, el tamaño full, las ocho celdas
no centradas de la rejilla de posición, el data-position del botón de cierre y
los tres tintes de salida (que sólo existen mientras data-state='closed' y
data-last-action COEXISTEN). Y dos costaron una segunda pasada por el VALOR del
atributo: la rejilla usa top-left / top-right (físicos), no top-start; y el botón
de cierre NO lleva data-position en esta demo aunque todas las reglas que leen
close-inset lo exigen.
VERIFICACIÓN
Sonda antes/después 0 diffs (480 valores · 8 estados · 8 nodos con el diálogo
abierto) · R-5.4 37/44 con las siete adjudicadas, exit 0 · component:audit PASS ·
censo --only 89 % · eidos-lint 15 morfo-backed / 0 invalid / 0 class-hooks ·
rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo conocido) · capturas 2×
· el ledger sigue en sus 63 hunks previos.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
4b9354bba2 |
uix(pin-input): temable — 65 % → 100 %, y un respaldo que mentía por 0,15
Dos claves nuevas (20 → 22), cuatro privados renombrados, VEINTIDÓS respaldos retirados y seis adjudicaciones medidas. Diff de computed 0 sobre 1.856 valores en 8 estados. SU 35 % DE DEUDA ERAN TRES DEFECTOS, NINGUNO DE DISEÑO 1. Un prefijo ABREVIADO: los privados se llamaban --_pin-cell-* dentro de un componente llamado pin-input, así que el censo no podía reconocerlos como suyos y los cuatro knobs que los leen contaban como deuda aunque DERIVAN de públicos. Renombrados a --_pin-input-cell-* — el cuarto caso de esta clase tras color-picker, metrics y time-picker. 2. Un respaldo A SÍ MISMO: font-family leía var(--style-label-font-family, var(--style-label-font-family)), que es un no-op con forma de defecto. Ahora es la costura. 3. La tinta del dígito iba a --color-content-primary a pelo → cell-fg. Y LOS VEINTIDÓS RESPALDOS ESCRITOS A MANO Cada var(--pin-input-x, <valor>) duplicaba lo que el contrato ya declara en :root: código muerto, y retirarlos dio 0 diffs, que es la prueba. Pero UNO MENTÍA: disabled-opacity respaldaba 0.55 cuando --opacity-disabled vale 0.4. Es la ley de los `, 1.4` contra un --font-line-height-sm de 1.45 que este mes ya salió en dos componentes, aquí con más deriva. Un respaldo no es una red de seguridad: es una segunda fuente que nadie actualiza. SEIS ADJUDICACIONES, Y DÓNDE VIVE CADA ESTADO La demo muestra un pin vacío, editable y válido, así que los seis tokens de estado no tenían nodo. Forzados sobre los nodos reales alcanzan los seis — con un detalle que costó una pasada: `filled` y `active` son atributos de la CELDA, pero `invalid` y `readonly` se estampan en el CONTENEDOR y cascadean (soma los OR-fusiona con el Field que las envuelve). Forzarlos en la celda no hace nada. VERIFICACIÓN Sonda antes/después 0 diffs (1.856 valores · 8 estados · 8 nodos) · R-5.4 16/22 con las seis adjudicadas, exit 0 · component:audit PASS · censo --only 100 % · eidos-lint 8 morfo-backed / 0 invalid / 0 class-hooks · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo conocido) · capturas 2× antes y después · el ledger sigue en sus 63 hunks previos. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
2ebeb9b16c |
uix(spin-field): ADJUDICADO — 67 % es su techo, y lo dice la cabecera de su propio CSS
CERO claves nuevas, un literal firmado, siete adjudicaciones medidas. Diff de computed 0 sobre 2.400 valores en 8 estados. EL TECHO ESTABA ESCRITO, Y ES DOCTRINA Ocho de sus knobs leen los privados RESUELTOS del Field (--_field-control-height, --_field-control-padding-inline, --_field-control-gap) porque los steppers y el scrubber IGUALAN la fila del input a cualquier talla. La cabecera del CSS lo dice con estas palabras: «never a parallel --spin-field-* chrome that would alias the Field base». Acuñar ahí sería el antipatrón que el fichero prohíbe por su nombre. Préstamo con dueño —se tema en la ficha de field— y el censo lo puntúa como deuda porque no sabe distinguirlo: el mismo artefacto que listbox (68 %) y radio-cards (61 %) ya registraron. Los dos factores del apilado (* 0.62 para el ancho del botón, * 0.34 para el glifo) tampoco se acuñan: viven dentro de un calc() sobre ese mismo privado de Field, así que un token propio no cambiaría quién manda. SIETE ADJUDICACIONES, Y UNA SORPRESA Los tres active-control-* no responden a :active NI forzando el pseudo por CDP: su estado es el [data-scrubbing] que soma pone en el SCRUBBER mientras se arrastra. Forzado el atributo sobre el nodo real, los tres alcanzan. Más focus-control-bg (pseudo forzado por CDP), control-disabled-opacity (0.48 → 0.137) y el par de transición sin congelar (0,12s → 11,5s). ES UNA CAPA, NO UN COMPONENTE No tiene wrapper ni ruta propia, así que el guard lo mide dentro de number-field — declarado ahora en `urls`, para que nadie tenga que saberlo. ⚠ Y una corrida de sonda dio 5 «nodos ausentes» que no eran nada: una recarga que no montó la talla xl. Repetida, 0 diffs y 0 ausentes contra el mismo ANTES. Un «missing node» tampoco se cree a la primera. VERIFICACIÓN Sonda antes/después 0 diffs · R-5.4 13/20 con las siete adjudicadas, exit 0 · component:audit sin hallazgos · censo 67 % con las ocho filas de préstamo explicadas · docs:check 0 · el ledger sigue en sus 63 hunks previos. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
4da40c63a2 |
style(theming): el bloque meter del ledger, como prettier lo quiere
El commit anterior dejó el fichero en 64 hunks (base 63): mi entrada añadía uno. Es justo lo que la revisión de hoy señalaba como E4, así que se corrige en el acto — reformateando SÓLO mi bloque, sin tocar los 63 ajenos que el fichero arrastra desde antes. Guard re-verificado: meter 24/28, exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
d6871eb103 |
uix(meter): ADJUDICADO — 64 % → 75 %, su techo, y el guard medía la MITAD
CERO claves nuevas: su contrato de 28 ya cubría todo lo que es suyo. Dos literales firmados, cuatro adjudicaciones medidas y tres filas que se quedan fuera A PROPÓSITO. Diff de computed 0 (416 valores, 7 estados), capturas antes/después idénticas. EL GUARD MEDÍA LA MITAD DEL COMPONENTE La demo arranca en shape='linear', así que los CATORCE tokens del anillo —doce pasos de tamaño y grosor, más su pista y su centro— no tenían nodo que pintar: 12 de 28. Con el barrido de data-shape sube a 24/28. LOS DOS border-radius DEL CÍRCULO NO SE ACUÑAN Son lo que hace circular a shape="circular": el exterior del anillo y el agujero del centro. Un --meter-circular-radius dejaría que un tema descirculara una forma que el consumidor pidió POR NOMBRE — identidad, no knob, la misma lectura que los dos 50 % de cropper. Nota de coherencia con badge, donde SÍ acuñé dot-radius para un --radius-full: allí el punto es un adorno cuya forma es estética (y knob.indicator-radius vale --radius-sm, que lo prueba); aquí el redondeo ES el valor del atributo. La prueba sigue siendo qué DECIDE el token, no qué valor tiene. --_meter-value-pct es CANAL DE VALOR: el wrapper lo escribe inline con el porcentaje, y de él salen la anchura de la barra y la parada del conic-gradient. Y los dos 100 % son identidad (la barra lineal ES el ancho de su contenedor; el indicador llena el alto de la pista), firmados en su declaración. Adjudicado con medida: las dos tintas de zona fuera de `optimum` (forzadas alcanzan) y el par de transición (sin congelar: 0,18s → 11,5s). VERIFICACIÓN Sonda antes/después 0 diffs · R-5.4 24/28, exit 0 · component:audit PASS · censo 75 % con las tres filas explicadas · eidos-lint 4 morfo-backed / 0 invalid / 0 class-hooks · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo conocido) · capturas 2× miradas · el ledger sigue en sus 63 hunks previos. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
863c6993c8 |
uix(emoji-picker): temable — 61 % → 100 %, y el cromo del trigger NO era suyo
Siete claves nuevas, TRES RETIRADAS por muertas, tres literales firmados y cinco
adjudicaciones medidas. Contrato 17 → 21. Diff de computed 0 sobre 6.080 valores
en 8 estados (176 nodos con el panel abierto), capturas 2× idénticas.
LOS NOMBRES LOS DIO EL CATÁLOGO
`open-trigger-fg` (accordion lo nombra igual), grid-padding-inline +
grid-padding-block-end (el eje lógico completo, como card-group / combobox /
command) y las tres del marcador de tono, la familia
timeline.marker-{size,radius,bg}. Se llama tone-marker-* y no marker-* porque el
pie lleva además un selector de TONO: dentro del propio componente, `marker` a
secas sería ambiguo.
TRES CLAVES RETIRADAS — EL CROMO DE REPOSO DEL TRIGGER NO ES SUYO
El trigger lleva también data-popover-trigger, y
[data-popover-trigger]:not([data-archetype='field-trigger']) es (0,2,0) contra
el (0,1,0) de esta receta: el radio, la tinta y el tamaño de letra los pinta
popover.css. Medido: mover --emoji-picker-trigger-{fg,radius,font-size} no
cambiaba NADA. Retiradas con sus declaraciones, 0 diffs — la prueba de que
estaban muertas. Es el defecto que gradient-picker documentó (36 de sus 45
tokens) y la misma respuesta. Sobreviven dos por razones distintas:
trigger-size, porque popover dimensiona con `height` y no con el par lógico, y
open-trigger-fg, porque su selector añade [data-state='open'] y gana por orden.
trigger-fg no llegó a existir: se acuñó y se midió muerta en el mismo pase.
CINCO ADJUDICACIONES, TODAS SOBRE NODOS REALES
Las tres del marcador de tono (la demo monta CERO celdas data-tone-capable;
forzado el atributo sobre una celda real, el ::after alcanza: 4px → 37px,
9999px → 37px, y el fondo), preview-name-fg (los hijos de la vista previa son
<span> desnudos, sin atributo del componente, fuera del conjunto medido) y
open-trigger-fg.
⚠ open-trigger-fg OSCILA ENTRE CORRIDAS: 17/21, 16/21, 16/21 con el mismo
código. Medido vivo CUATRO veces —la última replicando paso a paso el staticPass
del propio guard, que movió a la primera talla—, así que el token no miente: lo
que falla es el instrumento. La causa: el panel se cierra en algún punto de la
pasada y, durante la animación de SALIDA, el content sigue en el DOM mientras el
trigger ya perdió data-state='open', que es lo que la regla selecciona;
reopen() mira el CONTENT, cree que está abierto y no reabre. Probé un openMarker
sobre el trigger y NO basta (el clic de reapertura cae en esa misma ventana), así
que lo retiré en vez de dejar un override que no arregla. El arreglo real es que
reopen() espere a la CONDICIÓN en vez de dormir un número fijo — §13. Su entrada
de ledger saldrá STALE en las corridas donde alcanza, y está escrito en la razón
para que nadie la borre por eso.
Y EL INSTRUMENTO DE CAPTURA ESTABA ROTO DESDE SIEMPRE
__shot.ts tenía el puerto 5173 CABLEADO, así que cualquier sesión en otro puerto
moría con ERR_EMPTY_RESPONSE. Es probablemente por lo que los pasos 6 y 13 del
protocolo se saltaron en 33 componentes sin que nadie lo notara. Ahora toma la
URL como argumento —como la sonda y el guard— y un --open opcional para los
componentes cuya superficie sólo existe abierta. Estrenado aquí: capturas antes
y después, miradas y idénticas.
VERIFICACIÓN
Sonda antes/después 0 diffs (6.080 valores · 8 estados) · R-5.4 17/21 con las
cinco adjudicadas, exit 0 · component:audit PASS · censo --only 100 % ·
eidos-lint 17 morfo-backed / 0 invalid / 0 class-hooks · rtl:check 0 ·
docs:check 0 · suite eidos 439/440 (el rojo es skin-media-player, el conocido) ·
el ledger sigue en sus 63 hunks de prettier preexistentes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
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 |
|
|
2f243e1c08 |
docs(theming): la revisión del 23 entra al repo, y el protocolo aprende de sus dos huecos
Añade `REVIEW-theming-2026-08-23.md` —el análisis de los 26 commits posteriores a la revisión del 22 (33 componentes) que no habían pasado ninguno— con lo comprobado, lo refutado y el plan, ya marcado como ejecutado salvo P5. PLAN §7: las capturas 2× (pasos 6 y 13) no se hicieron en NINGUNO de los 33 componentes de los dos bloques. No se recuperan hacia atrás —para ésos el artefacto es el diff en vacío más el centinela—, así que se exigen DESDE el siguiente, y el paso 12 (píxel hacia arriba) queda obligatorio en cuanto el commit toque una regla :hover, que es justo donde el 19 costó cuatro commits. next-features §13 recoge dos huecos más que salieron midiendo: - el escenario de la demo de `background` cambia de ancho entre corridas (870 ↔ 1.350 px con el mismo código), y produce diffs de inlineSize que parecen regresión: una corrida con diffs SÓLO de inlineSize se repite antes de creerla; - `audio-player` no tiene README propio — el cuarto canónico sin ruta de demo es además el único sin documento, así que su «Talla y tema» queda pendiente de que exista dónde ponerla. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
e522e04e65 |
docs(theming): los 21 de la mañana recuperan su README y su pestaña Tokens
La revisión de hoy (`REVIEW-theming-2026-08-23.md`, punto P4) destapó que NINGUNO de los commits de tokenización de la mañana del 23 hizo los pasos 8 y 9 del protocolo: `git show --stat` de los diecisiete sólo tocaba CSS, base.ts, el ledger y las fichas. Veintidós componentes tokenizados sin la tabla de tokens en su README y veintiuno sin la pestaña que la enseña viva. QUÉ ENTRA - **README «Talla y tema»** en 22 (los 21 con demo + `surface`, que no tiene ruta). La tabla NO está escrita a mano: se DERIVA de `lib/recipes/base.ts` y de `theming-sentinel-exceptions.ts`, así que lo que el lector ve es lo que el contrato dice. Hasta 30 claves va la tabla completa clave → valor por defecto; por encima, agrupada por parte (con la paleta en su propio grupo, que si no se come la tabla: button tiene 70 claves de tono de 106). Debajo, lo que el guard da por silencioso con su razón medida, y la excepción POR PATRÓN cuando la razón es la cascada de paleta. - **Pestaña `Tokens`** en los 21 con demo, con el conteo real de claves. VERIFICADO EN EL NAVEGADOR, LOS 21 Cada pestaña abre y lista exactamente sus claves: menubar 35 · field 68 · onion-menu 19 · button 106 · callout 34 · empty-state 26 · dropdown-menu 28 · context-menu 28 · checkbox 47 · image 23 · anchor-nav 12 · banner 53 · date-range-field 7 · time-range-field 7 · tooltip 23 · section 4 · sticky 1 · button-group 1 · qr-code 10 · toggle-group 1 · split-button 1. ⚠ Y el verificador mintió DOS veces antes de acertar: primero buscaba el rótulo de la cabecera del panel en `innerText` (no lo encontraba aunque la tabla estaba ahí), y después clicaba con `element.click()` tras `waitUntil: 'load'` — la página aún NO ha hidratado, así que el `onclick` de Svelte no está enganchado y el clic no hace nada. Con `networkidle` + el clic de Playwright (que espera a que el nodo sea accionable), los 21 en verde. Es la ley de siempre: el instrumento miente primero. `audio-player` queda fuera: no tiene README propio — hueco aparte, anotado. Verificación: `npm run check` sin errores nuevos en las 21 demos (los 72 globales son ajenos y preexistentes) · `docs:check` 0 · cada README conserva su estructura de encabezados y **ninguno gana un hunk de prettier** (mi sección se formateó dentro de su propio recorte, sin tocar lo ajeno). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
bfe7727b0c |
fix(badge): la clave se llamaba como la PROPIEDAD — min-block-size-{k} → min-height-{k}
Corrección de nombre, sin píxel: la clave por talla que entró esta tarde salió
como `min-block-size-{k}` —el nombre de la propiedad CSS— cuando la ranura del
vocabulario para ella es `height`.
LO DICE EL CANON Y LO DICE EL PROPIO CENSO
recipe-contract §1: «Control height per size → control-height-{size} (o
{part}-height-{size} cuando la parte no es el control) · antipatrón: inventar un
tercer nombre por componente». Y `theming-census.ts` mapea, en su tabla de
propiedades, `min-block-size → height`: la herramienta que mide ya sabía cuál
era la ranura.
MEDIDO EN EL CATÁLOGO, NO SUPUESTO
24 componentes dimensionan por `…-height-{k}` (accordion, field, table,
tree-grid, sidebar, navigation-menu, select, tabs…) y `min-block-size-{k}`
existía SÓLO en badge. El gemelo con la forma exacta —raíz, por talla, sobre
`--size-{k}-control-height`— es `proof-of-human.min-height-{k}`, que además
resuelve igual (clave `min-height` con `declarations` por talla).
R-5.3 NO LO CAZA, Y ESO ES LO INTERESANTE
El guard de nombres cubre la ranura de tinta (`fg` vs `color`) y la posición del
modificador, pero no el vocabulario DIMENSIONAL: una clave con el nombre de la
propiedad pasa. Anotado en next-features §13 con el arreglo propuesto (extender
R-5.3 con la tabla propiedad → ranura que el censo ya tiene).
Verificación: sonda antes/después **0 diffs** (992 valores · 7 estados · 5
nodos) · R-5.4 29/71 idéntico, exit 0 · censo --only 75 % sin cambio ·
`--names` 0 desviadas · docs:check 0 · suite eidos 439/440 (el rojo conocido) ·
`component:audit` NEEDS-WORK preexistente (R-1.5, sin foco).
Sale de la revisión de hoy (`REVIEW-theming-2026-08-23.md`, punto P1).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
233ef989b3 |
fix(theming): float-panel tenía DOCE rojos sin medir — el guard R-5.4 vuelve a verde
El barrido del centinela sobre TODO el ledger (59 componentes) destapó que `float-panel` fallaba: 17/40 con doce tokens públicos sin adjudicar. No es regresión —la bisección de las NUEVE versiones del guard desde `cd6a9f4e3` da siempre 17/40 con los mismos doce— sino un rojo que su propio commit del 22 dejó escrito («lo rojo que queda son 12 tokens anteriores») y que nadie midió. Y la frase del handoff «desde el 23 no queda ningún rojo del bloque viejo» era FALSA: se adjudicaron drawer, metrics y color-picker; éste no. Corregida, con la lección: un componente cuyo commit dice «lo que queda» NO está cerrado, y la única forma de saberlo es correr el guard sobre el ledger ENTERO. LOS DOCE, MEDIDOS UNO A UNO SEIS son el plano de profundidad, y la predicción del 22 era exacta: el contenido lleva data-depth=overlay y [data-depth=overlay] declara background, border, box-shadow, font-family y line-height a la MISMA especificidad (0,1,0) y más tarde en la cascada. Verificado moviendo los tokens del propio plano sobre el nodo (superficie, borde, fuente y leading lo repintan) y enumerando las reglas que casan. border-width cae con border (el plano escribe el shorthand). Misma adjudicación que tooltip, misma decisión abierta (§12.9). ⚠ Y una corrección a mi propio diagnóstico: primero atribuí la sombra a [data-topmost] porque el panel de la demo arranca frontal. Falso — quitando el atributo sigue muerta: es el plano también. Lo que sí depende de topmost es su compañero shadow-topmost, que SÍ alcanza (→ rgb(4,5,6)) porque su regla es (0,2,0) y le gana al plano: la prueba de que la causa es la cascada y no un token roto. TRES son estados o partes que la demo no monta: active-shadow (forzado data-dragging → alcanza), resize-size (lo consumen las asas de ESQUINA se/ne/sw/nw y la demo monta sólo las de borde, e y s) y button-size (lo consumen [data-float-panel-action] y [data-float-panel-stage-trigger], ninguno montado — el único control es el cierre, un <Button> compuesto que se dimensiona solo: el mismo grupo que las tres action-* ya adjudicadas). UNO es el PUENTE DE PALETA: el contenido lleva data-color, así que --_float-panel-accent viene del forward THM-2 (--_float-panel-palette-border → rgb(7,8,9)); sin data-color la clave alcanza (→ rgb(1,2,3)). DOS son la ley del congelado: transition-duration / -ease no pueden moverse bajo un guard que congela `transition`. Pasada aparte: 0.12s → 11.5s y cubic-bezier(0.4,0,0.2,1) → steps(7). DE PASO, DOS ARREGLOS DE LA MISMA REVISIÓN - `background.parallax-travel` estaba MAL CLASIFICADO como estructural («el escenario no tiene scroll timeline»): lo tiene (animation-timeline: view()). Forzando data-parallax + speed 1, el translate sigue al token (14,6 → 60,5 px al mismo scrollY). La causa real es que el guard NO fotografía translate ni transform — registrado en §13 junto al hueco de mask-image, para entrar en PROPS en un pase con re-verificación del ledger entero. - `cropper`: el hueco de composición que el README daba por «anotado» y no lo estaba, ahora es fila de §Gaps con su disposición. Y las tablas de tokens de `cropper` y `waveform` pasan a la sección «Talla y tema», el molde del resto. La nueva constante PLANE_SUPERSEDED se iza sobre el objeto (un `const` usado antes de su declaración reventaba el guard, y el fallo se veía sólo mirando el exit REAL: tras la tubería, `$?` es el del grep). Verificación: R-5.4 float-panel 17/40 con 23 adjudicaciones, cero STALE, exit 0 · docs:check 0 · el ledger vuelve a sus 63 hunks de prettier preexistentes (mis entradas se reformatearon a mano, sin tocar las ajenas). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
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 |
|
|
f03ee5af46 |
uix(cropper): temable — 60 % → 94 %, y la suite corrigió el valor al entrar en el contrato
Dos claves nuevas (15 → 17), siete literales firmados. Diff de computed 0 sobre 3.744 valores en 7 estados; R-5.4 17/17, sin una sola adjudicación. LAS DOS CLAVES SON EL CROMO DEL BOTÓN DE ZOOM Su radio y su font-size. El segundo es la COSTURA: el valor es la escala de tipo del sistema, el knob es del componente, así que un tema puede dimensionar los glifos ± sin mover el texto md de toda la app. Y LA SUITE VOLVIÓ A CORREGIRLO, COMO EN BADGE El verbatim del CSS era el primitivo --font-size-md y recipe-css-contract exige la coordenada del BUNDLE (--size-md-font-size, theming §5). Dos veces en una tarde: SUBIR UNA DECLARACIÓN AL CONTRATO LA SOMETE A REGLAS QUE EN EL CSS NO SE LE APLICABAN. Corregido; el diff sigue en 0. SIETE LITERALES, Y LOS SIETE SON IDENTIDAD Cuatro 100% (el cropper ES el ancho de su contenedor, el viewport el del cropper, la imagen LLENA el viewport), dos 50% (el 50 % ES lo que hace redonda la selección; un tirador ES un círculo) y el line-height: 1 de un botón que sólo contiene un glifo. La clase 4 de F2-B al completo, en un componente. EL 6 % QUE QUEDA ES UNA FILA DE OTRA FIRMA El :hover del botón de zoom pinta var(--color-surface-default) a mano. No se acuña —hover-zoom-btn-bg bendeciría un hover por componente, que §38 y R-4.3 deprecan— y no se puede migrar aquí: [data-cropper-zoom-btn] es un hook EIDOS-ONLY, no una parte del morfo, así que no lleva data-archetype y la capa de estado no le alcanza. Darle arquetipo es morfo. Cola de la firma 3. Y un hueco de composición que sale de paso: ese botón debería COMPONER IconButton en vez de ser un <button> con cromo propio (radio, borde, fondo, tinta y foco a mano). No se toca aquí —mueve píxel y es composición— pero explica por qué su hover quedó huérfano de la capa de estado. VERIFICACIÓN Sonda antes/después 0 diffs (3.744 valores · 7 estados · 17 nodos) · R-5.4 17/17 · component:audit PASS · censo 94 % con la única fila restante explicada · eidos-lint 18 morfo-backed / 8 eidos-only / 0 invalid / 0 class-hooks · rtl:check 0 · docs:check 0 · suite eidos 439/440 (el rojo es skin-media-player, el conocido). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |