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 }
651 Commits (466b24f34f7be9e0bf40d77d1997c416ae233e7f)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
466b24f34f |
feat(theming)!: el sobre de trigger de popover es un SUELO - tercera ley 55
El "baseline button envelope" que popover.css pinta a sus triggers vivia a (0,2,0) con hover a (0,5,0): le ganaba a las recetas de sus HUESPEDES (el chip de anadir reaccion de chat-message perdia 9/9 propiedades disputadas y salia cuadrado gris entre pildoras - SU receta lo pintaba en el mismo selector-lista y PERDIA), mataba la capa de estado del sistema en hover (chronos plain = caja gris) y dejaba el trigger de calendar en manos del orden de carga (14/16/14/14px medidos - la moneda al aire). El sobre baja a :where() - base y hover, con el :not(field-trigger) DENTRO (where anula especificidad, no matching). El suelo pinta lo que el huesped CALLA; la receta gana donde habla; la capa de estado compone otra vez. Tercera aplicacion de la ley firmada (12.9 planos - B'/53 paleta - y archetypes.css:9-21 ya lo decia para SU capa). Cambio de codigo: 2 lineas. Medido (gate de dos niveles, 76 instancias, 16 rutas, 4 estados): - No afectados: 3 field-trigger diff VACIO; los 66 desnudos ganan EXACTAMENTE los dos valores del SISTEMA que el sobre tapaba (velo de hover de archetypes + su transition). 167 nodos de referencia: 0. - Los 7 movers, valor a valor por CDP hacia lo que SU receta declara: el chip vuelve pildora (36->26px, r9999) - chronos recupera su plain y su hover - calendar mes/anio pasa a su ghost compuesto Y SE VUELVE DETERMINISTA (8 cargas en dos ordenes, mismo pixel; antes 2 de 6 caian del otro lado) - emoji/palabras/ntp a sus recetas (ntp revive 4 claves: 44->48/62). - Capturas antes/despues x8 revisadas por el supervisor (chip, chronos, calendar, emoji, gradient, popover generico, palabras, ntp). - Guarda 55 en active-eidos-config.test.ts validada por SEIS mutaciones (la sexta se anadio porque la primera pasada dejo pasar un verde falso; y el arnes mintio con -t sobre 0 tests - detector de cero-tests anadido). - vitest 35/36 (rojo ajeno skin-media-player) - check 0 atribuibles - docs-check 0/0 - eidos-lint popover/chat-message 0 invalid. Registrado en 13 y fichas: los parches-pin de chronos/calendar pasan a REVISABLES (ahora redundantes o semi) - el suelo comparte peldano (0,0,0) con archetypes.css (medido 16 cargas: archetypes cae despues y el resultado es identico, pero es un empate real sin verificar en produccion) - la dependencia sin registrar de palabras queda anotada junto a su regla (no tiene README de eidos). changelog 55 escrito (la guarda citaba una seccion que debia existir). CON ESTA, LA LISTA "Lo que espera TU FIRMA" DEL CONTINUE QUEDA VACIA. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
1f8ce293bb |
fix(theming)!: avatar - el contrato dice la verdad: 4 claves, cero desviadas
Las ultimas CUATRO claves fuera de gramatica de las 4.558 publicas del catalogo, resueltas cada una por lo que ES (no eran cuatro iguales): - `badge-color-custom-contrast` -> `badge-fg-custom-contrast`: la unica TINTA real y alcanzable. Nombre derivado DE la gramatica D-TH.6 (la ranura se sustituye EN SU SITIO; `custom` no es interactivo ni rol, va detras) con el precedente firmado scrim-fg-over-dark - y es la salida literal del clasificador que consume R-5.3. Renombre a mano (el codemod ABORTA sobre la IIFE de avatar - deuda registrada en 13): value-preserving, verificado con sonda dirigida (la clave vieja movia antes y no despues; la nueva al reves). - `ring-color-custom` y `badge-color-custom` RETIRADAS del contrato publico: canales de valor INALCANZABLES (puerta data-*-custom y escritura inline nacen de la misma expresion - mentiras bajo R-5.4). Mecanismo: canal privado de envoltorio `--_avatar-*-color-custom` + respaldo currentColor (el patron de las 5 privadas-de-envoltorio del parque, 5/5 sin declaracion en receta), NO borrado (el CSS las lee) NI privada plana (cero precedente). Ley 8.bis re-aplicada: cero lectores fuera de avatar, re-barrido. - `group-carve-color` EXENTA en NAME_EXEMPT con razon medida: alimenta box-shadow (geometria del carve, no tinta; alcanza en 59 instancias) - `fg` seria gramatica correcta con semantica peor. Medido: sonda 7.4 0/576 - pixel visible IDENTICO (anillo ambar, insignia violeta, tinta white) e instancia imposible identica (currentColor preserva el default retirado) - Tokens 88 -> 86 EN VIVO con el nombre nuevo (captura revisada por el supervisor) - censo --names: DESVIADAS 0 EN 0 COMPONENTES (4.556 claves) - centinela exit 0 - lint 0 - docs-check 0/0 - vitest 442+1 ajeno - check 0 atribuibles. Hallazgo de instrumento NUEVO, adjudicado y registrado en 13: el chooser del centinela elige el valor por NOMBRE y no conoce `fg` MEDIAL (su prueba de tinta es `fg$`): las 5 claves que la propia D-TH.6 fabrica (badge-fg-custom- contrast, bubble-fg-in/-out, scrim-fg-over-dark/-light) reciben 1234px, invalido para color - y el veredicto depende de si el respaldo coincide por azar (bubble-fg-* leen vivas POR ACCIDENTE). Arreglarlo obliga a re-verificar el ledger - firma de instrumento aparte. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
2ce43db563 |
fix(morfo)!: tags-input - aria-selected sigue al resalte, no a un literal
`v.literal('true')` era el UNICO aria-selected incondicional de los 18 morfos
que declaran el atributo: el AX tree entregaba DOS option selected:true dentro
de un listbox multiselectable:false (mentira de plataforma), archetypes.css
(0,4,0) clavaba el velo de estado EN REPOSO (la etiqueta vivia en su propio
hover: reposo y hover byte-identicos) y `--tags-input-item-fg` no habia
pintado nunca.
Ahora `v.stateRef('active')` - el estado que soma YA deriva de
highlightedIndex, registrado como fuente por parte (states: { active }).
Precedente en casa: tag-group/listbox/tabs. `severity: 'optional'` NO hace
falta (inerte: solo la leen los checks de data-*, verificado en compile.ts).
Medido (ejecutor E-tags, heredando y VERIFICANDO la edicion de un ejecutor
interrumpido - dos claims sin medir corregidos, uno de atribucion: el tono de
la activa lo enmascara [data-highlighted] (0,3,0), no este atributo):
- Sonda: 14 diffs / 2.504 valores, UNA propiedad (backgroundImage), las dos
etiquetas x 7 pases sin puntero - el velo saliendo del reposo. Hover: 0
diffs = la afordancia recuperada (reposo 224,58 / hover 212,10; antes
212,10 = 212,10). Capturas antes/despues revisadas por el supervisor.
- AX: reposo false,false - ArrowLeft false,TRUE - Escape false,false.
Exactamente una navegando, cero en reposo.
- Centinela 63/91 -> 71/91 (revive item-fg; medida directa oklch(0.2435) ->
rgb(1,2,3)), exit 0, 0 sin adjudicar, 0 STALE, ceguera-a-patrones validada
a mano (17 cubiertas, todas muertas).
- Gates: morfo 222/222 - soma tags-input 3/3 - eidos 442+1 ajeno - check 0
atribuibles - docs-check 0/0 - eidos-lint 0 invalid.
Quedan ABIERTOS y registrados en next-features 13 (sin decidir aqui): el
morfo declara apg:grid pero implementa listbox/option - Provider y Control
llevan ambos role=listbox anidados - la tinta de tono de la activa la
enmascara [data-highlighted] (12.5) - migracion a grid (B-b) como
continuacion. Y una observacion de soma al paso: ArrowLeft desde el input no
saca el foco (:381).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
df3a4d054b |
fix(theming): form cede el cromo de submit/reset al Button que componen
El bloque de accion de form.css vestia CUATRO nodos con las mismas 23 claves:
submit/reset (que COMPONEN el Button canonico - ahi muertas Y contradictorias:
declaraban un boton solido de tinta blanca mientras se pintaba surface verde,
discrepando en silencio desde siempre) y array-add/array-remove, <button>
PELADOS donde las 23 son su UNICO cromo y estan 23/23 VIVAS (medido montandolos
a la fuerza: la demo nunca los monta).
Ejecuta la doctrina YA FIRMADA que nombra a Form.Submit por su nombre
(component-guide.md:126-146, consumer pattern rule 5) - la opcion de escalar a
(0,2,0) queda descartada por escrito: si se quiere el submit solido, el camino
es <Form.Submit variant="solid">, no ganar la cascada.
- El bloque de accion apunta ya SOLO a los dos botones del array; mueren 4
reglas y se estrechan 5 grupos. Los 4 privados THM-2 de submit/reset fuera
(nadie los consumia): el diff del generado son EXACTAMENTE 14 lineas (su
suelo y su forward). Las 23 publicas SE QUEDAN.
- Ceder submit/reset: 0 px sobre 79.296 valores (16 escenarios, V1) + sonda
0/834 con CONTROL POSITIVO (el CSSOM vivo no contiene una sola regla de
submit/reset ni un --_form-palette-*). El cromo del array, intacto contra
los valores pre-firma; su eje de talla sigue llegando por herencia.
- Centinela 22/64 exit 0, identico conjunto: solo cambia la RAZON de las 23
("rama array que la demo no monta") - la anterior era falsa a medias (los
botones del array NO llevan data-button) y el "24" era un error triplicado
(ficha, README, ledger): son 23.
- CONTINUE: la firma del compuesto EJECUTADA; gradient-picker (36) y
emoji-picker (3) des-RANCIADOS - ejecutados el 2026-08-20/23, hoy 0
adjudicaciones por compuesto (verificado; ademas su mecanismo era OTRO:
especificidad de popover.css, no orden de emision).
- next-features 13: DOS expedientes nuevos destapados y NO ejecutados aqui:
los botones del array deben COMPONER el Button (soma+morfo, clase A-112,
y son perceptualmente mudos) - y el eje size de form NO llega a sus
acciones (<Form size="xs"> renderiza acciones md; solo sobrevive el
row-gap).
Verificacion: V1 (verificador independiente, informe recuperado de disco tras
interrupcion) + ejecutor con gates completos (vitest 442+1 ajeno - check 0
atribuibles - docs-check 0/0 - eidos-lint 0 invalid).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
2daa683fa4 |
fix(theming)!: file-upload pinta lo SUYO - muere el barrido de descendientes
`[data-file-upload] [data-disabled]` (0,2,0) vestia todo nodo disabled bajo el provider, HUESPEDES incluidos, y ganaba el empate por orden de import - el accidente que B' condena. Medido en la composicion documentada del composer: el textarea huesped recibia la atenuacion TRES veces (0.4^3 = 0.064, el placeholder casi ilegible) con el file-upload NI SIQUIERA disabled, y `--chat-composer-disabled-opacity` no alcanzaba nunca. - La mitad descendiente se sustituye por los CINCO selectores por parte (label, dropzone, trigger, item-remove, clear-trigger; el provider ya estaba). El morfo declara `data-disabled` exactamente en esas partes y soma lo estampa siempre junto al atributo de parte: el barrido era 100 % redundante hacia dentro - solo anadia alcance hacia fuera. - Unicidad re-censada HOY: 171 recetas, unica ocurrencia con `data-disabled`. - Medido: file-upload CERO ESTRICTO (4.608 valores x 8 estados + pase disabled propio 0/35); composer recupera EXACTAMENTE 6 valores (opacity y alpha de textarea/input, cursor x2) y nada mas - la excepcion a D-TH.5 firmada, con capturas antes/despues. - Centinela: composer 29 -> 30/33 (revive `disabled-opacity`; su excepcion EXACTA salio STALE por si sola - el reverso de la ceguera a patrones); file-upload 61/98, exit 0 ambos. - README del composer corregido: su adjudicacion "no se ve hasta que un tema mueva" era FALSA para el textarea (triple atenuacion en el tema default). - Registro: PLAN 8 entrada fechada - CONTINUE item 3 EJECUTADA - notas en las fichas de ambos. Aviso de instrumento (en el registro): la sonda sancionada es CIEGA a esta firma (sin paso disabled; su filtro del composer no ve [data-textarea]) - su cero vale como regresion, no como testigo; el gate se cumplio con instrumento dedicado, exacto y sin extras. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
ffa45726fd |
feat(color)!: una palabra, un significado - primary/secondary son SIEMPRE jerarquia
La homonimia muere: `primary`/`secondary` significan JERARQUIA DE MARCA en el
catalogo ENTERO, tambien dentro de los seis primitivos de tinta (text, heading,
display, code, label, s-text). El paso de tinta del 82 % se llama `subtle` -
PROP y TOKEN, sin excepcion: el nombre es el contrato en el artefacto (la misma
ley que la FIRMA B' y la 12.9; se rechazo por escrito la via "solo el prop con
tabla de traduccion" - las excepciones legitimas son las FIRMADAS con razon,
no las inventadas al decidir para abaratar).
- Los seis CONTENT_INK, IDENTICOS: {subtle, muted, disabled, on-solid}; el
nivel-1 es el DEFAULT sin prop. `label` gana `on-solid` (cierra la
divergencia de familia registrada en
|
2 months ago |
|
|
e4fa616e5d |
docs(theming): registro post-B' - cinco hechos verificados entran al expediente
Pase de registro de lo que la firma B' descubrio y no arreglo (pre-existente, simetrico antes/despues). Seis claims de agentes -> verificacion adversarial independiente -> DOS murieron (label-inline era diseno firmado de la seccion 43; drag-drop refutado: su forward vive y alcanza) y UNO se fusiono (el color de `code` lo gana `[data-uix-docs] code` (0,1,1) - ES la firma pendiente 5.2 del harness, que se ENSANCHA de radio/padding a la tinta; medido por CDP, solo dos reglas declaran color). Entran en next-features 13 / CONTINUE: - El detector STALE del centinela es CIEGO a los patrones (filtra `k in ledger`, solo exactas): 207 claves revividas por B' y ni un aviso. Arreglo minimo anotado; clase re-verificar-ledger. - El guard no mide tono+estado a la vez (raiz de TONE_UNREACHED): tono solo en el paso estatico, hover sin tono, solo `toggle` declara eje de estado, switch/button sin entrada en COMPONENT_OVERRIDES (48). - Tres huecos de la sonda: el `open` de editable muere por CLIC sobre inputs ocultos (no por el localizador), button sin analogo de barrido de variantes, y NUEVE de las 33 escalas atadas a rol (purple slate indigo gray teal green orange red plum) - `plum` ES `loss`; 24 libres como reserva de sondeo. - Divergencia de familia: `label` es el unico primitivo de tinta sin el paso `on-solid` (tipo y runtime, auto-consistente); decision pendiente. Citas contrastadas contra el arbol (cuatro corregidas del verificador, incluida la deriva de +10 lineas del diff ajeno del sentinel). docs-check 0/0 sobre 815. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
8244cb4a62 |
feat(theming)!: FIRMA B' - la cascada de paleta es una ESCALERA sin empates
suelo :where([data-{c}]) (0,0,0) < forward [data-{c}]:where([data-color],
[data-color-custom]) (0,1,0) < tono [data-{c}][data-color='X'] (0,2,0).
El orden de emision deja de decidir: la especificidad ES el contrato,
legible en el artefacto (doctrina hermana de la FIRMA 12.9).
- Emisor (render-css.ts): isPaletteSlotToken PARTE el bucket host - solo
las ranuras de paleta bajan al suelo, el chasis del componente queda a
(0,1,0). 49 suelos + 49 forwards reescritos + 0 pares viejos; bloques
por tono (112), capa compartida y gradient finish byte-identicos.
- Neutra en pixel, MEDIDO: ~297.000 valores computados antes/despues
(105.248 planos lotes A+B, 57.720 planos lote C, 134.464 con los tonos
ESTAMPADOS en las 49 unidades, incluidos 5 @active), 0 diffs reales.
Los 17 crudos, probados ruido por reproduccion sobre codigo identico.
- Guarda por MUTACION (active-eidos-config.test.ts): suelo con contenido,
forward de un peldano, par viejo ausente, tono sin envolver, particion
del host, cierre estructural (toda declaracion de paleta vive en un
peldano) - 6 mutaciones inyectadas, 6 mordidas. El contrato del forward
pasa de vigilar 2 recetas a 49 (privadas incluidas, multi-parte bien).
- Ledger: PALETTE_SUPERSEDED muere (describia el mundo viejo); 207 de sus
353 claves pasan a VIVAS y las 146 restantes quedan bajo PALETTE_FLOOR
(el tono-default estampado resuelve por el forward: quitar el atributo
ES hablar en silencio) o TONE_UNREACHED (ningun paso del guard estampa
tono Y hoverea), con razon medida. stepper y tag-group, barridos por
primera vez. El detector STALE es CIEGO a patrones: la retirada fue
manual y por estrechamiento, guiada por medida.
- Docs: changelog 53 - reference THM-2 - next-features 13 (RESUELTA) -
CONTINUE-theming.
Supervision: 4 agentes Opus en 5 fases (baseline plano + baseline
estampado, emisor, guarda, verificacion de parque completo, docs), con
refutacion del supervisor sobre censo, emisor y guarda.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5d71d830e9 |
feat(theming)!: FIRMA §12.9 — el plano de profundidad es el SUELO, no el techo
El plano `data-depth` pinta el bundle de elevación (superficie · borde · sombra
· tipografía on-surface) y hasta hoy lo hacía a (0,1,0), la misma especificidad
que la receta del componente. La Decisión 8 daba por bueno ese empate porque
«las recetas cargan después de la fundación y ganan por ORDEN DE CASCADA».
ESA PREMISA ERA FALSA
La fundación la inyecta ActiveEidos en runtime como <style> gestionado, y las
recetas llegan como chunks code-split de Vite: a igual peso ganaba quien
cargara el último, y se midió AL REVÉS en dev que en producción (§13). No era
una decisión de diseño, era una moneda al aire — y la moneda cayó del lado del
plano.
LO QUE COSTABA, MEDIDO
Un toast `risk` y uno `fulfill` vestían la MISMA TARJETA GRIS: los seis tonos
idénticos y la franja de acento —el rasgo que identifica la intención de un
vistazo— reducida a 0,67 px de gris neutro, porque el atajo `border` del plano
pisaba el longhand `border-inline-start` en los cuatro lados. Las TRES variantes
de tooltip computaban lo mismo: `outline` indistinguible de `solid`, `ghost` un
backdrop-filter invisible tras una superficie opaca. Y ~35 claves públicas
quedaban adjudicadas como mudas en cinco componentes, con tres recetas que
habían RETIRADO su tipografía por esto.
LA REGLA
La regla de apariencia del plano se emite envuelta en `:where(...)` —
especificidad CERO. La receta gana donde el componente HABLA, en cualquier
orden de carga; el plano sigue pintando todo lo que el componente CALLA, que es
exactamente lo que significa «baseline». Vale igual para un plano que añada un
tema (jaula abierta).
EL FROST NO BAJA, Y ES DELIBERADO
`[data-depth='{plane}'][data-frost]` conserva sus (0,2,0). El baseline es un
suelo que la receta puede pisar; el frost es una petición explícita por
elemento —alguien escribió `data-frost`— y honrarla significa ganarle al fondo
propio del componente. Mismo atributo, intención opuesta: queda comentado en el
emisor para que nadie los «armonice», y el guard lo fija por los dos lados.
QUÉ MUEVE DE PÍXEL, ENTERO
De 19 adoptantes, DIECISÉIS con diff CERO sobre ~49.000 valores computados. Los
tres que se mueven son la firma haciendo su trabajo:
- toast: 35 diffs (7 fondos + 7 bordes de tono + 21 anchuras). Cuatro tonos
medidos en la demo real: 4 de 4 DISTINTOS donde antes 3 de 3 eran idénticos,
y la franja de acento pasa de 0,67 px de gris a 3 px del color de la
intención.
- tooltip: sus tres variantes vuelven a distinguirse — solid opaco con sombra,
outline transparente con borde, ghost translúcido al 70 %.
- popover, tooltip y link-preview: `line-height` de 1.25 (el `--leading-ui` del
plano) al que cada receta pide. Es EXACTAMENTE la decisión que la receta de
link-preview tenía escrita desde el 2026-08-21: «se quedan declaradas A
PROPÓSITO; retirarlas arreglaría el empate a favor del plano — una decisión
de píxel que pertenece a la firma pendiente de §12.9».
`font-family` no se movió en ninguno: las recetas piden el mismo
`--style-label-font-family` que el plano pinta, así que la seguridad
tipográfica del portal (Decisión 8) queda intacta.
Refutada una hipótesis propia: temía que el atajo `background` del plano
estuviera matando el velo de hover del sistema y que bajarlo lo resucitara
moviendo píxel. `backgroundImage` no cambia en ninguno de los 19 — el velo vive
en los ítems, no en la superficie.
EL LEDGER
17 claves salieron STALE solas y se retiran: toast (3), tooltip (5),
float-panel (5), link-preview (2), popover (2). Los cinco vuelven verdes —
toast pasa de 51/85 a 72/85. El ledger sigue en 87 bloques, sin duplicados, y
parsea.
DOS VECES QUE EL INSTRUMENTO MINTIÓ
La sonda compartida mide UN nodo en dialog, drawer, popover, tooltip,
context-menu, dropdown-menu y link-preview: nunca abre la superficie, que es
justo donde el plano pinta, así que sus «0 diffs» no probaban nada. La medición
buena reproduce el «antes» EN RUNTIME, inyectando la regla vieja a (0,1,0) al
final del head en vez de revertir el fichero — entra como
`scripts/__plane-open.mjs`.
Y el primer barrido del ledger dio 87 de 87 rojos: «todos fallan igual» es la
firma del instrumento, y era la misma trampa del CR de Python en Windows que ya
está registrada. Re-corrido con la lista limpia.
EL BARRIDO DEL LEDGER ENTERO
87 de 87 componentes con entrada en el ledger, re-corridos tras el flip: cero
NO EFFECT sin adjudicar, cero STALE, cero errores. El cambio es global y se
verificó globalmente.
GUARDS
vitest src/uix/eidos 439/440 (el rojo conocido skin-media-player) ·
active-eidos-config 75/75 · npm run check COMPLETED con los 72 errores
preexistentes de la rama y ninguno en ficheros de este cambio · rtl:check 0 ·
docs:check 0 · eidos-lint 0 invalid en los cinco tocados · capturas de las tres
superficies que se mueven.
Un test hermano afirmaba el selector desnudo para un plano añadido por un tema:
ahora afirma `:where()`, porque un plano de tema es un suelo igual que los
cinco de fábrica.
Doctrina en docs/theming/changelog.md §29 (junto a la Decisión 8 que corrige),
cierre del expediente en next-features §13 y handoff al día.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
d4a83cca68 |
docs(theming): la COLA A queda CERRADA — y §12.9 pasa a tener coste de producto
scroll-area y slider al 100 %, tabs cerrado en 97 %, toast al 100 %. Global 68 %, 45 componentes al 100 %. Los cuatro cerraron SIN acuñar una sola clave: a los cuatro les quedaba un literal y en los cuatro era identidad. Firmar un literal y cerrar es una respuesta tan válida como acuñar. LO QUE MÁS PESA, RE-MEDIDO EN LA SUPERVISIÓN Un toast risk y uno fulfill visten la misma tarjeta gris. Disparados los tres tonos en la demo real con transiciones y animaciones congeladas, risk, fulfill y affirm computan idénticos: fondo, borde, franja de acento de 0,67 px y sombra. La tarjeta lleva data-intent Y data-depth=overlay; --toast-risk-surface en :root no la mueve y --depth-overlay-border la repinta. La intención llega al DOM y muere en la cascada, 21 claves. Es la primera vez que §12.9 tiene coste de PRODUCTO y no sólo de contrato, así que sube el precio de dejarla sin firmar. Y queda anotada la trampa de medirlo: el tono viaja en data-intent, no en data-color — una sonda que lea data-color lo encuentra null y diagnostica «el tono no llega», que es un defecto distinto y manda la firma por el camino equivocado. LA LEY QUE DEJARON LOS OTROS DOS Antes de retirar una clave, mira quién la lee: scroll-area.auto-max-block leía muerta en su propia demo y la consumen cinco recetas ajenas; slider.min-block-size la fija media-player. Retirarlas habría roto seis componentes sin que un guard se pusiera rojo. Ya es el paso 8.bis de §7.3. Queda del eje: cero de cola A, tres de deuda B (cada uno por su razón), ninguna pestaña Tokens pendiente, y siete cosas esperando tu firma. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
fde65af7ea |
docs(theming): el registro §8 recoge tabs y toast, con su sha — y la cola A CIERRA
Los dos commits de esta sesión, con sus cifras y sus artefactos:
- `tabs` 96 % → 97 % CERRADO (`300153f9f`) — 79 claves, ninguna acuñada,
centinela 70/79 con 9 adjudicadas.
- `toast` 98 % → 100 % (`b8eccc1c4`) — 85 claves, ninguna acuñada, centinela
51/85 con 34 adjudicadas.
Y con ellos la Cola A queda CERRADA: los cuatro (`scroll-area`, `slider`,
`tabs`, `toast`) cerraron **sin acuñar una sola clave**. Sus contratos ya
estaban enteros y lo que quedaba fuera eran literales-identidad y, en `tabs`,
el canal de VALOR de soma. Cuando el número no se mueve porque no debe, eso ES
el resultado — y así está escrito en el handoff.
Lo que enseñaron los dos últimos, para el que siga:
- §12.9 en una tarjeta PORTALADA se lleva la TARJETA ENTERA, no sólo la
tipografía — 21 claves de `toast`, y con coste de producto: un toast `risk`
y uno `fulfill` visten la misma tarjeta gris. Medido, adjudicado con
`PLANE_SUPERSEDED` y registrado en next-features §12; sin firma no se toca.
- La misma clave puede mentir en reposo y decir la verdad en animación: los
`{tono}-accent` alcanzan bajo `[data-loading]`, donde el `@keyframes` del
pulso gana a toda declaración normal.
- Poner `openMarker` puede EMPEORAR la medición cuando la superficie se
auto-descarta: tres corridas del guard discreparon sobre código idéntico.
- El indicador de `tabs` es canal de valor: `MeasuredIndicator` escribe su rect
en cada movimiento, y un público encima sería un knob que rompe el
deslizamiento al fijarse.
Guard: `docs:check` 0 · prettier limpio sobre el contenido normalizado a LF.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
b8eccc1c4f |
uix(toast): temable — 98 % → 100 %, y el plano se lleva la TARJETA ENTERA
El contrato ya tenía sus 85 claves y `global` era CERO: no se acuña ninguna.
Lo único fuera de alcance era un literal, y era identidad.
Lo que entra:
- `opacity: 1` de la tarjeta firmado con su anotación `/* literal: */`
(recipe-contract §3): es el polo EN REPOSO del par abierto/cerrado, y el
que lleva tokens es el otro (`closed-offset`, `closed-scale`). «Presente
del todo» no tiene un segundo valor que sostener. 98 % → 100 %.
- Guard R-5.4: entrada nueva en `COMPONENT_OVERRIDES` que dispara la tarjeta
con el botón del demo — y que DELIBERADAMENTE no pone `openMarker`. Una
tarjeta se auto-descarta a los 5 s, así que «¿ya está abierta?» no tiene
respuesta útil: con `openMarker` tres corridas sobre código idéntico
discreparon en QUÉ token leía muerto. Sin él, el guard cae al marcador por
defecto (una parte que este componente no tiene) y dispara una tarjeta
nueva antes de CADA token: **51/85 en tres corridas seguidas**, determinista.
- Ledger: 34 adjudicaciones, ninguna retirada, todas MEDIDAS.
- La sonda aprende a disparar el toast (`DEMO_VARIANTS`): medía UN nodo (el
viewport) porque un toast no EXISTE hasta que algo lo lanza. Ahora 8.
EL HALLAZGO — §12.9 con una cara nueva y con coste de PRODUCTO:
`toast-item.svelte` sella `data-depth='overlay'`, y el plano declara
`background`, el ATAJO `border` y `box-shadow` con la misma especificidad
(0,1,0) y más tarde. Medido sobre la tarjeta real con transiciones congeladas:
escribir `--toast-{tono}-surface` / `-border`, `--toast-provider-border-width`,
`--toast-accent-width` o `--toast-provider-shadow` no mueve NADA; escribir
`--depth-overlay-surface` / `-border` / `-shadow` y `--border-width` en la
misma raíz lo repinta todo. Son 21 claves de 85, y a diferencia de `tooltip`
esto se VE: un toast `risk` y uno `fulfill` visten la misma tarjeta gris, y la
franja de acento —un `border-inline-start` que el atajo posterior pisa en los
cuatro lados— no aparece nunca en reposo.
Matiz que sólo aparece midiendo: los seis `{tono}-accent` NO están muertos.
Bajo `[data-loading]` la regla del pulso es (0,2,0) y su `@keyframes` gana a
toda declaración normal — 100 fotogramas del pulso real: sin escribir, el
color interpolado corre en oklab L 0.5032..0.8514; con el token en rgb(1,2,3),
0.0823..0.5032. La misma clave miente en reposo y dice la verdad en animación.
§12.9 sigue SIN FIRMAR, así que las 21 se ADJUDICAN con `PLANE_SUPERSEDED` y
la incidencia se registra en `next-features.md` §12. No se toca desde este eje.
Las 13 restantes: la pareja de transición (el guard congela `transition`),
`closed-offset` / `closed-scale` (estado de salida + `transform`, que el guard
no fotografía), los tres del anillo de foco de la acción (el guard hace
`blur`), los cinco `{tono}-action-hover-bg` (el guard estampa el tono en su
pasada estática y no en la de hover) y `provider-max-width`, cuyo centinela de
1234px se capa contra el `min(100%, …)` — medido desde el otro lado, 120px
encoge la tarjeta de 420 a 280.
Censo: 98 % → 100 % (45 knobs · 45 públicos · 0 globales · 0 privados ·
1 excepción firmada). Global 68 %, al 100 % 42 → 45. Sin cambios en
`recipes/base.ts` ni en `generated/base.css`.
Diff de computed: **0 diffs sobre 1.760 valores en 7 estados** (8 nodos en
reposo, 7 en hover). Capturas 2× de la tarjeta byte a byte idénticas — y van
por un script propio, porque su viewport es `position: fixed` y cae fuera del
recorte del escenario que usa `__shot`.
Más README con su sección «Talla y tema», pestaña `Tokens` en la demo (85
claves, verificada en el navegador) y ficha con veredicto §5.
Guards: centinela 51/85 verde (exit 0, sin STALE) · `component-audit --only
toast` PASS · `eidos-lint toast` 0 invalid (24 morfo-backed, 6 eidos-only) ·
`vitest run src/uix/eidos` 35/36 (el rojo conocido es `skin-media-player`) ·
`rtl:check` 0 · `docs:check` 0 · `check` COMPLETED sin un solo error en
ficheros de toast · prettier limpio sobre el contenido normalizado a LF.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
868bd235bf |
docs(theming): el protocolo aprende a mirar QUIÉN LEE una clave antes de retirarla
R-5.4 dice que un token que no mueve nada es un token que miente, y esta pasada ha retirado varias con razón: file-upload.button-bg no pintaba en ninguno de sus tres botones, avatar.group-max no lo leía nadie, editable.control-border no la consumía ninguna regla. Pero leer muerto en SU demo no es leer muerto en el CATÁLOGO, y las dos sesiones de hoy lo enseñaron a la vez. scroll-area.auto-max-block salía silenciosa en su propia página y la consumen cinco recetas ajenas —combobox, command, gradient-picker, select y palabras—. slider.min-block-size sólo la lee la orientación vertical, que su demo no monta, y es justo la que media-player fija para su volumen. Retirar cualquiera de las dos habría roto seis componentes sin que un solo guard se pusiera rojo, porque ninguno mide el catálogo entero. Entra como paso 8.bis de §7.3, con el comando: un grep sobre src/uix/eidos/components/ antes de retirar nada. Si aparece alguien más, la clave no se retira: se adjudica con esa razón. Las dos sesiones lo hicieron por criterio propio, sin que el protocolo lo pidiera. Ahora lo pide. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
999481e08c |
docs(theming): el registro §8 recoge scroll-area y slider, con su sha
Los dos cierran la cola A por arriba y los dos cierran **sin acuñar una sola clave**: llegaban con `global` y `private` a cero y un único literal cada uno, que se firma como identidad (`opacity: 1` de la barra visible · `inline-size: 100%` del rail horizontal). Diez adjudicaciones entre los dos, todas medidas. - `scroll-area` 94 % → 100 % (`3282ef978`) — la clave que el guard leía muerta (`auto-max-block`) es la que CINCO componentes escriben sobre su propio ScrollArea. - `slider` 97 % → 100 % (`4d3ca2fd8`) — con un solo valor el tick ACTIVO no existe: `data-active` es una relación con el rango, no un estado del tick. El registro va aparte del commit del componente porque un commit no puede contener su propio sha, y el marcador `(COMMIT)` ya costó trece entradas sin resolver. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
4d3ca2fd81 |
uix(slider): temable — 97 % → 100 %, y con un solo valor el tick ACTIVO no existe
CERO claves acuñadas. El componente llegaba con `global` a cero, `private` a
cero —sus cuatro privados son la escala por talla, que ya deriva de públicos— y
treinta y nueve claves cubriendo su cromo entero; lo único fuera de alcance era
UN literal. Este commit lo firma, adjudica sus siete silenciosas y escribe los
artefactos que le faltaban.
QUÉ ENTRA
- **El literal se firma como identidad**: `inline-size: 100%` en
`[data-slider][data-orientation='horizontal']` — un rail ocupa su contenedor.
El knob de verdad ya existe y es su SUELO: `min-inline-size`. Mismo
precedente que `separator.css:26`, cerrado el mismo día también sin acuñar.
- **Siete adjudicaciones en el ledger**, todas MEDIDAS sobre los nodos reales,
con `transition` congelada salvo donde el token ES la transición:
- `min-block-size` — sólo la lee `[data-orientation='vertical']` y el
escenario arranca horizontal. Con el chip de orientación: 160px -> 1234px.
- `active-thumb-scale` / `active-thumb-shadow` — el pickup vive en
`[data-slider-thumb]:active`, que pide el puntero MANTENIDO, y el pase
estático del guard lo aparca. Con `mouse.down()` real sobre el thumb real:
scale 1.15 -> 4.56, y la sombra sigue al centinela.
- `active-tick-bg` — un tick lleva `data-active` sólo mientras su valor cae
DENTRO de [min(valores), max(valores)] (soma, `SliderTickProvider.isActive`),
así que un pulgar único en 40 con ticks en 0/50/100 deja los tres inactivos:
la marca activa no es un estado del tick, es una RELACIÓN CON EL RANGO. Con
el chip `multiple` (20–80) el tick 50 se activa y el token alcanza.
- `disabled-opacity` — el escenario arranca habilitado; con su interruptor,
0.4 -> 0.123.
- `transition-duration` / `transition-ease` — SON la transición que el guard
congela; medidos sin congelar, 0.12s -> 11.5s y steps(4).
- README con su sección «Talla y tema» (39 claves por grupo, con la distinción
`hit-size-{k}` = agarre vs `track-size-{k}` = pintura) y veredicto §5 de la
ficha con las cifras.
QUÉ NO SE TOCA
- **Nada se retira ni se renombra**, y no es prudencia: este contrato lo COMPONEN
otros SIETE componentes que re-tiñen o re-dimensionan estas mismas claves sobre
su Slider embebido — `media-player`, `skin-media-player`, `waveform` (su
playhead ES este thumb), `color-picker`, `gradient-builder`,
`image-adjustments` y `time-range-picker`. `min-block-size`, que el centinela
leía muerta, es justo la que `media-player` escribe para su volumen vertical.
- `base.ts` y `generated/base.css`: sin cambio de contrato no hay nada que
regenerar. 39 -> 39 claves.
ARTEFACTOS
- Censo: 97 % (33 knobs · 31 públicos · 1 literal · 1 sistema) -> **100 %**
(32 · 31 · 0 literal · 1 excepción · 1 sistema). Global 68 %, no baja.
- Sonda antes/después: **0 diffs sobre 1.376 valores computados**, 7 estados,
7 nodos (raíz · secondary-range · range · thumb · 3 ticks).
- Captura 2× antes y después: idénticas.
- Centinela R-5.4: **32/39**, las 7 restantes adjudicadas -> verde.
- component-audit PASS · eidos-lint 25 morfo-backed / 5 eidos-only / **0
invalid** · `vitest run src/uix/eidos` 35/36 ficheros (el rojo conocido es
`skin-media-player`) · rtl:check 0 · docs:check 0.
- `npm run check`: UN error en `web/routes/uix/components/slider/+page.svelte`
(`Property 'keyboard' does not exist`, línea del `sliderMorfo.parts[2]`),
**PREEXISTENTE** desde `1857c7854` y ajeno a este commit; ningún otro error en
ficheros de slider.
- Prettier: los hunks de deriva del fichero son los MISMOS que en HEAD (2 en el
README, 0 en el CSS); mi bloque no añade ninguno.
NOTA DE CONCURRENCIA: la pestaña `Tokens` de su demo (paso 11 del protocolo) la
escribí yo, pero entró en HEAD por `9fc38b19a` + `c88b2f861` de otra sesión, que
la arrastró con un `git add` derivado y lo declaró. No se re-commitea aquí.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
3282ef9786 |
uix(scroll-area): temable — 94 % → 100 %, y la clave que el guard leía muerta la escriben CINCO componentes
CERO claves acuñadas. El componente llegaba con `global` a cero, `private` a
cero y trece claves públicas que ya cubrían su cromo entero; lo único fuera de
alcance era UN literal. Este commit lo firma, adjudica sus tres silenciosas y
escribe los artefactos que le faltaban.
QUÉ ENTRA
- **El literal se firma como identidad**: `opacity: 1` en
`[data-scroll-area-scrollbar][data-state='visible']` deshace el `0` del
estado oculto de la regla de encima — es el otro extremo de un par, no un
knob. Un `--scroll-area-visible-opacity` sería una clave cuyo único valor
sensato es `1`, y además asimétrica: el `0` hermano el censo ni lo cuenta.
Precedente literal en `navigation-menu.css:360` y `select.css:363`.
- **Tres adjudicaciones en el ledger**, todas MEDIDAS sobre los nodos reales:
- `auto-max-block` — su regla pide `[data-autosize]` y el escenario monta el
modo fijo. Forzado sobre la raíz real: `max-block-size` none -> 1234px, y
al quitar el token vuelve a `none`. NO es decorativa: la escriben
`combobox`, `command`, `gradient-picker`, `select` y `palabras` sobre su
propio ScrollArea. Retirarla habría roto cinco componentes. El atributo lo
estampa el envoltorio de eidos desde una prop, no lo declara el morfo, así
que la excepción de demo de PLAN §7.8 tampoco lo abre.
- `transition-duration` / `transition-ease` — SON la transición que el guard
congela para poder medir lo demás. Medidos sin congelar: 0.12s -> 11.5s y
cubic-bezier(0.4, 0, 0.2, 1) -> steps(4), en la barra y en el thumb.
- README con su sección «Talla y tema» (13 claves por grupo) y veredicto §5 de
la ficha con las cifras.
QUÉ NO SE TOCA
- `thumb-bg-hover` se queda con el modificador DETRÁS: es un hover NEUTRO, y
los hovers neutros están EXCLUIDOS del codemod de D-TH.6 porque migran a la
capa de estado (firma 3). Su migración sigue bloqueada por morfo — el thumb
lleva `archetype: 'thumb'`, que no recibe velo.
- `base.ts` y `generated/base.css`: sin cambio de contrato no hay nada que
regenerar. 13 -> 13 claves.
ARTEFACTOS
- Censo: 94 % (17 knobs · 15 públicos · 1 literal · 1 sistema) -> **100 %**
(16 · 15 · 0 literal · 1 excepción · 1 sistema). Global 68 %, no baja.
- Sonda antes/después: **0 diffs sobre 896 valores computados**, 7 estados,
4 nodos (raíz · viewport · barra vertical · thumb).
- Captura 2× antes y después: idénticas.
- Centinela R-5.4: **10/13**, las 3 restantes adjudicadas -> verde.
- component-audit PASS · eidos-lint 17 morfo-backed / 1 eidos-only / **0
invalid** · `vitest run src/uix/eidos` 35/36 ficheros (el rojo conocido es
`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con **cero**
errores en ficheros de scroll-area.
- Prettier: los hunks de deriva del fichero son los MISMOS que en HEAD (3 en el
README, 3 en el CSS, ambos preexistentes); mi bloque no añade ninguno.
NOTA DE CONCURRENCIA: la pestaña `Tokens` de su demo (paso 11 del protocolo) la
escribí yo, pero entró en HEAD por `9fc38b19a` + `c88b2f861` de otra sesión, que
la arrastró con un `git add` derivado y lo declaró. No se re-commitea aquí.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
300153f9f6 |
uix(tabs): temable — 96 % → 97 %, y su indicador es CANAL DE VALOR, no tema
El contrato ya estaba entero (79 claves) y NO se acuña ninguna: las tres declaraciones que quedaban fuera lo están por doctrina, y así se firma. Lo que entra: - `width: 100%` de `fitted` firmado con su anotación `/* literal: */` (recipe-contract §3): es IDENTIDAD — `fitted` ES «la lista llena el eje inline», y un token ahí sólo podría tomar un valor sin desdecir la prop. Sale del ratio: 96 % → 97 %. - La propuesta §4.1 de la ficha (acuñar `indicator-width` / `-height` sobre `var(--indicator-w, 0px)`) se RECHAZA por escrito. Esas vars son el canal de VALOR de soma: la capa `MeasuredIndicator` escribe el rect del trigger activo en cada movimiento, así que un público encima sería un knob que un tema puede FIJAR — y fijarlo rompe el deslizamiento. Misma adjudicación que `navigation-menu` lleva escrita para su propio `indicator-w` (y la razón por la que su `-x` se retiró, muerto). El comentario de la receta lo dice ahora en el sitio donde se lee. - Guard R-5.4: entrada nueva en `COMPONENT_OVERRIDES` (barrido de `data-variant` line/surface/pills/segmented + las dos superficies de URL del propio demo, `perm.orientation=vertical` y `perm.disabled=true`): 40/79 → **70/79** sin adjudicar una clave de más. - Ledger: 9 adjudicaciones, todas MEDIDAS a mano sobre los nodos reales — los cuatro tokens de transición (el guard congela `transition`), los tres del anillo de foco (el guard hace `blur` a propósito), `trigger-bg` (la demo monta el Indicator y la regla que sube la etiqueta por encima de la píldora gana 0,2,0; sin indicador alcanza) y `scrollable-fade`, que además pinta por `mask-image`, fuera del juego de propiedades del guard. - README con su sección «Talla y tema» (tabla derivada del contrato) y pestaña `Tokens` en la demo (79 claves, verificada en el navegador). - Ficha `docs/audit/theming/tabs.md` con su veredicto §5. Comprobado y refutado: el trigger NO compone el `Button` canónico (`tabs-trigger.svelte` → `Tabs.Trigger` de soma, un `<button>` desnudo), así que la clase «el compuesto gana a la receta que lo compone» de toolbar / form no le aplica y no hay declaración muerta que ceder. Censo: 96 % → 97 % (77 knobs · 74 públicos · 2 globales · 0 literales · 1 excepción firmada · 1 sistema). Sin cambios en `recipes/base.ts` ni en `generated/base.css` — no hacía falta regenerar. Diff de computed: **0 diffs sobre 2.016 valores en 8 estados** (8 nodos en reposo, 7 en hover). Capturas 2× antes/después, idénticas. Guards: centinela 70/79 verde · `component-audit --only tabs` PASS · `eidos-lint tabs` 0 invalid (13 morfo-backed, 44 eidos-only) · `vitest run src/uix/eidos` 35/36 (el rojo conocido es `skin-media-player`) · `rtl:check` 0 · `docs:check` 0 · `check` COMPLETED sin un solo error en ficheros de tabs · prettier limpio sobre el contenido normalizado a LF. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
5f00609abe |
fix(theming): la prosa escrita a mano en una ficha SOBREVIVE a la regeneración
El generador de fichas conservaba un solo bloque —el veredicto §5, entre sus marcadores— y reescribía todo lo demás desde la plantilla. Así que una elaboración que un humano hubiera añadido en §1.1–§1.4 desaparecía en silencio: donde alguien escribió «_Ninguno_ — los cuatro que había (el padding-block del divisor, el radio de foco de la fila de evento…) están cosidos», la regeneración dejaba «_Ninguno._». Le pasó DOS VECES en el mismo día a las dos fichas de chat-*: la primera la cosí a mano, y mientras trabajaba otra sesión regeneró y la volvió a borrar. Restaurar a mano es jugar al topo; el defecto está en el generador. EL CONTRATO NUEVO Prosa a mano entre `<!-- mano:start -->` y `<!-- mano:end -->`, y el generador la re-inserta después del MISMO encabezado bajo el que estaba. Un bloque cuyo encabezado ya no exista NO se pierde: se añade al final bajo «Prosa rescatada» para que alguien lo reubique. Perder prosa no es nunca el comportamiento por defecto. Verificado corriendo `--report` sobre las 170 fichas con la prosa ya envuelta: los cuatro bloques de chat-log y chat-composer siguen ahí después. Que la regeneración sea mayoritariamente inocua y ocasionalmente destructiva es el peor reparto posible, porque nadie lee ese diff. Ahora no hace falta leerlo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
2498010a21 |
docs(theming): el handoff recoge la segunda tanda del 24 — ocho componentes, seis al 100 %
chat-message, chat-typing, fab, image-adjustments, separator y collapsible al 100 %; toolbar cerrado en 94 % y tags-input en 90 %, los dos por doctrina y no por deuda. Global 68 %, y los componentes al 100 % pasan de 36 a 42. Esta vez ningún commit se llevó trabajo ajeno: la ley del índice compartido ya iba en el brief. EL HALLAZGO QUE MÁS VALE Ceder el cromo al componente compuesto SALE GRATIS. toolbar deja que [data-button] gane —misma especificidad, emitido después— y no pierde ni una clave, porque su receta ya no escribe reglas sobre el botón. Medido antes de tocar nada: 51/54, y ninguna silenciosa era del botón. Es el reverso exacto de form, que conserva 23 declaraciones muertas por la misma causa. La firma pendiente de §13 tiene una salida barata y ya probada: no escribir la regla. LO QUE LA SUPERVISIÓN ARREGLÓ La sonda no congelaba nada, y es la que mide el gate del protocolo. Con transition y animation congeladas, los 18 diffs fantasma de chat-typing pasan a 0 sobre 1.568 valores. Las 164 fichas regeneradas quedaron clasificadas una a una en vez de por la cifra. Y refutado un susto: una sesión avisó de que cuatro veredictos §5 podían estar vacíos en HEAD; comprobados los ocho, intactos. DOS DEFECTOS REALES ANOTADOS Y NO TOCADOS El chip de añadir reacción de chat-message lo pinta popover.css y se ve en la captura: los chips de reacción son píldoras redondas y el de añadir un cuadrado gris. Y el morfo de tags-input sella aria-selected='true' como literal en cada etiqueta, así que archetypes.css le fija la tinta en reposo y su token nunca ha pintado — con cara de defecto de a11y. Los dos esperan decisión. Quedan cuatro de la cola A: scroll-area, tabs, slider y toast. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
10832bef4a |
fix(theming): la sonda no congelaba NADA — 18 diffs fantasma sobre código idéntico
El gate del protocolo §7 es «el diff de computed es CERO», y la sonda que lo mide no inyectaba ninguna congelación: una propiedad en transición devolvía el valor VIEJO y una bajo animación en BUCLE devolvía donde el bucle estuviera. Ruido puro sobre el único artefacto que prueba que un commit no mueve píxel. Lo destapó chat-typing, cuyos tres puntos montan el bucle pulse del sistema: 18 diffs de opacity corriendo la sonda DOS VECES sobre el mismo código. Con la congelación de transition Y animation antes de cada instantánea: 0 diffs sobre 1.568 valores. Un token que SEA la motion lee congelado y se mide a mano sin congelar, que es el idioma que el ledger ya usa para transition-duration / -ease. Queda registrado en §13 lo que NO arreglo aquí: el guard congela transition pero no animation, y cambiarlo obliga a re-verificar el ledger entero porque los tokens que son la animación pasarían a leer muertos. Misma clase que «el guard no fotografía transform», mismo bloqueo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
82aa500797 |
docs(theming): el registro §8 recoge fab y tags-input, con su sha
Las dos entradas que faltaban de la tanda del 24, cada una con el sha resuelto (la deuda de los trece `(COMMIT)` no se repite): - `fab` 88 % → 100 % (`5fd2fcdd8`), contrato 10 → 12, centinela 11/12 con 1 adjudicada. El cualificador de MODO va detrás; el guard no fotografía `translate` y el centinela se auto-cancela al llevarse el nodo de debajo del cursor. - `tags-input` 88 % → 90 % CERRADO (`92180c390`), contrato 90 → 91, centinela 63/91 con 28 adjudicadas. Sus cuatro privados son el puente THM-2, así que 90 % es su techo; y su `item-fg` no ha pintado nunca porque el morfo sella `aria-selected='true'` en cada etiqueta. docs:check 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
92180c390c |
uix(tags-input): temable — 88 % → 90 % CERRADO, y su tinta no ha pintado nunca
Los cinco knobs fuera de alcance se clasificaron UNO A UNO antes de tocar una
línea, que es la mitad del trabajo:
- **uno era la COSTURA**: `[data-tags-input-control][data-invalid]` leía
`var(--color-risk-border)` A PELO. Entra como
`--tags-input-invalid-control-border`, valor verbatim, con el nombre Y el
default de `field.invalid-control-border` — la misma parte del mismo chasis.
NO se reusó el `risk-border` de la paleta: la cascada `[data-color]` lo
re-enruta por instancia y se llevaría con él el estado inválido, que no es
una elección de tono. `global` a CERO.
- **los otros cuatro son el MISMO puente THM-2**: el borde del control
enfocado y los tres slots de la etiqueta activa leen
`--_tags-input-palette-{border,track,text}`. Ni conmutador ni escala por
talla. No se acuñan (CONTINUE §3.pre): un público encima dejaría que un tema
los fijara y matara en silencio el `color=` por instancia.
**Así que 90 % ES el techo, y es doctrina bien aplicada, no deuda.** Los siete
privados dimensionales ya derivan de públicos; sus bloques `[data-size]` del
CSS SE QUEDAN porque aquí no los emite el TSC (las claves de talla son planas,
sin `scope: 'size:{k}'`) — retirarlos rompería el eje. Migrar esa escala al TSC
es cambio de mecanismo, no de alcance, y queda fuera.
Censo: 46 knobs · público 37 → 38 · global 1 → 0 · privado 4 (el puente) ·
sistema 4 (fuera del ratio) · 88 % → 90 %. Contrato 90 → 91 claves.
`--names`: 0 desviadas (67 conformes + 24 role-slot canónicas).
Diff de computed: VACÍO en las dos superficies. 2.496 valores × 8 estados en el
escenario por defecto (válido, sonda estándar, 10 nodos) y 459 valores × 5
tallas + 3 variantes + hover en el estado INVÁLIDO, con una sonda de un solo
uso porque la demo arranca válida. Captura 2× antes/después byte a byte
idéntica. No se tocó ninguna regla `:hover`, así que el paso 12 no aplica.
Centinela R-5.4: **63/91**, 28 adjudicadas, cuatro razones y todas MEDIDAS:
1. **Las 24 claves de tono — la cascada de paleta** (excepción por PATRÓN). El
wrapper resuelve `color` y estampa `data-color` en TODA instancia, incluida
la del default, así que gana el bloque genérico
`[data-tags-input][data-color], [data-tags-input][data-color-custom]`, que
se emite el ÚLTIMO a la misma (0,2,0) que los ocho por tono. Medido sobre la
etiqueta real forzada a `data-state=active`: `--tags-input-primary-border`
no mueve nada (el borde sigue en `oklch(0.8043 0.0918 309.69)`) mientras
`--palette-border` en el mismo nodo lo repinta (`rgb(4, 5, 6)`); quita
`data-color` y `--tags-input-primary-border` vuelve a pintar
(`rgb(1, 2, 3)`).
2. **`transition-duration` / `transition-ease`** SON la transición que el guard
congela. Medidos sin congelar: 0.12s → 4.321s y
`cubic-bezier(0.4, 0, 0.2, 1)` → `steps(3)`.
3. **`placeholder-fg`**: soma sólo pone el atributo `placeholder` mientras el
input está VACÍO (`isEmpty ? opts.placeholder : undefined`) y el escenario
arranca con dos etiquetas — y `::placeholder` sobre un input SIN placeholder
devuelve el estilo del ELEMENTO (la trampa ya medida en `field`). Vaciar el
escenario no vale para esa corrida: borra los nodos de etiqueta, donde pinta
un tercio del contrato. Medido de las dos formas: pulsando el propio `Clear`
de la demo el input queda con `placeholder="Add tag"`, y forzando el
atributo sobre el input real el token alcanza (`rgb(1, 2, 3)`; default
`oklch(0.61 0 0)` = `--color-content-muted`).
4. **`item-fg` — y ésta NO es del instrumento, es del COMPONENTE.** El morfo
sella `aria-selected='true'` como LITERAL en CADA etiqueta, así que la regla
de `archetypes.css`
`[data-archetype='item'][aria-selected='true']:not([data-state='checked']):not([data-state='on'])`
**(0,4,0)** gana siempre a `[data-tags-input-item]` **(0,1,0)**: la tinta de
la etiqueta es la del arquetipo y su velo de estado se pinta en TODAS las
etiquetas en reposo. Medido: con el atributo tal como se envía el token no
mueve nada (`oklch(0.2435 0 0)`, la del arquetipo); con `aria-selected=false`
sobre la etiqueta real, la misma escritura alcanza (`rgb(1, 2, 3)`). Los
tres slots `*-text` del tono llevan esta SEGUNDA causa encima de la primera.
Es la clase de `table.selected-row-fg` y la tinta de `listbox`. Toca morfo Y
mueve píxel ⇒ se mide, se REGISTRA (next-features §12, con su cara de a11y:
un lector anuncia todas las etiquetas como seleccionadas) y se sigue.
Lo que el instrumento aprendió: **el guard ABRE haciendo clic en el control**,
lo que estampa `data-focus`, y la regla de foco re-tinta el borde a la misma
(0,2,0) pero más tarde — así que `control-border`, un token perfectamente vivo,
leía muerto. Es la clase de `command.input-border`, otra vez, y la cura es
barrer la AUSENCIA (`null`) de `data-focus`, `data-invalid` y `data-disabled`:
**60/91 → 63/91 sin adjudicar una clave de más**, y de paso reviven
`invalid-control-border` y `disabled-opacity`. Es una entrada por componente:
no toca a nadie más. `fab` re-verificado tras el cambio del guard: 11/12, sin
regresión ni STALE.
Guards: censo `--only tags-input` 90 % (global 68 %, no baja) · `--names` 0
desviadas · `component-audit --only tags-input` PASS · `eidos-lint tags-input`
0 invalid (22 morfo-backed, 6 eidos-only) · `vitest run src/uix/eidos` 35/36
ficheros, el único rojo es el conocido `skin-media-player` en `lint.test.ts` ·
`rtl:check` 0 · `docs:check` 0 · `npm run check` COMPLETED, cero errores en los
ficheros tocados (los 72 globales son de otras sesiones) · prettier limpio
sobre el contenido normalizado a LF.
README con su sección «Talla y tema», pestaña `Tokens` en la demo verificada en
navegador (91 claves, cero errores de página) y veredicto §5 escrito en la
ficha.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
bcb958e5dc |
docs(theming): el registro §8 recoge chat-message y chat-typing, con su sha
Las dos entradas del bloque de hoy sobre la familia chat, con las cifras medidas y su «lo que enseñó»: `chat-message` 84 % → 100 % (`f882e1b9d`, contrato 75 → 81, centinela 77/81 con 4 adjudicadas) y `chat-typing` 89 % → 100 % (`d39147c11`, contrato 7 → 8, centinela 8/8 sin adjudicar). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
d39147c119 |
uix(chat-typing): temable — 89 % → 100 %, con UNA clave y siete de sus ocho ya vivas
Protocolo PLAN-theming §7 sobre `chat-typing`. Censo 89 % → **100 %**, contrato 7 → **8** claves, centinela **8/8** con **cero adjudicadas**. ## Lo que entra: una clave, y es la COSTURA `dot-radius` (`var(--radius-full)`), el único knob que leía el sistema a pelo. El valor sigue siendo el del sistema; el knob pasa a ser del componente. **El nombre sale del CATÁLOGO, no del generador.** La ficha proponía `indicator-radius` —nombra por el primer selector de la regla, `[data-chat-typing-indicator] > span`— cuando el nodo que PINTA es el punto y el contrato ya habla `dot-size` / `dot-gap` / `dot-fg`. Es el defecto de `tree-view` («root-bg» para una guía de indentación) en pequeño. ## Lo que el instrumento no veía: 3 nodos de 8 Los tres puntos son `> span` DESNUDOS del indicador —sin `data-chat-typing-*`, la clase de la pastilla del separador de `chat-log`— y la demo arranca con NADIE escribiendo, así que `data-state='idle'` esconde a todos los hijos (presencia = visibilidad, N-7). Con el selector extra y un typer encendido por `prepareWith`: **8 nodos**, y el centinela ya daba **7/7 antes de tocar el código**. ## El diff de computed NO cerró en cero, y es RUIDO reproducido 18 diffs, los 18 de `opacity` y los 18 en los tres `span[data-animation-style=pulse]`. Sus puntos montan el loop `pulse` del SISTEMA, que anima `opacity` sin parar, así que cada lectura cae en una fase distinta: corriendo la sonda dos veces sobre el MISMO código salen los mismos 18 (control `after` vs `after2`). Ninguna otra propiedad se mueve, la clave tocada es `border-radius`, y las capturas 2x antes/después son **idénticas byte a byte** (1.568 valores · 7 estados · 8 nodos). ## Guards censo `--only chat-typing` 100 % (global 68 %, no baja; los que llegan al 100 % pasan de 36 a 42) · `component-audit` PASS · `eidos-lint` 0 invalid (8 morfo-backed, 0 eidos-only) · `vitest run src/uix/eidos` sin rojos nuevos (el único vivo es el conocido `skin-media-player`) · `rtl:check` 0 · `docs:check` 0 · `check` COMPLETED 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` (8 claves, verificada en navegador) y ficha con su veredicto §5. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
f882e1b9d9 |
uix(chat-message): temable — 84 % → 100 %, y las TREINTA muertas eran ejes que la demo no enciende
Protocolo PLAN-theming §7 sobre `chat-message`, el mayor de la familia chat.
Censo 84 % → **100 %**, contrato 75 → **81** claves, centinela **77/81** con 4
adjudicadas. El default NO se mueve: diff de computed VACÍO (4.192 valores · 8
estados · 16 nodos) y capturas 2x antes/después **idénticas byte a byte**, en
reposo y con la barra tapback abierta.
## Otra vez, lo caro fue VER
El guard leía **45/75** antes de tocar una línea de código. Una fila de chat es
una PILA de superficies opt-in (reply citado, read-by, estado de entrega,
mención) y de ejes de PRESENTACIÓN (`run`, `direction`, `emphasized`) que la
demo arranca en su posición más pobre: `solo` + `in`, sin ninguna de las cuatro.
Con las superficies encendidas por `prepareWith` y los cinco ejes barridos como
PRODUCTO: **71/75 antes de acuñar nada**. La sonda pasó de 12 nodos a 16 en
reposo, y a 24 con el panel abierto.
## Lo que entra (6 claves, la COSTURA de los seis globales)
`focus-radius` · `mentioned-fg` · `reply-fg` · `reaction-fg` ·
`reaction-inner-gap` · `quick-react-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 `radius`
(colisiona con `emphasize-radius`, que ES la esquina en reposo de la MISMA
fila), `bubble-fg` (el knob es de la MENCIÓN: `mentioned-bg` y
`mentioned-accent` ya existían), `reaction-width` + `reaction-height` para el
glifo (`reaction-height` ya existe y es la altura del CHIP) y
`quick-reactions-width` para un `max-content` que es identidad.
## El caso que obligó a decidir: `reaction-gap` ya existía con otro sentido
La receta la pinta en la fila `reactions` — el hueco ENTRE chips — mientras el
knob nuevo es el ritmo INTERNO del chip, el emoji y su cuenta. Mismo valor
(`--space-1`), dos papeles: un chip más denso no es una fila más apretada.
Reusar la clave habría cambiado en silencio lo que mueve un tema que ya la usa,
así que entra como `reaction-inner-gap`. El resto del bloque `{parte}-gap` de
esta receta (`meta-gap`, `read-by-gap`, `header-gap`, `actions-gap`) significa
«dentro de la parte»: la anómala es la vieja, y renombrarla es churn con riesgo.
## Lo que SALE: una regla que no ha pintado nunca
`[data-chat-message-reaction] svg, [data-chat-message-reaction-add] svg` fijaba
`1.1em` en los dos ejes «porque un svg de sólo viewBox computa 0x0». El glifo
por defecto es el `Icon` compuesto, que emite `style="width:
var(--icon-size-sm); height: ..."` EN LÍNEA, y un estilo en línea gana a todo
selector. Medido: **16 px** (el paso `sm` del icono), no los 15,4 px que `1.1em`
daría sobre los 14 px heredados. La otra mitad del selector no tiene nodo: los
chips llevan un emoji de texto. **Retirada: 0 diffs.** Tercera vez en la familia
(chat-log y chat-composer, ayer).
## Identidades firmadas (4, fuera del ratio)
`inline-size: max-content` de la barra tapback (la barra ES su fila de emoji),
`line-height: 1` de la celda (la celda es la caja del glifo) y los dos
`opacity: 1` de la pastilla de acciones (el final del fundido 0 → 1).
## Adjudicadas (4) — las cuatro son límites del INSTRUMENTO, medidas a mano
- `bubble-tail-radius` — el guard fotografía UNA esquina (`borderTopLeftRadius`)
y la cola es la de ABAJO. Medido en las 8 combinaciones dirección x run:
4 px → 1234 px en `solo` y `last`, en las dos direcciones. Su hermana
`bubble-radius-run` lee viva porque `middle` aplana la esquina START, que sí
está en la lista.
- `emphasize-duration` — ES la transición que el guard congela para medir todo
lo demás. Sin congelar: 0,24 s → 4,321 s.
- `focus-radius` — la fila sólo es tabulable compuesta DENTRO de un Feed (soma
fusiona la identidad de `Feed.Article` cuando hay Feed ancestro) y su propia
demo la monta suelta: `:focus-visible` no tiene nodo ahí. Medido en la demo de
`chat-log`, donde las filas SÍ son artículos de feed (`tabindex=0`): reposo
6 px, enfocada 4 px → 1234 px, por foco programático y por recorrido con Tab.
- `quick-react-hover-scale` — `transform` no está en la lista de propiedades del
guard (punto ciego ya adjudicado en background / rating-group / card) y la
celda es un botón PORTALADO con regla `:hover`. Con puntero real:
`matrix(1.18…)` → `matrix(7.77…)`.
## Un defecto real medido y NO corregido aquí (mueve píxel)
El chip de añadir reacción lleva también `data-popover-trigger`, y
`[data-popover-trigger]:not([data-archetype='field-trigger'])` pesa (0,2,0)
contra los (0,1,0) de `[data-chat-message-reaction-add]`: su fondo, borde,
radio, tinta, altura, padding y tamaño de letra los pinta `popover.css`. Se ve
en la captura — los dos chips de reacción son píldoras redondas y el de añadir
es un cuadrado gris. Los `reaction-*` no mienten (alcanzan sobre los chips
normales), así que no hay nada que retirar: es una decisión de diseño. Clase
`gradient-picker` / `emoji-picker`. Queda REGISTRADO, no tocado (D-TH.5).
## Guards
censo `--only chat-message` 100 % (global 68 %, no baja) · `component-audit`
PASS · `eidos-lint` 0 invalid (37 morfo-backed / 41 eidos-only) · `vitest run
src/uix/eidos` sin rojos nuevos (el único vivo es el conocido
`skin-media-player`) · `rtl:check` 0 · `docs:check` 0 · `check` COMPLETED 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` (81 claves,
verificada en navegador) y ficha con su veredicto §5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5c8e707a0d |
docs(theming): 164 fichas regeneradas — dos perdían prosa medida, y el generador es el culpable
Una sesión regeneró todas las fichas de docs/audit/theming con el --report del censo y las dejó sucias en el árbol. Antes de commitearlas las clasifiqué una a una en vez de mirar la cifra: - 155 sólo cambiaban la FECHA de medida. Inocuo, y correcto: el censo corrió hoy. - 7 traían cifras nuevas y buenas (collapsible y toolbar, que acaban de cerrar) o retiraban una propuesta §4 ya cumplida. Mejora. - 2 —chat-log y chat-composer— BORRABAN prosa medida: donde un humano escribió «_Ninguno_ — los cuatro que había (el padding-block del divisor, el radio de foco de la fila de evento…) están cosidos», la plantilla dejaba «_Ninguno._», y en chat-composer se llevaba además el bloque de las cuatro declaraciones retiradas por muertas. Esas dos van cosidas: el cuerpo de HEAD con la línea de cabecera regenerada. El resto entra tal cual. Que la regeneración sea mayoritariamente buena y ocasionalmente destructiva es el peor reparto posible, porque nadie la mira. Registrado en §13 con su arreglo: extender los marcadores tipo veredicto:end a cualquier bloque que un humano haya ampliado, o que el generador respete una línea que no empiece por su propia plantilla. Mientras tanto, regenerar fichas y commitear sin leer el diff es una pérdida de datos silenciosa. Y con él, la hermana que reportó una sesión de la tanda: snapshot-y-restaura sobre un directorio COMPARTIDO pisa a quien escriba en medio. Dos sesiones hicieron cp -r de docs/audit/theming y la segunda restauró desde un snapshot anterior al trabajo de la primera, devolviéndole sus veredictos a «pendiente» a media faena. El árbol de trabajo también es compartido: respalda por FICHERO tocado, nunca por directorio. Quedan fuera a propósito las fichas de chat-message y tags-input: sus sesiones siguen trabajando. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
2b6b6aa10b |
docs(theming): el registro §8 recoge image-adjustments y separator, con su sha
Las dos entradas de la tanda, con el sha PUESTO (no el marcador `(COMMIT)`, que ya dejó trece filas sin resolver): `image-adjustments` 67 % → 100 % (`e76d2db2b`) y `separator` 67 % → 100 % (`acf9c3a23`). Lo que las dos dejan escrito, y no estaba en el registro: - **El techo puede estar en el contrato que YA existe.** `separator` cierra en el 100 % sin acuñar una sola clave: sus dos knobs fuera de alcance eran los `100%` de cada orientación, que son la IDENTIDAD del primitivo y se FIRMAN. - **Medir de más midió menos, y por un tope numérico**: el pase de hover del centinela recorre como mucho 30 nodos, así que ampliar `extraNodes` de una fila a seis empujó el control medido al puesto 32 y su token leyó muerto por una razón ajena a él. - **Un token muerto por la ORIENTACIÓN que la demo no monta se arregla midiendo**: `sweepAttr` sobre `data-orientation` recorre las dos sobre los mismos nodos, mientras que cambiar el chip de la demo cambia una por la otra. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
9e471e818d |
docs(theming): el registro §8 recoge collapsible y toolbar, con su sha puesto
Las dos entradas de la sesión del 24, cada una con el sha REAL del commit del componente (que es por lo que van en un commit aparte: trece entradas quedaron un día con el marcador `(COMMIT)` sin resolver y hubo que arreglarlas). - `collapsible` 90 % → 100 % (`1621de93c`) — una clave, la costura del `gap` del encabezado; el que ANIMA su apertura no tiene un solo knob de motion porque su firma es el par de eventos, no un `@keyframes`. - `toolbar` 91 % → 94 % CERRADO (`26713f288`) — cero claves acuñadas: sus dos privados son conmutadores por variante cuya segunda rama es la identidad de la variante, y ceder el cromo del botón al `<Button>` compuesto le sale GRATIS, al revés que a `form`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
acf9c3a234 |
uix(separator): temable — 67 % → 100 %, SIN acuñar una sola clave
Su alcance no subía porque le faltaran tokens: subía firmando lo que nunca fue
un knob. Los dos que quedaban fuera eran `inline-size: 100%` en el horizontal y
`block-size: 100%` en el vertical — la IDENTIDAD del primitivo. Una regla ocupa
su contenedor; un separador que no lo hiciera sería otro componente, y su propio
README ya lo decía en sus Gaps («Horizontal already fills 100%»). Llevan ahora su
anotación `/* literal: … */` (recipe-contract §3) y salen del ratio.
Contrato **3 → 3 claves**: no entra ninguna, y ésa es la decisión. `thickness`
(el mismo token alimenta `block-size` en horizontal e `inline-size` en vertical),
`fg` (el slot 6 `--color-neutral-separator`, que existe para retocar divisores
sin tocar bordes de control) y `min-length` son TODA su apariencia. Acuñar un
`--separator-length` habría sido inventar un eje que nadie pidió.
Censo: 6 knobs · 4 públicos · 2 literales · **67 %**
→ 4 knobs · 4 públicos · 0 literales · 2 excepciones · **100 %**.
Diff de computed **VACÍO**: 448 valores, 7 estados, sonda antes y después
(el cambio es de comentarios: no puede mover un píxel, y se midió igual).
Capturas 2× antes/después, miradas: idénticas.
Centinela R-5.4 **2/3 → 3/3, cero adjudicadas**, y ahí estuvo el trabajo:
`min-length` leía MUERTO y no mentía. La demo arranca en el ejemplo `stacked`,
que monta sólo reglas horizontales, y la mitad de la receta cuelga de
`[data-orientation='vertical']`. Se arregla midiendo, no adjudicando: un
`sweepAttr` sobre `data-orientation` en `COMPONENT_OVERRIDES` recorre las DOS
orientaciones sobre los mismos nodos. Cambiar el chip de la demo al ejemplo
`toolbar` no habría servido — cambia una orientación por la otra en vez de
sumarlas, la trampa de «montar MÁS puede medir MENOS» otra vez.
Guards: censo `--only separator` 100 % · `component-audit` PASS ·
`eidos-lint` invalid 0 · `vitest run src/uix/eidos` 35/36 ficheros (el rojo
conocido `skin-media-player`) · `rtl:check` 0 · `docs:check` 0 · `check` sin un
solo error atribuible a este componente · prettier limpio con el contenido
normalizado a LF.
Más el README con su sección «Talla y tema», la pestaña `Tokens` de la demo
(3 claves, verificada en navegador) y el veredicto §5 de su ficha, que escribe
la cifra cerrada: el techo de este componente ES el 100 %.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
26713f2887 |
uix(toolbar): temable — 91 % → 94 % CERRADO, y ceder el cromo del botón SALE GRATIS
Cero claves acuñadas, y eso es el resultado: el censo daba `global 0` — la receta ya lee su propio contrato en cada declaración, con el eje `size` resuelto por el TSC a través de siete privados que sólo reapuntan claves públicas por talla. Lo que quedaba fuera del alcance eran tres cosas CLASIFICADAS, no tres deudas. La mitad del trabajo de este eje es adjudicar. 1. Los DOS privados son CONMUTADORES por variante, medidos variante a variante sobre el nodo real: `--_toolbar-bg` vale `var(--toolbar-bg)` (oklch(0.9821 0 0)) en `surface` y `transparent` en `outline` y `ghost`; `--_toolbar-shadow` vale `var(--toolbar-shadow)` y `none` en las mismas. Ese segundo valor es la IDENTIDAD de la variante, no un knob: una barra `ghost` ES la que no tiene relleno ni sombra, y un público encima dejaría que un tema la rellenara y matara la variante en silencio. Se quedan privados (clase «conmutador» de F2-B, sexto caso tras textarea, spinner, skeleton, code y label). Ni escala por talla ni puente THM-2: esta barra no tiene paleta. 2. El único literal es una IDENTIDAD y ahora está FIRMADO: el `inline-size: 100%` del separador horizontal abarca el eje transversal de la barra — el mismo trabajo que `align-self: stretch` hace en el gemelo vertical (medido: 112 px sobre un contenedor de 126 px). Su grosor y su suelo sí son tokens. Con su anotación `/* literal: */` sale del ratio. 3. LA CASCADA DEL COMPONENTE COMPUESTO NO LE CUESTA UNA SOLA CLAVE, y es la lección. `Toolbar.Button` compone el `<Button>` canónico, así que sus nodos llevan `data-button` Y `data-toolbar-button`, y `[data-button]` casa con la misma especificidad (0,1,0) pero se emite DESPUÉS. La diferencia con `form` —que conserva 24 declaraciones que Button anula— es que esta receta YA CEDIÓ el cromo del botón (A-112) y no escribe ni una regla `[data-toolbar-button]`. Medido ANTES de tocar nada: 51/54 vivos, y ninguna de las tres silenciosas era del botón. Las claves `control-*` visten el Link y el GroupItem, que sí son superficie de la barra. Censo: 35 → 34 knobs · público 30 · privado 2 · literal 1 → 0 · excepción 0 → 1 · sistema 2 · 91 % → 94 %. Contrato 54 claves, intacto. Global del catálogo 68 %, sin bajar. Diff de computed: VACÍO — 2.464 valores en 7 estados sobre 11 nodos (la barra, sus tres botones compuestos, dos separadores, el grupo, sus tres items y el enlace). Capturas 2× antes/después: idénticas. Centinela R-5.4: 52/54, dos adjudicadas, cero muertas sin razón. - `transition-duration` / `transition-ease` SON la transición que el guard congela para poder leer todo lo demás. Medidas sin congelar sobre el Link real, que transiciona CUATRO propiedades: `0.12s ×4 → 4.321s ×4` y `cubic-bezier(0.4, 0, 0.2, 1) ×4 → steps(3) ×4`. Al ledger con esa razón. - `disabled-opacity` NO se adjudica: se ARREGLA. El guard enciende ahora el interruptor «group disabled» de la demo, y comprobado que no tapa nada — la regla de hover es `[data-toolbar-link]:hover, [data-toolbar-group-item]:hover:not([data-disabled])` y el Link no pertenece al grupo, así que conserva las dos claves de hover. Corrido antes y después del control: 51/54 → 52/54, el conjunto muerto encoge en uno y no gana ninguno. Guards: censo `--only` 94 % · `component-audit --only toolbar` PASS · `eidos-lint toolbar` 16 morfo-backed / 5 eidos-only / 0 invalid · `vitest run src/uix/eidos` 35/36 ficheros (el rojo es `skin-media-player`, el conocido) · `rtl:check` 0 · `docs:check` 0 · `check` COMPLETED sin un solo error atribuible a este componente · prettier: la anotación `/* literal: */` sobrevive en la MISMA línea y mi bloque del README queda limpio; los 12 hunks de deriva del README y los 12 de la demo son PREEXISTENTES en HEAD y no se tocan. Artefactos de documentación del protocolo: README con su `## Talla y tema` derivada del contrato (los nueve ejes + la clasificación de los privados), pestaña `Tokens` en la demo (54 claves resueltas en vivo, verificada en navegador) y veredicto §5 de la ficha. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
e76d2db2be |
uix(image-adjustments): temable — 67 % → 100 %, y medir de MÁS midió menos
Sus cuatro knobs fuera de alcance eran LA COSTURA (PLAN §2-A) y ninguno una
clave nueva de diseño: el valor se queda donde estaba, el knob pasa a ser del
componente.
Entran cuatro claves (contrato 12 → 16), valor verbatim:
- `head-gap` = `var(--space-2)` y `label-line-height` = `var(--leading-ui)`,
que la receta leía a pelo — un tema no podía apretar la línea de cabecera sin
mover esos primitivos en toda la app.
- `hover-reset-fg` = `var(--color-content-primary)`. NO es un hover inventado
por componente: es TINTA, y el velo del sistema es `background-image`, que un
control sin superficie no puede recibir. Molde del catálogo: once
`hover-{parte}-fg` ya escritos así.
- `focus-reset-radius` = `var(--radius-sm)`. Precedente exacto
`rating-group.focus-radius`, la misma declaración dentro de la misma regla
`:focus-visible`. La §4 generada proponía `reset-radius` (el control no tiene
radio en reposo) e `item-label-line-height` (el bloque ya habla `label-*`):
el catálogo decide el nombre, no la propuesta.
El literal que quedaba se FIRMA, no se acuña: `outline-color: Highlight` bajo
`@media (forced-colors: active)` es la palabra clave del sistema — la paleta del
SO manda ahí. Pasa a `exception`, fuera del ratio.
El canal de VALOR sigue sin acuñarse y aquí no había ninguno que confundir: la
salida del panel es la CADENA `filter` que soma entrega por `onFilterChange`,
nunca toca el CSS de la receta.
Censo: 18 knobs · 10 públicos · 4 global · 1 literal · 3 sistema · **67 %**
→ 17 knobs · 14 públicos · 0 global · 0 literal · 3 sistema · 1 excepción
· **100 %**.
Diff de computed **VACÍO**: 5.440 valores, 7 estados, 26 nodos, sonda antes y
después. Capturas 2× antes/después, miradas: idénticas.
Píxel hacia arriba (§7.4-12, obligatorio porque toca una regla `:hover`): el
píxel bajo el puntero ES el `<button data-image-adjustments-reset>`; el hover
mueve `color` y SÓLO `color` en ese nodo (oklch(0.5032 0 0) → oklch(0.2435 0 0))
y ni él ni un solo ancestro pintan `background-image`, ni en reposo ni en hover.
Centinela R-5.4 **15/16**, 1 adjudicada — y el instrumento enseñó dos cosas:
1. `hue-track` leía muerto (11/12) y estaba vivísimo: pinta en el `::before` del
`<Slider>` COMPUESTO, cuyo nodo lleva `data-slider*`. Clase de `waveform`.
`extraNodes` en `COMPONENT_OVERRIDES`.
2. Ese selector apunta SÓLO a la fila `hue`, y la precisión es funcional: con
las seis filas el conjunto medido pasó a 32 nodos y el reset se volvió el
nº 32, fuera del tope de 30 del pase de hover — `hover-reset-fg` leía muerto
por una razón ajena al token. **Medir de más midió menos.**
La adjudicación restante es de estado: `focus-reset-radius` sólo pinta bajo
`:focus-visible` y el guard desenfoca a propósito; medido a mano sobre el
reset real, 4px → 1234px.
Guards: censo `--only image-adjustments` 100 % · `component-audit` PASS ·
`eidos-lint` invalid 0 · `vitest run src/uix/eidos` 35/36 ficheros (el rojo
conocido `skin-media-player`) · `rtl:check` 0 · `docs:check` 0 · `check` sin un
solo error atribuible a este componente · `--names` sin desviadas suyas ·
prettier limpio con el contenido normalizado a LF.
Más el README con su sección «Talla y tema», la pestaña `Tokens` de la demo
(16 claves, verificada en navegador) y el veredicto §5 de su ficha.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5fd2fcdd86 |
uix(fab): temable — 88 % → 100 %, y el modo va DETRÁS, no delante
Le faltaban DOS knobs y los dos son del pill extendido: el FAB circular no declara ni `padding-inline` ni `gap`, pero la regla `[data-button][data-fab][data-extended]` sí, y leía `var(--space-5)` / `var(--space-2)` A PELO. La COSTURA del PLAN §2-A: el valor sigue siendo del sistema, el knob pasa a ser del componente. `global` a CERO. Claves que entran (2, defaults verbatim): - `--fab-padding-inline-extended: var(--space-5)` - `--fab-gap-extended: var(--space-2)` El nombre lleva el cualificador DETRÁS. `extended` es un MODO del FAB, no un estado interactivo (el vocabulario cerrado es hover · active · selected · disabled · checked · open · focus · invalid · current), así que cae en la otra mitad de la frase firmada en D-TH.6 —«delante lo interactivo, detrás lo dimensional y contextual»—, igual que `sidebar.width-icon` y `radio-group.gap-vertical`. Un `--fab-padding-inline` a secas habría prometido a TODO FAB un padding que sólo tiene el pill. Lo que NO se acuña, y por qué el 100 % no lleva las tres claves de la §4: el `font-size: 1em` del glifo es identidad de contexto y ya lleva su anotación `/* literal: */` (fuera del ratio por recipe-contract §3), y la colocación flotante es de la capa `viewport-placement`, cuya ranura de override Fab escribe sin acuñar vocabulario paralelo (`--fab-offset` / `--fab-z` se retiraron por eso en 2026-08-15). La composición NO le quita nada, y valía la pena medirlo: el mismo `<button>` lleva `data-button` Y `data-fab`, la forma exacta del hallazgo de `gradient-picker` (36 claves muertas bajo `popover.css`). Aquí no ocurre por construcción — las reglas dimensionales del FAB casan `[data-button][data-fab][data-fab-size]` (0,3,0) contra los (0,2,0) de `[data-button][data-size]`, así que ganan sea cual sea el orden de carga de los chunks. Medido: padding computado 20px = `--space-5`, no el del Button. Tampoco lleva `data-depth`, así que §12.9 no le aplica. Censo: 16 knobs · público 14 → 16 · global 2 → 0 · excepción 1 (fuera del ratio) · 88 % → 100 %. Contrato 10 → 12 claves. Diff de computed: VACÍO en las dos formas. 416 valores × 7 estados en el escenario por defecto (circular, sonda estándar) y 188 valores × 4 tallas + hover en el pill extendido, con una sonda de un solo uso porque la demo arranca circular. Capturas 2× antes/después byte a byte IDÉNTICAS en las dos. No se tocó ninguna regla `:hover`, así que el paso 12 no aplica. Centinela R-5.4: **11/12**, 1 adjudicada. `lift` es la laguna del INSTRUMENTO, no del token: la receta lo consume con la propiedad `translate` (no `transform`, para no pisar el press-squeeze del Button) dentro de una regla `:hover`, y el guard ni fotografía `translate` —la misma laguna ya adjudicada tres veces sobre `transform` en background / rating-group / card— ni pasa el ratón en su pasada estática. Medido a mano con puntero real: `--fab-lift: 1234px` escrito ANTES de entrar da `translate: 0px -1234px` a los 300 ms → alcanza. Y trae una trampa nueva: el centinela SE AUTO-CANCELA — un lift de ese tamaño se lleva el nodo de debajo del cursor, `:hover` cae y el valor vuelve a `none` hacia t+900 ms. Añadirle una pasada de hover al guard no lo mediría. El instrumento aprendió dos cosas de este componente, las dos por el §2 «cuenta los nodos»: un FAB es UN nodo, así que su segunda superficie pintada —el hueco de icono del Button compuesto— entra por `EXTRA_NODES` (1 → 2 nodos); y su eje de talla es `data-fab-size`, NO `data-size`, así que el barrido genérico del guard no sellaba nada. Con el barrido cartesiano `data-fab-size` × `data-extended` el guard pasa de **3/12 a 11/12** sin adjudicar una sola clave de más. Los dos interruptores son entradas por componente: no tocan a nadie más y no exigen re-verificar el ledger. Guards: censo `--only fab` 100 % (global 68 %, no baja) · `--names` 12 conformes, 0 desviadas · `component-audit --only fab` PASS · `eidos-lint fab` 0 invalid (14 eidos-only) · `vitest run src/uix/eidos` 35/36 ficheros, el único rojo es el conocido `skin-media-player` en `lint.test.ts` · `rtl:check` 0 · `docs:check` 0 · `npm run check` COMPLETED, cero errores en los ficheros tocados (los 72 globales son de otras sesiones) · prettier limpio sobre el contenido normalizado a LF. README con su sección «Talla y tema» (tabla derivada del contrato), pestaña `Tokens` en la demo verificada en navegador (12 claves, cero errores de página) y veredicto §5 escrito en la ficha. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
1621de93c4 |
uix(collapsible): temable — 90 % → 100 %, y el que ANIMA no tiene un knob de motion
Una sola clave, y es la COSTURA (PLAN §2-A): el `gap` del encabezado leía `var(--space-2)` A PELO. El valor es del sistema; el knob no era de nadie, así que un tema no podía apretar esta cabecera sin mover el paso de espaciado en toda la app. El nombre lo decide el CATÁLOGO, no la propuesta de la ficha: `trigger-gap` ya existe ocho veces en `base.ts`, cinco de ellas con exactamente `var(--space-2)`. Qué entra: - `--collapsible-trigger-gap: var(--space-2)` — valor verbatim, cero píxel. Qué NO entra, y por qué: - Los dos knobs restantes son SISTEMA TRANSVERSAL, fuera del ratio: el velo de hover es `linear-gradient(var(--state-hover), var(--state-hover))` (la capa de `archetypes.css`, nunca una invención por componente) y el anillo de foco es `--focus-ring-*`. - **No hay clave de motion que acuñar.** Este componente «anima su apertura» y aun así su receta no declara un solo `@keyframes`: la firma es el par de eventos `emerge-expand` / `emerge-collapse` que materializa `EidosConfig.motion.signatures` (recipe-contract §2, R-4.5). Lo único suyo es el par `transition-*`, que ya estaba en el contrato. Censo: 12 knobs · público 9 → 10 · global 1 → 0 · sistema 2 · 90 % → 100 %. Contrato 11 → 12 claves. Global del catálogo 68 %, sin bajar. Diff de computed: VACÍO — 736 valores en 8 estados (reposo, cinco tallas, abierto y hover) sobre 3 nodos, que son las TRES partes del morfo, en cerrado y en abierto. Capturas 2× antes/después, reposo y abierto: idénticas. Centinela R-5.4: 10/12, dos adjudicadas, cero muertas sin razón. - `transition-duration` / `transition-ease` SON la transición que el guard congela para poder leer todo lo demás (la clase que `color-picker` documentó el 2026-08-23). Medidas sin congelar sobre el encabezado real: `0.18s, 0.18s → 4.321s, 4.321s` y `cubic-bezier(0.4, 0, 0.2, 1) ×2 → steps(3) ×2` — dos entradas porque el trigger transiciona `background` Y `color`. Al ledger con esa razón. - `disabled-opacity` NO se adjudica: se ARREGLA. Encender el interruptor `disabled` de la demo para toda la corrida se habría llevado el tinte de hover por delante (`pointer-events: none` en el provider — «montar más mide menos»), así que el estado se mide como SUPERFICIE EXTRA por la URL de la demo (`?perm.disabled=true`), precedente `radio-group`. 8/11 → 10/12. Guards: censo `--only` 100 % · `component-audit --only collapsible` PASS · `eidos-lint collapsible` 7 morfo-backed / 0 invalid · `vitest run src/uix/eidos` 35/36 ficheros (el rojo es `skin-media-player`, el conocido) · `rtl:check` 0 · `docs:check` 0 · `check` COMPLETED sin un solo error atribuible a este componente · prettier: mi bloque limpio, la deriva del README y de la demo es PREEXISTENTE en HEAD y no se toca. Artefactos de documentación del protocolo: README con su `## Talla y tema` derivada del contrato, pestaña `Tokens` en la demo (12 claves resueltas en vivo, verificada en navegador) y veredicto §5 de la ficha. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
bf6cd201cf |
docs(theming): el handoff recoge la deuda B saldada — quince de dieciocho
Quedan tres, y los tres por una razón concreta: audio-player no tiene README de eidos donde escribir la sección, y palabras y proof-of-human son carriles propios. Y queda anotada la deuda hermana que destapó hacerlo: ninguno de los quince tiene pestaña Tokens en su demo, porque el paso 11 del protocolo llegó después de que cerraran. Hasta que la tengan, la tabla del README es la fuente — está escrito en los quince README, no sólo aquí. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
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 |
|
|
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 |
|
|
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 |