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 }
245 Commits (2c0fca431989ccec6955a582a9f5b0f788de19bd)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
53810cb5ec |
refactor(eidos): item 2 - los slots de forma de la capa deslizante llevan el _ del alias
Firma (a) del autor: --indicator-duration/-ease eran el ALIAS de la capa (la especie de --_indicator-x, opcionales-con-fallback), no un pomo de tema - la ortografia bare prometia una superficie que la cascada negaba. Flip a --_indicator-{duration,ease} (1 escritor radio-group.css alimentando desde sus claves de CONTRATO segmented-transition-*, 1 lector lib/sliding-indicator.css); reparto de propiedad escrito: la capa posee QUE propiedades deslizan (y su colapso reduced-motion), el anfitrion A QUE VELOCIDAD via contrato. Contrafactico MEDIDO pre-flip: bare en :root a 9s = 0.18s intacto (no se retira superficie); post 4/4: pixel identico, bare inerte y vacio en el pill, contrato alcanza (7s), alias en :root inerte. Comentarios themeable-so-bare reescritos; prosa del sentinel al nombre vivo (clave intacta). Lint 0 invalid, reach-floor 5/5, censo neutro.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
1cb07c1e15 |
refactor(morfo): data-ready es contrato — los morfos lo declaran y la bolsa lo emite
Item 0 del handoff theming (firma ii del autor, 2026-08-27): el estampado manual de data-ready muere en los dos providers; la parte indicadora de tabs y la selection-indicator de radio-group declaran el estado 'ready' (stateRef, presence, severity optional) y el render bag lo emite desde la fuente registrada (() => indicator.ready). ready no es prop: es un hecho de runtime de la instancia — la misma especie que checked o active. La puerta anti-flash (tabs.css:329, sliding-indicator.css:66) queda declarada donde el guard la exige; 'data-ready' sale de EIDOS_ONLY_ATTRS con acta en el propio fichero (ya no es eidos-only: es contrato). Verificado: guard "hardcoded Soma component data attrs" sin los 2 rojos de este eje - morfo 16/16 (222 tests) - suites tabs/radio-group + visual-attrs 3/3 - eidos-lint: [data-tabs-indicator]:not([data-ready]) pasa a morfo-backed, 0 invalid en ambos - dinamica CDP: tabs ready="" opacity 1 y desliza (translate 0 -> 103.9px, inline-size 99.9 -> 75.8); radio-group segmented ready="" y el pill desliza; control negativo: pane oculto (rAF congelado) = sin medida, sin attr, opacity 0 — la puerta anti-flash aguanta. Viajan con atribucion declarada (acuerdo por canal con la sesion P0 vicen-42): las altas de data-aura-status-label/detail y data-waveform-played/remaining en scripts/eidos-only-attrs.ts son suyas (sus guards de contracts.test); su commit sigue a este por dependencia (su guard consume el registro y necesita estas declaraciones en el arbol). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
613215fe7c |
docs(theming): el dia queda cerrado - handoff 2026-08-26, causa corregida y suelo en 66
Cierre documental tras el adversarial de SS14 (firma sostenida; un claim de
ACTA cayo y se corrige aqui):
- La causa de la extension transitiva del censo era CONTRAFACTUAL en tres
sitios (census.ts, next-features, CONTINUE): el alias de SS14 no lleva
prefijo propio y el censo lo descarta antes - clasifica global con la
razon CORRECTA (medido construyendolo: 1 new, rojo). La extension se
justifica por tooltip (alias propio sobre canal propio), no por el alias.
Reescrita con el contrafactico medido.
- El suelo sube a minAtHundred 66 - SS14 llevo a tabs al 100% y el
adversarial cazo el suelo rezagado de su propia ley ("only moves up").
- SS15 NUEVO en next-features, redactado por el adversarial: el GEMELO un
piso arriba - floating.svelte.ts publica cinco medidas de instancia como
--floating-* (publico sin dueño, ~8 recetas lectoras); mas grande que SS14
porque el posicionador sirve a muchos hosts. Dimensionar antes de firmar.
- Handoff 2026-08-26: las cinco firmas del dia con sus adversariales, lo
primero de mañana por orden de valor (SS15 - la especie de forma sin dueño
- cableado motion - palabras/timeline), el estado de la rama compartida
(peer vicen-63 con su C2c/hook, que push falta) y las leyes nuevas del dia
(el nombre dice la verdad en las dos direcciones; grep ciego a llaves;
sonda ciega a canales; una causa sin contrafactico acaba corregida).
Suelo 5/5 con 66 - docs:check 0/0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
8ac23047f1 |
refactor(theming)!: MeasuredIndicator escribe en el namespace del HOST - la capa es la pluma, no la dueña
Firma SS14 (2026-08-26, nombre poseido tras rechazar el nombre generico de
capa: habria repetido el defecto un piso abajo). La capa compartida
publicaba el rect medido como --indicator-{x,y,w,h} - forma PUBLICA sin
dueño, invisible para la ley del espacio cerrado (que audita --{c}-*) y
para todos los guards. Tercera aplicacion de la doctrina del canal
(navigation-menu fue la segunda, tabs la habia firmado por escrito citando
a navmenu como precedente).
- MeasuredIndicatorOpts gana `component: string`; los DOS hosts (tabs,
radio-group - barrido completo, no hay mas) pasan xxxMorfo.kebab, NUNCA
un literal: el nombre del canal queda atado a la declaracion que lo posee.
- tabs.css lee el poseido directo; el css COMPARTIDO (sliding-indicator)
lee el alias local que cada receta declara (--_indicator-x:
var(--_radio-group-indicator-x)) - el cableado del puente THM-2, contrato
en el artefacto. --indicator-{duration,ease} INTACTOS a proposito: son
ranuras de FORMA, no canal - el _ separa las dos especies en el mismo
fichero; su falta de dueño queda flagged como especie pendiente.
- El censo aprende el CANAL TRANSITIVO (molde de derivesFromPublic,
memoizado, a prueba de ciclos, con la mutacion que impide que un alias
sobre un privado declarado clasifique canal). Efecto colateral MEDIDO con
acta: tooltip.css:27 pasa de exception a channel - su comentario firmado
ya decia "per-instance VALUE CHANNEL"; faltaba el mecanismo, no el
criterio.
- Ledger: la clave tabs RETIRADA entera (2 entradas global) con acta que
hace la lectura honesta - no se tokenizo nada ni se perdono deuda: se
corrigio una mala clasificacion en su fuente. 1154 -> 1152, 0/0.
- Numeros: tabs 97% -> 100% (global 2->0, channel 0->2, ni una clave
acunada) - atHundred 65 -> 66 - reach global 73% y public 3072 intactos.
- Dinamica verbatim en los dos hosts (radio-group manifiesta en segmented):
el canal poseido LLEVA el rect del item activo (x 784=784, w 71=71 /
x 793=793, w 102=102), el indicador desliza, los nombres viejos computan
vacio, control negativo quieto y positivo probando la CADENA del alias.
Re-verificado DESPUES de aterrizar el codemod del peer. Sonda estandar de
tabs 2528 valores x 10 estados a 0 diffs - dicho en voz alta: esa sonda
es CIEGA al canal; su 0 prueba lo circundante.
- Guards: 154 tests verdes - centinela tabs 70/79 identico (ninguna
adjudicacion citaba las medidas) - audit 162 PASS - docs:check 0/0 -
src/ sigue a 0 errores.
ATRIBUCION DECLARADA (acordada por canal entre sesiones): este commit CARGA
ademas la retirada de 5+5 `syncAttrs: true` en tabs-provider y
radio-group-provider - trabajo de "P0 fase C2c, audit 2026-08-26 - retirada
de syncAttrs, sesion de la auditoria" (vicen-63), que aterrizo en disco
durante esta construccion y cuya restauracion habria sido churn sin valor.
Su commit de C2c anota el viaje desde el otro lado.
BREAKING: --indicator-{x,y,w,h} ya no existen; el canal es
--_{c}-indicator-* del host y el css compartido lee el alias por receta.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
9dffa541ef |
fix(uix): fase A cierre — los seis rojos del censo morfo:check, adjudicados
Cada uno leído antes de tocarlo; tres clases distintas: - combobox.input y gradient-builder.track: el morfo declara el data-* SIN value (soma posee el valor — el idioma que el propio trigger de combobox documenta) y nadie lo escribía. El comentario del input además afirmaba que la bolsa lo resolvía, cosa que una declaración sin fuente no puede hacer. Escritura manual, como sus hermanos. - menu-dial.trigger: componente de scope eidos (contrato espejado a mano); el trigger estampaba marker y aria pero olvidó data-state — la lista de al lado sí lo lleva. Espejo del idioma existente. - calendar (data-calendar-surface) y fab (data-fab-size): attrs visuales de wrapper / hooks compartidos de eidos, sancionados FUERA del morfo por la doctrina firmada (precedente: data-combobox-control). El instrumento no conocía la doctrina: nace scripts/eidos-only-attrs.ts como lista ÚNICA que consumen morfo-check y eidos-lint-all, para que los dos instrumentos no puedan divergir. - palabras.handle: el grip porta el escape del focus-scope a propósito (comentario in situ con la razón); la declaración alcanza a la implementación sancionada. Los otros cuatro rojos del censo previo no eran contrato: accordion, background y link eran timeouts de compilación fría (pasan en caliente) y color-field lo sanó la unificación de la bolsa por sí sola. Verificación: morfo:check 160/161 con los seis en PASS — el único rojo restante (natural-time-picker) es la clase flaky del instrumento «demo que navega bajo el eval» (no falló en ninguna de las dos pasadas previas; la ruta verificada a mano en navegador con su contrato completo) · schema sweep 89/89 · eidos:lint exit 0 · combobox 11/11 · palabras 84/84. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
2ec0181079 |
feat(gate): fase B de P0 — la puerta existe y sabe fallar
El hallazgo mayor confirmado de la auditoría 2026-08-26: ~16 validadores y
429 ficheros de test que nada ejecutaba (sin CI en ninguna rama de la
historia, hooks .sample, eidos-lint sin script npm). Esta fase los cablea:
- `check:gate` (scripts/check-gate.ts): svelte-check con política — src/
debe cero; web/ se mide contra el ledger menguante scripts/check-debt.ts
(34 ficheros, 71 errores congelados; sólo puede bajar, la disciplina de
theming-census-debt). Guard anti-vacío: sin marcador COMPLETED o con
conteo que no cuadra, falla — un gate que no inspeccionó nada no pasa.
- `eidos:lint` deja de ser invocación cruda (exit 1 real en invalid/dead).
- `gate`: check:gate → validadores rápidos → vitest al final. `lint` queda
deliberadamente FUERA: hay ~2.300 ficheros de deuda de formato
preexistente (nunca se formateó el repo entero; el one-shot pendiente es
`npm run format` en árbol quieto y re-añadirlo — documentado en el hook).
- scripts/hooks/pre-push: la fuente del hook, SIN armar. Se armó en
caliente, bloqueó el push legítimo del eje theming (secuencia mal: verde
primero, puerta después) y se desarmó — de paso la puerta demostró que
sabe fallar, que era el requisito de verificación de la fase.
- .prettierrc endOfLine:auto — neutraliza la clase CRLF/autocrlf de
Windows (~350 falsos rojos), sin cambiar formato real.
Verificación: check:gate exit 0 sobre HEAD (71 dentro del ledger, src/ a
cero tras
|
1 month ago |
|
|
cec75d04e4 |
docs(theming): la deriva que midio el adversarial del espacio cerrado
7/7 claims confirmados; la acunacion de phone-shadow resulto ser la pieza que impide una regresion que el commit habria metido sin ella (verificado el contrafactico). Tres derivas de prosa de la propia firma, saldadas: - base.ts: text-scramble gana sus dos anotaciones - el default `inherit` es inerte POR MECANISMO (CSS-wide keyword en :root -> IACVT -> unset -> hereda, que ES la intencion) y `--font-mono` es nombre de capa app que eidos nunca emite (misma clase que el primitive-neutral-12 de mockup, anotada igual). - color-swatch/README: "la forma que recipe-css-contract sanciona" paso a pasado con anotacion fechada - la sancion la retiro esta ley; la adjudicacion (canal de valor, fuera del contrato) queda intacta y el nombre vive en PENDING_PRIVATE_RENAME con su destino. - component-audit: la nota de R-5.2 que describia el idioma como sancionado se reescribe a la ley nueva (y de paso al ingles, ley del repo). Censo byte-identico tras los comentarios (los lectores textuales de base.ts no se inmutan: 4914/3074/73%, text-scramble 4 knobs contract 2), 50 tests verdes, docs:check 0/0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
1c239bf797 |
docs(theming): precision de prosa que midio el adversarial de los 318
13/13 claims confirmados (particion re-derivada clave a clave, 22 css 100% comentario por tokenizador propio, valvula irrompible ante declaracion ajena, suelo 73/65 exacto sin holgura, canario del centinela byte-identico). Cuatro precisiones de prosa, ninguna de clasificacion: - component-audit: el bloque R-5 decia 1088/74 (cifras del 25); ahora ancla 1154/76 al baseline del 26 con fecha. - theming-census: "los 29 nombres tienen escritor en envoltorio o soma" era 28 de 29 - el 29 (scroll-frames viewport) es el hatch que su contrato firma como geometria del SITIO: su escritor es la pagina, por diseño. - CONTINUE: unidades normalizadas en la lista de contradicciones (timeline 10 knobs/5 notas - listbox 6 knobs/5 notas - proof-of-human ya decia knobs). - recipe-contract: el "(1088 -> 1087)" historico gana su "that day" para no leerse como estado. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
90b93a79e0 |
docs(theming): la firma de los 318 queda EJECUTADA - el suelo sube a 73/65
Tercera pieza (F3): los ratchets suben en el commit que los gana y la prosa "318 sin ratchet" pasa a historia fechada. - Suelo: reachPct 69 -> 73 (3074/4228; el numerador NO se movio - ninguna receta cambio un valor; el denominador cayo exactamente los 252 que dejaron de contar como no-alcanzados: 132 bridge + 36 channel + 84 anotados; los 66 del ledger SE QUEDAN dentro) y minAtHundred 45 -> 65. Mordida verificada en ambas direcciones (74/66 -> rojo con el mensaje exacto; restaurado -> 5/5). El bloque de doctrina cuenta el CIERRE del agujero, no el agujero: los dos ratchets dicen lo mismo desde dos alturas - el suelo rechaza una caida NETA, el ledger una clave sin nombre. - recipe-contract SS4: la ley completa de las CINCO salidas de un privado no-derivado (bridge mecanico - channel mecanico - anotacion private: - entrada de ledger - derivar de un publico). 1088 -> 1154 donde era estado. - CONTINUE: la firma pendiente -> EJECUTADA 2026-08-26 con su seccion ( |
1 month ago |
|
|
a74aeec7b6 |
feat(theming): los 150 privados del residuo quedan adjudicados - 84 firmados, 66 contados
Segunda pieza de la firma de los 318 (F2). El residuo que F1 dejo se
adjudica POR CLAVE, cada acta con su medida: 150 = 84 ANOTADOS + 66 al
LEDGER + 0 sin nombre.
- Valvula nueva /* private: <razon> */ -> clase exception (vocabulario
cerrado). Corre en una CUARTA pasada, la ultima: donde una prueba mecanica
ya decidio, una firma no tiene nada que firmar. La nota va en el bloque de
comentario ENCIMA de la declaracion (al final de linea, prettier partiria
el var() - un commit de anotacion no reescribe el CSS que viene a firmar);
el paseo hacia arriba solo salta lineas que eran solo-comentario.
- private es DebtClass: clave `private - {fichero} - {selector} -
{propiedad}`, newDebt y STALE simetricos. Un privado no-derivado nuevo ya
no puede entrar sin nombre. Ledger 1088 -> 1154 (+66, 0 claves perdidas,
verificado contra el blob de HEAD, no regenerado en bloque).
- ANOTADOS 84: 59 con ficha SS5 firmada que lo dice (card, avatar, badge,
surface, switch, timeline, textarea, spinner, skeleton, metrics,
float-panel, image, toolbar, button, drawer, listbox) + 25 medidos
(proof-of-human 17: el puente UN NIVEL bajo el knob, base verbatim del
forward, medido dos veces; form 4: conmutador-identidad; 4 sueltos).
- LEDGER 66: casi todo UN patron - el conmutador de tono A MANO
([data-color=risk] { --_c-accent: var(--color-risk-solid) }) sin adoptar
el forward THM-2 (time-range-picker 19, chronos 14, time-picker 12,
date-range-picker 9...) mas las tallas prestadas de field. Se retiran el
dia que esa familia adopte la escalera de paleta.
- Contradiccion con ficha RESUELTA por medida: metrics SS5 decia que el
conmutador del icono derivaba entero de publicos - cierto para track/text,
falso para solid/contrast (leen roles crudos): 3 anotados, 2 al ledger.
timeline SS5 (pre-B') se respeta y queda señalado para reabrir.
Mutaciones (backup+restore en finally, arbol comprobado): privado nuevo ->
newDebt lo nombra y suelo ROJO; anotado -> verde; registrado -> verde;
ledger'd que gana su nota -> STALE hasta borrar la linea. --debt final:
1154 registered - 0 new - 0 stale, dos corridas. Suelo 5/5, audit 162 PASS
sin flips, tsc 0 propios, diff de los 22 css = 100% comentario (verificado
por strip programatico contra el blob de HEAD), prettier 0 regresiones.
Reach 71% -> 73% (3074/4228). El suelo (69/45) y la prosa "318" los sube F3.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
e812d3ffd3 |
feat(theming): el censo distingue PUENTE y CANAL - 318 privados dejan de ser un bulto
Primera pieza de la firma "clasificacion de los 318" (F1). Dos clases nuevas
de knob, MEDIDAS contra el emisor y no adivinadas por nombre (la ceguera del
chooser, escarmentada en este mismo eje):
- bridge (132): el knob lee el privado que el forward THM-2 ESCRIBE -
verificado contra la CSS generada real (la linea `--_{c}-palette-{slot}:
var(--palette-{slot}, ...)` de renderRecipePaletteForward), no contra la
forma del nombre: un `--_c-palette-shadow` que nadie forwardea se queda en
residuo. Alcanzable DOS veces (capa --palette-* + tonos publicos); un
publico encima dejaria a un tema PINearlo y matar el color= por instancia
(los SS5 de card/tags-input/avatar ya lo decian).
- channel (36): el privado que NADIE declara - ni la receta ni el generador -
porque soma o el envoltorio lo escriben POR INSTANCIA (29 nombres, cada
uno con su escritor real verificado). Un tema no debe alcanzarlo.
- Precedencia puente > canal > residuo; `every`, no `some`; un privado
GENERADO nunca es canal (los 4 knobs de gradient finish quedan en residuo
con su razon medida - adjudicar una clase "finish" seria inventarla sin
firma).
Aritmetica: 318 = 132 puente + 36 canal + 150 RESIDUO (la adjudicacion por
clave es de F2). Ambas clases salen del denominador como system/structural:
reach 69% -> 71% (3074/4312). Cero knobs de otras clases movidos (diff
programatico de las 162 filas). Mutacion del instrumento sobre copia:
vaciar los forwards -> bridge 0; declarar-todo -> channel 0 - las clases
las manda la medida. Nuevo `--residue <out>` vuelca el residuo con la
cadena de fuentes de cada privado (el material de F2).
Casos firmados, contrastados: card 8 = 4 puente + 4 residuo (su SS5 exacto) -
tags-input 4/4 puente - toolbar 2 residuo ("esta barra no tiene paleta") -
avatar 6 residuo (su canal custom esta un nivel POR DEBAJO del knob) - el
indicador de tabs NO esta en los 318 (es clase global y ya vive en el
ledger de deuda).
Suelo 5/5 verde (el ledger literal|global no se toca; el ratchet grueso
sube en F3), audit 162 PASS identico, tsc 0 propios, prettier sin
desajustes nuevos. Deuda de prosa (los "318" en cabeceras/docs y el suelo
en 69) queda para F3, nombrada.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
1ba518fcc2 |
fix(theming): lo que el adversarial del cierre midio - numeros de prosa y el exit de --debt
La verificacion adversarial del cierre (11 confirmados, 2 refutaciones de NARRACION, 7 mutaciones con arbol restaurado byte a byte) dejo cuatro correcciones, ninguna de mecanismo: - El "114" de palabras eran 117 nombres --palabras-* consumidos (103 con fallback + 14 sin, los 117 bajo --palabras-scheme-*): el punto doctrinal sale REFORZADO - todo el canal es proyeccion del scheme. Corregido en el README y en la cabecera del ledger. - Los "18 sin contrato" de recipe-contract SS4 son 23: el titulo dejaba fuera a los cinco estructurales que su propia enumeracion lista dentro. Renumerado con el desglose recontado. - --debt no fijaba exit code: un modo de chequeo que no puede fallar es medio guard. Ahora process.exitCode=1 con deuda nueva o STALE (verificado por mutacion: HEAD exit 0, con literal inyectado exit 1, restaurado). - El 5o test del suelo se llamaba "mutation probe" y no muta nada: renombrado a lo que es (canario de cordura del scanner), con la historia de donde SI se vio el rojo por mutacion. Hallazgos del adversarial que quedan registrados sin ejecutar: las fichas de docs/audit/theming estan OBSOLETAS respecto a la clase structural (--report sin re-correr; tarea aparte con supervision por ficha) - el desglose "Knobs de apariencia" de la ficha no suma (preexistente) - el suelo de reach tiene ~0,5pp de holgura por redondeo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
69d69d43c6 |
feat(theming)!: R-5.1/5.2 a error contra el LEDGER DE DEUDA - el ratchet es por clave
La pieza grande del CIERRE, con la forma firmada hoy: la deuda de alcance no
se tolera en warn ni se disfraza de excepcion - se REGISTRA, clave a clave,
y desde ahi la regresion es imposible y la mejora queda contada.
- scripts/theming-census-debt.ts (NUEVO): 1088 claves (763 global + 325
literal, 74 componentes), clave `{clase} - {fichero} - {selector} -
{propiedad}` INDEPENDIENTE de linea (mover una regla no fabrica
regresion), comparacion MULTISET, generacion reproducible (dos corridas =
mismo sha256), nace prettier-limpio. NO es un fichero de excepciones: es
deuda registrada, la otra clase de acta - la valvula R-5.x exception de
los README sigue intacta y NUNCA ciega el ratchet. Los carriles WIP ENTRAN
(palabras 359 + chronos 209 = 568): la deuda es real viva donde viva, y
dejarla fuera haria del gate una afirmacion sobre dos tercios del arbol.
Con la salvedad MEDIDA de palabras escrita: sus nombres --palabras-* son
canal de VALOR del scheme del documento, no contrato de tema - sus 103
"public" del censo estan en cuestion.
- theming-census.ts: censusAudit() -> {newDebt, stale} + CLI --debt
[--write] que imprime el delta que va a cometer (regenerar en masa borra
el ratchet: el escritor grita y la cabecera lo prohibe sin firma).
- theming-reach-floor.test.ts (reescrito): newDebt=0 y stale=0 con las
claves NOMBRADAS; los techos burdos maxLiteral/maxGlobal RETIRADOS
(superseded por el por-clave: 5 regresiones ya no se esconden bajo 5
arreglos); reachPct sube a 69 como ratchet grueso - y cubre el hueco
nombrado: los 318 privados no-derivados siguen SIN ratchet por clave
(acotado por la firma a literal|global; pendiente de firma propia);
atHundred corrige su criterio (public>0, 14 -> 45: los 31 de diferencia
eran denominadores vacios, ninguno un avance real).
- component-audit.ts: filas R-5.1 y R-5.2 a ERROR consumiendo censusAudit()
(dos implementaciones de una medida son dos medidas); R-5.2 honesto sobre
los 18 sin-contrato (11 nada-que-declarar all-system/0-knobs; field-langs
cubierto POR el ledger - la entrada ES su registro; 3 consumidores de capa
calendar; mockup y text-scramble PASS con nota del idioma var(..,fallback)
sin contrato - forma real sin nombre, pendiente de decision; palabras
fuera del catalogo del audit). R-5.3 YA estaba en error (verificado,
--names 0 desviadas). El skip por censo roto ahora GRITA por consola (la
leccion del prepareWith: un guard saltado nunca es mudo - y el suelo de
vitest queda de red mecanica).
- docs: canon/recipe-contract.md SS4 y theming/reference.md SS12 reflejan la
ley (gate F3 = censo 100% ADJUDICADO); completion-checklist gana las dos
filas (exigido por el guard I5); el stub RECIPE_CONTRACT.md solo actualiza
su linea de enforcement.
Mutaciones, todas mordiendo: literal nuevo en mark -> newDebt lo nombra,
suelo rojo, R-5.1 falla; clave de aura tokenizada -> STALE rojo hasta borrar
la linea; literal sin registrar en field-langs -> R-5.2 muerde. Guards en
HEAD: component:audit 162 PASS (cero flips; los 4 NEEDS-WORK son R-1.x
ajenos), suelo 5/5, docs:check 0/0.
BREAKING: los techos maxLiteral/maxGlobal del suelo desaparecen; anadir un
literal o un global crudo a una receta exige desde ahora tokenizar, anotar
/* literal: */ o firmar la entrada en el ledger de deuda.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
2c61946fba |
feat(theming): la clase structural del censo - el 0% por NATURALEZA deja de contar como deuda
Pieza del CIERRE del eje (SS13: el censo no distingue "0% por deuda" de "0% POR NATURALEZA" y el gate de F3 era inalcanzable por construccion). Nueva clase structural en theming-census.ts, la forma de LAYER_VOCABULARY: la lista Y la razon por componente EN el artefacto, por COMPONENTE entero, con el SS5 firmado de cada ficha como fuente. No es un cajon para "este es dificil": una entrada exige veredicto escrito, y un componente que gane superficie de tema real sale de la lista. Los cinco medidos 2026-08-22: aspect-ratio (faceta de box, knob prestado) - text-blur (el 1px de la tecnica sr-only) - cascade y motion (el opacity del gate antiparpadeo, mecanica del canal cuyo valor vive en EidosConfig.motion) - date-picker (la correccion max-content del pie, un unico valor correcto). Aritmetica cuadrada: structural 9 knobs (global -1, literal -8), knobs 4998 intacto (salen del DENOMINADOR, como system), reach 68% -> 69%, no-contract 23 -> 18, <20% 12 -> 7. Diff de tablas: exactamente 5 filas cambian (0% -> strct), las otras 157 byte a byte. Los knobs estructurales se siguen LISTANDO en SS2-bis de su ficha con su razon; la seccion de propuestas los excluye (proponer un token contradiria el SS5). component:audit identico (162 PASS; el NEEDS-WORK de motion es R-1.1, raiz sin declarar, ortogonal al alcance). Suelo del censo verde con margen. Candidatos NO incluidos, reportados con dato: field-langs es deuda REAL (31 globales crudos) - range-calendar/month-grid/year-grid son la pregunta abierta de las capas compartidas - display/heading/text ya son all-system. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
4cb76403a0 |
docs(theming): la GRANDE EJECUTADA y verificada 12/12 - TONE_UNREACHED ha muerto
Cierre de la firma de instrumento grande. La verificacion adversarial
confirmo los 12 claims (aritmetica del ledger cargando el modulo en cada
commit, monotonicidad E2E con comparador propio, seis catas empiricas
incluida la sorpresa de tags-input dos veces y el test de dos caras del
PALETTE_FLOOR, la sonda sana, y la estatica fina del codigo).
- Corrige el acta de la retirada de tags-input en el ledger: la asimetria
del estampado (data-color en todos los nodos vs solo el proveedor) EXISTE
pero NO es la causa de la revivida - medido en forma de produccion, el
token mueve 6 nodos igual porque el privado hereda del proveedor al item.
- Anota en next-features SS13 las tres cegueras como EJECUTADAS (S1/S2/S3
con sus commits y numeros) y registra la deuda nueva del adversarial:
asimetria del estampado, ternario falsy de la restauracion de atributos
(
|
1 month ago |
|
|
b9cef9a43f |
fix(theming): S3 de la GRANDE - el guard mide TONO y ESTADO a la vez, y TONE_UNREACHED muere
Tercer barrido de la firma de instrumento grande (ceguera 2 + su cuarto
defecto). Cuatro piezas en theming-sentinel.ts:
- F2.1: el pase de hover estampa el tono (data-color + data-intent) y lo
restaura al salir, simetrico al estatico.
- F2.2: toneOf() con (^|-){tono}- a nivel de modulo, viajando como parametro
a los dos page.evaluate - el tono MEDIAL existe (censo: 4556 claves, 556
nombran tono, 16 mediales, las 16 de tag-group, cero falsos positivos).
- F2.3: el pase de hover corre para toda clave de TONO que siga muerta,
aunque su nombre no diga hover (las 21 de file-upload).
- F2.4: seis ejes de estado como DATO en COMPONENT_OVERRIDES, cada valor
sacado del morfo/receta/DOM real (button variant; switch state; checkbox
variant x state - indeterminate FUERA con medida, comparte bloque con
checked; radio-group +state; tags-input +state 4o eje; tag-group variant x
state). Ningun eje nuevo bajo ninguna cuenta.
Barrido S3 del ledger entero contra la base S2: 91/91, 43,8 min, 0 rojos,
0 avisos, 0 bajadas, 0 movedores ajenos - exactamente los nueve previstos,
+140 claves (catalogo 2778 -> 2918). 130 de las 132 TONE_UNREACHED reviven;
las 2 que no (checkbox/radio-group primary-solid-hover) nunca fueron la
clase: son el tono HOST por defecto, absorbidas en PALETTE_FLOOR tras el
test de dos caras. La firma de los ocho componentes es una sola: el unico
tono que queda muerto es siempre el default estampado del host.
Ledger: 8 patrones RETIRADOS (button 35/35 - file-upload 28/28, la entrada
que NOMBRO el tercer defecto - switch 10/10 - toggle 10/10 - tags-input
14/14 - tag-group 21/21 y 6/6 - toast action-hover-bg 5/5, la que ESCRIBIO
la clase), 2 ESTRECHADOS a PALETTE_FLOOR (checkbox, radio-group), 5 exactas
retiradas (button.palette-track/-border/-text con su razon corregida - el
guard escribe en el nodo, no solo :root; tag-group.solid-fg que se retiro a
si misma; hover-item-fg re-atribuida: la callaba su data-state=selected
nativo, no el arquetipo), 2 razones reescritas por medida. La constante
TONE_UNREACHED RETIRADA como huerfana - la muerte que su docstring pedia.
Tier de patrones 26 -> 16; 15 de los 16 son ya el unico hecho PALETTE_FLOOR.
Dos contradicciones del expediente, reproducidas dos veces: las -text de
tags-input SI reviven (la causa del arquetipo solo tapa el ITEM RESALTADO y
la escena no tiene ninguno; el token pinta ademas dos nodos hermanos fuera
de esa regla) y tag-group.hover-item-fg estaba mal atribuida. Queda señalado
en acta para expediente propio: el pase estatico estampa data-color en TODOS
los nodos mientras produccion lo estampa solo en el proveedor - anterior a
esta firma.
Los nueve componentes editados re-corridos tras el ledger: verdes, STALE 0.
label 1/2 byte a byte; switch 27->37 por diseño, reproducido dos veces.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
b4dd5a9067 |
fix(theming): S2 de la GRANDE - el centinela elige la sonda por el VALOR, no por el nombre
Segundo barrido de la firma de instrumento grande (ceguera 3 del expediente VA). sentinelFor(key) pasa a sentinelFor(key, kind): el guard ya leia base.ts para extraer las claves y ahora captura en el mismo pase el VALOR por defecto de cada una y tipa la sonda por el (literales por sintaxis; var() por el vocabulario del sistema, con resolucion transitiva dentro del catalogo via recipeTokenIndex). La escalera de nombre queda como respaldo para lo no clasificable. La regla: la sonda tiene que ser imposible EN LA DIRECCION en que la propiedad puede moverse. Censo del cambio: 357 claves cambian de sonda (320 clase A color<-1234px en 40 componentes - la clase entera del "vivo por accidente" IACVT - + 17 B + 8 E + 1 F + 11 menores). Easing (52 claves) intacto y explicito. Dos desviaciones del boceto, ambas medidas: el % NO se clasifica (opacity 62% vs width 42% - ambiguo) y el entero/0 tampoco (la "clase E de 24" del expediente era una mala lectura: 22 son calc(px * var(--scaling)), longitudes; y tipar el 0 habria matado en falso 7 claves vivas con default 0 - no monotono). Barrido S2 del ledger entero contra la base S1: 91/91 verdes, MONOTONO (0 componentes bajan), 0 rojos, 0 avisos de prepareWith, 39,7 min. Catalogo 2776/3577 -> 2778/3577: avatar 80->81 y stepper 62->63, exactamente las dos victimas medidas del expediente. Ninguna de las 102 claves clase A cubiertas por patron revivio - esperan la ceguera 2 (S3), como estaba escrito. Un fantasma no reproducido (spin-field 0/20 en 6,2s, la pagina no rindio; rerun 13/20 identico a S1) queda archivado como flake del instrumento. Ledger: DOS retiradas exactas con acta y medida - avatar.badge-fg-custom- contrast (default white, la entrada describia la sonda, no el token) y stepper.neutral-text (el unico caso donde la sonda mala daba VEREDICTO malo: la IACVT caia en la tinta heredada que el tono neutral practicamente es). background.scrim-fg-over-* siguen muertas por su puerta real y su entrada sobrevive tal cual. Re-corridos tras editar: verdes, sin STALE. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
6392d6003f |
fix(theming): S1 de la GRANDE - el prepareWith GRITA y el STALE ve los patrones
Primer barrido de la firma de instrumento grande (cegueras 6 + 1 del
expediente VA). Dos cambios en theming-sentinel.ts:
- Ceguera 6: el catch del bucle prepareWith avisa SIEMPRE por stderr - el
count() previo ya filtro la ausencia, asi que lo que cae ahi es un control
que estaba y fallo, la fuente de las muertes fantasma (chat-message midio
59/81 y 77/81 sobre codigo identico). No lanza: un barrido debe terminar,
pero una corrida con aviso NO es certificable.
- Ceguera 1: stale/oscillating filtran por reasonFor(k) (exactas Y patrones)
en vez de k in ledger (solo exactas) - 236 de las 821 ranuras adjudicadas
(29%) no podian disparar STALE, el silencio que costo 207 claves en B'. El
mensaje distingue: exacta -> retirar la entrada; patron -> ESTRECHARLO
(nunca retirarlo: cubre una familia y las demas siguen muertas).
Barrido S1 del ledger ENTERO: 91/91 componentes VERDES, cero unadjudicated,
cero avisos de prepareWith (corrida certificable), 40,8 min. label 1/2 y
switch 27/52 byte a byte identicos a las bases - los cambios no tocan
veredictos, solo el informe.
Cosecha: 18 claves STALE, todas de PATRON, todas de toast - los dos patrones
PLANE_SUPERSEDED ({tono}-{surface|border} y {tono}-accent) adjudicados el
2026-08-24 y dejados rancios ESA MISMA NOCHE por SS12.9 (el plano bajo a
:where() y la receta volvio a ganar; el handoff registra los seis tonos
restaurados). Reproducido 3/3 sobre codigo identico. 18/18 vivas = familias
enteras = ambos patrones RETIRADOS (no estrechados) con acta en el ledger;
toast re-corrido tras la retirada: 72/85, exit 0, 0 STALE. La tercera entrada
de toast (action-hover-bg) es clase tono-en-hover: cosecha de S3, intacta.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
0474643895 |
fix(theming): la mitad gratis del instrumento - el codemod lee la IIFE y la sonda habla la puerta del centinela
Firma de instrumento (expediente VA, cegueras 4 y 5): coste de ledger CERO,
tres scripts, ni una entrada de theming-sentinel-exceptions.ts tocada.
- __names-codemod.ts: blocks() devuelve {name, at, end, depth} con offsets
reales del fichero; la IIFE de avatar acota su region al return{...} con
depth 3 (y LANZA si no lo encuentra) y los muros 2-3 leen por fin sus 97
claves (86 publicas + 11 privadas); el pase A renombra a \t{depth}.
Laboratorio sobre copias: duplicado inyectado a 3 tabs DETECTADO,
renombrado de una clave de avatar = 1 linea. La via de carga SE QUEDA en
tsx: theming-census importa src/uix/morfo/compile sin extension y todo
src/uix/morfo esta escrito asi.
- theming-sentinel.ts: COMPONENT_OVERRIDES se exporta (UNA tabla de puertas,
no dos) con guarda de entrypoint via realpathSync - sin el realpath la
guarda muere a traves de un junction (exit 0 sin inspeccionar nada) y este
repo usa worktrees con junctions; UIX_DEV_URL reemplaza el :5173 clavado.
Importarlo: 0,85 s sin navegador. label 1/2 y switch 27/52 byte a byte
identicos a las bases pre-firma. Incluye +10 lineas de comentario
PREEXISTENTES de otra sesion (la justificacion de image-adjustments en
COMPONENT_OVERRIDES, solo prosa, verificada contra su acta del 24).
- __theming-probe.ts: el pase open habla el vocabulario del centinela
(prepareWith/openBy/openWith/openMarker, con OPEN_TRIGGER podada de sus
copias literales) y su catch AVISA en stderr distinguiendo "no hay trigger"
de "el gesto fallo"; editable registra por fin su bloque open (25 filas, 6
con data-editing; dos corridas sobre codigo identico = 0 diffs en TODOS los
bloques); pases nuevos de FOCO (la cabecera lo prometia y nada llamaba a
.focus()) y disabled (bloque aparte y ULTIMO de la corrida);
PROBE_ROLE_BOUND_SCALES + PROBE_SAFE_SCALES + assertProbeSafeScale con la
discrepancia risk amber/orange documentada; UIX_DEV_URL. card y editable a
0 diffs contra sus bases en los bloques pre-firma; menubar (6 nodos -> 7
con el panel) y chat-message (24 filas x 2 corridas, 0 diffs) abren via las
entradas del centinela.
Fuera de la firma, registrado en next-features SS13: el barrido de variantes
de la sonda (ensanche diferido), el clear-trigger de search-field en el pase
open, la asimetria de escenario de los seis con prepareWith sin fila en
DEMO_VARIANTS, y la GRANDE (cegueras 6+1+3+2, barridos S1-S3), que sigue
esperando firma. El catch del prepareWith del centinela sigue MUDO a
proposito: es la ceguera 6, S1 de la GRANDE.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month 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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
2e0f4b6504 |
fix(theming): el guard aprende a decir OSCILANTE, y deja de dar falsas alarmas
Un token puede leerse vivo unas corridas y muerto otras sobre el MISMO HEAD, sin mentir: la culpa es de la apertura del guard, no del contrato. Hasta hoy eso rompía el ledger por los dos lados. - Si el token está adjudicado y la corrida lo lee VIVO, el guard gritaba STALE y la sesión siguiente borraba una adjudicación correcta. - Si NO está adjudicado y la corrida lo lee muerto, el guard fallaba R-5.4 con un token que alcanza perfectamente. Una razón que empiece por OSCILLATES: describe justo eso. El guard la respeta en los dos sentidos: adjudica cuando lee muerto y, cuando lee vivo, imprime «oscillating — read ALIVE this run; the entry stays» en vez de STALE. Marcadas las dos carreras ya medidas: - emoji-picker.open-trigger-fg (17/21 vs 16/21 en el mismo código; vivo cuatro veces, una de ellas replicando el staticPass paso a paso). Tres corridas: vivo, vivo, muerto — exit 0 las tres, ninguna falsa alarma. - editable.submit-fg (vivo 3 de 4, 42/56 vs 41/56). Salir del modo edición es lo que hace un blur y el guard abre por foco + prepareWith, así que la superficie que mide no es determinista. Cuatro corridas: exit 0 las cuatro. Sale del plan de la revisión del 24 (P6). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
88a2086441 |
fix(theming): HEAD lleva cuatro commits con el ledger del centinela ROTO por una coma
`scripts/theming-sentinel-exceptions.ts` tiene `},,` en la costura entre el bloque de `rating-group` y el de `toggle`: un literal de objeto con una coma de más, o sea que el fichero NO PARSEA. Lo introdujo |
2 months ago |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
509d1144ff |
uix(calendar): temable — 84 % → 89 %, y una entrada de FAMILIA no se juzga en la ruta de UN componente
CERO claves acuñadas: el censo no tenía nada que coser. Su columna `global` ya
era 0 desde la capa calendar-surface (2026-08-21), así que lo único fuera de
alcance eran cuatro literales de IDENTIDAD. Todo el trabajo fue MEDIR, y ahí
estaba el hallazgo.
Qué entra:
- Cuatro literales firmados con su razón (recipe-contract §3), fuera del
ratio: el inline-size: max-content del panel y de la tabla (su anchura ES
day-size × 7 más el espaciado — precedente progress), el min-inline-size:
max-content del panel de mes y el inline-size: 100% de la cabecera. La
propuesta §4 pedía acuñar width / month-panel-width / grid-width para ellos:
sería dar a un tema la anchura de una caja cuya anchura es su contenido.
- Ninguna línea de CSS nueva. Las 74 claves del contrato quedan como estaban.
Censo: 84 % → 89 % (71 knobs, 57 públicos, 4 literales → 67 knobs, 57
públicos, 0 literales, 4 excepciones). Los 7 que quedan fuera son los forwards
de paleta THM-2: no se acuñan. CERRADO en su 89 %. Global 68 %, no baja.
Centinela R-5.4: 45/74 → 68/74, 6 adjudicadas. Verde (exit 0).
Lo que enseñó:
1. Una entrada de receta de FAMILIA no se puede juzgar en la ruta de UN
componente. Esta entrada es el vocabulario de las cuatro superficies de
rejilla de fechas (lo dice lib/calendar-surface.css): range-calendar,
month-grid y year-grid consumen --calendar-* y no acuñan nada — de ahí su
0 % HONESTO. Sus partes llevan data-month-grid-* / data-range-calendar-*,
invisibles al filtro data-calendar: 23 de sus 29 «tokens muertos» eran eso.
Con urls a las tres rutas + extraNodes + barrido de variant, 45/74 → 68/74.
Los tres consumidores NO se han tocado y siguen en su 0 % honesto.
2. Y la propia demo tapa tres claves más: su cabecera monta SELECTORES de mes
y año donde iría el heading, así que heading-{fg,font-size,font-weight} no
tienen nodo aquí; los tiene month-grid.
3. HALLAZGO — el tamaño de letra de los selectores de mes / año es NO
DETERMINISTA. La sonda dio 36 diffs contra un cambio que era SÓLO
comentarios; corrida dos veces sobre el MISMO código dio 24, en los mismos
dos nodos y las mismas dos propiedades. Causa medida:
[data-calendar-month-select][data-button] (calendar-select.css, la regla
que existe precisamente para fijar la letra del Button a la del calendario)
y [data-popover-trigger]:not([data-archetype='field-trigger'])
(popover.css) empatan a (0,2,0), así que gana el módulo que Vite inyecte el
ÚLTIMO: cuatro cargas dieron 14 / 16 / 14 / 14 px, con el orden de las
hojas invertido en la que dio 16. Es la clase del empate por orden de carga
de tree-grid (§12); arreglarlo mueve píxel → next-features §13.
Regla que confirma: ante un diff inesperado, corre la sonda dos veces sobre
el mismo código ANTES de sospechar de tu cambio.
4. calendar.select-min-width no tiene nodo en NINGUNA página del repo: su
único consumidor es [data-range-calendar-month-select] / -year-select, y la
demo de range-calendar renderiza un heading de texto mientras
DateRangePicker importa los selectores del CALENDARIO. Hueco de demo → §13.
Diff de computed: sonda antes/después, 22.656 valores en 7 estados. Los 36
diffs son ÍNTEGRAMENTE el no-determinismo del punto 3 (misma corrida contra sí
misma: 24) y caen en dos nodos y dos propiedades; fuera de ellos, 0. Capturas
2× antes/después: IDÉNTICAS byte a byte.
Guards: censo --only calendar 89 % · component-audit PASS · eidos-lint 0
invalid · vitest src/uix/eidos sin rojos nuevos (los dos son ajenos:
skin-media-player, el conocido, y un fantasma de radio-group de otra sesión) ·
rtl:check 0 · docs:check 0 · npm run check COMPLETED con 0 errores en ficheros
de calendar · prettier limpio sobre el contenido normalizado a LF.
README «Talla y tema» actualizado y pestaña Tokens en la demo (74 claves,
verificada en navegador: 0 errores de consola).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
cc010f79aa |
uix(select): temable — 83 % → 92 %, y un token que ALCANZA y aun así no pinta
Dos claves de COSTURA (PLAN §2-A: el valor es del sistema, el knob es del componente) y tres literales de identidad firmados. Ni un píxel movido. Qué entra en el contrato (101 → 103 claves): - invalid-border — las TRES declaraciones del estado inválido (el borde en reposo, el borde con foco/abierto y el anillo box-shadow que lo dobla) leían --color-risk-border A PELO. Es UNA clave, no dos: la propuesta §4 pedía invalid-trigger-border + open-invalid-trigger-border, y las filas agrupadas por VALOR son una sola. Bare como sus vecinas disabled-* (las ranuras de estado de esta receta son las del trigger) y como las siete invalid-border del catálogo. - group-gap — el hueco entre filas de un grupo iba a var(--space-1) directo. Nombre CONTADO en base.ts antes de acuñarlo: toolbar.group-gap. Tres literales firmados con su razón (recipe-contract §3), fuera del ratio: los dos inline-size: 100% (identidad — el select ES la anchura de su contenedor, el trigger ES la caja del select) y el opacity: 1 del check revelado, que deshace el 0 de la regla base. Censo: 83 % → 92 % (72 knobs, 54 públicos, 3 globales, 3 literales → 69 knobs, 57 públicos, 0 globales, 0 literales, 3 excepciones). Los 5 que quedan fuera son los forwards de paleta THM-2 leídos a pelo: no se acuñan. CERRADO en su 92 %. Global 68 %, no baja. Diff de computed: sonda antes/después, 2.176 valores en 8 estados = 0 diffs. Capturas 2× antes/después (cerrado y abierto): IDÉNTICAS byte a byte. Centinela R-5.4: 69/103, 34 adjudicadas en el ledger, todas MEDIDAS sobre el nodo real con las transiciones congeladas. Verde (exit 0). Lo que enseñó, todo del PORTAL: 1. El guard tiene que mantener el panel ABIERTO para medir los ~30 tokens de dentro, y el estado abierto TAPA los de reposo: trigger-border y trigger-indicator-fg leen muertos abiertos y MUEVEN con el panel cerrado. El instrumento sólo puede estar en un estado a la vez. 2. Tres knobs viven en nodos SIN data-select-*: la z del panel está en el [data-floating-wrapper] que soma porta (el caso popover.content-z) y el ritmo del viewport lo pinta el ScrollArea compuesto. Con extraNodes, 65/101 → 69/103. Nodos: 4 en reposo, 42 con el panel abierto. 3. La cascada de paleta anula sus 24 tonos, aquí en su forma MULTI-PARTE (trigger + content, porque el panel se porta fuera). Medido sobre el trigger abierto: --select-primary-border no mueve nada, --palette-border sobre el mismo nodo repinta. 4. separator-size ALCANZA y aun así no pinta: flex-shrink 1 en la columna del ScrollArea y un panel que desborda (scrollHeight 670 vs clientHeight 310) aplastan su 1px a 0px; con flex-shrink 0 el token sigue (1px → 9px). Un token vivo sobre un nodo aplastado lee igual que uno muerto. Defecto de píxel → next-features §13, no se arregla en este eje. §12.9 respetado: el contenido lleva data-depth=overlay, así que no se acuñó font-family ni line-height para el panel. Guards: censo --only select 92 % · component-audit PASS · eidos-lint 0 invalid · vitest src/uix/eidos sin rojos nuevos (los dos rojos son ajenos: skin-media-player, el conocido, y un fantasma de radio-group de otra sesión) · rtl:check 0 · docs:check 0 · npm run check COMPLETED con 0 errores en ficheros de select · prettier limpio sobre el contenido normalizado a LF. README con su sección «Talla y tema» y pestaña Tokens en la demo (103 claves, verificada en navegador: 0 errores de consola). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
fd8f01bace |
uix(chat-log): temable — 77 % → 100 %, y el instrumento daba DIECISÉIS falsos muertos de 31
Protocolo PLAN-theming §7 sobre `chat-log`. Censo 77 % → **100 %**, contrato
31 → **35** claves, centinela **34/35** con 1 adjudicada. El default NO se
mueve: diff de computed VACÍO (1.920 valores · 7 estados · 9 nodos), capturas
2x antes/después idénticas.
## Lo caro no fue acuñar: fue VER
El guard leía **15/31** antes de tocar una línea de código, y las dieciséis
"muertas" estaban las dieciséis VIVAS. Tres cegueras, ninguna del componente:
1. **El viewport que scrollea es del componente COMPUESTO.** El log pinta su
`padding-inline` / `padding-block` sobre `[data-virtual-list-viewport]`, un
nodo sin un solo `data-chat-log-*`: fuera del filtro de la sonda y del
guard. Cuarta forma del mismo punto ciego (prose · navigation-menu ·
waveform).
2. **La demo no montaba TRES de las seis partes.** Separador de día y divisor
de no-leídos no existían en el escenario, y la fila de evento vivía en el
índice 0 de una lista virtualizada anclada al FINAL — fuera de la ventana.
Once claves sin nodo que pintar. La demo los monta ya cerca del final
(instrumento: lo que la demo no monta, nadie lo mide).
3. **La pastilla del separador es un `> span` sin atributo** — seis claves más.
Con las tres arregladas, **31/31 antes de acuñar nada**.
## Lo que entra (4 claves, la COSTURA de los cuatro globales)
`divider-padding-block` · `event-radius` · `pill-gap` · `to-latest-radius`.
El valor sigue siendo el del sistema; el knob pasa a ser del componente.
Los nombres salen del CATÁLOGO, no del generador: la ficha proponía
`divider-unread-padding-block` y `pill-new-gap` —nombra por el atributo de la
parte— cuando el contrato lleva `divider-fg` / `-line` / `-font-size` / `-gap`
y `pill-bg` / `-fg` / `-radius`. La familia manda.
## Lo que SALE: una regla que no ha pintado nunca
`[data-chat-log-to-latest] svg { block-size: 1em; inline-size: 1em }` no puede
ganar: el `Icon` compuesto emite `style="width: var(--icon-size-sm); height:
..."` EN LÍNEA, y un estilo en línea gana a todo selector. El glifo mide 16 px
(paso `sm` del icono), no los 14 px que `1em` daría sobre la fuente heredada
del botón. **Retirada: 0 diffs**, que es la prueba de que estaba muerta. Es la
clase `carousel.item-gap` / `drag-drop.preview-z`, con una vuelta más: aquí el
inline lo escribe un COMPONENTE COMPUESTO, no soma.
## Identidades firmadas (3, fuera del ratio)
`block-size: 100%` del shell y del viewport (el log ocupa la caja que la app le
da) e `inline-size: fit-content` de la pill (la dimensiona su contenido).
## Adjudicada (1)
`event-radius` — sólo pinta bajo `:focus-visible` y el guard hace blur tras
abrir. Medido enfocando con TECLADO la fila real, con `transition` congelada:
0 px en reposo, 4 px enfocada, 1234 px con el centinela.
## Guards
censo `--only chat-log` 100 % (global 67 %, no baja) · `component-audit` PASS ·
`eidos-lint` 0 invalid · `vitest run src/uix/eidos` sin rojos nuevos (los dos
vivos son ajenos: `skin-media-player` y `radio-group.row-min-height-touch`) ·
`rtl:check` 0 · `docs:check` 0 · `check` sin un solo error del componente ·
prettier limpio sobre el contenido normalizado a LF.
README con su sección «Talla y tema», demo con pestaña `Tokens` verificada en
navegador, ficha con su veredicto §5 y registro en PLAN §8.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
2117d7422f |
uix(editable): temable — 75 % → 82 %, y el guard CERRABA la superficie que medía
Protocolo PLAN-theming §7 sobre `editable`. Censo 75 % → **82 %**, contrato 56
claves, centinela **42/56** con 14 adjudicadas. El default NO se mueve.
## Lo que costó medirlo: dos superficies y una apertura frágil al revés
- **Preview e input comparten celda de rejilla y se excluyen** (`display: none`),
igual que los triggers (Edit en reposo, Save/Cancel editando): una pasada deja
fuera la mitad de la receta. Todo se midió DOS veces.
- **Salir del modo edición es lo que hace un `blur`** —da igual lo que diga
`submitMode`, esa opción sólo decide si el valor se compromete— y el guard
blurea justo después de abrir. Abriendo con clic en el trigger, la superficie
ya estaba cerrada cuando se medía: `submit-fg` leía muerto y mueve
perfectamente abierta (`rgb(255,255,255)` → `rgb(1,2,3)`). Se abre por FOCO,
con la demo en `activationMode=focus`, que es la apertura que el guard no
deshace. Misma ley que `navigation-menu`, con el gesto invertido.
## Lo que entra al contrato (1 clave)
`disabled-fg` — la tinta apagada de TODO el componente: preview, input y los
tres triggers comparten UNA regla, así que el nombre desnudo del catálogo es el
que toca (`label` y `select` ya lo llevan con este mismo valor). Era el único
knob que iba a un primitivo a pelo, y encima con un respaldo escrito a mano
—`var(--color-content-disabled, var(--color-content-muted))`— que estaba MUERTO:
el token sí está declarado, así que el respaldo no podía pintar nunca. Retirado
con él.
## Lo que sale (1 clave huérfana)
`control-border`: ninguna regla lo consumía. El borde en reposo del control es
`transparent` por diseño y el del input es el acento
(`--_editable-palette-border`), así que esa clave pública prometía un knob que no
existe — la deuda INVERSA del eje. Diff 0, y el centinela lo confirmaba muerto.
## Dos literales de identidad firmados
El `fit-content` del preview (es tan ancho como el texto que enseña; la ficha
proponía acuñarlo como `preview-width`, que sería acuñar la definición de la
parte) y el `100 %` del input (llena la celda que comparte con el preview).
## Lo que se queda privado (el techo honesto es 82 %)
Los SIETE knobs por privado son el puente de paleta THM-2
(`--_editable-palette-{solid,border,solid-hover}`), que la capa compartida
alimenta por instancia desde `[data-color]`: un público encima dejaría que un
tema lo fijara y matara el `color=` de cada instancia. Otros cuatro son sistema
transversal (anillo de foco y velo de hover), ya fuera del ratio.
## Las catorce adjudicaciones, en dos razones — y una tercera que casi se cuela
- El par `transition-*` **ES** la transición que el guard congela; medido sin
congelar: `0.12s → 4.321s` y `cubic-bezier(0.4, 0, 0.2, 1) → steps(3)`.
- Las doce claves de tono son la cascada de paleta, por PATRÓN y con el mecanismo
a la vista: el nodo lleva `--palette-solid` de la capa por instancia, el bloque
genérico `[data-editable][data-color]` —emitido EL ÚLTIMO, misma
especificidad— lo lee, y el respaldo que nombra la clave del componente no
llega nunca. Quítale `data-color` a la misma instancia y
`--editable-primary-solid` vuelve a pintar (`rgb(1, 2, 3)`).
- ⚠ **`risk-border` NO cae en ese patrón**: las tres reglas de inválido la leen
DIRECTAMENTE, así que su silencio tiene otra causa —la demo es válida— y
entrada propia: forzando `data-invalid` alcanza en el input Y en el control.
Una excepción por patrón que engulle una clave con vida propia es una
adjudicación falsa.
## Artefactos
- Sonda: **0 diffs** en las dos caras — modo preview (1.696 valores, 7 estados) y
modo edición (2.528 valores, 8 estados).
- Captura 2× del reposo idéntica al byte. La de edición NO es comparable por
bytes: la traza de la demo imprime un TIMESTAMP, así que dos corridas del mismo
código difieren (comprobado antes de creerme el diff). Revisada a ojo.
- `component-audit --only editable`: **PASS** · `eidos-lint` 0 invalid ·
`vitest src/uix/eidos` sin rojos nuevos (el conocido `skin-media-player`) ·
`rtl:check` 0 · `docs:check` 0 · `npm run check` COMPLETED, 0 errores en
`editable`.
- README «Talla y tema» + pestaña `Tokens` (56 filas, verificada en el navegador
con `networkidle` y clic real).
## Defecto anotado, NO arreglado
El tinte inválido ES la clave de tono (`--editable-risk-border`): dos knobs con
una sola llave — un tema que quiera otro color de error mueve también las
instancias `color="risk"`. El arreglo es una clave de estado por parte
(`invalid-input-border` / `invalid-control-border`, la forma que `switch` acuñó
el mismo día) y es contrato: se lista.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |