# CONTINUE — eje Theming «theme-reach» — **CERRADO 2026-08-25**
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
## EMPIEZA AQUÍ
**EL EJE ESTÁ CERRADO** (gate de F3 rediseñado y en verde el 2026-08-25;
sección §«EL CIERRE, EJECUTADO» abajo). Lo que vigila el estado desde hoy no
es este documento sino los guards: `theming-reach-floor.test.ts` (newDebt=0 ·
STALE=0 · reach ≥ 73 % · ≥65 al 100 %), `component-audit` R-5.1/5.2/5.3 en
`error` , y el centinela R-5.4. La deuda restante vive NOMBRADA clave a clave
en `scripts/theming-census-debt.ts` (1154 entradas que sólo pueden menguar).
Trabajo nuevo de theming se abre como entrada nueva de §13/next-features, no
feat(theming)!: la ley del espacio cerrado - un --{c}-* existe si y solo si base.ts lo declara
Firma 2026-08-26. El espacio de nombres publico queda CERRADO sobre el
contrato: no hay tercer estado. El fallback es seguridad de VALOR, no
escapatoria de contrato; declarada la clave, el fallback inline muere (el
default vive en UN sitio, base.ts).
- El barrido real del catalogo: 25 nombres propios con fallback fuera de
contrato en 10 componentes (la prosa decia 13 en 2). ONCE eran knobs de
tema y quedan DECLARADOS con su default verbatim, scope root medido:
mockup 9 (con --mockup-phone-shadow ACUNADA - un nombre cargaba shadow-4
en el marco y shadow-5 en el bisel: un nombre con dos defaults es la
mentira que la ley mata) y text-scramble 2. Fallbacks inline retirados.
- Los otros QUINCE no son knobs: 14 canales de VALOR que soma/envoltorio
escriben por instancia (destino ya firmado por la firma de los 318:
--_{c}-*; el codemod es un eje propio) y el default de motion cuyo hogar
es EidosConfig.motion (su entrada structural queda intacta). Viven en el
registro PENDING_PRIVATE_RENAME del guard - nombrados, fechados, con
destino escrito y STALE simetrico: contarlos, no bendecirlos. La firma
medida de color-swatch.fill (2026-08-23) queda INTACTA y citada.
- El guard de fantasmas endurecido al "si y solo si": un --{c}-* del propio
componente fuera de contrato es ROJO con o sin fallback; el prestamo
ajeno y el sistema conservan sus reglas. Mutaciones: var inventado con
fallback -> rojo nombrado; prestamo ajeno -> verde; entrada de registro
rancia -> rojo STALE.
- Neutralidad PROBADA: generated/base.css = +11 lineas y nada mas; computed
A/B en navegador reconstruyendo el mundo viejo inline sobre el mismo nodo
- mockup 3 nodos x 2 cromos x 6 propiedades identicos (el bisel conserva
shadow-5), text-scramble identico. mockup se midio donde monta de verdad
(/blocks/feature-split): no tiene demo propia.
- Numeros: solo no-contract 18 -> 16. El suelo NO sube y la razon importa:
la ley cerraba un hueco de CONTRATO, no de alcance - esas declaraciones
ya puntuaban public; lo que faltaba era declarar el NOMBRE.
- Efecto lateral anotado en la clave, el handoff y next-features: el crudo
var(--primitive-neutral-12) migro verbatim a base.ts y R-4.6 (que escanea
CSS) ya no lo ve - la deuda sigue, ahora nombrada en el contrato.
- docs: recipe-contract SS4 reescrito con la ley y sus corolarios (el
value-reference con-fallback queda acotado a vocabulario ajeno/sistema);
CONTINUE y next-features al dia - pendientes del eje: el codemod de los
14 canales, el cableado del canal de motion, palabras y timeline.
BREAKING: consumir un --{c}-* propio no declarado es rojo desde hoy, con o
sin fallback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
heredando de aquí. Las DOS firmas que el cierre dejó pendientes están
**EJECUTADAS**: la de los 318 privados no-derivados (§«FIRMA EJECUTADA — los
318» abajo) y la del idioma `var(--{c}-x, fallback)` sin contrato (§«FIRMA
EJECUTADA — la ley del espacio cerrado»). Heredada de la segunda queda la
re-clasificación de los 117 nombres `--palabras-*` que el censo puntúa `public`
siendo canal de VALOR, más DOS deudas nuevas de eje propio que ella misma
refactor(theming)!: trece canales de valor hablan como lo que son - privados
Eje-codemod firmado 2026-08-26 (destino firmado dos veces: los 318 y la ley
del espacio cerrado). Flip atomico escritor+lectores por nombre, barrido por
git ls-files (94 ocurrencias en 36 ficheros; el barrido destapo lectores que
ninguna lista traia: el comentario del morfo de knob, dos demos, y PLAN-
background). 32 ficheros.
- background pointer-{x,y,px,py} + progress · color-swatch fill ·
emoji-picker columns · knob {angle,progress,start-angle,sweep} · menubar
panel-anchor-width · text-gradient duration -> --_{c}-*. El nombre viejo
computa vacio en los siete componentes.
- PARADO con expediente: --navigation-menu-indicator-h NO se renombra - es
una de CUATRO hermanas escritas en un literal, el README de soma las
enseña como API del consumidor (dos ejemplos de CSS de app leen -h) y -w
es clave DECLARADA del contrato. Privatizar una de cuatro parte una API
documentada. Tres opciones redactadas en next-features SS13, sin elegir;
el registro PENDING_PRIVATE_RENAME queda con DOS entradas (esta + motion),
cada una con su razon.
- La trampa del censo NO mordio y la prediccion estaba mal por un orden de
magnitud: UNA reclasificacion (color-swatch.background), no ~15 - el censo
cuenta knobs de APARIENCIA y doce canales viven en geometria o conservan
un publico hermano. public 3074->3073, channel 36->37, reach 73%,
atHundred 65: el suelo no se toca.
- Verificacion dinamica de los SIETE canales vivos por CDP (verbatim en el
acta de la sesion): el parallax sigue al puntero con la privada (translate
-28,-24 -> 32,28 = x*depth), el knob rota por teclado (-27deg -> 0deg,
arco 108 -> 135 = progress*sweep), el chip pinta su prop, columns 9/6/12
tracks (control negativo: el nombre viejo a 3 no mueve nada), el panel
toma 886px del anchor, text-gradient 8s. Estatica: sonda 7/7 a 0 diffs
reales (el unico diff, un velo de emoji-picker, reproducido 2/2 = ruido);
color-swatch sin ruta de demo declarado en voz alta (la sonda con 0 nodos
es un guard que no inspecciona nada) y medido donde monta.
- Guard mutado por sus dos caras: entrada retirada reintroducida -> STALE;
nombre viejo devuelto a una receta -> missing. Docs ANOTADOS con fecha
(la adjudicacion medida de color-swatch del 23-08 intacta), volcados solo
donde describen codigo vivo. audit 162 PASS - docs:check 0/0 - --debt
1154/0/0 sin una clave movida - --names 0 - check 0 atribuibles.
Deuda menor anotada: la fila generada de audit/theming/background.md:72 la
regenerara el --report supervisado pendiente.
BREAKING: los trece nombres publicos viejos ya no existen; el canal se lee
--_{c}-* y sigue sin ser tuyo para fijarlo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
nombró: el codemod de los 14 canales públicos a `--_{c}-*` —
refactor(theming)!: el indicador de navigation-menu es CANAL - y el consumidor estiliza la PARTE
Firma "(a) completada" (2026-08-26), cerrada tras rechazar la especie
`output` por abrir excepciones (clase barata - frontera de prosa - patron ya
rechazado dos veces): las cuatro hermanas --navigation-menu-indicator-
{x,y,w,h} pasan a --_ (la adjudicacion que tabs ya firmo citando a ESTE
componente como precedente), indicator-w se RETIRA del contrato, y el README
de soma deja de enseñar a saltarse la composicion.
- Flip atomico escritor+lectores. Trampa del barrido, medida: el grep del
nombre LITERAL es ciego a la forma con llaves {x,y,w,h} - escondia tres
menciones. Barrido final: 0 consumos vivos de los nombres viejos.
- indicator-w retirada con acta MEDIDA (y una auto-correccion: la primera
acta decia "con la barra cerrada" y era falso - el indicador se monta
condicional y hay 0 nodos; lo real, con transiciones CONGELADAS: solo una
regla !important de autor le llegaba, y la unica ventana donde asomaba
era el indicador montado sin rect - un subrayado de ancho cero). Contrato
44 -> 43, generated -1 linea, ningun ledger rancio.
- README de soma: las medidas siguen tabuladas como canales privados "not
consumer API"; la seccion nueva enseña la PARTE ([data-navigation-menu-
indicator] + data-state + los tres pomos thickness/bg/radius) con
ejemplos VERIFICADOS POR MEDICION (el ejemplo 1 es literalmente el
control positivo: block-size 2 -> 9px). Hueco FLAGGED sin acuñar: el
ejemplo viejo de pildora no tiene traduccion - falta un eje de forma en
la parte; en SS13.
- Registro PENDING_PRIVATE_RENAME -> UNA entrada (motion). SS14 NUEVO en
next-features: unificar tabs (--indicator-* SIN prefijo, MeasuredIndicator
:80-83, 2 claves global en el ledger) - con el hallazgo de que ningun
guard los caza HOY porque no llevan prefijo: el espacio cerrado premio al
que nombraba mejor.
- Numeros: public 3073->3072, channel 37->38, reach 73% y atHundred 65
intactos (ningun redondeo cayo), --names 4566 con 0 desviadas, centinela
nav-menu 42/43 con la misma unica adjudicacion, --debt identico.
- Dinamica verbatim: el indicador DESLIZA (left 0 -> 111px, ancho 107 ->
108.56 = rect del trigger, canal w/h == triggerRect), los nombres viejos
computan vacio en el elemento (control negativo 777/333: nada se mueve).
Guards: 78 tests verdes + soma 9/9 + mutacion por las dos caras + audit
162 PASS + docs:check 0/0.
BREAKING: los cuatro nombres publicos del indicador ya no existen y
--navigation-menu-indicator-w sale del contrato; el indicador se estiliza
por su parte y sus pomos.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
**EJECUTADO 2026-08-26 (14 de 14: 13 en el codemod + el 14.º por firma propia,
ver §«FIRMA EJECUTADA — el indicador de navigation-menu»)** — y el cableado
`EidosConfig.motion` → CSS
refactor(theming)!: trece canales de valor hablan como lo que son - privados
Eje-codemod firmado 2026-08-26 (destino firmado dos veces: los 318 y la ley
del espacio cerrado). Flip atomico escritor+lectores por nombre, barrido por
git ls-files (94 ocurrencias en 36 ficheros; el barrido destapo lectores que
ninguna lista traia: el comentario del morfo de knob, dos demos, y PLAN-
background). 32 ficheros.
- background pointer-{x,y,px,py} + progress · color-swatch fill ·
emoji-picker columns · knob {angle,progress,start-angle,sweep} · menubar
panel-anchor-width · text-gradient duration -> --_{c}-*. El nombre viejo
computa vacio en los siete componentes.
- PARADO con expediente: --navigation-menu-indicator-h NO se renombra - es
una de CUATRO hermanas escritas en un literal, el README de soma las
enseña como API del consumidor (dos ejemplos de CSS de app leen -h) y -w
es clave DECLARADA del contrato. Privatizar una de cuatro parte una API
documentada. Tres opciones redactadas en next-features SS13, sin elegir;
el registro PENDING_PRIVATE_RENAME queda con DOS entradas (esta + motion),
cada una con su razon.
- La trampa del censo NO mordio y la prediccion estaba mal por un orden de
magnitud: UNA reclasificacion (color-swatch.background), no ~15 - el censo
cuenta knobs de APARIENCIA y doce canales viven en geometria o conservan
un publico hermano. public 3074->3073, channel 36->37, reach 73%,
atHundred 65: el suelo no se toca.
- Verificacion dinamica de los SIETE canales vivos por CDP (verbatim en el
acta de la sesion): el parallax sigue al puntero con la privada (translate
-28,-24 -> 32,28 = x*depth), el knob rota por teclado (-27deg -> 0deg,
arco 108 -> 135 = progress*sweep), el chip pinta su prop, columns 9/6/12
tracks (control negativo: el nombre viejo a 3 no mueve nada), el panel
toma 886px del anchor, text-gradient 8s. Estatica: sonda 7/7 a 0 diffs
reales (el unico diff, un velo de emoji-picker, reproducido 2/2 = ruido);
color-swatch sin ruta de demo declarado en voz alta (la sonda con 0 nodos
es un guard que no inspecciona nada) y medido donde monta.
- Guard mutado por sus dos caras: entrada retirada reintroducida -> STALE;
nombre viejo devuelto a una receta -> missing. Docs ANOTADOS con fecha
(la adjudicacion medida de color-swatch del 23-08 intacta), volcados solo
donde describen codigo vivo. audit 162 PASS - docs:check 0/0 - --debt
1154/0/0 sin una clave movida - --names 0 - check 0 atribuibles.
Deuda menor anotada: la fila generada de audit/theming/background.md:72 la
regenerara el --report supervisado pendiente.
BREAKING: los trece nombres publicos viejos ya no existen; el canal se lee
--_{c}-* y sigue sin ser tuyo para fijarlo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
(las dos, con su lista, en `next-features.md` ). **Lo que sigue pendiente en
este carril: el cableado de motion · la re-clasificación de `palabras` · la
`timeline` §5 pre-B′ .**
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
**El eje ya no tiene cola.** Los 16 componentes que nunca habían pasado están
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
cerrados o adjudicados, la deuda de artefactos está saldada, y ** §12.9 y la
firma B′ quedaron FIRMADAS Y EJECUTADAS** — las dos decisiones más caras
pendientes. Global **73 %** (68 % antes de la clase `structural` , 69 % antes de
`bridge` /`channel`), **65 componentes al 100 %** .
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
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
## HANDOFF 2026-08-26 (noche) — POR AQUÍ MAÑANA
**El día ejecutó CINCO firmas más, todas con su adversarial**: la
clasificación de los 318 privados (`e812d3ffd`+`a74aeec7b`+`90b93a79e`,
adversarial 13/13) · la ley del ESPACIO CERRADO (`6499eb2a4`, 7/7) · el
codemod de los 13 canales (`e100ea520`, atómico verificado) · el indicador de
navigation-menu, (a) completada (`de2e136a0`, 6/6 — la especie `output` se
propuso y se RECHAZÓ por abrir excepciones) · ** §14, MeasuredIndicator con
nombre poseído** (`8ac23047f` — «la capa es la pluma, no la dueña»; `tabs`
cierra al 100 %). La familia de indicadores entera habla UNA doctrina.
### Lo PRIMERO mañana, por orden de valor
0. ~~**Los DOS guards rojos de `contracts.test.ts` que tocan el indicador**~~ —
** ✅ EJECUTADO 2026-08-26 (`1cb07c1e1`, firma ii del autor)**: no la
declaración desnuda — la PLENA. `ready` es ESTADO de la parte (la especie
de `checked` , no un prop): los dos morfos declaran
`{ attr: 'data-ready', value: v.stateRef('ready'), severity: 'optional' }`
con `states: ['ready']` , los providers registran la fuente
(`() => this.indicator.ready`) y **el estampado manual muere** — la bolsa
es la única tubería también aquí. `data-ready` SALE de
`EIDOS_ONLY_ATTRS` con acta (ya no es eidos-only: es contrato).
Verificado: guard sin los 2 rojos · morfo 222/222 · suites 3/3 ·
eidos-lint `[data-tabs-indicator]:not([data-ready])` morfo-backed, 0
invalid · check 0 atribuibles POR FICHERO · dinámica CDP: tabs
`ready=""` desliza (0→103.9px), radio-group `segmented` ídem; control
negativo GRATIS: pane oculto (rAF congelado) ⇒ sin medida ⇒ sin attr ⇒
`opacity: 0` — la puerta anti-flash aguanta. Coordinación con el peer P0
(vicen-42) por canal: `eidos-only-attrs.ts` era edición COMPARTIDA (sus
altas de aura/waveform viajaron en mi commit con atribución declarada;
su commit va detrás por dependencia de su guard). ⚠ Su adjudicación
THEME-SYS-1 sobre `header-z` fue OBJETADA con tres hechos (token MEDIDO
VIVO en sentinel-exceptions:410/437 · dos STALE · decisión del autor
pendiente en `next-features.md:808` en dirección CONTRARIA) y ACEPTADA:
revirtió entero y su guard registra la deuda NOMBRADA. El peldaño de
«cabecera pegajosa» sigue esperando TU firma.
Expediente original:
(aviso de cierre del peer P0: su primera corrida histórica de la suite
completa destapó 8 rojos preexistentes; 6 son suyos para su mañana, DOS
son de este eje). El guard «hardcoded Soma component data attrs» flaguea
`data-ready` estampado a mano en `tabs-provider.svelte.ts:473` y
`radio-group-provider.svelte.ts:366` . **Proveniencia VERIFICADA: NO es de
§14** (0 apariciones en `8ac23047f` ) — lo introdujo `76f18a5e8` , cuyo
propio mensaje ya avisaba «aparece un punto ciego del guard». La
adjudicación está pre-masticada: `data-ready` es contrato REAL — lo leen
`tabs.css:329` y `sliding-indicator.css:64-66` (la puerta anti-flash
hasta la primera medida) — así que se DECLARA en los morfos de las dos
partes indicadoras (tabs + radio-group), que es lo que el guard exige; ni
exención ni retirada. Cambio de morfo ⇒ con su rigor, no de madrugada.
⚠ El hook pre-push sigue SIN ARMAR por esto (el peer no arma puerta en
rojo — promesa cumplida); detalle de los 8 en `CONTINUE-audit-p0.md` .
1. ~~**§15 — el GEMELO un piso arriba**~~ — ** ✅ EJECUTADO 2026-08-26 (firma
refactor(soma)!: §15 — la geometría del posicionador es canal del ANFITRIÓN
Firma A del autor (§14 literal, cuarta aplicación de «la capa es la pluma,
no la dueña»): FloatingContentOpts gana `component` (kebab del morfo, nunca
literal — 11 hilos de creación en 9 anfitriones) y las medidas por instancia
del posicionador aterrizan como `--_{host}-floating-{transform-origin,
available-width,available-height,anchor-width,anchor-height}`. El sexto
nombre que el expediente no contaba (`--floating-native-offset`, rama
nativa) queda canal INTERNO de capa (`--_floating-native-offset`: lo escribe
la capa en su propio wrapper, lo leen solo sus reglas foundation). El lector
COMPARTIDO (preset scale-fade de motion) lee el alias neutro
`--_floating-transform-origin` que cada receta anfitriona declara desde su
canal — cableado sliding-indicator, 9 declaraciones. getFloatingContentCSSVars
(export muerto, next-features §13.ii) MUERE con la firma.
Matiz que la ejecución destapó: el content de MENUBAR compone DropdownMenu —
su canal es --_dropdown-menu-floating-* y el alias de menubar se acota al
PANEL (el canal sigue al componente que POSEE la composición flotante);
split-button y palabras leen el canal ajeno de su composición en el punto de
composición, anotado en cada sitio.
Verificado: suites 96+60+78 en verde - eidos-lint x10 con 0 invalid -
reach-floor 5/5 (ledger 0 NEW / 0 STALE) - component:audit 162 PASS / 4
NEEDS-WORK idéntico - check 0 atribuibles POR FICHERO - dinámica CDP 9/9
anfitriones: canal vivo con px por instancia, los nombres VIEJOS computan
VACÍO en todos, positivo exacto (tooltip max-block-size 525.033px == canal
525.0326px; combobox ídem; panel de menubar anchor-width 886px = la barra;
sidebar popout ENGANCHADO 720px/35px), negativo fijando los viejos en :root
= nada se mueve. Trampa reconfirmada: el popout SIN ANCLAR da undefinedpx —
comprobar que la superficie estaba abierta.
Viaja con atribución declarada (acuerdo por canal con la sesión P0
vicen-42, precedente 1cb07c1e1): los tres hunks de fase C en
docs/architecture/soma-architecture.md (runtime.part sin syncAttrs,
partProps = render bag, el párrafo del imperativo) son suyos.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
A del autor: §14 literal)**. Canal en el namespace del ANFITRIÓN:
`FloatingContentOpts.component` (kebab del morfo, 11 hilos / 9 hosts),
`--_{host}-floating-{transform-origin,available-w/h,anchor-w/h}` ; el sexto
nombre (`native-offset`) = canal INTERNO de capa `--_floating-native-offset` ;
el preset `scale-fade` lee el alias neutro `--_floating-transform-origin`
declarado por cada receta (cableado sliding-indicator × 9);
`getFloatingContentCSSVars` MUERTO. Matiz destapado: el content de menubar
compone DropdownMenu ⇒ su canal es de dropdown-menu y el alias de menubar
se acota al PANEL — el canal sigue al DUEÑO de la composición flotante;
split-button/palabras leen canal ajeno en el punto de composición, anotado.
Verificado: suites 96+60+78 · lint × 10 0 invalid · reach-floor 5/5 ·
audit 162 PASS · **dinámica CDP 9/9** con viejos VACÍOS, positivo exacto
(tooltip 525.033 == canal; panel menubar 886px = barra) y negativo en
`:root` . Acta completa: `next-features.md` §15.
*Fe de erratas de atribución* : los tres hunks de `soma-architecture.md`
que el cuerpo de `c494fb395` declara del peer eran de **vicen-41**
(eje P0-docs; su commit hermano `70c01870a` los RECLAMA en su cuerpo —
el fichero mismo viajó en `c494fb395` , 13 s antes), no de vicen-42. Ley del día, ya en el handoff P0: quien barre por RUTA se
lleva los hunks del otro — la atribución se declara, y si se yerra el
nombre, se corrige por acta, nunca por amend.
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
2. ~~**La especie de FORMA sin dueño**: `--indicator-duration`/`-ease`~~ —
** ✅ EJECUTADO 2026-08-26 (firma (a) del autor)**: ninguna de las dos
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
opciones del expediente — son el ALIAS de la capa (especie de
`--_indicator-x` , opcionales-con-fallback). Flip a `--_indicator-*` ; la
superficie de tema queda donde ya estaba y alcanza (las claves de contrato
del anfitrión). Reparto de propiedad escrito: la capa posee QUÉ desliza,
el anfitrión A QUÉ VELOCIDAD. Contrafáctico medido PRE-flip (el bare en
`:root` jamás alcanzó: no se retiró superficie); post 4/4 caras. Acta
completa: `next-features.md` , hueco flagged de §14.
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
3. **Cableado `EidosConfig.motion`→CSS** — mata la última entrada del registro
`PENDING_PRIVATE_RENAME` .
4. **Re-clasificar `palabras`** (canal de valor del scheme, no tema) y
**reabrir `timeline`** (§5 pre-B′ ) — los dos con expediente escrito.
### Estado de la RAMA al cerrar el día (léelo antes de tocar nada)
- **SIN PUSH desde `e100ea520` **: el codemod de canales, navigation-menu,
§14 (`8ac23047f`) y el cierre documental del día. El resto del día está
pusheado hasta `cec75d04e` .
- **Sesión peer `vicen-63` ACTIVA en la rama** (auditoría P0): su C2c retiró
los `syncAttrs` (los de tabs/radio-group VIAJARON en `8ac23047f` con
atribución declarada y acuerdo por canal), su cirugía del runtime y su
commit venían detrás, y **re-armará el hook pre-push** (`scripts/hooks/
pre-push` es la fuente; el gate ya pasa en verde sobre HEAD con el lint
fuera hasta el one-shot de formato). Si un push falla, el mensaje del gate
dice qué. La sesión de fichas (`vicen-3c`) commiteó `cc2894b36` .
- **Protocolo de rama compartida que el día confirmó tres veces**: staging
por RUTA explícita (nunca `add -A` — 375 ficheros a punto de colarse una
vez), la RAÍZ del repo también se stagea (STUMBLES.md se quedó fuera una
vez), y antes de medir un fichero, `git diff HEAD -- <f>` por si el peer lo
movió.
### Las leyes nuevas del día (además de las firmas)
- **El nombre dice la verdad en las DOS direcciones** — ni knobs que un tema
no puede mover (el inline gana), ni privados que un README enseña como API.
Cuando ninguna de las dos ortografías dice la verdad, la respuesta NO es
una especie nueva: es preguntar qué está mal en el DISEÑO (así cayó
`output` , y así el README de navigation-menu aprendió a enseñar la PARTE).
- **El grep literal es ciego a la forma con llaves** (`--x-{a,b,c}`) — se
barre por STEM.
- **La sonda estándar es CIEGA a los canales** (PROPS sin
translate/rotate/gridTemplateColumns/animationDuration): su 0-diff prueba
lo circundante; el canal se verifica en DINÁMICA por CDP con control
negativo y positivo.
- **Un alias sin prefijo propio ni siquiera entra al clasificador** — y una
causa escrita sin su contrafáctico medido acaba corregida por el
adversarial (pasó dos veces hoy).
## HANDOFF 2026-08-25 (noche) — histórico
docs(theming): handoff 2026-08-25 noche - por aqui manana
Las cinco firmas del eje EJECUTADAS y los tres expedientes de 13 de la tarde
commiteados (ARIA F-1, velo/atajo 56, talla A-112). Manana, en orden: la
firma de instrumento "mitad gratis" (PRESENTADA, sin firmar - coste de
ledger CERO) - la GRANDE de cuatro cegueras con TRES barridos escalonados
(~3h dimensionadas, NO fusionar S2/S3) - y el cierre del eje (deuda B, gate
F3, R-5 a error). Fuera del carril, registrados: E1 composicion del array
(con la correccion de E-talla), lo abierto por el ARIA, y el parrafo de
doctrina que querria vivir en reference.md.
Leyes de la sesion escritas: interrupciones matan agentes (informe a disco
INCREMENTAL) - el supervisor mira capturas antes de cada commit - las demos
no entran ni como prueba central - F5 compartidas en serie.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
**Las CINCO firmas del eje están EJECUTADAS y pusheadas** (`2daa683fa`
file-upload · `df3a4d054` form/compuesto · `2ce43db56` tags-input aria ·
`1f8ce293b` avatar · `466b24f34` chip/suelo §55). Después cayeron los
expedientes de §13: `d5a27b87e` (árbol ARIA de tags-input, cierra F-1) ·
`3bf7930ba` (el velo no muere por un atajo + pin de chronos, §56) ·
`318aac207` (la talla de form LLEGA, doctrina anchura-vs-densidad).
### Lo PRIMERO mañana: dos firmas de INSTRUMENTO, en este orden
1. ~~**«La mitad gratis»**~~ — ** ✅ FIRMADA Y EJECUTADA 2026-08-25**
(`047464389`; ver §«FIRMA EJECUTADA — la mitad gratis» justo abajo).
Expediente original: scratchpad de la sesión
docs(theming): handoff 2026-08-25 noche - por aqui manana
Las cinco firmas del eje EJECUTADAS y los tres expedientes de 13 de la tarde
commiteados (ARIA F-1, velo/atajo 56, talla A-112). Manana, en orden: la
firma de instrumento "mitad gratis" (PRESENTADA, sin firmar - coste de
ledger CERO) - la GRANDE de cuatro cegueras con TRES barridos escalonados
(~3h dimensionadas, NO fusionar S2/S3) - y el cierre del eje (deuda B, gate
F3, R-5 a error). Fuera del carril, registrados: E1 composicion del array
(con la correccion de E-talla), lo abierto por el ARIA, y el parrafo de
doctrina que querria vivir en reference.md.
Leyes de la sesion escritas: interrupciones matan agentes (informe a disco
INCREMENTAL) - el supervisor mira capturas antes de cada commit - las demos
no entran ni como prueba central - F5 compartidas en serie.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
`6314e22b…/scratchpad/bprime/exped/va/informe.md` (1.019 líneas).
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
(007c2af52, hoy inocuo), checkbox.stroke-ease, residuo del hover.
- Anota la retirada de TONE_UNREACHED en la cronica de B' (changelog SS53 y
next-features) y en las leyes del handoff.
- Reescribe el handoff: las DOS firmas de instrumento estan ejecutadas; el
eje pasa a su CIERRE (deuda B, gate de F3, R-5 a error).
Catalogo tras la firma: 2918/3577 claves vivas (78% -> 82%). Tier de
patrones 28 -> 16, 15 de 16 son PALETTE_FLOOR, cero zombis, 659 muertas
todas con razon.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
2. ~~**La GRANDE: cuatro cegueras + TRES BARRIDOS escalonados.**~~ —
** ✅ FIRMADA Y EJECUTADA 2026-08-25** (`6392d6003` S1 · `b4dd5a906` S2 ·
`b9cef9a43` S3; ver §«FIRMA EJECUTADA — la GRANDE» abajo). Se ejecutó
exactamente con el plan de VA: tres barridos escalonados, sin fusionar S2 y
S3, y la atribución quedó limpia.
docs(theming): handoff 2026-08-25 noche - por aqui manana
Las cinco firmas del eje EJECUTADAS y los tres expedientes de 13 de la tarde
commiteados (ARIA F-1, velo/atajo 56, talla A-112). Manana, en orden: la
firma de instrumento "mitad gratis" (PRESENTADA, sin firmar - coste de
ledger CERO) - la GRANDE de cuatro cegueras con TRES barridos escalonados
(~3h dimensionadas, NO fusionar S2/S3) - y el cierre del eje (deuda B, gate
F3, R-5 a error). Fuera del carril, registrados: E1 composicion del array
(con la correccion de E-talla), lo abierto por el ARIA, y el parrafo de
doctrina que querria vivir en reference.md.
Leyes de la sesion escritas: interrupciones matan agentes (informe a disco
INCREMENTAL) - el supervisor mira capturas antes de cada commit - las demos
no entran ni como prueba central - F5 compartidas en serie.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
refactor(theming)!: trece canales de valor hablan como lo que son - privados
Eje-codemod firmado 2026-08-26 (destino firmado dos veces: los 318 y la ley
del espacio cerrado). Flip atomico escritor+lectores por nombre, barrido por
git ls-files (94 ocurrencias en 36 ficheros; el barrido destapo lectores que
ninguna lista traia: el comentario del morfo de knob, dos demos, y PLAN-
background). 32 ficheros.
- background pointer-{x,y,px,py} + progress · color-swatch fill ·
emoji-picker columns · knob {angle,progress,start-angle,sweep} · menubar
panel-anchor-width · text-gradient duration -> --_{c}-*. El nombre viejo
computa vacio en los siete componentes.
- PARADO con expediente: --navigation-menu-indicator-h NO se renombra - es
una de CUATRO hermanas escritas en un literal, el README de soma las
enseña como API del consumidor (dos ejemplos de CSS de app leen -h) y -w
es clave DECLARADA del contrato. Privatizar una de cuatro parte una API
documentada. Tres opciones redactadas en next-features SS13, sin elegir;
el registro PENDING_PRIVATE_RENAME queda con DOS entradas (esta + motion),
cada una con su razon.
- La trampa del censo NO mordio y la prediccion estaba mal por un orden de
magnitud: UNA reclasificacion (color-swatch.background), no ~15 - el censo
cuenta knobs de APARIENCIA y doce canales viven en geometria o conservan
un publico hermano. public 3074->3073, channel 36->37, reach 73%,
atHundred 65: el suelo no se toca.
- Verificacion dinamica de los SIETE canales vivos por CDP (verbatim en el
acta de la sesion): el parallax sigue al puntero con la privada (translate
-28,-24 -> 32,28 = x*depth), el knob rota por teclado (-27deg -> 0deg,
arco 108 -> 135 = progress*sweep), el chip pinta su prop, columns 9/6/12
tracks (control negativo: el nombre viejo a 3 no mueve nada), el panel
toma 886px del anchor, text-gradient 8s. Estatica: sonda 7/7 a 0 diffs
reales (el unico diff, un velo de emoji-picker, reproducido 2/2 = ruido);
color-swatch sin ruta de demo declarado en voz alta (la sonda con 0 nodos
es un guard que no inspecciona nada) y medido donde monta.
- Guard mutado por sus dos caras: entrada retirada reintroducida -> STALE;
nombre viejo devuelto a una receta -> missing. Docs ANOTADOS con fecha
(la adjudicacion medida de color-swatch del 23-08 intacta), volcados solo
donde describen codigo vivo. audit 162 PASS - docs:check 0/0 - --debt
1154/0/0 sin una clave movida - --names 0 - check 0 atribuibles.
Deuda menor anotada: la fila generada de audit/theming/background.md:72 la
regenerara el --report supervisado pendiente.
BREAKING: los trece nombres publicos viejos ya no existen; el canal se lee
--_{c}-* y sigue sin ser tuyo para fijarlo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
### FIRMA EJECUTADA (2026-08-26) — el codemod de los 14 canales (13 de 14)
**Qué se ejecutó**: los nombres públicos-con-forma que soma o el envoltorio
escriben POR INSTANCIA pasan a privados `--_{c}-*` — el destino que la firma de
los 318 ya había firmado (clase `channel` ) y que el registro
`PENDING_PRIVATE_RENAME` sólo contaba. **Trece renombrados, sus trece entradas
del registro RETIRADAS con acta**; el registro queda en **DOS** (no en una): la
de motion, que era la prevista, y una PARADA.
**El método, y es la mitad del resultado**: barrido `git ls-files` **de cada
nombre por el árbol trackeado entero** (94 ocurrencias en 36 ficheros), y flip
**ATÓMICO por nombre** — escritor y TODOS los lectores en la misma edición.
Nada de grepear los propios patrones: el barrido destapó lectores que ninguna
lista traía (el comentario del morfo de `knob` , las dos páginas de demo, nueve
menciones en `PLAN-background.md` ).
refactor(theming)!: el indicador de navigation-menu es CANAL - y el consumidor estiliza la PARTE
Firma "(a) completada" (2026-08-26), cerrada tras rechazar la especie
`output` por abrir excepciones (clase barata - frontera de prosa - patron ya
rechazado dos veces): las cuatro hermanas --navigation-menu-indicator-
{x,y,w,h} pasan a --_ (la adjudicacion que tabs ya firmo citando a ESTE
componente como precedente), indicator-w se RETIRA del contrato, y el README
de soma deja de enseñar a saltarse la composicion.
- Flip atomico escritor+lectores. Trampa del barrido, medida: el grep del
nombre LITERAL es ciego a la forma con llaves {x,y,w,h} - escondia tres
menciones. Barrido final: 0 consumos vivos de los nombres viejos.
- indicator-w retirada con acta MEDIDA (y una auto-correccion: la primera
acta decia "con la barra cerrada" y era falso - el indicador se monta
condicional y hay 0 nodos; lo real, con transiciones CONGELADAS: solo una
regla !important de autor le llegaba, y la unica ventana donde asomaba
era el indicador montado sin rect - un subrayado de ancho cero). Contrato
44 -> 43, generated -1 linea, ningun ledger rancio.
- README de soma: las medidas siguen tabuladas como canales privados "not
consumer API"; la seccion nueva enseña la PARTE ([data-navigation-menu-
indicator] + data-state + los tres pomos thickness/bg/radius) con
ejemplos VERIFICADOS POR MEDICION (el ejemplo 1 es literalmente el
control positivo: block-size 2 -> 9px). Hueco FLAGGED sin acuñar: el
ejemplo viejo de pildora no tiene traduccion - falta un eje de forma en
la parte; en SS13.
- Registro PENDING_PRIVATE_RENAME -> UNA entrada (motion). SS14 NUEVO en
next-features: unificar tabs (--indicator-* SIN prefijo, MeasuredIndicator
:80-83, 2 claves global en el ledger) - con el hallazgo de que ningun
guard los caza HOY porque no llevan prefijo: el espacio cerrado premio al
que nombraba mejor.
- Numeros: public 3073->3072, channel 37->38, reach 73% y atHundred 65
intactos (ningun redondeo cayo), --names 4566 con 0 desviadas, centinela
nav-menu 42/43 con la misma unica adjudicacion, --debt identico.
- Dinamica verbatim: el indicador DESLIZA (left 0 -> 111px, ancho 107 ->
108.56 = rect del trigger, canal w/h == triggerRect), los nombres viejos
computan vacio en el elemento (control negativo 777/333: nada se mueve).
Guards: 78 tests verdes + soma 9/9 + mutacion por las dos caras + audit
162 PASS + docs:check 0/0.
BREAKING: los cuatro nombres publicos del indicador ya no existen y
--navigation-menu-indicator-w sale del contrato; el indicador se estiliza
por su parte y sus pomos.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
**✅ RESUELTO — `--navigation-menu-indicator-h` , con (a) FIRMADA Y EJECUTADA
(2026-08-26, tarde).** Estuvo PARADO porque no era un canal suelto: el provider
escribe **CUATRO hermanas** en un mismo literal, el README de soma las enseñaba
las cuatro bajo `## CSS Variables` como forma controlada por el consumidor (con
dos ejemplos leyendo `-h` ), y ** `-w` era clave DECLARADA del contrato** — la
única razón por la que el guard veía a `-h` sola. Ver §«FIRMA EJECUTADA — el
indicador de navigation-menu» abajo. **El registro queda en UNA** (motion).
refactor(theming)!: trece canales de valor hablan como lo que son - privados
Eje-codemod firmado 2026-08-26 (destino firmado dos veces: los 318 y la ley
del espacio cerrado). Flip atomico escritor+lectores por nombre, barrido por
git ls-files (94 ocurrencias en 36 ficheros; el barrido destapo lectores que
ninguna lista traia: el comentario del morfo de knob, dos demos, y PLAN-
background). 32 ficheros.
- background pointer-{x,y,px,py} + progress · color-swatch fill ·
emoji-picker columns · knob {angle,progress,start-angle,sweep} · menubar
panel-anchor-width · text-gradient duration -> --_{c}-*. El nombre viejo
computa vacio en los siete componentes.
- PARADO con expediente: --navigation-menu-indicator-h NO se renombra - es
una de CUATRO hermanas escritas en un literal, el README de soma las
enseña como API del consumidor (dos ejemplos de CSS de app leen -h) y -w
es clave DECLARADA del contrato. Privatizar una de cuatro parte una API
documentada. Tres opciones redactadas en next-features SS13, sin elegir;
el registro PENDING_PRIVATE_RENAME queda con DOS entradas (esta + motion),
cada una con su razon.
- La trampa del censo NO mordio y la prediccion estaba mal por un orden de
magnitud: UNA reclasificacion (color-swatch.background), no ~15 - el censo
cuenta knobs de APARIENCIA y doce canales viven en geometria o conservan
un publico hermano. public 3074->3073, channel 36->37, reach 73%,
atHundred 65: el suelo no se toca.
- Verificacion dinamica de los SIETE canales vivos por CDP (verbatim en el
acta de la sesion): el parallax sigue al puntero con la privada (translate
-28,-24 -> 32,28 = x*depth), el knob rota por teclado (-27deg -> 0deg,
arco 108 -> 135 = progress*sweep), el chip pinta su prop, columns 9/6/12
tracks (control negativo: el nombre viejo a 3 no mueve nada), el panel
toma 886px del anchor, text-gradient 8s. Estatica: sonda 7/7 a 0 diffs
reales (el unico diff, un velo de emoji-picker, reproducido 2/2 = ruido);
color-swatch sin ruta de demo declarado en voz alta (la sonda con 0 nodos
es un guard que no inspecciona nada) y medido donde monta.
- Guard mutado por sus dos caras: entrada retirada reintroducida -> STALE;
nombre viejo devuelto a una receta -> missing. Docs ANOTADOS con fecha
(la adjudicacion medida de color-swatch del 23-08 intacta), volcados solo
donde describen codigo vivo. audit 162 PASS - docs:check 0/0 - --debt
1154/0/0 sin una clave movida - --names 0 - check 0 atribuibles.
Deuda menor anotada: la fila generada de audit/theming/background.md:72 la
regenerara el --report supervisado pendiente.
BREAKING: los trece nombres publicos viejos ya no existen; el canal se lee
--_{c}-* y sigue sin ser tuyo para fijarlo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
**⚠ LA TRAMPA DEL CENSO NO MORDIÓ, y la predicción estaba MAL por un orden de
magnitud.** Se esperaba que ~15 knobs pasaran de `public` a `channel` y que el
suelo pudiera rozar el redondeo. Medido: **UNA sola clave** se reclasifica
—`color-swatch.background`— porque el censo cuenta **knobs de APARIENCIA** , y
las otras doce viven en declaraciones de GEOMETRÍA (`translate`, `rotate` ,
`inline-size` , `grid-template-columns` , `animation-duration` ) o en
declaraciones que **conservan un público hermano** y siguen puntuando `public`
(el `conic-gradient` de `knob` lee `--knob-track-bg` ; el panel de `menubar` lee
`--menubar-panel-min-width` como fallback). Números: `public` 3074 → **3073** ,
`channel` 36 → **37** , denominador 4228 → 4227, reach **73 %** , `atHundred`
**65**, ledger **1154 · 0 NEW · 0 STALE** . **El suelo NO se toca** — no hubo
nada que ajustar ni que fingir.
**Neutralidad, medida en dos planos.** Estática: sonda estándar antes/después
sobre los 7 componentes, **0 diffs reales** ; el único diff (`emoji-picker`, un
`background-image` de velo en el trigger, bloque `open` ) se **reprodujo 2/2
sobre código idéntico** — ruido del instrumento. ⚠ `color-swatch` **no tiene
ruta de demo** (404) y la sonda devuelve **0 nodos** : su «0 diffs» es un guard
que no inspecciona nada y NO cuenta como prueba; se midió donde de verdad monta.
Dinámica (donde estos canales viven y la sonda no llega), 7/7 por CDP:
`background` puntero →`_x − 0.7/0.8`, `_y − 0.6/0.7` , `_px 15 %/90 %` ,
`_py 20 %/85 %` , translate `− 28px − 24px` → `32px 28px` (= x × depth 40px, exacto)
y el foco del spotlight `at 15 % 20 %` → `at 90 % 85 %` ; el quinto canal
(`--_background-progress`) es la rama `@supports not(view())` que Chrome nunca
corre, verificada forzando el gate: `0.379 → 1` al scrollear · `knob` accionado
por teclado, `_angle − 27deg → 0deg` , `_progress 0.4 → 0.5` , el indicador rota
igual y la parada del arco `108deg → 135deg` (= progress × sweep) ·
`color-swatch` tres chips, `#7c3aed/#06b6d4/#f59e0b` → `rgb(124,58,237)` /
`rgb(6,182,212)` / `rgb(245,158,11)` · `emoji-picker` privado 9 → 9 tracks, y
moverlo a 6 y a 12 da 6 y 12 tracks, **mientras fijar el nombre VIEJO a 3 no
mueve nada** (control negativo) · `menubar` panel anclado, `_anchorWidth 886px`
= barra 886 = panel 886 · `navigation-menu` (el PARADO) sin regresión, `-h`
sigue pública en 36px = altura del trigger activo · `text-gradient` inline
`8s` → `animation-duration: 8s` en el hijo `[data-text-gradient-fill]` .
**En los siete, el nombre VIEJO computa vacío.**
**Guard mutado por sus dos caras**: reintroducir una entrada retirada →
**STALE nombrándola**; devolver un nombre público viejo a una receta →
**`missing` nombrándolo**. Suites de los tocados 18/18, `component:audit`
**162 PASS / 4 NEEDS-WORK** idéntico, `docs:check` **0/0** , `--names` **0
desviadas**, `npm run check` **0 errores atribuibles** (verificado POR FICHERO).
**Docs: se ANOTARON, no se reescribieron** — fichas medidas, README de
`color-swatch` , `PLAN-background.md` (una anotación fechada cubre sus nueve) y
`STUMBLES.md` §7. El nombre nuevo sí se volcó donde el texto describe código
VIVO (READMEs de componente y las dos demos). Queda anotada la fila GENERADA
`audit/theming/background.md:72` , que la regenerará el `--report` pendiente.
**Hallazgo lateral, ajeno**: el control `columns` de la demo de `emoji-picker`
es un `<Slider>` DESNUDO y `slider.svelte` renderiza sólo su provider — un
`div[data-slider]` **vacío** , sin raíl ni pulgar. No se puede accionar.
refactor(theming)!: el indicador de navigation-menu es CANAL - y el consumidor estiliza la PARTE
Firma "(a) completada" (2026-08-26), cerrada tras rechazar la especie
`output` por abrir excepciones (clase barata - frontera de prosa - patron ya
rechazado dos veces): las cuatro hermanas --navigation-menu-indicator-
{x,y,w,h} pasan a --_ (la adjudicacion que tabs ya firmo citando a ESTE
componente como precedente), indicator-w se RETIRA del contrato, y el README
de soma deja de enseñar a saltarse la composicion.
- Flip atomico escritor+lectores. Trampa del barrido, medida: el grep del
nombre LITERAL es ciego a la forma con llaves {x,y,w,h} - escondia tres
menciones. Barrido final: 0 consumos vivos de los nombres viejos.
- indicator-w retirada con acta MEDIDA (y una auto-correccion: la primera
acta decia "con la barra cerrada" y era falso - el indicador se monta
condicional y hay 0 nodos; lo real, con transiciones CONGELADAS: solo una
regla !important de autor le llegaba, y la unica ventana donde asomaba
era el indicador montado sin rect - un subrayado de ancho cero). Contrato
44 -> 43, generated -1 linea, ningun ledger rancio.
- README de soma: las medidas siguen tabuladas como canales privados "not
consumer API"; la seccion nueva enseña la PARTE ([data-navigation-menu-
indicator] + data-state + los tres pomos thickness/bg/radius) con
ejemplos VERIFICADOS POR MEDICION (el ejemplo 1 es literalmente el
control positivo: block-size 2 -> 9px). Hueco FLAGGED sin acuñar: el
ejemplo viejo de pildora no tiene traduccion - falta un eje de forma en
la parte; en SS13.
- Registro PENDING_PRIVATE_RENAME -> UNA entrada (motion). SS14 NUEVO en
next-features: unificar tabs (--indicator-* SIN prefijo, MeasuredIndicator
:80-83, 2 claves global en el ledger) - con el hallazgo de que ningun
guard los caza HOY porque no llevan prefijo: el espacio cerrado premio al
que nombraba mejor.
- Numeros: public 3073->3072, channel 37->38, reach 73% y atHundred 65
intactos (ningun redondeo cayo), --names 4566 con 0 desviadas, centinela
nav-menu 42/43 con la misma unica adjudicacion, --debt identico.
- Dinamica verbatim: el indicador DESLIZA (left 0 -> 111px, ancho 107 ->
108.56 = rect del trigger, canal w/h == triggerRect), los nombres viejos
computan vacio en el elemento (control negativo 777/333: nada se mueve).
Guards: 78 tests verdes + soma 9/9 + mutacion por las dos caras + audit
162 PASS + docs:check 0/0.
BREAKING: los cuatro nombres publicos del indicador ya no existen y
--navigation-menu-indicator-w sale del contrato; el indicador se estiliza
por su parte y sus pomos.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
### FIRMA EJECUTADA (2026-08-26) — el indicador de navigation-menu
**Qué se firmó**: la opción ** (a)** del PARADO. Las CUATRO medidas del trigger
activo pasan a privadas — `--_navigation-menu-indicator-{x,y,w,h}` , flip
ATÓMICO escritor + todos los lectores, con barrido `git ls-files` por nombre —,
**`indicator-w` se RETIRA del contrato** (44 → 43 filas) y la sección
`## CSS Variables` del README de soma se reescribe al camino de la casa: el
consumidor estiliza **la PARTE** (`[data-navigation-menu-indicator]` y su
`data-state` ) con los tres pomos de forma, no las medidas.
**Lo que se RECHAZÓ, y por qué importa**: (b) declarar `-x/-y/-h` para casar con
el README bendeciría como superficie de tema cuatro medidas por instancia —
justo lo que la clase `channel` de la firma de los 318 existe para negar. Y se
rechazó una especie nueva, ** `output` ** (tercera clase entre público y privado):
abre excepciones sobre una clase barata con frontera de PROSA, patrón ya
rechazado dos veces.
**`-w` era un token-que-miente, MEDIDO** (CDP, transiciones CONGELADAS — en esta
parte `inline-size` va transicionada y una lectura inmediata devuelve el valor
VIEJO; el probe informaba «no se movió» de TODO hasta congelarlas): con el
subrayado pintado, escribirlo en la raíz del componente —lo que hace el
centinela— deja `inline-size` en **107px** , y en `:root` igual; **sólo una regla
`!important` de autor llega** (1234px), porque soma escribe INLINE en el
elemento. La única ventana donde la declaración asomaba es el indicador montado
**SIN rect todavía** (`isOpen` true, `triggerRect` aún null; o `forceMount` ):
ahí `inline-size` lee el `0px` que daba esta clave y un write en el host lo
mueve a 1234px. Es decir, llegaba **sólo donde no pintaba nada** . ⚠ El
indicador está montado CONDICIONALMENTE (`{#if state.isOpen || forceMount}`):
con la barra cerrada hay **0 nodos** en la página.
**Números**: `public` 3073 → **3072** , `channel` 37 → **38** , denominador
4227 → 4226, reach **73 %** y `atHundred` **65** intactos, `--names`
4567 → **4566** (0 desviadas), ledger **1154 · 0 new · 0 stale** . Centinela
`navigation-menu` **43/44 → 42/43** , misma única adjudicación
(`disabled-trigger-fg`): el total baja porque la clave sale del contrato, no
porque nada deje de llegar — **el fichero de excepciones no se toca** .
`component:audit` **162 PASS / 4 NEEDS-WORK** idéntico.
**Dinámica, que es la que vale aquí** (la sonda estándar es ciega a estos
canales): Products `w=107px h=36px` = rect del trigger, Solutions
`w=108.5625px h=36px` , `inline-size` las sigue (107 → 108.562) y `left`
**0px → 111px** — el subrayado DESLIZA — con `translateY(36px)` estable.
**Control negativo**: los nombres viejos computan **VACÍO** en el indicador, y
fijarlos en la raíz a 777px/333px no mueve nada. **Control positivo** : los tres
pomos del contrato siguen llegando (`block-size` 2 → 9px, `background` →
`rgb(1,2,3)` ).
**Guard**: `PENDING_PRIVATE_RENAME` queda en **UNA** entrada (motion), con acta
en el propio registro. Mutado por sus dos caras: reintroducir la entrada
retirada → **STALE nombrándola** ; devolver `--navigation-menu-indicator-w` a la
receta → ** `missing` nombrándolo**.
**⚠ Trampa del barrido**: el grep del nombre LITERAL es CIEGO a la forma con
llaves `--…-indicator-{x,y,w,h}` , que escondía tres menciones más (el comentario
de `navigation-menu.svelte` de eidos y dos filas de la demo). Hay que barrer
también la familia.
**Hueco FLAGGED, no acuñado**: el ejemplo viejo de *píldora / fondo de trigger*
no tiene traducción a pomos — la receta clava el `block-size` al grosor. Queda
en §13 de `next-features.md` , sin inventar un eje de forma.
**Abre expediente**: §14 de `next-features.md` — unificar `tabs` bajo la misma
adjudicación (`--indicator-{x,y,w,h}` SIN prefijo, escritos por la capa
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
compartida `MeasuredIndicator` , 2 entradas `global` en el ledger). **EJECUTADA
el mismo día**; ver la firma inmediatamente debajo.
### FIRMA EJECUTADA (2026-08-26) — §14, MeasuredIndicator con nombre POSEÍDO
**Qué se firmó**: la geometría que una capa COMPARTIDA publica es **canal** y
aterriza en el **namespace del ANFITRIÓN** —`--_{c}-indicator-{x,y,w,h}`—, no en
uno de capa. Tercera aplicación de la doctrina (`navigation-menu` fue la
segunda). **La capa es la PLUMA, no la dueña** : el rect es un hecho de cada
instancia del host. Un solo nombre de capa habría repetido el defecto un piso
más abajo — una medida por instancia en un espacio que nadie posee.
**Cómo llega el nombre**: `MeasuredIndicatorOpts` gana **un** campo,
`component: string` , y los dos hosts —los únicos, `git grep "new
MeasuredIndicator"`— pasan `tabsMorfo.kebab` / `radioGroupMorfo.kebab` , **nunca
un literal**: el canal queda atado a la declaración de morfo que lo posee.
**Cableado del CSS compartido** (`lib/sliding-indicator.css`, que no puede
deletrear el nombre del host): cada receta declara su alias local explícito
—`--_indicator-x: var(--_radio-group-indicator-x)`— y el compartido lee el
alias. Forma del puente THM-2, la misma que `calendar-surface.css` usa para
`--_calendar-surface-accent` : contrato EN el artefacto. `tabs` no consume la capa
(tiene bloque propio) y lee el nombre poseído directo.
**Números**: `tabs` **97 % → 100 %** (global 2 → 0, canal 0 → 2; 77 knobs y 79
claves de contrato INTACTOS — ni una acuñada ni retirada). Catálogo `atHundred`
**65 → 66**, global 763 → 761, canal 38 → 41, reach global **73 % intacto** ,
`--names` 4566 · 0 desviadas. Ledger: las **2 entradas de `tabs` retiradas**
(la clave entera desaparece), **1154 → 1152 · 0 NEW · 0 STALE** , con acta en la
cabecera de `theming-census-debt.ts` . `radio-group` no mueve una cifra.
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
**⚠ La trampa de clasificación, prevista y resuelta** — *causa CORREGIDA por el
adversarial el mismo día*: la premisa del alias que «esquiva y cae a residuo»
era CONTRAFACTUAL — el alias de §14 no lleva prefijo propio, el censo lo
descarta antes de coleccionar privados, y un knob que lo lea clasifica `global`
con la razón CORRECTA (medido construyéndolo: `1 new` , rojo). La extensión
TRANSITIVA del tercer paso se justifica por `tooltip` (alias con prefijo propio
sobre canal propio, reclasificado `exception` → `channel` como su comentario
firmado afirmaba); molde de `derivesFromPublic` . **Mutación de rigor** : un alias hacia un privado que SÍ
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
está declarado NO clasifica canal — `refs.length > 0` es la línea que lo impone.
Y el ORDEN de pasos es carga estructural: el segundo (deriva de un público) corre
antes, y por eso `--_tooltip-max-width` sigue siendo público.
**⚠ Un knob AJENO se reclasificó, con acta**: `tooltip.css:27` pasó de
`exception` a `channel` . **No es regresión** : el comentario firmado de esa
declaración ya decía «per-instance VALUE CHANNEL» con esas palabras — faltaba el
mecanismo, no el criterio, que es literalmente lo que el cuarto paso del censo
dice de sí mismo. `tooltip` no mueve su alcance. Acta en su ficha, §2-quater.
**⚠ La sonda estándar es CIEGA a esta clase de firma**: lee valores computados,
no nombres de var, así que un flip de nombre correcto le sale idéntico por
construcción. Sus **0 diffs en 2528 valores × 10 estados** prueban lo
CIRCUNDANTE, no el flip. Quien prueba el flip es la dinámica, y hay que
CONGELAR transiciones o `inline-size` devuelve el valor viejo: `tabs` desliza
(`translate 0 → 183.719px`, `inline-size 99.906 → 71.359px` , indicador exacto
sobre el trigger activo), `radio-group` sólo manifiesta su indicador en la
variante ** `segmented` ** y desliza igual (`4px 32px → 4px 60px`). Los cuatro
nombres viejos computan **cadena vacía** en ambos; control negativo en `:root` a
cero; control positivo probando además la CADENA del alias.
**Hueco FLAGGED, no acuñado**: ~~`--indicator-duration` / `--indicator-ease`
siguen bare~~ — **RESUELTO el item 2 (2026-08-26, `53810cb5e`)** : eran el ALIAS
de la capa, no contrato ni vocabulario; hoy son `--_indicator-{duration,ease}` .
Acta en `next-features.md` (hueco flagged de §14).
refactor(theming)!: el indicador de navigation-menu es CANAL - y el consumidor estiliza la PARTE
Firma "(a) completada" (2026-08-26), cerrada tras rechazar la especie
`output` por abrir excepciones (clase barata - frontera de prosa - patron ya
rechazado dos veces): las cuatro hermanas --navigation-menu-indicator-
{x,y,w,h} pasan a --_ (la adjudicacion que tabs ya firmo citando a ESTE
componente como precedente), indicator-w se RETIRA del contrato, y el README
de soma deja de enseñar a saltarse la composicion.
- Flip atomico escritor+lectores. Trampa del barrido, medida: el grep del
nombre LITERAL es ciego a la forma con llaves {x,y,w,h} - escondia tres
menciones. Barrido final: 0 consumos vivos de los nombres viejos.
- indicator-w retirada con acta MEDIDA (y una auto-correccion: la primera
acta decia "con la barra cerrada" y era falso - el indicador se monta
condicional y hay 0 nodos; lo real, con transiciones CONGELADAS: solo una
regla !important de autor le llegaba, y la unica ventana donde asomaba
era el indicador montado sin rect - un subrayado de ancho cero). Contrato
44 -> 43, generated -1 linea, ningun ledger rancio.
- README de soma: las medidas siguen tabuladas como canales privados "not
consumer API"; la seccion nueva enseña la PARTE ([data-navigation-menu-
indicator] + data-state + los tres pomos thickness/bg/radius) con
ejemplos VERIFICADOS POR MEDICION (el ejemplo 1 es literalmente el
control positivo: block-size 2 -> 9px). Hueco FLAGGED sin acuñar: el
ejemplo viejo de pildora no tiene traduccion - falta un eje de forma en
la parte; en SS13.
- Registro PENDING_PRIVATE_RENAME -> UNA entrada (motion). SS14 NUEVO en
next-features: unificar tabs (--indicator-* SIN prefijo, MeasuredIndicator
:80-83, 2 claves global en el ledger) - con el hallazgo de que ningun
guard los caza HOY porque no llevan prefijo: el espacio cerrado premio al
que nombraba mejor.
- Numeros: public 3073->3072, channel 37->38, reach 73% y atHundred 65
intactos (ningun redondeo cayo), --names 4566 con 0 desviadas, centinela
nav-menu 42/43 con la misma unica adjudicacion, --debt identico.
- Dinamica verbatim: el indicador DESLIZA (left 0 -> 111px, ancho 107 ->
108.56 = rect del trigger, canal w/h == triggerRect), los nombres viejos
computan vacio en el elemento (control negativo 777/333: nada se mueve).
Guards: 78 tests verdes + soma 9/9 + mutacion por las dos caras + audit
162 PASS + docs:check 0/0.
BREAKING: los cuatro nombres publicos del indicador ya no existen y
--navigation-menu-indicator-w sale del contrato; el indicador se estiliza
por su parte y sus pomos.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
feat(theming)!: la ley del espacio cerrado - un --{c}-* existe si y solo si base.ts lo declara
Firma 2026-08-26. El espacio de nombres publico queda CERRADO sobre el
contrato: no hay tercer estado. El fallback es seguridad de VALOR, no
escapatoria de contrato; declarada la clave, el fallback inline muere (el
default vive en UN sitio, base.ts).
- El barrido real del catalogo: 25 nombres propios con fallback fuera de
contrato en 10 componentes (la prosa decia 13 en 2). ONCE eran knobs de
tema y quedan DECLARADOS con su default verbatim, scope root medido:
mockup 9 (con --mockup-phone-shadow ACUNADA - un nombre cargaba shadow-4
en el marco y shadow-5 en el bisel: un nombre con dos defaults es la
mentira que la ley mata) y text-scramble 2. Fallbacks inline retirados.
- Los otros QUINCE no son knobs: 14 canales de VALOR que soma/envoltorio
escriben por instancia (destino ya firmado por la firma de los 318:
--_{c}-*; el codemod es un eje propio) y el default de motion cuyo hogar
es EidosConfig.motion (su entrada structural queda intacta). Viven en el
registro PENDING_PRIVATE_RENAME del guard - nombrados, fechados, con
destino escrito y STALE simetrico: contarlos, no bendecirlos. La firma
medida de color-swatch.fill (2026-08-23) queda INTACTA y citada.
- El guard de fantasmas endurecido al "si y solo si": un --{c}-* del propio
componente fuera de contrato es ROJO con o sin fallback; el prestamo
ajeno y el sistema conservan sus reglas. Mutaciones: var inventado con
fallback -> rojo nombrado; prestamo ajeno -> verde; entrada de registro
rancia -> rojo STALE.
- Neutralidad PROBADA: generated/base.css = +11 lineas y nada mas; computed
A/B en navegador reconstruyendo el mundo viejo inline sobre el mismo nodo
- mockup 3 nodos x 2 cromos x 6 propiedades identicos (el bisel conserva
shadow-5), text-scramble identico. mockup se midio donde monta de verdad
(/blocks/feature-split): no tiene demo propia.
- Numeros: solo no-contract 18 -> 16. El suelo NO sube y la razon importa:
la ley cerraba un hueco de CONTRATO, no de alcance - esas declaraciones
ya puntuaban public; lo que faltaba era declarar el NOMBRE.
- Efecto lateral anotado en la clave, el handoff y next-features: el crudo
var(--primitive-neutral-12) migro verbatim a base.ts y R-4.6 (que escanea
CSS) ya no lo ve - la deuda sigue, ahora nombrada en el contrato.
- docs: recipe-contract SS4 reescrito con la ley y sus corolarios (el
value-reference con-fallback queda acotado a vocabulario ajeno/sistema);
CONTINUE y next-features al dia - pendientes del eje: el codemod de los
14 canales, el cableado del canal de motion, palabras y timeline.
BREAKING: consumir un --{c}-* propio no declarado es rojo desde hoy, con o
sin fallback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
### FIRMA EJECUTADA (2026-08-26) — la ley del espacio cerrado
**Qué se firmó**: el espacio de nombres público es **CERRADO sobre el
contrato** — un `--{c}-*` existe **si y sólo si** `base.ts` lo declara, no hay
tercer estado. Corolarios: el fallback es dispositivo de seguridad de VALOR, no
escapatoria de contrato; declarada la clave, el fallback inline sobre el nombre
público PROPIO muere (el default vive en UN sitio); el guard de fantasmas pasa
al «si y sólo si» — un `--{c}-*` propio fuera de contrato es rojo, con o sin
fallback. El vocabulario AJENO (préstamo de otro componente) y el de sistema
conservan sus reglas: el guard filtra por prefijo propio y no los ve.
**Lo que el barrido previo encontró — y por qué importa**: no eran dos
componentes. El catálogo tenía **25 nombres propios con fallback fuera de
contrato en 10 componentes** (27 sitios), y se parten en DOS CLASES:
- **11 knobs de tema de verdad** → declarados: `mockup` × 9, `text-scramble` × 2.
- **14 CANALES DE VALOR** que soma o el envoltorio escriben inline por
instancia → **NO se declaran** (declararlos revertiría la firma medida del
2026-08-23 que retiró `--color-swatch-fill` del contrato) **ni se renombran
aquí** (es codemod de otro eje). Van a un REGISTRO nombrado y fechado dentro
del propio test, `PENDING_PRIVATE_RENAME` , con razón y destino por entrada.
\+ `--motion-stagger-each-default` , que no es canal (nadie lo escribe): su
default pertenece a `EidosConfig.motion` . **15 entradas.**
El registro es el patrón ledger de la casa: **no bendice, cuenta** , y **sólo
puede menguar** — una entrada que deja de describir un consumo (renombrada,
declarada, muerta) se reporta **STALE** y sigue roja hasta borrar la línea.
**La mentira que la ley mató, en concreto**: `--mockup-shadow` cargaba DOS
defaults bajo un nombre — `var(--shadow-4)` en el marco, `var(--shadow-5)` en
el bisel del teléfono — así que un tema que lo moviera no podía saber cuál de
los dos tocaba. Se acuñó `--mockup-phone-shadow` : superficie distinta, nombre
distinto. El TSC no podía expresarlo de otro modo (sus ejes de scope son
cerrados y `data-chrome` no es uno).
**Neutra en píxel, medida dos veces**: el diff de `generated/` son esas 11
líneas con su default verbatim y NADA más; y el A/B en navegador — cada token
nuevo forzado a `initial` con las declaraciones viejas restauradas inline —
dio computed idéntico en los tres mockups de `/blocks/feature-split` (ambos
cromos; el bisel conserva `shadow-5` y el marco `shadow-4` , que era justo lo
que la acuñación protegía) y en `text-scramble` . ⚠ `mockup` **no tiene ruta de
demo propia**: se mide donde de verdad monta, en `/blocks/*` .
**Números**: `no contract entry` **18 → 16** ; todo lo demás QUIETO — reach
73 %, 65 al 100 %, ledger 1154 · 0 NEW · 0 STALE, audit **162 PASS / 4
NEEDS-WORK** idéntico, `--names` 0 desviadas, `docs:check` 0/0. El suelo NO
sube: la ley cerraba un hueco de CONTRATO, no de alcance (esas declaraciones ya
puntuaban `public` — lo que faltaba era declarar el NOMBRE).
**Muta-prueba de tres caras**: `var(--mockup-inventado, red)` (propio, CON
fallback) → **rojo nombrando la clave** · el mismo inyectado con un nombre
AJENO y fallback → **verde** · una entrada del registro que deja de describir
un consumo → **rojo STALE nombrándola** .
**Efecto lateral que hay que saber**: el crudo `var(--primitive-neutral-12)`
migró verbatim de `mockup.css:73` a `base.ts` como default de
`mockup.phone-bezel` . Sigue siendo deuda R-4.6 — pero la regla escanea CSS de
componente y ya no lo ve, así que la fila de `mockup` perdió ese error **sin
que nadie lo arreglara**. Queda anotado en la propia clave y en
`next-features.md` ; `mockup` sigue NEEDS-WORK por su E-2.3 (README ausente).
### FIRMA EJECUTADA (2026-08-26) — los 318 privados no-derivados
**Qué se firmó**: la «clasificación de los 318», en tres piezas —
`e812d3ffd` (F1: el censo aprende a MEDIR puente y canal) · `a74aeec7b`
(F2: el residuo adjudicado clave a clave) · este commit (F3: el suelo sube y
la prosa se salda). Cierra el agujero que la cabecera del ledger nombraba: la
tercera clase no-alcanzada ya no vive sólo bajo el `reachPct` grueso.
**La aritmética, sin resto**: 318 = **132 puente** + **36 canal** + **84
anotados** + **66 al ledger** . Las dos primeras las decide la MEDIDA (el
puente contra la salida real de `renderRecipePaletteForward` , no contra la
forma del nombre; el canal contra quién escribe el privado — nadie lo
declara, lo pone soma o el envoltorio por instancia); las otras dos son actos:
la válvula nueva `/* private: <razón> */` sobre la declaración (clase
`exception` , la de siempre, no un tier nuevo) y una entrada de ledger con
`private` como `DebtClass` de pleno derecho, con `newDebt` y STALE simétricos.
**Los cuatro números que quedan vigentes**: reach **73 %** (3074/4228 —
el numerador NO se movió, cayó el denominador 4480 → 4228) · **65 componentes
al 100 %** · ledger **1154** claves (763 global + 325 literal + 66 private) ·
**162 PASS** en `component:audit` , idéntico.
**Las cuatro contradicciones con ficha que la medida destapó** (F2 las dejó
señaladas; ninguna se resolvió a ojo):
- `metrics` — su §5 firmado decía que el conmutador del icono derivaba ENTERO
de públicos. Cierto para `track` /`text`, **falso** para `solid` /`contrast`,
que leen roles crudos. Resuelto POR MEDIDA: 3 anotados, 2 al ledger.
- `timeline` — su §5 es **pre-B′ ** y se respetó tal cual (10 knobs, 5 notas). Queda
SEÑALADO para reabrir si la escalera de paleta de B′ pesa más que aquel
veredicto.
- `proof-of-human` — 17 knobs adjudicados por DOS notas, **sin §5 propia** que
lo dijera: la base del alias es verbatim la que el forward declara para ese
slot (medido dos veces). El alias `--_proof-of-human-accent{,-soft}` es
**borrable a coste cero de píxel** — leer el puente directo clasificaría
`bridge` sin anotación; registrado como trabajo futuro en §13.
- `listbox` — sus 6 knobs (5 notas) dicen «adopto la capa `list-surface` », y son
**reversibles** el día que §13 le dé receta propia a esa capa (diez
componentes de golpe).
### FIRMA EJECUTADA (2026-08-25) — «la mitad gratis»: cegueras 4 y 5, coste de ledger CERO
**Qué se firmó** (`047464389`): las dos piezas del expediente VA que NO
compartían el coste caro — el codemod ciego a la IIFE con sus dos hermanos, y
los cinco huecos de la sonda más el sexto propio (el pase de FOCO prometido e
inexistente). Tres ficheros, **ni una entrada del ledger** . Ejecutada por
cuatro agentes (tres constructores + uno ADVERSARIAL con mandato de refutar),
con bases capturadas ANTES de editar.
**Los números**: centinela `label` 1/2 y `switch` 27/52 **byte a byte
idénticos** a las bases pre-firma; sonda de `card` **0 diffs en sus 7 bloques
viejos**; `editable` estrena bloque `open` (25 filas, 6 con `data-editing` ) y
dos corridas sobre código idéntico dan **0 diffs en TODOS los bloques** ;
`menubar` abre por la entrada del centinela (6 nodos → 7, con el panel) y
`chat-message` 24 filas × 2 corridas = 0 diffs; codemod 145/145 bloques,
avatar `depth 3` con **97** claves (86 públicas + 11 privadas), laboratorio
sobre copias (duplicado inyectado DETECTADO, renombrado = 1 línea); importar
el centinela: 0,85 s sin navegador.
**Las decisiones que deja escritas**:
- `COMPONENT_OVERRIDES` es **UNA tabla** : la sonda la importa y `OPEN_TRIGGER`
se poda de sus copias literales. La guarda de entrypoint lleva
`realpathSync` — hallazgo del adversarial: sin el realpath muere a través de
un junction (exit 0 sin inspeccionar nada), y este repo usa worktrees con
junctions.
- La vía de carga del codemod **SE QUEDA en tsx** : «el censo corre con node
pelado» era FALSO (todo `src/uix/morfo` importa sin extensión).
- `prepareWith` en la sonda sólo corre sin fila en `DEMO_VARIANTS` (re-clicar
APAGA los checkboxes que `prepare()` ya encendió) — y eso deja a la vista la
deuda de `search-field` (§13).
- El no-determinismo de `chat-message` quedó ACOTADO al bloque `rest` de la
sonda (13 vs 16 nodos, chips sin cuajar al medir) — dato para la GRANDE.
**Lo que quedó fuera, con su registro en §13**: el barrido de variantes de la
sonda (ensanche diferido por el propio expediente) · el clear-trigger de
`search-field` en el pase `open` · la asimetría de escenario de los seis con
`prepareWith` sin fila · el cortocircuito `alreadyOpen` que la sonda no tiene ·
y **TRES lectores independientes** de la estructura de `base.ts` (codemod,
censo, centinela — la próxima forma nueva se enseña tres veces). El `catch`
del `prepareWith` del CENTINELA sigue MUDO **a propósito** : es la ceguera 6,
S1 de la GRANDE.
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
(007c2af52, hoy inocuo), checkbox.stroke-ease, residuo del hover.
- Anota la retirada de TONE_UNREACHED en la cronica de B' (changelog SS53 y
next-features) y en las leyes del handoff.
- Reescribe el handoff: las DOS firmas de instrumento estan ejecutadas; el
eje pasa a su CIERRE (deuda B, gate de F3, R-5 a error).
Catalogo tras la firma: 2918/3577 claves vivas (78% -> 82%). Tier de
patrones 28 -> 16, 15 de 16 son PALETTE_FLOOR, cero zombis, 659 muertas
todas con razon.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
### FIRMA EJECUTADA (2026-08-25) — «la GRANDE»: el guard deja de estar ciego, en tres barridos
**Qué se firmó** (`6392d6003` · `b4dd5a906` · `b9cef9a43` ): las cegueras
6+1+3+2 del expediente VA, UNA firma, TRES barridos del ledger ENTERO (91
componentes cada uno), ejecutada con el mismo esquema de agentes que «la mitad
gratis» (tres constructores en serie + adversarial con mandato de refutar:
**12/12 claims confirmados**).
- **S1** — el `prepareWith` GRITA (lo que cae en su catch es un control que
estaba y falló — la fuente de las muertes fantasma) y el STALE ve los
PATRONES (`reasonFor`, mensaje que distingue «retira la exacta» de
«ESTRECHA el patrón»). Barrido: 91/91 verdes, 40,8 min, 0 avisos. Cosecha:
los dos patrones `PLANE_SUPERSEDED` de `toast` (18 claves), rancios desde la
noche de §12.9, RETIRADOS con 3/3 de reproducción.
- **S2** — el chooser tipa la sonda por el VALOR por defecto leído de
`base.ts` , no por el nombre (357 claves cambian de sonda; 320 de la clase A
«vivo por accidente» IACVT). MONÓTONO medido: 91/91, sólo `avatar` +1 y
`stepper` +1, sus dos exactas retiradas. Ni `%` ni enteros se clasifican
(tipar el `0` habría matado en falso 7 claves vivas).
- **S3** — tono+estado: tono en el pase de hover · tono MEDIAL `(^|-)` (las
16 de `tag-group` ) · hover para claves de tono muertas (las 21 de
`file-upload` ) · seis ejes de estado como DATO, valores del morfo/receta/DOM
real. Barrido: 91/91, 43,8 min, exactamente los 9 previstos, ** +140 claves
(catálogo 2776 → 2918, 78 % → 82 % de claves vivas)**. **130/132
`TONE_UNREACHED` reviven; las 2 que no eran `PALETTE_FLOOR` ** (el tono HOST
por defecto — test de dos caras en checkbox y radio-group, firma idéntica en
los ocho componentes).
**El ledger después**: 10 patrones retirados + 2 estrechados + 7 exactas
retiradas + la constante `TONE_UNREACHED` RETIRADA (la muerte que su docstring
pedía). Tier de patrones **28 → 16, 15 de los 16 son el único hecho
`PALETTE_FLOOR` **, y el adversarial verificó que los 16 cubren SOLO claves
muertas — cero zombis — y que ninguna clave muerta quedó sin razón (659
muertas, 0 sin adjudicar).
**Dos correcciones al expediente, reproducidas dos veces antes de tocar**: las
`-text` de `tags-input` SÍ reviven (la causa del arquetipo sólo tapa el ítem
RESALTADO; la escena no tiene ninguno, y el token pinta además dos nodos
hermanos fuera de esa regla) · `tag-group.hover-item-fg` la callaba su
`data-state='selected'` nativo — el nodo es un `<a data-archetype='trigger'>`
que ninguna regla de arquetipo toca.
**Deuda nueva registrada en §13** (adversarial, ninguna bloquea): la asimetría
del estampado (`data-color` en TODOS los nodos vs sólo el proveedor en
producción — medido que NO es la causa de ninguna revivida) · el ternario
falsy de la restauración de atributos (un `attr=""` se borra en vez de
restaurarse; hoy inocuo) · `checkbox.stroke-ease` con sonda de color (única
de las 51 de easing) · el residuo del recorte del hover
(`button.palette-element`, escrito en su propia razón).
### EL CIERRE, EJECUTADO (2026-08-25) — deuda B + clase `structural` + R-5 a `error` con LEDGER
**✅ EJECUTADO** con el mismo esquema de agentes (tres constructores + un
adversarial que confirmó 11 claims y refutó dos números de prosa). Cinco
commits: `2c61946fb` (clase `structural` ) · `ef47f3447` (deuda B) ·
`69d69d43c` (el ledger de deuda) · `1ba518fcc` (correcciones del adversarial).
- **Deuda B saldada**: `proof-of-human` (20 claves derivadas) ·
`audio-player` (README nuevo; es un skin sobre media-player que consume sus
61 claves y añade 8; sin demo propia a propósito) · `palabras` (sección
honesta SIN tabla: sin contrato en `base.ts` , y sus 117 nombres
`--palabras-*` son la proyección del `scheme-style` del documento — canal
de VALOR, otro eje; la clasificación del censo sobre él queda EN CUESTIÓN,
§13).
- **Clase `structural` **: los cinco 0 %-por-naturaleza (`aspect-ratio` ·
`text-blur` · `cascade` · `motion` · `date-picker` ) salen del denominador
con su razón EN el artefacto (forma `LAYER_VOCABULARY` ). Reach 68 → 69 %,
no-contract 23 → 18, el gate deja de ser inalcanzable por construcción.
- **R-5 a `error` con LEDGER DE DEUDA — la firma que rediseñó F3**: la deuda
real (1088 claves: 763 global + 325 literal, carriles WIP DENTRO) se
registra UNA vez por clave en `scripts/theming-census-debt.ts` — deuda
registrada, NO excepciones; la válvula sigue intacta y nunca ciega el
ratchet. R-5.1/5.2 a `error` contra el ledger (R-5.3 ya lo estaba): deuda
nueva = rojo NOMBRADO, entrada rancia = STALE hasta borrarla. Los techos
burdos del suelo RETIRADOS (el ratchet es por clave); `atHundred` corrige
su criterio (`public > 0`, 14 → 45). El gate de F3 queda redefinido
honesto: ** «censo 100 % ADJUDICADO»** — y está EN VERDE.
- **Pendiente de TU firma, nombrado en §13 y en la cabecera del ledger**:
~~los **318 privados no-derivados**~~ — ** ✅ FIRMADA Y EJECUTADA 2026-08-26**
(`e812d3ffd` · `a74aeec7b` + F3; ver §«FIRMA EJECUTADA — los 318» arriba) ·
feat(theming)!: la ley del espacio cerrado - un --{c}-* existe si y solo si base.ts lo declara
Firma 2026-08-26. El espacio de nombres publico queda CERRADO sobre el
contrato: no hay tercer estado. El fallback es seguridad de VALOR, no
escapatoria de contrato; declarada la clave, el fallback inline muere (el
default vive en UN sitio, base.ts).
- El barrido real del catalogo: 25 nombres propios con fallback fuera de
contrato en 10 componentes (la prosa decia 13 en 2). ONCE eran knobs de
tema y quedan DECLARADOS con su default verbatim, scope root medido:
mockup 9 (con --mockup-phone-shadow ACUNADA - un nombre cargaba shadow-4
en el marco y shadow-5 en el bisel: un nombre con dos defaults es la
mentira que la ley mata) y text-scramble 2. Fallbacks inline retirados.
- Los otros QUINCE no son knobs: 14 canales de VALOR que soma/envoltorio
escriben por instancia (destino ya firmado por la firma de los 318:
--_{c}-*; el codemod es un eje propio) y el default de motion cuyo hogar
es EidosConfig.motion (su entrada structural queda intacta). Viven en el
registro PENDING_PRIVATE_RENAME del guard - nombrados, fechados, con
destino escrito y STALE simetrico: contarlos, no bendecirlos. La firma
medida de color-swatch.fill (2026-08-23) queda INTACTA y citada.
- El guard de fantasmas endurecido al "si y solo si": un --{c}-* del propio
componente fuera de contrato es ROJO con o sin fallback; el prestamo
ajeno y el sistema conservan sus reglas. Mutaciones: var inventado con
fallback -> rojo nombrado; prestamo ajeno -> verde; entrada de registro
rancia -> rojo STALE.
- Neutralidad PROBADA: generated/base.css = +11 lineas y nada mas; computed
A/B en navegador reconstruyendo el mundo viejo inline sobre el mismo nodo
- mockup 3 nodos x 2 cromos x 6 propiedades identicos (el bisel conserva
shadow-5), text-scramble identico. mockup se midio donde monta de verdad
(/blocks/feature-split): no tiene demo propia.
- Numeros: solo no-contract 18 -> 16. El suelo NO sube y la razon importa:
la ley cerraba un hueco de CONTRATO, no de alcance - esas declaraciones
ya puntuaban public; lo que faltaba era declarar el NOMBRE.
- Efecto lateral anotado en la clave, el handoff y next-features: el crudo
var(--primitive-neutral-12) migro verbatim a base.ts y R-4.6 (que escanea
CSS) ya no lo ve - la deuda sigue, ahora nombrada en el contrato.
- docs: recipe-contract SS4 reescrito con la ley y sus corolarios (el
value-reference con-fallback queda acotado a vocabulario ajeno/sistema);
CONTINUE y next-features al dia - pendientes del eje: el codemod de los
14 canales, el cableado del canal de motion, palabras y timeline.
BREAKING: consumir un --{c}-* propio no declarado es rojo desde hoy, con o
sin fallback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
~~el idioma **`var(--{c}-x, fallback)` sin contrato**~~ — ** ✅ FIRMADA Y
EJECUTADA 2026-08-26** (§«FIRMA EJECUTADA — la ley del espacio cerrado»
arriba) · QUEDA la **re-clasificación de `palabras`** (117 nombres
`--palabras-*` puntuados `public` que son canal de VALOR) y las DOS deudas
de eje propio que la ley nombró (14 canales → `--_{c}-*` · cableado
`EidosConfig.motion` ), ambas detalladas en `next-features.md` .
· Deuda menor registrada: las fichas de `docs/audit/theming/`
esperan un `--report` supervisado post-`structural` (tarea aparte).
docs(theming): handoff 2026-08-25 noche - por aqui manana
Las cinco firmas del eje EJECUTADAS y los tres expedientes de 13 de la tarde
commiteados (ARIA F-1, velo/atajo 56, talla A-112). Manana, en orden: la
firma de instrumento "mitad gratis" (PRESENTADA, sin firmar - coste de
ledger CERO) - la GRANDE de cuatro cegueras con TRES barridos escalonados
(~3h dimensionadas, NO fusionar S2/S3) - y el cierre del eje (deuda B, gate
F3, R-5 a error). Fuera del carril, registrados: E1 composicion del array
(con la correccion de E-talla), lo abierto por el ARIA, y el parrafo de
doctrina que querria vivir en reference.md.
Leyes de la sesion escritas: interrupciones matan agentes (informe a disco
INCREMENTAL) - el supervisor mira capturas antes de cada commit - las demos
no entran ni como prueba central - F5 compartidas en serie.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
### FUERA del carril de theming (registrados HOY, no se ejecutan desde aquí)
- **E1 — los botones del array de form COMPONEN el Button** (clase A-112):
expediente completo de VC en `exped/vc/` + la corrección de E-talla: E2
ahorró el CONTEXTO pero no la LECTURA — E1 debe pasar `size` al Button que
inyecte o es la regresión medida (26→36 px en xs). Y las partes son MUDAS
(morfo sin evento; verbos canon: `commit-set-add` /`commit-remove`).
- Lo abierto por el ARIA: `tag-group` filas SIN celdas (el «precedente»
refutado midiendo) · `search-field` F-1 · la regla del censo de citas APG.
- El párrafo anchura-vs-densidad querría vivir TAMBIÉN en `reference.md`
junto a la norma tapada (dicho por E-talla, fuera de su alcance).
### Las leyes que dejó el día (sesión 2)
- **Una interrupción del autor MATA a los agentes en vuelo** — informe.md a
disco INCREMENTAL siempre; el disco sobrevive (V1 se recuperó íntegro).
- **El supervisor MIRA las capturas antes de cada commit** (regla del autor).
- **Las demos del sistema NO entran** ni como prueba central de una firma
(reafirmada sobre la captura del velo; la prueba citable es el barrido de
las 14 identidades del catálogo).
- **F5 compartidas se RETIENEN y liberan EN SERIE** cuando varios ejecutores
comparten `next-features` /`CONTINUE` — tres ejecutores hoy, cero pisadas.
- La sonda estándar ganó DOS mentiras registradas (se pisa el `data-size`
forzado sobre nodos compuestos · los `clamp()` fluidos no comparan sin
declarar viewport) — están en §«Lo que el instrumento aprendió».
Lo que queda de firma vieja NO cambia: la lista «Lo que espera TU FIRMA» de
más abajo quedó VACÍA el 2026-08-25 y las entradas EJECUTADAS de hoy están
intercaladas tras esta sección.
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
fix(theming): el velo del sistema no muere por un atajo - y el pin de chronos sobra
Dos hechos de cascada, hermanos de la firma 55:
1. Las reglas del suelo de popover usaban el ATAJO `background:` - expande a
`background-image: none` y MATA el velo de hover del sistema
(archetypes) cuando el orden de carga cae del otro lado. La regla dura lo
prohibe por escrito ("hover is the system's"). Partido a
`background-color:`: 0 px sobre las 14 identidades del catalogo (68
lecturas reposo + 68 hover, todas a cero; `rules split=2` en las catorce
como anti-vacio; control negativo 5/4), y el velo SOBREVIVE al orden
invertido - verificado con experimento de cascada aislado.
2. El pin de `chronos.css:417` RETIRADO: sus cinco declaraciones eran copias
textuales de `[data-button]` - 20 combinaciones variant x size identicas
con y sin el (control negativo 0/20). La adjudicacion de 13 era FALSA:
al `+N more` el velo se lo mata `button.css:69`/`:88`, con pin o sin el.
`calendar-select.css:14` NO es pin (vivo en 3 de 4 tallas) - se queda.
- Guarda extendida (active-eidos-config.test.ts): el suelo declara
`background-color` y NUNCA el atajo - validada por 4 mutaciones (las dos
ultimas prueban la mitad NEGATIVA, anadidas porque 1-2 solas la dejaban
sin morder).
- Sondas popover 0/448 y chronos 0/36.832 - eidos 443+1 ajeno - check
identico byte a byte antes/despues - docs-check 0/0 x2 - lint 0 invalid.
- Registro: changelog 56 (la prueba citable es el barrido de catalogo) -
13: `background-image` RESUELTO y `transition` como RESIDUO VIVO con su
numero (suelo `background,border-color` vs arquetipo
`opacity,background-color`: hoy el border-color del hover SALTA en vez de
animarse) - fichas de chronos (7 filas stale corregidas, recuentos
contados contra fichero: 202->198, 50->47), calendar (su HALLAZGO ya
resuelto por 55, cerrado) y emoji-picker - 5 textos stale ANOTADOS sin
reescribir (cada medida fue correcta con la cascada de su dia), con dos
matices: en gradient-picker solo caduco la mitad base, y open-trigger-fg
gana ahora por ESPECIFICIDAD, no por orden.
- Fuera del registro del eje, por regla dura del autor: el material de
sitio/demo (la inversion de imports de /alpha) - ademas desactivado por
esta misma firma en la capa que importa.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
### FIRMA EJECUTADA (2026-08-25) — el velo del sistema no muere por un ATAJO
**Qué se firmó** (changelog §56, reverso de §55 el mismo día): al bajar el sobre
de trigger de `popover.css` al suelo, §55 lo dejó a ** (0,0,0) — el mismo peldaño
que `archetypes.css` **, que es quien pinta el velo de estado del sistema. Y el
suelo declaraba su superficie con el ATAJO `background:` , que expande a
`background-image: none` — **la propiedad exacta donde vive ese velo** . Resultado:
el velo de hover de todo trigger desnudo dependía de qué hoja cayera después.
No sólo por la regla de hover: el `:where()` deja también la de REPOSO empatada
con la de hover del arquetipo, y ésa sola bastaba. La corrección son DOS
PALABRAS — `background-color:` en `popover.css:60` y `:75` .
**Los números**: **0 px** en el barrido de las **14 identidades del catálogo**
que montan un `[data-popover-trigger]` (68 lecturas en reposo → 0 movidas, 68 en
hover → 0 movidas, `rules split=2` en las 14) con control negativo diff 5 / 4;
las dos sondas del eje a **0 diffs** (`popover` 448 valores / 8 estados, `chronos`
36 832 / 7); y **el velo sobrevive al orden invertido** , donde con el atajo moría
(`linear-gradient(…8 %…)` → `none` ). Cae con la firma el pin `chronos.css:417`
(cinco declaraciones a (0,3,0) que ya no defendían nada): **0 diffs en 20
combinaciones `variant` × `size` **, control negativo 20/20 — §13 lo había
adjudicado mal, al velo del `+N more` lo mata `button.css:69` /`:88`. Guarda §55
apartado ** (f)** en `active-eidos-config.test.ts` , **4 mutaciones / 4 mordidas**
(las dos primeras muerden la mitad positiva, las dos segundas —el atajo AÑADIDO
junto al longhand— la negativa).
**Lo que quedó fuera, con su número en `next-features.md` §13**: el residuo
`transition` del MISMO empate (suelo `background, border-color` vs arquetipo
`opacity, background-color` , las dos a (0,0,0) — hoy el `border-color` del hover
de popover salta en vez de animarse), la decisión de producto «popover deja de
declarar hover propio» (no es coste cero: 0.9821 → 0.931 **más** el velo hoy,
sólo el velo después) y `calendar-select.css:14` , que **no es un pin** — retirarlo
rompe el tipo en 3 de 4 tallas (12 / 14 / 20 → 16 px).
**Fichas y prosa saneadas**: `chronos.md` (censo 202→198, propuesta 50→47, en
bloques `<!-- mano:… -->` para que sobrevivan a `--report` ), `calendar.md` (su
⚠ HALLAZGO «no determinista» lo cerró §55 y ya no apunta a §13), `emoji-picker.md`
y los tres comentarios de código que seguían afirmando ** (0,2,0)** del sobre
(`emoji-picker.css`, `gradient-picker.css` —sólo su mitad base, la de estados
sigue viva— y `lib/recipes/base.ts` ). Se ANOTAN, no se reescriben: cada medida
fue correcta con la cascada de su día.
fix(eidos): el eje size de form LLEGA a sus acciones - contexto A-112
<Form size="xs"> renderizaba acciones md: la talla moria en el provider
(form-submit/reset con default 'md', nada la propagaba) y del eje entero solo
sobrevivia el row-gap. Contexto de eidos calcado 1:1 de toolbar/context.ts
(el precedente A-112): form provee su size resuelto; Submit/Reset lo
consumen como default (su prop explicita gana; md standalone).
El eje va VERBATIM, no tapado en md - la bifurcacion de doctrina queda
RESUELTA Y ESCRITA (next-features 13 "Anchura vs densidad"):
reference.md:590 (tapar en md, precedente Dialog.Close) gobierna ejes de
ANCHURA; el de form es DENSIDAD declarada cuya receta ya escribio los cinco
peldanos.
- 5 ficheros de codigo, solo eidos (context.ts NUEVO); los dos costes
avisados NO se tocan, verificado con linea: la excepcion A11 de
form-auto-fields y el duck type CompatibleFormProvider quedan intactos
(el puente es setContext/getContext con Simbolo propio, disjunto).
- Medido: 84 diffs y NI UNO fuera - submit 40, reset 40, form 4 (su panel);
CERO en array/widget/error-summary; CERO en md. Alto -10/-6/0/+8/+16 px;
la letra lg/xl difiere de la prediccion (+4/+12 vs +2/+8) por causa MEDIDA:
--font-size-lg/xl son clamp() fluidos que saturan desde ~1200px - ningun
valor fuera de la escalera. Capturas xs/md/xl revisadas por el supervisor.
- Los botones del array siguen POR HERENCIA CSS, intactos (0 diffs) -
respuesta para E1: E2 ahorra el contexto, no la lectura (E1 debera pasar
size al Button que inyecte o sigue siendo la regresion medida).
- Dos mentiras NUEVAS del instrumento, registradas: la sonda estandar fuerza
data-size sobre el nodo compuesto y SE PISA (su 0 es por construccion) -
y los clamp() fluidos no son comparables sin declarar viewport.
- Registro: 13 cierra E2 (diagnostico original conservado tachado - era
exacto) y abre alert-dialog (mismo agujero; a el le toca la norma TAPADA
por ser eje de anchura), error-summary con data-size que nadie lee, la
escalera de fuente 3-sobre-5 que viola el 1:1 (E1, su carril), y la cita
colgada de dialog/context.ts:9. Pendiente dicho: el parrafo de doctrina
querria vivir tambien en reference.md (fuera del alcance liberado).
- Gates: eidos 443+1 ajeno - check 0 atribuibles - docs-check 0/0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
### FIRMA EJECUTADA (2026-08-25) — el eje `size` de `form` LLEGA a sus acciones
**Qué se firmó**: ceder el cromo de `submit` /`reset` al `Button` compuesto
(firma del 2026-08-24) destapó el reverso. `form-submit.svelte:20` y
`form-reset.svelte:15` traían su propio `size = 'md'` y **nada les pasaba la
talla del formulario**, así que un `<Form size="xs">` los renderizaba con
`data-size="md"` —36 px de alto y 16 px de letra— **en las cinco tallas** ; del
eje sólo sobrevivía el `row-gap` . Quitar el default no arreglaba nada (el
`Button` tiene el suyo): hacía falta el puente, y el precedente es literal.
Nuevo `eidos/components/form/context.ts` calcado **1:1 de `toolbar/context.ts`**
(`Symbol('form-eidos-ctx')` + getter de propiedad), `form.svelte` publica el
`resolvedSize` que ya calculaba, y las dos acciones leen
`size={size ?? form?.size}` — la prop explícita gana, y standalone cae en el
`md` del propio `Button` sin re-declararlo. **Sólo eidos: cinco ficheros, cero
morfo / soma / sema; el contrato de 64 claves y el ledger, intactos.**
**Los números**: alto ** − 10 / − 6 / 0 / +8 / +16** px y letra
**− 4 / − 2 / 0 / +4 / +12** px, sobre `submit` y `reset` por igual; ** `md` no
mueve un solo valor**; 84 diffs en total y **cero** en los cuatro nodos del
array, el widget y el resumen de errores. Sonda estándar antes/después **0 sobre
832 valores en 7 estados**; instrumento propio reproducible (dos pasadas sobre
código idéntico ⇒ 0 diffs). `vitest src/uix/eidos` 443/444 (el rojo es el ajeno
conocido `skin-media-player` ), `check` 0 errores atribuidos a los cinco
ficheros, `docs:check` 0/0.
**La doctrina que hubo que adjudicar**: **VERBATIM, no la norma tapada en `md`** .
La tapa de `reference.md` §«Container→part derivation» gobierna contenedores
cuyo eje es ANCHURA (su primer consumidor es `Dialog.Close` ); el de `form` es
DENSIDAD declarada, y su propia receta ya había escrito los cinco peldaños
distintos de la acción. Escrita en `next-features.md` §13 §«Anchura vs
densidad», con el corolario de que a `alert-dialog` —mismo agujero, eje de
anchura— le toca la TAPADA.
**Lo que quedó fuera, con su entrada en §13**: `alert-dialog` (no medido),
`Form.ErrorSummary` con un `data-size` que ninguna regla lee, la escalera de
fuente `12·12·14·14·16` de la acción de `form` (que corrige E1 en su carril) y
la cita colgada de `dialog/context.ts:9` .
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
### FIRMA B′ EJECUTADA (2026-08-24) — la cascada de paleta es una ESCALERA
**Qué se firmó**: los tres escritores de `--{c}-palette-*` pasan a tres peldaños
que **no empatan** — 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)` . Antes el forward genérico se emitía el
ÚLTIMO empatado a `(0,2,0)` con los bloques por tono, así que **ganaba por orden
de emisión** y 419 claves públicas de tono en 49 recetas no pintaban nunca.
**Por qué B′ y no reordenar la emisión** (que es lo que §13 proponía): el orden
es **contrato invisible** —no se lee en el artefacto, no lo verifica un guard sin
recorrer la hoja entera, se rompe moviendo una línea—. La especificidad es
**contrato EN el artefacto**. Y es la misma ley que §12.9 acababa de firmar para
el plano de profundidad: **una doctrina aplicada dos veces** , no dos parches.
**Los números**: neutra en píxel sobre ** ~297.000 valores computados**
comparados antes/después (70.912 + 34.336 planos en dos lotes, 57.720 en el
tercero, 134.464 con los tonos ESTAMPADOS en las 49 unidades) — **0 diffs
reales**, y los 17 crudos probados ruido reproduciéndolos sobre código idéntico.
**207 de 353 claves** de tono volvieron a mover un valor computado. Guarda por
**mutación** en `active-eidos-config.test.ts:1761` (6 mutaciones, 6 mordidas;
cierre estructural: toda declaración de paleta vive en uno de los tres peldaños;
anti-vacío `> 40` ). Contrato del forward **ensanchado de 2 a 49 recetas** —
vigilaba sólo las de paleta pública y era ciego a las 47 privadas. Suite 35/36
(el rojo `skin-media-player` es AJENO y conocido).
**Dónde vive todo**: doctrina en [`theming/changelog.md` ](../theming/changelog.md ) §53 ·
contrato en [`theming/reference.md` ](../theming/reference.md ) (bloque THM-2) ·
emisor `src/uix/eidos/lib/render-css.ts` (`isPaletteSlotToken` parte el bucket
host — **sólo las ranuras de paleta bajan** , el chasis se queda a `(0,1,0)` ) ·
guarda `active-eidos-config.test.ts` · ledger `scripts/theming-sentinel-exceptions.ts` .
**Tres leyes que deja escritas, y las tres costaron una medida**:
1. **El silencio del guard NO es señal cuando la adjudicación es por PATRÓN.**
`theming-sentinel.ts` detecta STALE sólo contra el ledger EXACTO
(`k in ledger`), nunca contra `SENTINEL_PATTERN_EXCEPTIONS` . Las 207 claves
resucitadas no dispararon ni un aviso: el estrechamiento hubo que hacerlo
comparando a mano contra las 13 entradas. La única que el guard sí vio fue
`editable.risk-border` , que era exacta.
2. **Un tono por defecto ESTAMPADO resuelve por el forward, no por el suelo.**
El envoltorio estampa `data-color` en toda instancia, la default incluida, así
que `<Button color="primary">` lee el forward y `--button-primary-solid` no
pinta. Quitar el atributo ES hablar en silencio, y entonces sí pinta (medido:
`oklch(0.5556 0.1829 305.86)` → `rgb(1, 2, 3)` ). Eso es `PALETTE_FLOOR` ; el
resto de supervivientes son `TONE_UNREACHED` (el guard no sabe combinar el
estampado del tono con el hover ni con la variante). Ledger 17 → **28 patrones** .
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
(007c2af52, hoy inocuo), checkbox.stroke-ease, residuo del hover.
- Anota la retirada de TONE_UNREACHED en la cronica de B' (changelog SS53 y
next-features) y en las leyes del handoff.
- Reescribe el handoff: las DOS firmas de instrumento estan ejecutadas; el
eje pasa a su CIERRE (deuda B, gate de F3, R-5 a error).
Catalogo tras la firma: 2918/3577 claves vivas (78% -> 82%). Tier de
patrones 28 -> 16, 15 de 16 son PALETTE_FLOOR, cero zombis, 659 muertas
todas con razon.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
*(Anotación 2026-08-25: la GRANDE retiró `TONE_UNREACHED` — el guard ya
combina; queda `PALETTE_FLOOR` y el tier volvió a 16.)*
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
3. **Un `0/N` se investiga, no se reporta.** `switch` dio **0 de 12** claves de
tono vivas y `button` sólo 14 de 49 — y ninguna de las dos era la cascada: la
ficha de `switch` monta UN switch y arranca `unchecked` (y todas sus ranuras
cuelgan de `[data-state=checked]` ), y `button` no declara `COMPONENT_OVERRIDES` ,
así que no se barre `data-variant` y su ficha monta UN botón sólido. Forzando
el estado, las dos alcanzan. Es la ley 2 del §«Lo primero que debes saber»,
confirmada una vez más.
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
### Lo primero que debes saber mañana
1. ** ⚠⚠ EL ÍNDICE DE GIT ES COMPARTIDO.** Un solo `.git/index` para todas las
sesiones de este worktree. Verificar con `git diff --cached` NO basta: entre
que miras y confirmas, otra sesión puede reescribirlo. **Verificación y
`git commit` van ENCADENADOS en la misma invocación de shell.** Costó un
commit con trabajo ajeno dentro y un ledger sin parsear durante cuatro
commits de HEAD. Y me lo hice yo mismo una segunda vez con un `git add`
derivado de `git diff` en vez de rutas explícitas.
2. **El instrumento miente antes que el código, y hoy mintió cinco veces.**
La sonda no congelaba nada · el guard mide UN nodo en siete portalados · un
árbol de trabajo rancio da un `0/98` falso · un grep con la frase exacta
encuentra 2 de 7 · y una lista escrita por Python en Windows lleva `\r` y
revienta el barrido entero con «todos fallan igual». **Un `0/N` o un «todos
igual» no es un resultado: es el instrumento.**
3. **Antes de retirar una clave, mira quién la lee** (paso 8.bis de §7.3, nuevo).
`scroll-area.auto-max-block` leía muerta en su demo y la consumen CINCO
recetas ajenas. Retirarla habría roto seis componentes sin que un guard se
pusiera rojo.
### Qué hay para hacer, por orden
- **Nada de tokenización.** Si aparece un componente nuevo, el protocolo §7 del
PLAN es la ley y el brief de agentes vive en el scratchpad de la sesión.
- **Deuda B — 3, cada uno por su razón**: `audio-player` (no tiene README de
eidos donde escribir «Talla y tema»), `palabras` y `proof-of-human` (carriles
propios).
- **Deuda de instrumento, registrada en §13 y sin bloquear a nadie**: el guard
congela `transition` pero NO `animation` (la sonda ya sí) y no fotografía
`transform` /`translate`; `eidos-lint` no conoce las exenciones que el test de
vitest sí tiene; la columna `size` del censo se apaga cuando el eje sube al
TSC. Las tres piden re-verificar el ledger entero, así que son firma pequeña.
- **Lo que espera TU FIRMA** (todo medido, ninguno bloquea):
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
1. ~~**La cascada de paleta**~~ — ** ✅ FIRMADA Y EJECUTADA 2026-08-24 como
firma B′ **: era la pregunta hermana de §12.9 y se resolvió con la misma
herramienta, `:where()` . Todo (doctrina, contrato, emisor, guarda, ledger)
está en §«FIRMA B′ EJECUTADA» de aquí arriba. **No queda nada que firmar.**
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
2. ~~**El componente COMPUESTO contra la receta que lo compone**~~ — ** ✅
FIRMADA Y EJECUTADA 2026-08-24**: el bloque de acción de `form.css` apunta
ya sólo a los dos botones del array de AutoFields, `submit` /`reset` ceden
todo su cromo al `Button` que componen (0 diffs medidos) y mueren sus
cuatro forwards `_palette-*` ; las 23 públicas se quedan, re-adjudicadas
como rama que la demo no monta. `gradient-picker` (36) y `emoji-picker` (3)
**ya estaban ejecutados** (2026-08-20 y 2026-08-23, verificado el
2026-08-24: hoy ninguno adjudica una sola clave por supersesión del
compuesto). **Salida barata ya probada** : `toolbar` cede el cromo al
`Button` y no pierde ni una clave, porque su receta no escribe la regla.
docs(theming): registro post-B' - cinco hechos verificados entran al expediente
Pase de registro de lo que la firma B' descubrio y no arreglo (pre-existente,
simetrico antes/despues). Seis claims de agentes -> verificacion adversarial
independiente -> DOS murieron (label-inline era diseno firmado de la seccion 43;
drag-drop refutado: su forward vive y alcanza) y UNO se fusiono (el color de
`code` lo gana `[data-uix-docs] code` (0,1,1) - ES la firma pendiente 5.2 del
harness, que se ENSANCHA de radio/padding a la tinta; medido por CDP, solo dos
reglas declaran color).
Entran en next-features 13 / CONTINUE:
- El detector STALE del centinela es CIEGO a los patrones (filtra `k in ledger`,
solo exactas): 207 claves revividas por B' y ni un aviso. Arreglo minimo
anotado; clase re-verificar-ledger.
- El guard no mide tono+estado a la vez (raiz de TONE_UNREACHED): tono solo en
el paso estatico, hover sin tono, solo `toggle` declara eje de estado,
switch/button sin entrada en COMPONENT_OVERRIDES (48).
- Tres huecos de la sonda: el `open` de editable muere por CLIC sobre inputs
ocultos (no por el localizador), button sin analogo de barrido de variantes,
y NUEVE de las 33 escalas atadas a rol (purple slate indigo gray teal green
orange red plum) - `plum` ES `loss`; 24 libres como reserva de sondeo.
- Divergencia de familia: `label` es el unico primitivo de tinta sin el paso
`on-solid` (tipo y runtime, auto-consistente); decision pendiente.
Citas contrastadas contra el arbol (cuatro corregidas del verificador, incluida
la deriva de +10 lineas del diff ajeno del sentinel). docs-check 0/0 sobre 815.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
**Se ENSANCHA a la TINTA (verificado 2026-08-24)** : la misma firma §5.2 del
harness cubre ya el `color` de `code` . Medido por CDP
(`getMatchedStylesForNode`): sobre `[data-code]` **sólo DOS reglas declaran
`color` ** — `[data-code]` (0,1,0) y `[data-uix-docs] code` (0,1,1,
`web/routes/uix/uix.css:792` , `var(--uix-text)` = `rgb(24,24,27)` ) — y gana
el harness. Con `data-color='risk'` estampado, `--_code-palette-text` y
`--_code-color` SÍ se mueven, pero `color` no: la cadena del componente
funciona y la pisa la del harness al final. **No es entrada nueva** : es el
mismo expediente que el ledger ya cita para `code.radius`
(`theming-sentinel-exceptions.ts:665`) y `code-block.pre-padding` (`:676`),
y que reaparece por tercera vez en `prose.code-bg` / `code-radius` /
`code-font-family` (`:862-865`). Lo que cambia es el ALCANCE de la firma:
de radio / padding / tipografía **a incluir también la tinta** .
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
3. ~~**`file-upload` barre DESCENDIENTES**~~ — ** ✅ FIRMADA Y EJECUTADA
2026-08-24**: la mitad descendiente pasa a cinco selectores por parte propia
(el morfo declara `data-disabled` en 6 nodos y los 6 llevan su attr de
parte, así que el barrido era redundante hacia dentro). Única ocurrencia en
**171** recetas, no 162. `file-upload` e `image-picker` con diff CERO;
`chat-composer` recupera 6 valores —el textarea salía a **0.4³ = 0.064** de
alpha en el tema POR DEFECTO, 925 px— y su entrada del ledger se RETIRA.
Detalle en §8 del PLAN.
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
4. ~~**Las cuatro claves de `avatar` fuera de gramática**~~ — ** ✅ FIRMADA Y
EJECUTADA 2026-08-25** (opción A-c): las cuatro **no eran la misma cosa** ,
y la medida las separó en tres tratos. **UNA se renombra** —
`badge-color-custom-contrast` → ** `badge-fg-custom-contrast` **, la única
tinta de verdad (alimenta `color:` ) y alcanzable desde `:root` (medido:
`white` → `rgb(4,5,6)` ); es la salida literal del clasificador firmado, que
deja el calificador contextual DETRÁS de la ranura como en el precedente
`scrim-color-on-dark` → `scrim-fg-over-dark` . **DOS se retiran del
contrato** — `ring-color-custom` y `badge-color-custom` son **canal de
valor**: la puerta `data-*-custom` y la escritura inline nacen de la MISMA
expresión del envoltorio, así que no existe ni puede existir instancia en
la que un tema les gane. Pasan a privadas `--_avatar-{ring,badge}-color-custom`
escritas por el envoltorio y leídas con `var(…, currentColor)` — la forma
que `background` , `carousel` , `checkbox-group` , `file-upload` y
`gradient-builder` ya usan (5 de 5 privadas de envoltorio NO se declaran en
la receta), y la adjudicación que `tabs` hizo con su indicador. **UNA queda
EXENTA** — `group-carve-color` alimenta `box-shadow` : es la GEOMETRÍA del
carve, no tinta, y `group-carve-fg` sería gramática correcta con semántica
peor. Contrato público **88 → 86** (medido en vivo: la pestaña se llama ya
«Tokens 86»), censo `--names` **4 desviadas → 0 en TODO el catálogo**
(4556 claves, exentas 13 → 14). Sonda §7.4: **0 diffs sobre 576 valores** ,
y el píxel de los nodos con puerta idéntico (anillo ámbar
`rgb(245,158,11)` , insignia violeta `rgb(124,58,237)` , tinta `white` ),
incluida la «instancia imposible». **0 píxeles** , como firmaba la opción.
Abrió dos deudas de INSTRUMENTO, las dos en next-features §13: el codemod
de nombres **aborta sobre `avatar`** (`blockRange()` no lee la IIFE, la
misma ceguera que `f68bac4a6` arregló en censo y centinela), y el centinela
**elige el valor de sonda por el NOMBRE** (`fg$`, sin `-fg-` ), así que las
cinco claves del catálogo con `fg` MEDIAL reciben `1234px` . Detalle en §8
del PLAN.
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
5. ~~**`tags-input`** sella `aria-selected='true'` como LITERAL en cada
etiqueta~~ — ** ✅ FIRMADA Y EJECUTADA 2026-08-25** (opción B-a2): el morfo
ata `aria-selected` al estado que soma YA deriva de `highlightedIndex`
(`v.literal('true')` → `v.stateRef('active')` ), una línea. Era el ** único
`aria-selected` incondicional del catálogo**. El árbol AX pasa de **dos
`option` con `selected: true` dentro de dos `listbox` con
`multiselectable: false` ** a **cero en reposo y exactamente uno navegando**
(medido por CDP). `--tags-input-item-fg` **revive** —el centinela sube a
**71/91** y su entrada del ledger se RETIRA— y la etiqueta **recupera la
afordancia de hover**: reposo y hover eran byte a byte IDÉNTICOS (media RGB
212,10 en los dos) y ahora son 224,58 → 212,10. Diff de sonda: **14
valores de 2.504, todos `background-image` de las dos etiquetas en los
siete pases sin puntero** — el velo de estado saliendo del reposo, y nada
fix(morfo)!: tags-input habla UN patron ARIA - layout grid, cierra F-1
El AX hablaba tres dialectos rotos a la vez (medido por CDP): dos listbox
anidados (las opciones eran hijas del Control; el Provider no tenia ninguna),
button DENTRO de option (rol hoja: el nombre se fundia - "svelte Eliminar
etiqueta" como una sola cosa) y un combobox sin aria-expanded/aria-controls
apuntando activedescendant a etiquetas commiteadas. F-1, adjudicado
2026-07-07; el registro de ayer era una re-deteccion parcial.
Estructura B (firmada): Control = grid de UNA fila - etiquetas = gridcell
(conservan el aria-selected -> stateRef de 2ce43db56; gridcell lo admite) -
el boton de borrar CONVIVE en la celda de su etiqueta ("a cell contains one
widget... link, button" - lo que lo prohibia era option, Children
Presentational) - el input en celda propia como TEXTBOX nativo (combobox
EXIGE controls/expanded y no hay popup) - el Provider pierde su listbox.
Dos partes privadas nuevas (Row, InputCell) con display:contents: grid solo
posee filas, row solo celdas.
- Teclado: la navegacion estaba MUERTA (ArrowLeft x2 avanzaba 0) y ahora
camina; el resalte mueve foco DOM - la CONDICION de retirar el
activedescendant (su destino debe ser descendiente y era hermano).
Tabulacion sigue en UNA parada.
- aria-orientation RETIRADO (no es propiedad de grid; Chrome no la expone,
medido): se conserva como comportamiento, no como atributo.
- Pixel CERO: sonda 2.496 valores por identidad de nodo, 0 diffs, geometria
al centesimo; capturas byte-identicas. CSS: 7 lineas display:contents.
- Gates: morfo 222/222 - soma tags-input - attr-audit con el techo APRETADO
1->0 - eidos 443+1 ajeno - morfo:check PASA - check 0 propios - docs 0/0.
- Registro: F-1 CERRADO (ficha de componente, nota fechada) - el item 12.5
del tono MOVIDO de 13 a 12 con sus dos cifras corregidas ((0,4,0); gana el
BLOQUE de archetypes) - abiertos: tag-group filas sin celdas (el
"precedente" refutado midiendo: CERO gridcell), search-field F-1, y la
regla del censo de citas APG - demo: 3 filas de su tabla a11y actualizadas
para no mentir sobre los roles nuevos.
- Trampa nueva anotada: `const state = Provider.create()` SOMBREA la runa
$state (compila y revienta en render); un error SSR no llega al navegador -
se caza navegando por el router desde otra pagina.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
más. Detalle en §8 del PLAN. Lo que NO arregla: la tinta de tono de la
etiqueta activa.
**Enmienda del 2026-08-25** : esa tinta ya no está abierta en §13 sino en
**next-features §12** , como cuarta ocurrencia de §12.5 y con su decisión ya
redactada (`docs/next-features.md:516`) — es de la capa del SISTEMA, no del
componente. Y las dos cifras de esta entrada estaban mal: la especificidad
es ** (0,4,0)**, no (0,3,0), y el ganador no es el selector de
`data-highlighted` sino **el BLOQUE** `archetypes.css:245-257` , cuyos dos
selectores —`data-highlighted` y `aria-selected` — casan LOS DOS la
etiqueta activa desde esta misma firma; retirar uno no mueve nada.
Los dos `listbox` anidados que esta entrada describe **ya no existen** : la
firma «el árbol ARIA de `tags-input` habla UN patrón» (2026-08-25, F-1 de
la ficha de componente) los sustituyó por el layout grid del `apg`
—`grid > row > gridcell`, el campo un textbox en su celda— sin mover un
píxel: **0 diffs sobre 2496 valores computados** en los 8 pases de la
sonda, y ningún CSS del ecosistema selecciona por `role` . No es theming y
no toca el ledger de claves; el centinela no se re-corrió en esa firma
(su script está en obras en otra sesión), pero no hay valor computado que
se haya movido.
feat(theming)!: el sobre de trigger de popover es un SUELO - tercera ley 55
El "baseline button envelope" que popover.css pinta a sus triggers vivia a
(0,2,0) con hover a (0,5,0): le ganaba a las recetas de sus HUESPEDES (el
chip de anadir reaccion de chat-message perdia 9/9 propiedades disputadas y
salia cuadrado gris entre pildoras - SU receta lo pintaba en el mismo
selector-lista y PERDIA), mataba la capa de estado del sistema en hover
(chronos plain = caja gris) y dejaba el trigger de calendar en manos del
orden de carga (14/16/14/14px medidos - la moneda al aire).
El sobre baja a :where() - base y hover, con el :not(field-trigger) DENTRO
(where anula especificidad, no matching). El suelo pinta lo que el huesped
CALLA; la receta gana donde habla; la capa de estado compone otra vez.
Tercera aplicacion de la ley firmada (12.9 planos - B'/53 paleta - y
archetypes.css:9-21 ya lo decia para SU capa). Cambio de codigo: 2 lineas.
Medido (gate de dos niveles, 76 instancias, 16 rutas, 4 estados):
- No afectados: 3 field-trigger diff VACIO; los 66 desnudos ganan EXACTAMENTE
los dos valores del SISTEMA que el sobre tapaba (velo de hover de
archetypes + su transition). 167 nodos de referencia: 0.
- Los 7 movers, valor a valor por CDP hacia lo que SU receta declara: el chip
vuelve pildora (36->26px, r9999) - chronos recupera su plain y su hover -
calendar mes/anio pasa a su ghost compuesto Y SE VUELVE DETERMINISTA (8
cargas en dos ordenes, mismo pixel; antes 2 de 6 caian del otro lado) -
emoji/palabras/ntp a sus recetas (ntp revive 4 claves: 44->48/62).
- Capturas antes/despues x8 revisadas por el supervisor (chip, chronos,
calendar, emoji, gradient, popover generico, palabras, ntp).
- Guarda 55 en active-eidos-config.test.ts validada por SEIS mutaciones (la
sexta se anadio porque la primera pasada dejo pasar un verde falso; y el
arnes mintio con -t sobre 0 tests - detector de cero-tests anadido).
- vitest 35/36 (rojo ajeno skin-media-player) - check 0 atribuibles -
docs-check 0/0 - eidos-lint popover/chat-message 0 invalid.
Registrado en 13 y fichas: los parches-pin de chronos/calendar pasan a
REVISABLES (ahora redundantes o semi) - el suelo comparte peldano (0,0,0) con
archetypes.css (medido 16 cargas: archetypes cae despues y el resultado es
identico, pero es un empate real sin verificar en produccion) - la
dependencia sin registrar de palabras queda anotada junto a su regla (no
tiene README de eidos). changelog 55 escrito (la guarda citaba una seccion
que debia existir).
CON ESTA, LA LISTA "Lo que espera TU FIRMA" DEL CONTINUE QUEDA VACIA.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
6. ~~**El chip de añadir reacción de `chat-message` ** lo pinta `popover.css` :
los chips de reacción son píldoras redondas y el de añadir un cuadrado
gris.~~ — ** ✅ FIRMADA Y EJECUTADA 2026-08-25** (opción b, «la ley del
suelo»): el arreglo NO fue de `chat-message` sino del sobre de
`popover.css` , que se autodescribe como _«a baseline button envelope»_ y
estaba a ** (0,2,0)** con su `:hover` a ** (0,5,0)**. Baja a
`:where(...)` — (0,0,0) — reposo y hover. **Tercera aplicación de la ley**
de §12.9 y de B′ /§53, y la primera que cae en una receta escrita a mano.
**76 instancias en 16 rutas, cuatro estados** : 69 no mueven un valor de
receta (los 64 botones desnudos del sitio de docs, `gradient-picker` , la
demo `data-perm-step` y los tres field-trigger excluidos) y **7 mueven, las
7 hacia lo que su propia receta declara** — el chip vuelve a ser **píldora**
(34× 26, radio 9999, 12px), `chronos` recupera su `plain` , `calendar` pasa a
ghost y **deja de ser no determinista** (reproducido antes: 2 de 6 cargas en
14px en vez de 16px; después: 8 cargas en dos órdenes, el mismo píxel),
`emoji-picker` , `palabras` y `natural-time-picker` recuperan lo suyo. **0
movimientos** en 167 nodos de referencia. Centinela: `natural-time-picker`
**44/62 → 48/62** ; ninguna entrada del ledger salió STALE (ninguna estaba
adjudicada por este sobre). Cierra de paso el empate latente de
`chat-message.css:462` . Guarda por mutación en
`active-eidos-config.test.ts` (§55, 6 mutaciones, 6 mordidas). Doctrina en
`theming/changelog.md` §55; lo que queda abierto —los dos estados a (0,3,0)
y los pines redundantes— en `next-features.md` §13.
**CON ESTO LA LISTA QUEDA VACÍA: no espera NINGUNA firma tuya en este eje.**
Los seis puntos están ejecutados. Lo que siga tiene que abrirse como entrada
nueva, no heredarse de aquí.
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
### Lo último que se hizo (2026-08-24 noche): §12.9 FIRMADA
**El plano de profundidad es el SUELO, a especificidad cero.** La Decisión 8
daba por bueno el empate a `(0,1,0)` porque «las recetas cargan después de la
fundación y ganan por orden de cascada» — y esa premisa era FALSA: la fundación
se inyecta en runtime y las recetas llegan como chunks de Vite, así que ganaba
quien cargara el último, medido AL REVÉS en dev que en producción. Una moneda al
aire, no una decisión.
La regla de apariencia del plano se emite en `:where(...)` : la receta gana donde
el componente HABLA, el plano pinta lo que CALLA. **El `frost` NO baja** — es un
opt-in explícito por elemento y debe ganarle al fondo del componente.
**Restauró**: los seis tonos de `toast` (4 de 4 distintos donde antes 3 de 3
eran idénticos, y la franja de acento de 0,67 px de gris a 3 px del color de la
intención) · las tres variantes de `tooltip` · 17 claves que salieron STALE
solas del ledger. **Movió** : 16 de 19 adoptantes con diff CERO sobre ~49.000
valores; los tres restantes son la firma trabajando, incluido el `line-height`
que la receta de `link-preview` tenía escrito como pendiente de esta firma.
⚠ **Para medir el plano** : la sonda compartida mide UN nodo en los portalados y
nunca abre la superficie. El «antes» se reproduce EN RUNTIME inyectando la regla
vieja a `(0,1,0)` (`scripts/__plane-open.mjs`), nunca revirtiendo el fichero.
---
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(theming): el handoff recoge la tanda de DOCE y lo que encontró supervisarla
Doce componentes cerrados por cinco sesiones en paralelo — cinco al 100 %
(chat-log, chat-composer, rating-group, toggle) y card cerrado en su 78 %,
que ES su techo. Global 66 % -> 68 %.
Y la parte que importa: los doce se supervisaron uno a uno, y la supervisión
encontró cinco cosas que la ejecución no vio. Cuatro salieron del §7.7.
Las dos primeras son de la rama, no del eje: el índice de git es COMPARTIDO
—verificar el árbol indexado no basta, porque otra sesión puede reescribirlo
entre que lo miras y confirmas— y un árbol de trabajo rancio hace mentir al
instrumento sin tocar un solo commit (el guard de card daba 0/98 por un fichero
sucio; desde HEAD limpio, 49/98 verde).
Las otras tres son del eje: la cascada de paleta se lleva también el tono por
defecto, el canal inline filtrado al contrato son cuatro claves y no dos, y la
sonda y el guard mueren con --import tsx/esm.
Queda escrito además el gate del diff cero con su matiz: dos componentes no
cerraron a cero y los dos lo declararon; los dos son ruido reproducido sobre
código idéntico. Un diff no cero no es automáticamente una regresión, pero sólo
se declara ruido reproduciéndolo.
Y dicho sin esconderlo: la demo de chat-log se tocó como instrumento.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
> **LO ÚLTIMO (2026-08-24): DOCE componentes en paralelo, con SUPERVISIÓN.**
> `chat-log` 77 → **100 %** (`fd8f01bac`) · `chat-composer` 79 → **100 %**
> (`71a097ddc`) · `rating-group` 80 → **100 %** (`f6a618328`) · `toggle`
> 81 → **100 %** (`edc019515` + `007c2af52`) · `select` 83 → **92 %**
> (`cc010f79a`) · `avatar` 75 → **90 %** (`f68bac4a6`) · `calendar` 84 → **89 %**
> (`509d1144f`) · `file-upload` 76 → **83 %** (`0c06d42aa`) · `editable`
> 75 → **82 %** (`2117d7422`) · `switch` 76 → **81 %** (`bbdc77c07`) ·
> `radio-group` 77 → **81 %** (`f5d252443`) · `card` 78 → **78 % CERRADO**
> (`f3189a05a`). Global **68 %**.
>
> **Los doce se supervisaron uno a uno, y la supervisión encontró cosas.**
> Refutación estática de los doce commits (cero líneas ajenas en el generado),
> centinelas re-corridos, y cinco hallazgos propios que están abajo. **El
> protocolo §7.7 no es un adorno: cuatro de los cinco salieron de él.**
>
> **Lo que enseñó esta tanda, en una línea cada una:**
> el ÍNDICE DE GIT ES COMPARTIDO y verificar el árbol indexado NO BASTA ·
> un árbol rancio hace MENTIR al instrumento sin tocar un commit ·
> la cascada de paleta se lleva TAMBIÉN el tono por defecto ·
> un componente puede BARRER DESCENDIENTES y comerse el token de sus huéspedes ·
> y la sonda y el guard MUEREN con `--import tsx/esm`.
> **HISTÓRICO (2026-08-23, tarde): SIETE componentes.** `navigation-menu`
> 44 → **100 %** (`85988785d`) · `waveform` 55 → **86 %** (`11b92ded6`) ·
> `color-field` 56 → **93 %** (`3c6742b9c`) · `background` 57 → **95 %**
> (`9bdc5a5d5`) · `s-text-virtual-list` 58 → **70 %** (`1f785b6f2`) · `badge`
> 59 → **75 %** (`271fcd4df`) · `cropper` 60 → **94 %** (`f03ee5af4`).
> Global **66 %**. Los siete con diff 0 y su guard limpio.
>
> **Las cinco cosas que enseñaron, en una línea cada una** (detalle abajo):
> el instrumento tiene TRES caras del mismo punto ciego · un guard puede
> CERRAR lo que mide y montar MÁS puede medir MENOS · subir un privado al
> contrato lo somete a reglas nuevas · lo que se escribe INLINE nunca es tema ·
> y la mitad del trabajo que queda es ADJUDICAR, no acuñar.
uix(theming): revisión adversarial de F2-B — 4 hipótesis, 3 refutadas, 1 token que mentía
El plan (§7.7) exige una revisión escéptica antes de cerrar un bloque, y F2-B
no la tenía. Molde F2-A: worktree en la base del bloque (`8400e5bdd`) con su
propio dev server, medición independiente.
**REFUTADA \u2014 «el default cambió en algún sitio que la demo no mira».** 77 casos
FORZADOS (variantes, formas, tallas y estados que las demos NO montan, en los
21 componentes) comparados base vs HEAD: **0 diferencias**. Era la sospecha más
fuerte, porque cuatro componentes miden UN nodo (`link`, `code`, `skeleton`,
`link-preview`) y sus tokens viven justo en las variantes que la demo no
renderiza.
**REFUTADA \u2014 «hay tokens huérfanos».** 339 públicos de los 21 bloques, 0 sin
consumo. El primer extractor daba «SIN BLOQUE» en los 21 \u2014 el mismo antipatrón
que audita este eje \u2014 y se rehízo contando llaves; muta-prueba: un token falso
inyectado sale detectado y el árbol se restaura.
**REFUTADA \u2014 «el gate de 0 diffs pasó sobre casi nada».** Contados los nodos que
ve cada sonda; los cuatro de un nodo se cubrieron forzando sus variantes arriba.
**HALLAZGO REAL \u2014 `drag-drop.preview-z` mentía, y lo escondía una adjudicación
mía sobre un nodo SINTÉTICO.** El ledger lo daba por vivo («forzado → alcanza,
100 → 4321»), pero ese nodo lo había creado yo con JS. El preview REAL que soma
monta durante un arrastre lleva `z-index: 9999` **INLINE**
(`drag-drop-provider.svelte.ts:663,671`): el token resuelve a 4321 y el nodo
computa 9999. Ninguna cascada puede ganarle. **Retirado con 0 diffs** contra el
snapshot original (1.827 valores × 7 estados), misma clase que el `item-gap*`
de carousel que retiró la revisión de F2-A. Era el único público que drag-drop
tenía antes del eje; su alcance se mantiene en 89 %.
**La lección que generaliza, y va al protocolo**: una adjudicación «forzado →
alcanza» vale lo que valga el nodo que se forzó \u2014 si lo creaste tú, no lleva lo
que soma le pone. Re-verificado el resto de la misma clase contra nodos reales:
`clipboard` (indicador tras un clic real) y `picker-shell` (pie real) coinciden
con lo adjudicado y no llevan inline; el inline de `skeleton-line` es de
`inline-size`, no del eje tokenizado.
DOS HALLAZGOS DE INSTRUMENTO en la propia revisión (→ §13):
- **El orden de carga NO es el mismo en dev que en producción.** Medido con
`npm run build` + preview y CDP: en dev la receta de `link-preview` va ANTES
del plano `overlay`; en producción queda EN MEDIO de sus dos reglas. El
ganador coincide por casualidad. La fragilidad de §12.9 queda medida en los
dos entornos, y confirma que restaurar el par fue lo correcto.
- **Un worktree cuyo `node_modules` es una junction fuera del root NO HIDRATA**:
Vite responde 403 a `@fs/…` y SvelteKit no arranca, así que la página SSR se
ve pero ningún componente monta. La primera pasada de esta revisión comparó
contra una base MUERTA y devolvió «77 casos, 1 diferencia» sin que nada lo
delatara. Se arregla con `server: { fs: { allow: [...] } }`; queda escrito en
el handoff junto a la regla: **comprueba que un componente monta antes de
comparar**.
Gates: censo global 50 % · `--names` DESVIADAS 0 · drag-drop 89 % ·
component:audit PASS · eidos-lint 0 invalid · R-5.4 verde · suite eidos sin
rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio.
Worktree eliminado quitando la junction ANTES del `remove --force`, con el
`node_modules` real verificado intacto (memoria
`git-worktree-remove-recurses-into-junctions`).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
**Estado: EN EJECUCIÓN — F0 y F1 CERRADAS · F2 en curso, bloque F2-B CERRADO
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
con su revisión adversarial pasada (2026-08-22); la cola sigue abierta y
docs(theming): el handoff recoge la sesión entera del 23 — 65 %, 16 componentes
Cabecera al día (65 % global, 25 componentes al 100 %, <20 % baja de 14 a 12) y
una sección nueva con la tabla de los dieciséis, las CINCO LEYES que salieron y
todo lo que aprendió el instrumento.
Las leyes, que es lo que hay que leer antes de seguir la cola:
1. El portal es una frontera de cascada — un privado de la raíz no la cruza.
2. El plano `overlay` gana donde el componente habla, y en `tooltip` se queda
también el fondo, el borde y la sombra: sus tres variantes computan lo mismo.
3. La cascada de paleta anula los tonos del componente — 419 claves, 49 recetas.
4. Un respaldo escrito a mano envejece contra su token.
5. Donde hay un par, el defecto viene en par.
Firmas actualizadas: la 1 (§12.9) deja de ser sólo tipografía y suma la
superficie del tooltip; la 7 pasa de UN canónico sin demo a CUATRO
(picker-shell, mockup, surface, audio-player) con la nota de que el guard sobre
una página vacía miente en verde-rojo; y entra la 11, las dos reglas con
`:global()` que el navegador descarta.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`text-gradient` ya está dentro (2026-08-22) y el **2026-08-23 entraron
DIECISÉIS** (tabla abajo).** Alcance global **65 %** (33 % al abrir el eje, 45 %
tras F2-A, 50 % tras F2-B, y ** +6 puntos al arreglar la MEDICIÓN**, no el
código). Sin contrato **24** ; **al 100 % 25** ; alcance < 20 % **12** . Ú ltimos: `chart` 9 % → **89 %**
tooling(theming): el censo aprende a leer la válvula del canon — clase `exception`
Global 58 % → **59 %** sin tocar una línea de CSS: 54 knobs que eran deuda
resultan ser desviaciones que el canon ya había firmado.
`recipe-contract` §3 dice que una desviación anotada `/* literal: <razón> */`
EN SU PROPIA DECLARACIÓN es válida, y `component-audit` la honra desde siempre
(`declarationWindow` + `/literal:/i` en R-2.1, R-2.6 y R-2.7). El censo era el
único instrumento que no: su `strip()` blanquea los comentarios ANTES de
clasificar, así que las **81 anotaciones del catálogo** contaban como literales
sin excusa. Dos instrumentos, un canon, dos respuestas — y la que mandaba era la
del que no sabía leerlo.
Ahora un literal anotado cae en la clase **`exception`, fuera del ratio** como
`system`, y por la misma razón: no es que un tema no lo alcance, es que el canon
ya aceptó por escrito que ahí no va un token.
**54 knobs en 12 componentes**: `prose` 21 (su escala editorial em-relativa, que
su README documenta como decisión — «No 5× duplicated scale»), `proof-of-human`
16 (la escena de tono fijo), `palabras` 3, `timeline` 2 (73 % → **77 %**),
`result` 1 (86 % → **90 %**), y siete más con una cada uno.
Detalles que costaron medición:
- **La anotación vale para la DECLARACIÓN entera**, no sólo para su primera
línea: un valor partido en varias líneas lleva la nota al final. Se comprueban
todas las líneas que abarca la declaración.
- **`strip()` blanquea en el sitio** (sustituye por espacios, conserva los
saltos), así que el cuerpo despojado y el crudo quedan alineados línea a línea
y basta con guardar el crudo al lado.
- Muta-prueba: retirar una anotación de `prose` mueve el knob de `exception` a
`literal` (21 → 20) y el conteo vuelve al restaurarla.
Efecto colateral bueno: cada ficha gana una **§1.4 «Excepciones firmadas»** que
las LISTA con su razón. Estaban escritas en el CSS y no se leían desde ninguna
parte; ahora la ficha del componente las enseña, que es donde se decide si una
sigue siendo cierta.
Las 163 fichas cambian porque la plantilla cambia (sección nueva + la línea de
reparto); el README de la auditoría gana la fila de la clase y la nota de que
`system` y `exception` quedan fuera del denominador.
Guards: `--names` 4.105 claves, DESVIADAS 0 · component-audit PASS · docs:check
0 · `check` con 72 errores globales y 0 en los ficheros tocados.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
y `result` 14 % → **90 %** , los dos con `global` a CERO tras la COSTURA. El
censo cuenta 54 knobs menos: los literales ANOTADOS salen del ratio (clase
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`exception` ). Y `prose` 1 % → **83 %** .
fix(theming): float-panel tenía DOCE rojos sin medir — el guard R-5.4 vuelve a verde
El barrido del centinela sobre TODO el ledger (59 componentes) destapó que
`float-panel` fallaba: 17/40 con doce tokens públicos sin adjudicar. No es
regresión —la bisección de las NUEVE versiones del guard desde `cd6a9f4e3` da
siempre 17/40 con los mismos doce— sino un rojo que su propio commit del 22
dejó escrito («lo rojo que queda son 12 tokens anteriores») y que nadie midió.
Y la frase del handoff «desde el 23 no queda ningún rojo del bloque viejo» era
FALSA: se adjudicaron drawer, metrics y color-picker; éste no. Corregida, con
la lección: un componente cuyo commit dice «lo que queda» NO está cerrado, y la
única forma de saberlo es correr el guard sobre el ledger ENTERO.
LOS DOCE, MEDIDOS UNO A UNO
SEIS son el plano de profundidad, y la predicción del 22 era exacta: el
contenido lleva data-depth=overlay y [data-depth=overlay] declara background,
border, box-shadow, font-family y line-height a la MISMA especificidad (0,1,0)
y más tarde en la cascada. Verificado moviendo los tokens del propio plano
sobre el nodo (superficie, borde, fuente y leading lo repintan) y enumerando
las reglas que casan. border-width cae con border (el plano escribe el
shorthand). Misma adjudicación que tooltip, misma decisión abierta (§12.9).
⚠ Y una corrección a mi propio diagnóstico: primero atribuí la sombra a
[data-topmost] porque el panel de la demo arranca frontal. Falso — quitando el
atributo sigue muerta: es el plano también. Lo que sí depende de topmost es su
compañero shadow-topmost, que SÍ alcanza (→ rgb(4,5,6)) porque su regla es
(0,2,0) y le gana al plano: la prueba de que la causa es la cascada y no un
token roto.
TRES son estados o partes que la demo no monta: active-shadow (forzado
data-dragging → alcanza), resize-size (lo consumen las asas de ESQUINA
se/ne/sw/nw y la demo monta sólo las de borde, e y s) y button-size (lo
consumen [data-float-panel-action] y [data-float-panel-stage-trigger], ninguno
montado — el único control es el cierre, un <Button> compuesto que se
dimensiona solo: el mismo grupo que las tres action-* ya adjudicadas).
UNO es el PUENTE DE PALETA: el contenido lleva data-color, así que
--_float-panel-accent viene del forward THM-2 (--_float-panel-palette-border →
rgb(7,8,9)); sin data-color la clave alcanza (→ rgb(1,2,3)).
DOS son la ley del congelado: transition-duration / -ease no pueden moverse
bajo un guard que congela `transition`. Pasada aparte: 0.12s → 11.5s y
cubic-bezier(0.4,0,0.2,1) → steps(7).
DE PASO, DOS ARREGLOS DE LA MISMA REVISIÓN
- `background.parallax-travel` estaba MAL CLASIFICADO como estructural («el
escenario no tiene scroll timeline»): lo tiene (animation-timeline: view()).
Forzando data-parallax + speed 1, el translate sigue al token (14,6 → 60,5 px
al mismo scrollY). La causa real es que el guard NO fotografía translate ni
transform — registrado en §13 junto al hueco de mask-image, para entrar en
PROPS en un pase con re-verificación del ledger entero.
- `cropper`: el hueco de composición que el README daba por «anotado» y no lo
estaba, ahora es fila de §Gaps con su disposición. Y las tablas de tokens de
`cropper` y `waveform` pasan a la sección «Talla y tema», el molde del resto.
La nueva constante PLANE_SUPERSEDED se iza sobre el objeto (un `const` usado
antes de su declaración reventaba el guard, y el fallo se veía sólo mirando el
exit REAL: tras la tubería, `$?` es el del grep).
Verificación: R-5.4 float-panel 17/40 con 23 adjudicaciones, cero STALE, exit 0
· docs:check 0 · el ledger vuelve a sus 63 hunks de prettier preexistentes (mis
entradas se reformatearon a mano, sin tocar las ajenas).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Desde el 2026-08-23 (tarde) NO queda ningún rojo del bloque viejo** —
`drawer` (24), `metrics` (18), `color-picker` (25) y ** `float-panel` (12)**
medidos uno a uno y adjudicados por escrito; el guard R-5.4 pasa en todos. Los
tres hallazgos reales que salieron —el velo del cajón que no pinta, las tallas
del cajón que soma escribe inline y el eje `size` del picker que muere en el
portal— están en §13 y esperan firma.
⚠ **Esta frase estuvo MAL un día** : se escribió el 23 por la mañana dando por
cerrado el bloque viejo cuando `float-panel` seguía con sus doce rojos sin
medir, escritos como «lo que queda» en su propio commit del 22. Lo destapó el
barrido del centinela sobre TODO el ledger (`REVIEW-theming-2026-08-23.md`).
**Un componente cuyo commit dice «lo rojo que queda» NO está cerrado**, y la
única forma de saberlo es correr el guard sobre el ledger entero, no sobre los
que tocas.
docs(theming): la COLA A queda CERRADA — y §12.9 pasa a tener coste de producto
scroll-area y slider al 100 %, tabs cerrado en 97 %, toast al 100 %. Global
68 %, 45 componentes al 100 %. Los cuatro cerraron SIN acuñar una sola clave: a
los cuatro les quedaba un literal y en los cuatro era identidad. Firmar un
literal y cerrar es una respuesta tan válida como acuñar.
LO QUE MÁS PESA, RE-MEDIDO EN LA SUPERVISIÓN
Un toast risk y uno fulfill visten la misma tarjeta gris. Disparados los tres
tonos en la demo real con transiciones y animaciones congeladas, risk, fulfill
y affirm computan idénticos: fondo, borde, franja de acento de 0,67 px y
sombra. La tarjeta lleva data-intent Y data-depth=overlay; --toast-risk-surface
en :root no la mueve y --depth-overlay-border la repinta. La intención llega al
DOM y muere en la cascada, 21 claves.
Es la primera vez que §12.9 tiene coste de PRODUCTO y no sólo de contrato, así
que sube el precio de dejarla sin firmar. Y queda anotada la trampa de medirlo:
el tono viaja en data-intent, no en data-color — una sonda que lea data-color
lo encuentra null y diagnostica «el tono no llega», que es un defecto distinto
y manda la firma por el camino equivocado.
LA LEY QUE DEJARON LOS OTROS DOS
Antes de retirar una clave, mira quién la lee: scroll-area.auto-max-block leía
muerta en su propia demo y la consumen cinco recetas ajenas;
slider.min-block-size la fija media-player. Retirarlas habría roto seis
componentes sin que un guard se pusiera rojo. Ya es el paso 8.bis de §7.3.
Queda del eje: cero de cola A, tres de deuda B (cada uno por su razón), ninguna
pestaña Tokens pendiente, y siete cosas esperando tu firma.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## LA COLA A ESTÁ CERRADA (2026-08-24)
`scroll-area` 94 → **100 %** · `slider` 97 → **100 %** · `tabs` 96 → **97 %
CERRADO** · `toast` 98 → **100 %** . Global **68 %** , componentes al 100 %
**45**.
**Los cuatro cerraron SIN ACUÑAR UNA SOLA CLAVE**, y eso es el resultado, no un
atajo: a los cuatro les quedaba un literal, y en los cuatro era identidad
(`opacity: 1` que deshace el `0` del estado oculto · el `100%` de un raíl cuyo
knob real es su suelo `min-inline-size` · el `width: 100%` de `fitted` , que ES
«la lista llena el eje» · el `opacity: 1` del polo en reposo de un par
abierto/cerrado). Firmar un literal de identidad y cerrar es una respuesta tan
válida como acuñar.
### Las dos leyes que dejó
1. ** ⚠⚠ ANTES DE RETIRAR UNA CLAVE, MIRA QUIÉN LA LEE** — ya es el paso
**8.bis de §7.3** (`868bd235b`). `scroll-area.auto-max-block` leía muerta en
su propia demo y la consumen **cinco recetas ajenas** (`combobox`,
`command` , `gradient-picker` , `select` , `palabras` );
`slider.min-block-size` la fija `media-player` para su volumen vertical.
Retirarlas habría roto seis componentes **sin que un solo guard se pusiera
rojo**, porque ninguno mide el catálogo entero. Leer muerto en SU demo no es
leer muerto en el catálogo.
2. **El indicador de un tablist es CANAL DE VALOR, no superficie de tema.** La
ficha de `tabs` proponía acuñar `indicator-width` /`-height` sobre las vars
que `MeasuredIndicator` escribe en cada movimiento: un público encima sería
un knob que un tema puede FIJAR, y fijarlo rompe el deslizamiento. Rechazado
por escrito, con el precedente de `navigation-menu` .
### ⚠⚠ El hallazgo con más coste del eje: §12.9 se lleva la tarjeta de `toast`
**Un toast `risk` y uno `fulfill` visten la misma tarjeta gris.** Re-medido en
la supervisión sobre la demo real con transiciones y animaciones congeladas:
`risk` , `fulfill` y `affirm` computan **idénticos** (fondo, borde, franja de
acento de 0,67 px y sombra). La tarjeta lleva `data-intent` **y**
`data-depth='overlay'` ; escribir `--toast-risk-surface` en `:root` no la mueve
y `--depth-overlay-border` la repinta. **La intención llega al DOM y muere en
la cascada** — 21 claves.
Es la primera vez que §12.9 tiene coste de PRODUCTO y no sólo de contrato, así
que sube el precio de dejarla sin firmar. ⚠ Al medirlo, el tono viaja en
**`data-intent`**, no en `data-color` : una sonda que lea `data-color` lo
encuentra `null` y diagnostica «el tono no llega», que es un defecto DISTINTO.
### Qué queda del eje
- **Cola A: nada.** Los 16 que nunca habían pasado, cerrados o adjudicados.
- **Deuda B: tres**, cada uno por su razón — `audio-player` (sin README de
eidos donde escribir la sección), `palabras` y `proof-of-human` (carriles
propios).
- **Pestañas `Tokens` : ninguna pendiente.** Las 15 entregadas, y de propina el
contador de la pestaña pasa a DERIVARSE del contrato en las 105 demos
(`9fc38b19a` + `c88b2f861` ): tres mentían (`carousel` 30/27, `drag-drop`
10/9, `link-preview` 33/35).
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
- ✅ ** §12.9 FIRMADA Y EJECUTADA (2026-08-24)** — el plano es el SUELO,
`:where()` , especificidad cero: la receta gana donde el componente HABLA, en
cualquier orden de carga, y el plano sigue pintando lo que CALLA. El `frost`
NO baja (opt-in explícito por elemento). Doctrina en `changelog.md` §29,
emisor en `render-css.ts` , guarda en `active-eidos-config.test.ts` .
**Medido** : de 19 adoptantes, **16 con diff CERO** sobre ~49.000 valores; los
tres que se mueven son la firma haciendo su trabajo (`toast` recupera sus
seis tonos y una franja de acento de 3 px en vez de 0,67 px de gris;
`tooltip` sus tres variantes; `popover` /`tooltip`/`link-preview` el
`line-height` que sus recetas piden — la decisión de píxel que la receta de
`link-preview` tenía escrita como pendiente de esta firma). 17 claves
salieron STALE y se retiraron del ledger.
- **Esperan tu firma**: la cascada de
docs(theming): la COLA A queda CERRADA — y §12.9 pasa a tener coste de producto
scroll-area y slider al 100 %, tabs cerrado en 97 %, toast al 100 %. Global
68 %, 45 componentes al 100 %. Los cuatro cerraron SIN acuñar una sola clave: a
los cuatro les quedaba un literal y en los cuatro era identidad. Firmar un
literal y cerrar es una respuesta tan válida como acuñar.
LO QUE MÁS PESA, RE-MEDIDO EN LA SUPERVISIÓN
Un toast risk y uno fulfill visten la misma tarjeta gris. Disparados los tres
tonos en la demo real con transiciones y animaciones congeladas, risk, fulfill
y affirm computan idénticos: fondo, borde, franja de acento de 0,67 px y
sombra. La tarjeta lleva data-intent Y data-depth=overlay; --toast-risk-surface
en :root no la mueve y --depth-overlay-border la repinta. La intención llega al
DOM y muere en la cascada, 21 claves.
Es la primera vez que §12.9 tiene coste de PRODUCTO y no sólo de contrato, así
que sube el precio de dejarla sin firmar. Y queda anotada la trampa de medirlo:
el tono viaja en data-intent, no en data-color — una sonda que lea data-color
lo encuentra null y diagnostica «el tono no llega», que es un defecto distinto
y manda la firma por el camino equivocado.
LA LEY QUE DEJARON LOS OTROS DOS
Antes de retirar una clave, mira quién la lee: scroll-area.auto-max-block leía
muerta en su propia demo y la consumen cinco recetas ajenas;
slider.min-block-size la fija media-player. Retirarlas habría roto seis
componentes sin que un guard se pusiera rojo. Ya es el paso 8.bis de §7.3.
Queda del eje: cero de cola A, tres de deuda B (cada uno por su razón), ninguna
pestaña Tokens pendiente, y siete cosas esperando tu firma.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
paleta (que se lleva también el tono por defecto) · el componente compuesto
contra la receta que lo compone (con la salida barata ya probada en
`toolbar` ) · el barrido de descendientes de `file-upload` · las cuatro claves
de `avatar` fuera de gramática · el `aria-selected` literal de `tags-input`
· el chip de reacción de `chat-message` .
docs(theming): el handoff recoge la segunda tanda del 24 — ocho componentes, seis al 100 %
chat-message, chat-typing, fab, image-adjustments, separator y collapsible al
100 %; toolbar cerrado en 94 % y tags-input en 90 %, los dos por doctrina y no
por deuda. Global 68 %, y los componentes al 100 % pasan de 36 a 42. Esta vez
ningún commit se llevó trabajo ajeno: la ley del índice compartido ya iba en el
brief.
EL HALLAZGO QUE MÁS VALE
Ceder el cromo al componente compuesto SALE GRATIS. toolbar deja que
[data-button] gane —misma especificidad, emitido después— y no pierde ni una
clave, porque su receta ya no escribe reglas sobre el botón. Medido antes de
tocar nada: 51/54, y ninguna silenciosa era del botón. Es el reverso exacto de
form, que conserva 23 declaraciones muertas por la misma causa. La firma
pendiente de §13 tiene una salida barata y ya probada: no escribir la regla.
LO QUE LA SUPERVISIÓN ARREGLÓ
La sonda no congelaba nada, y es la que mide el gate del protocolo. Con
transition y animation congeladas, los 18 diffs fantasma de chat-typing pasan a
0 sobre 1.568 valores. Las 164 fichas regeneradas quedaron clasificadas una a
una en vez de por la cifra. Y refutado un susto: una sesión avisó de que cuatro
veredictos §5 podían estar vacíos en HEAD; comprobados los ocho, intactos.
DOS DEFECTOS REALES ANOTADOS Y NO TOCADOS
El chip de añadir reacción de chat-message lo pinta popover.css y se ve en la
captura: los chips de reacción son píldoras redondas y el de añadir un cuadrado
gris. Y el morfo de tags-input sella aria-selected='true' como literal en cada
etiqueta, así que archetypes.css le fija la tinta en reposo y su token nunca ha
pintado — con cara de defecto de a11y. Los dos esperan decisión.
Quedan cuatro de la cola A: scroll-area, tabs, slider y toast.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## LO QUE DEJÓ LA SEGUNDA TANDA DEL 2026-08-24 (ocho componentes)
Ocho más, por cuatro sesiones en paralelo, **con la ley del índice compartido
ya en el brief** — y esta vez ningún commit se llevó trabajo ajeno. Global
**68 %**, componentes al 100 % **36 → 42** .
| componente | antes → después | lo que enseñó |
| --- | --- | --- |
| `chat-message` | 84 → **100 %** | el guard leía 45/75 y las TREINTA muertas eran ejes que la demo no enciende |
| `chat-typing` | 89 → **100 %** | sus puntos son `> span` desnudos y la demo arranca en `idle` : 3 nodos de 8 |
| `fab` | 88 → **100 %** | el centinela **se auto-cancela** : un lift de 1234 px se lleva el nodo de debajo del cursor |
| `image-adjustments` | 67 → **100 %** | **medir de MÁS midió menos** : el pase de hover recorre 30 nodos como mucho |
| `separator` | 67 → **100 %** | sin acuñar UNA sola clave: sus dos `100%` son identidad |
| `collapsible` | 90 → **100 %** | el que ANIMA no tiene un knob de motion: su firma es `emerge-expand` /`-collapse` |
| `toolbar` | 91 → **94 % CERRADO** | **ceder el cromo al compuesto SALE GRATIS** |
| `tags-input` | 88 → **90 % CERRADO** | su tinta de etiqueta **no ha pintado nunca** (`aria-selected` literal en el morfo) |
**Dos techos, y los dos son doctrina**: los 4 privados de `tags-input` son los
cuatro el puente THM-2, y los 2 de `toolbar` son la identidad de la variante
(una barra `ghost` ES la que no tiene relleno ni sombra).
### El hallazgo que más vale de la tanda
**Ceder el cromo al componente compuesto SALE GRATIS.** `toolbar` deja que
`[data-button]` gane —misma especificidad, emitido después— y **no pierde ni
una clave**, porque su receta ya no escribe reglas sobre el botón (A-112).
Medido ANTES de tocar nada: 51/54, y ninguna silenciosa era del botón. Es el
**reverso exacto de `form` **, que conserva 23 declaraciones muertas por la
misma causa. La firma pendiente de §13 («¿manda el compuesto o la receta que lo
compone?») tiene por tanto una salida barata y ya probada: no escribir la regla.
### Lo que la supervisión arregló
- **La sonda NO congelaba nada** (`10832bef4`). El gate del protocolo es «diff
de computed CERO» y quien lo mide leía transiciones a medias y animaciones en
bucle donde pillaran. `chat-typing` dio **18 diffs de `opacity` corriendo la
sonda dos veces sobre código idéntico**; con la congelación, **0 sobre 1.568
valores**. ⚠ El GUARD sigue congelando sólo `transition` : cambiarlo obliga a
re-verificar el ledger entero (§13).
- **164 fichas regeneradas, clasificadas una a una** (`5c8e707a0`): 155 sólo la
fecha, 7 mejoraban, **2 borraban prosa medida** — cosidas. El generador pisa
lo escrito a mano y eso ya está en §13 con su arreglo.
- **Refutado un susto**: una sesión avisó de que había revertido fichas ajenas y
de que cuatro veredictos §5 podían estar vacíos en HEAD. Comprobados los ocho:
**intactos, de 27 a 81 líneas cada uno** .
### Defectos reales anotados, NO corregidos (mueven píxel o tocan morfo)
- **`chat-message`**: el chip de añadir reacción lleva `data-popover-trigger` y
`popover.css` (0,2,0) le pinta fondo, borde, radio, tinta, altura, padding y
tamaño de letra. **Se ve en la captura** : los chips de reacción son píldoras
redondas y el de añadir es un cuadrado gris. Espera decisión de diseño.
- **`tags-input`**: el morfo sella `aria-selected='true'` como LITERAL en cada
etiqueta, así que `archetypes.css` (0,4,0) le fija tinta y velo de estado EN
REPOSO y su token nunca ha pintado. Tiene cara de defecto de a11y (un lector
anuncia todas las etiquetas como seleccionadas). Toca morfo ⇒ §12.
docs(theming): el registro §8 recoge tabs y toast, con su sha — y la cola A CIERRA
Los dos commits de esta sesión, con sus cifras y sus artefactos:
- `tabs` 96 % → 97 % CERRADO (`300153f9f`) — 79 claves, ninguna acuñada,
centinela 70/79 con 9 adjudicadas.
- `toast` 98 % → 100 % (`b8eccc1c4`) — 85 claves, ninguna acuñada, centinela
51/85 con 34 adjudicadas.
Y con ellos la Cola A queda CERRADA: los cuatro (`scroll-area`, `slider`,
`tabs`, `toast`) cerraron **sin acuñar una sola clave**. Sus contratos ya
estaban enteros y lo que quedaba fuera eran literales-identidad y, en `tabs`,
el canal de VALOR de soma. Cuando el número no se mueve porque no debe, eso ES
el resultado — y así está escrito en el handoff.
Lo que enseñaron los dos últimos, para el que siga:
- §12.9 en una tarjeta PORTALADA se lleva la TARJETA ENTERA, no sólo la
tipografía — 21 claves de `toast`, y con coste de producto: un toast `risk`
y uno `fulfill` visten la misma tarjeta gris. Medido, adjudicado con
`PLANE_SUPERSEDED` y registrado en next-features §12; sin firma no se toca.
- La misma clave puede mentir en reposo y decir la verdad en animación: los
`{tono}-accent` alcanzan bajo `[data-loading]`, donde el `@keyframes` del
pulso gana a toda declaración normal.
- Poner `openMarker` puede EMPEORAR la medición cuando la superficie se
auto-descarta: tres corridas del guard discreparon sobre código idéntico.
- El indicador de `tabs` es canal de valor: `MeasuredIndicator` escribe su rect
en cada movimiento, y un público encima sería un knob que rompe el
deslizamiento al fijarse.
Guard: `docs:check` 0 · prettier limpio sobre el contenido normalizado a LF.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### Cola A: CERRADA (2026-08-24)
Los cuatro, por dos sesiones en paralelo: `scroll-area` 94 → **100 %**
(`3282ef978`) · `slider` 97 → **100 %** (`4d3ca2fd8`) · `tabs` 96 → **97 %
CERRADO** (`300153f9f`) · `toast` 98 → **100 %** (`b8eccc1c4`). **Los cuatro
cerraron sin acuñar UNA sola clave**: sus contratos ya estaban enteros y lo que
quedaba fuera eran tres literales-identidad (un rail al 100 %, una barra al
`opacity: 1` , la lista `fitted` al 100 %, la tarjeta al `opacity: 1` ) y, en
`tabs` , el canal de VALOR de soma. Cuando el número no se mueve porque no debe,
eso ES el resultado.
**Lo que dejaron los dos últimos, en una línea cada uno:**
- **`tabs`** — la mitad de un contrato puede vivir en las VARIANTES (40/79 →
70/79 barriendo `data-variant` y usando las dos URL que el propio demo
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
ofrece), y su indicador es **canal de valor** : `--_tabs-indicator-{x,y,w,h}`
los escribe `MeasuredIndicator` en cada movimiento, así que un público encima
docs(theming): el registro §8 recoge tabs y toast, con su sha — y la cola A CIERRA
Los dos commits de esta sesión, con sus cifras y sus artefactos:
- `tabs` 96 % → 97 % CERRADO (`300153f9f`) — 79 claves, ninguna acuñada,
centinela 70/79 con 9 adjudicadas.
- `toast` 98 % → 100 % (`b8eccc1c4`) — 85 claves, ninguna acuñada, centinela
51/85 con 34 adjudicadas.
Y con ellos la Cola A queda CERRADA: los cuatro (`scroll-area`, `slider`,
`tabs`, `toast`) cerraron **sin acuñar una sola clave**. Sus contratos ya
estaban enteros y lo que quedaba fuera eran literales-identidad y, en `tabs`,
el canal de VALOR de soma. Cuando el número no se mueve porque no debe, eso ES
el resultado — y así está escrito en el handoff.
Lo que enseñaron los dos últimos, para el que siga:
- §12.9 en una tarjeta PORTALADA se lleva la TARJETA ENTERA, no sólo la
tipografía — 21 claves de `toast`, y con coste de producto: un toast `risk`
y uno `fulfill` visten la misma tarjeta gris. Medido, adjudicado con
`PLANE_SUPERSEDED` y registrado en next-features §12; sin firma no se toca.
- La misma clave puede mentir en reposo y decir la verdad en animación: los
`{tono}-accent` alcanzan bajo `[data-loading]`, donde el `@keyframes` del
pulso gana a toda declaración normal.
- Poner `openMarker` puede EMPEORAR la medición cuando la superficie se
auto-descarta: tres corridas del guard discreparon sobre código idéntico.
- El indicador de `tabs` es canal de valor: `MeasuredIndicator` escribe su rect
en cada movimiento, y un público encima sería un knob que rompe el
deslizamiento al fijarse.
Guard: `docs:check` 0 · prettier limpio sobre el contenido normalizado a LF.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
sería un knob que un tema puede fijar — y fijarlo rompe el deslizamiento.
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
⚠ **Actualizado 2026-08-26 (§14)** : entonces se llamaban `--indicator-*` , sin
prefijo, y por eso el censo sólo podía puntuarlos `global` — el techo de
`tabs` NO era 97 %, era **100 %** , y el 3 % que faltaba era el NOMBRE.
docs(theming): el registro §8 recoge tabs y toast, con su sha — y la cola A CIERRA
Los dos commits de esta sesión, con sus cifras y sus artefactos:
- `tabs` 96 % → 97 % CERRADO (`300153f9f`) — 79 claves, ninguna acuñada,
centinela 70/79 con 9 adjudicadas.
- `toast` 98 % → 100 % (`b8eccc1c4`) — 85 claves, ninguna acuñada, centinela
51/85 con 34 adjudicadas.
Y con ellos la Cola A queda CERRADA: los cuatro (`scroll-area`, `slider`,
`tabs`, `toast`) cerraron **sin acuñar una sola clave**. Sus contratos ya
estaban enteros y lo que quedaba fuera eran literales-identidad y, en `tabs`,
el canal de VALOR de soma. Cuando el número no se mueve porque no debe, eso ES
el resultado — y así está escrito en el handoff.
Lo que enseñaron los dos últimos, para el que siga:
- §12.9 en una tarjeta PORTALADA se lleva la TARJETA ENTERA, no sólo la
tipografía — 21 claves de `toast`, y con coste de producto: un toast `risk`
y uno `fulfill` visten la misma tarjeta gris. Medido, adjudicado con
`PLANE_SUPERSEDED` y registrado en next-features §12; sin firma no se toca.
- La misma clave puede mentir en reposo y decir la verdad en animación: los
`{tono}-accent` alcanzan bajo `[data-loading]`, donde el `@keyframes` del
pulso gana a toda declaración normal.
- Poner `openMarker` puede EMPEORAR la medición cuando la superficie se
auto-descarta: tres corridas del guard discreparon sobre código idéntico.
- El indicador de `tabs` es canal de valor: `MeasuredIndicator` escribe su rect
en cada movimiento, y un público encima sería un knob que rompe el
deslizamiento al fijarse.
Guard: `docs:check` 0 · prettier limpio sobre el contenido normalizado a LF.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **`toast`** — ** §12.9 en una tarjeta PORTALADA se lleva la TARJETA ENTERA**,
21 claves, y con coste de PRODUCTO: un toast `risk` y uno `fulfill` visten la
misma tarjeta gris, y la franja de acento no se ve nunca en reposo (el plano
declara el ATAJO `border` , que pisa el `border-inline-start` ). Matiz para la
firma: los seis `{tono}-accent` SÍ alcanzan bajo `[data-loading]` , donde el
`@keyframes` del pulso gana a toda declaración normal — **la misma clave
miente en reposo y dice la verdad en animación**. Y una del instrumento:
**poner `openMarker` EMPEORA la medición** cuando la superficie se
auto-descarta (tres corridas discrepando); sin marcador el guard dispara una
tarjeta nueva antes de cada token y da 51/85 tres veces seguidas.
De la deuda B siguen tres: `audio-player` (sin README de eidos donde escribir
la sección), `palabras` y `proof-of-human` (carriles propios). Más las pestañas
`Tokens` que queden pendientes, la deuda hermana que destapó saldar la B.
docs(theming): el handoff recoge la segunda tanda del 24 — ocho componentes, seis al 100 %
chat-message, chat-typing, fab, image-adjustments, separator y collapsible al
100 %; toolbar cerrado en 94 % y tags-input en 90 %, los dos por doctrina y no
por deuda. Global 68 %, y los componentes al 100 % pasan de 36 a 42. Esta vez
ningún commit se llevó trabajo ajeno: la ley del índice compartido ya iba en el
brief.
EL HALLAZGO QUE MÁS VALE
Ceder el cromo al componente compuesto SALE GRATIS. toolbar deja que
[data-button] gane —misma especificidad, emitido después— y no pierde ni una
clave, porque su receta ya no escribe reglas sobre el botón. Medido antes de
tocar nada: 51/54, y ninguna silenciosa era del botón. Es el reverso exacto de
form, que conserva 23 declaraciones muertas por la misma causa. La firma
pendiente de §13 tiene una salida barata y ya probada: no escribir la regla.
LO QUE LA SUPERVISIÓN ARREGLÓ
La sonda no congelaba nada, y es la que mide el gate del protocolo. Con
transition y animation congeladas, los 18 diffs fantasma de chat-typing pasan a
0 sobre 1.568 valores. Las 164 fichas regeneradas quedaron clasificadas una a
una en vez de por la cifra. Y refutado un susto: una sesión avisó de que cuatro
veredictos §5 podían estar vacíos en HEAD; comprobados los ocho, intactos.
DOS DEFECTOS REALES ANOTADOS Y NO TOCADOS
El chip de añadir reacción de chat-message lo pinta popover.css y se ve en la
captura: los chips de reacción son píldoras redondas y el de añadir un cuadrado
gris. Y el morfo de tags-input sella aria-selected='true' como literal en cada
etiqueta, así que archetypes.css le fija la tinta en reposo y su token nunca ha
pintado — con cara de defecto de a11y. Los dos esperan decisión.
Quedan cuatro de la cola A: scroll-area, tabs, slider y toast.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(theming): el handoff recoge la tanda de DOCE y lo que encontró supervisarla
Doce componentes cerrados por cinco sesiones en paralelo — cinco al 100 %
(chat-log, chat-composer, rating-group, toggle) y card cerrado en su 78 %,
que ES su techo. Global 66 % -> 68 %.
Y la parte que importa: los doce se supervisaron uno a uno, y la supervisión
encontró cinco cosas que la ejecución no vio. Cuatro salieron del §7.7.
Las dos primeras son de la rama, no del eje: el índice de git es COMPARTIDO
—verificar el árbol indexado no basta, porque otra sesión puede reescribirlo
entre que lo miras y confirmas— y un árbol de trabajo rancio hace mentir al
instrumento sin tocar un solo commit (el guard de card daba 0/98 por un fichero
sucio; desde HEAD limpio, 49/98 verde).
Las otras tres son del eje: la cascada de paleta se lleva también el tono por
defecto, el canal inline filtrado al contrato son cuatro claves y no dos, y la
sonda y el guard mueren con --import tsx/esm.
Queda escrito además el gate del diff cero con su matiz: dos componentes no
cerraron a cero y los dos lo declararon; los dos son ruido reproducido sobre
código idéntico. Un diff no cero no es automáticamente una regresión, pero sólo
se declara ruido reproduciéndolo.
Y dicho sin esconderlo: la demo de chat-log se tocó como instrumento.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## LO QUE DEJÓ LA SESIÓN DEL 2026-08-24 (doce componentes + supervisión)
Doce componentes cerrados por cinco sesiones en paralelo, cada uno con su
commit aislado, y **una pasada de supervisión sobre los doce** (refutación
estática de cada commit + centinela re-corrido + medición propia de todo claim
que no fuese trivial). Cinco componentes llegan al **100 %** ; `card` cierra en
**78 %** porque ése ES su techo, y así está escrito en su ficha.
### Los cinco hallazgos de la SUPERVISIÓN (no de la ejecución)
1. ** ⚠⚠ EL ÍNDICE DE GIT ES COMPARTIDO** (`5be7dabf4`). Hay un solo
`.git/index` para todas las sesiones. Construir el índice desde HEAD y
comprobarlo con `git diff --cached` protege del árbol ajeno, **no de la
ventana entre mirar y confirmar**. Costó `edc019515` (salió con tres
fragmentos de `rating-group` y sin la mitad de los suyos), su reparación
`007c2af52` , y **una coma de más que dejó `theming-sentinel-exceptions.ts`
SIN PARSEAR durante cuatro commits de HEAD** (`88a208644`). El guard no
quedaba en rojo: quedaba MUERTO, y sólo se veía en checkout limpio.
**Regla nueva: verificación y `git commit` en la MISMA invocación de shell.**
2. **Un árbol de trabajo rancio hace MENTIR al instrumento sin tocar un
commit.** El guard de `card` daba `0/98` —la firma del instrumento ciego—
por un `theming-sentinel.ts` sucio con el bloque de `chat-log` DUPLICADO.
Desde copia limpia de HEAD: `49/98` , verde. **Antes de creer un `0/N` ,
comprueba que el instrumento coincide con HEAD.**
3. **La cascada de paleta se lleva TAMBIÉN el tono por defecto** (`b7f5a7d75`).
El §13 decía que las `{c}-primary-*` salvan a la instancia sin `data-color` ;
donde soma trata el color como valor RESUELTO lo estampa siempre y `neutral`
cae con los otros once. Medido en `switch` y `editable` .
4. **El canal inline filtrado al contrato son CUATRO claves, no dos**
(`009af3300` + `8a4bb8e0e` ). Los dos de `avatar` parecían fuera porque su
bloque de `base.ts` es una IIFE que el censo no supo leer hasta `f68bac4a6` .
Re-medidos: ni el fondo del badge ni el `box-shadow` del anillo se mueven
desde `:root` , y **no puede existir instancia alcanzable** — la puerta
`data-*-custom` y la escritura inline viajan JUNTAS.
5. **La sonda y el guard MUEREN con `--import tsx/esm`** (`b4e4fe1fe`).
`ReferenceError: __name is not defined` dentro de `page.evaluate` : el
ayudante `keepNames` de esbuild no existe en la página. Van con `node` a
secas. El error no nombra ni a tsx ni a la sonda.
### Lo que enseñó cada componente
| componente | antes → después | lo que enseñó |
| --- | --- | --- |
| `chat-log` | 77 → **100 %** | el instrumento daba 15/31 y las DIECISÉIS «muertas» estaban vivas |
| `chat-composer` | 79 → **100 %** | ** `file-upload` BARRE DESCENDIENTES** y se come el token del huésped |
| `rating-group` | 80 → **100 %** | una escala privada sube al contrato; el guard no fotografía `transform` |
| `toggle` | 81 → **100 %** | el guard sólo sabía barrer UN eje: 36/126 → 70/126 sin adjudicar nada |
| `select` | 83 → 92 % | el portal parte el instrumento: el estado que abre TAPA los de reposo |
| `avatar` | 75 → 90 % | su contrato era INVISIBLE para los dos lectores (una IIFE en `base.ts` ) |
| `calendar` | 84 → 89 % | una entrada de receta de FAMILIA no se juzga en la ruta de UN componente |
| `file-upload` | 76 → 83 % | una clave que no pintaba en NINGUNO de sus tres botones — retirada |
| `editable` | 75 → 82 % | el guard CERRABA la superficie que medía (sale del modo con un `blur` ) |
| `switch` | 76 → 81 % | su tono NEUTRAL cae con los otros once |
| `radio-group` | 77 → 81 % | su punto NUNCA ha pintado su escala (el SVG escribe `1em` inline) |
| `card` | 78 → **78 % CERRADO** | el número cerrado ES el resultado: sus 8 privados son puente y conmutador |
### Dos verdades sobre el GATE del «diff cero»
Dos componentes NO cerraron a cero, y los dos lo declararon. **Los dos son
ruido del instrumento, reproducido por la supervisión sobre código idéntico**:
- `calendar` : **28 diffs corriendo la sonda dos veces sin tocar nada** , en los
dos mismos nodos (`month-select` / `year-select` ) y las dos mismas
propiedades. Empate de especificidad resuelto por orden de carga de Vite. Su
commit además era SÓLO comentarios, así que no podía mover un píxel.
- `chat-composer` : 2 diffs de `blockSize` (30 ↔ 36 px) en `[data-…-attach]` ,
reproducidos en tres corridas del mismo código.
**Un diff no cero no es automáticamente una regresión — pero SÓLO se puede
declarar ruido reproduciéndolo sobre código idéntico.** Los dos lo hicieron.
### Lo que hay que saber antes de seguir
- **`card` y `radio-group` están CERRADOS por debajo del 100 %** y no es
deuda: sus privados son puente THM-2 y conmutadores por variante. Un público
encima mataría el `color=` por instancia.
- **`file-upload` es HOY el único componente con un barrido de descendientes**
(`[data-file-upload] [data-disabled]`, una sola ocurrencia en 162 recetas).
Acotarlo mueve píxel de cualquier huésped → espera firma.
- **El guard no fotografía `transform` ** y ya son tres los componentes que lo
sufren (`background`, `rating-group` , `card` ). Arreglarlo obliga a
re-verificar el ledger entero, así que se adjudica de uno en uno.
- **La demo de `chat-log` se TOCÓ como instrumento** (montaba tres de sus seis
partes sólo en la prosa, así que once claves no tenían nodo que pintar). Roza
la regla de que las demos quedan fuera del eje: queda dicho, no escondido.
docs(theming): la cola eran TREINTA Y CUATRO, no once — y dos huecos más del instrumento
Ejecuta P3, P4 y P5 del plan de la revisión del 24.
P4 — LA COLA DEL HANDOFF ESTABA MAL, Y ERA MI ERROR
La bala que escribí al cerrar la tanda listaba once pendientes. Contados contra
el censo y el registro §8 son treinta y cuatro, y la lista sin separar tampoco
servía, porque mezcla dos cosas distintas:
- 16 que NUNCA han pasado por el eje (sin entrada §8 ni README): field-langs,
chronos, mockup, sidebar, image-adjustments, separator, chat-message, fab,
tags-input, chat-typing, collapsible, toolbar, scroll-area, tabs, slider,
toast. Ésa es la cola de verdad.
- 18 que SÍ pasaron y sólo les falta el README «Talla y tema»: el paso se
volvió obligatorio después de que cerraran y e522e04e6 recuperó 21, pero
éstos quedaron fuera. No es cola de tokenización, es deuda de documentación.
Queda escrito además cómo regenerar la lista, para que nadie la escriba de
memoria otra vez: alcance < 100 % y sin sección «Talla y tema», y el desempate
entre A y B es si tiene entrada en §8.
P3 — LA FECHA DE MEDIDA DE SEIS FICHAS
select, calendar, radio-group, rating-group, toggle y card se midieron y
commitearon pasada la medianoche; sus fichas decían 23. La fecha es parte del
artefacto.
P5 — DOS HUECOS DE INSTRUMENTO EN §13
- eidos-lint no conoce las exenciones que el test de vitest SÍ tiene
(CSS_ONLY_LAYERS, WIP_TRACKS, KNOWN_MISSING_MORFO, raíces competidoras): sobre
spin-field muere con «No morfo file» en vez de eximirlo. El guard de la suite
y el script de línea de comandos discrepan sobre la misma ley, y el que se
corre a mano es el que miente.
- La columna `size` del censo se apaga cuando el eje de talla SUBE al contrato:
la calcula leyendo bloques [data-size] del CSS, así que promover una escala
con scope 'size:{k}' —la forma canónica— la borra del recuento. Bajó de 57 a
55 justo al hacerlo mejor. El instrumento premia la forma vieja.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **LA COLA, con la separación que la primera redacción se dejó** (corregido
2026-08-24 al revisar: decía once y son treinta y cuatro, contados contra el
censo y el registro §8).
**A. Nunca han pasado por el eje — 16.** Sin entrada en §8 y sin README:
`field-langs` 0 % (bloqueado por el mandato Field) · `chronos` 1 % (carril
WIP) · `mockup` 38 % (⚠ sin ruta de demo) · `sidebar` 55 % (eje propio) ·
`image-adjustments` 67 % · `separator` 67 % · `chat-message` 84 % ·
`fab` 88 % · `tags-input` 88 % · `chat-typing` 89 % · `collapsible` 90 % ·
`toolbar` 91 % · `scroll-area` 94 % · `tabs` 96 % · `slider` 97 % ·
`toast` 98 %.
**B. Pasaron por el eje pero les FALTABA el README «Talla y tema» — 18,
quedan 3.** ✅ **Quince saldados el 2026-08-24** (`a6df34c05`), con la tabla
DERIVADA del contrato y del ledger. Quedan `audio-player` (no tiene README de
eidos: no hay dónde escribir la sección), `palabras` y `proof-of-human`
(carriles propios). ⚠ **Y sale una deuda hermana** : ninguno de los quince
tiene pestaña `Tokens` en su demo — el paso 11 del protocolo llegó después de
que cerraran, así que hasta que la tengan **la tabla del README es la
fuente**, y así está escrito en los quince. La lista original era: Su
docs(theming): la cola eran TREINTA Y CUATRO, no once — y dos huecos más del instrumento
Ejecuta P3, P4 y P5 del plan de la revisión del 24.
P4 — LA COLA DEL HANDOFF ESTABA MAL, Y ERA MI ERROR
La bala que escribí al cerrar la tanda listaba once pendientes. Contados contra
el censo y el registro §8 son treinta y cuatro, y la lista sin separar tampoco
servía, porque mezcla dos cosas distintas:
- 16 que NUNCA han pasado por el eje (sin entrada §8 ni README): field-langs,
chronos, mockup, sidebar, image-adjustments, separator, chat-message, fab,
tags-input, chat-typing, collapsible, toolbar, scroll-area, tabs, slider,
toast. Ésa es la cola de verdad.
- 18 que SÍ pasaron y sólo les falta el README «Talla y tema»: el paso se
volvió obligatorio después de que cerraran y e522e04e6 recuperó 21, pero
éstos quedaron fuera. No es cola de tokenización, es deuda de documentación.
Queda escrito además cómo regenerar la lista, para que nadie la escriba de
memoria otra vez: alcance < 100 % y sin sección «Talla y tema», y el desempate
entre A y B es si tiene entrada en §8.
P3 — LA FECHA DE MEDIDA DE SEIS FICHAS
select, calendar, radio-group, rating-group, toggle y card se midieron y
commitearon pasada la medianoche; sus fichas decían 23. La fecha es parte del
artefacto.
P5 — DOS HUECOS DE INSTRUMENTO EN §13
- eidos-lint no conoce las exenciones que el test de vitest SÍ tiene
(CSS_ONLY_LAYERS, WIP_TRACKS, KNOWN_MISSING_MORFO, raíces competidoras): sobre
spin-field muere con «No morfo file» en vez de eximirlo. El guard de la suite
y el script de línea de comandos discrepan sobre la misma ley, y el que se
corre a mano es el que miente.
- La columna `size` del censo se apaga cuando el eje de talla SUBE al contrato:
la calcula leyendo bloques [data-size] del CSS, así que promover una escala
con scope 'size:{k}' —la forma canónica— la borra del recuento. Bajó de 57 a
55 justo al hacerlo mejor. El instrumento premia la forma vieja.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
número está adjudicado y su commit hecho; lo que falta es el artefacto del
paso §7 que se volvió obligatorio después de que cerraran (`e522e04e6`
recuperó 21, éstos quedaron fuera): `proof-of-human` · `palabras` ·
`audio-player` · `drawer` · `radio-cards` · `password-field` · `tag-group` ·
`popover` · `color-picker` · `timeline` · `stepper` · `aura` · `metrics` ·
`float-panel` · `chart` · `accordion` · `gradient-builder` · `nav-tree` .
**No es cola de tokenización: es deuda de documentación** , y se salda con un
barrido derivado del contrato como el que ya se hizo una vez.
Regenera siempre esta lista del censo, nunca de memoria: el criterio es
«alcance < 100 % y sin secci ó n `## Talla y tema` », y el desempate entre A y B
es si tiene entrada en el registro §8.
docs(theming): el handoff recoge la tanda de DOCE y lo que encontró supervisarla
Doce componentes cerrados por cinco sesiones en paralelo — cinco al 100 %
(chat-log, chat-composer, rating-group, toggle) y card cerrado en su 78 %,
que ES su techo. Global 66 % -> 68 %.
Y la parte que importa: los doce se supervisaron uno a uno, y la supervisión
encontró cinco cosas que la ejecución no vio. Cuatro salieron del §7.7.
Las dos primeras son de la rama, no del eje: el índice de git es COMPARTIDO
—verificar el árbol indexado no basta, porque otra sesión puede reescribirlo
entre que lo miras y confirmas— y un árbol de trabajo rancio hace mentir al
instrumento sin tocar un solo commit (el guard de card daba 0/98 por un fichero
sucio; desde HEAD limpio, 49/98 verde).
Las otras tres son del eje: la cascada de paleta se lleva también el tono por
defecto, el canal inline filtrado al contrato son cuatro claves y no dos, y la
sonda y el guard mueren con --import tsx/esm.
Queda escrito además el gate del diff cero con su matiz: dos componentes no
cerraron a cero y los dos lo declararon; los dos son ruido reproducido sobre
código idéntico. Un diff no cero no es automáticamente una regresión, pero sólo
se declara ruido reproduciéndolo.
Y dicho sin esconderlo: la demo de chat-log se tocó como instrumento.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(theming): el handoff recoge la sesión entera del 23 — 65 %, 16 componentes
Cabecera al día (65 % global, 25 componentes al 100 %, <20 % baja de 14 a 12) y
una sección nueva con la tabla de los dieciséis, las CINCO LEYES que salieron y
todo lo que aprendió el instrumento.
Las leyes, que es lo que hay que leer antes de seguir la cola:
1. El portal es una frontera de cascada — un privado de la raíz no la cruza.
2. El plano `overlay` gana donde el componente habla, y en `tooltip` se queda
también el fondo, el borde y la sombra: sus tres variantes computan lo mismo.
3. La cascada de paleta anula los tonos del componente — 419 claves, 49 recetas.
4. Un respaldo escrito a mano envejece contra su token.
5. Donde hay un par, el defecto viene en par.
Firmas actualizadas: la 1 (§12.9) deja de ser sólo tipografía y suma la
superficie del tooltip; la 7 pasa de UN canónico sin demo a CUATRO
(picker-shell, mockup, surface, audio-player) con la nota de que el guard sobre
una página vacía miente en verde-rojo; y entra la 11, las dos reglas con
`:global()` que el navegador descarta.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## LO QUE DEJÓ LA SESIÓN DEL 2026-08-23
**Dieciséis componentes** (11 cosidos + 6 de cola + 2 adjudicados sin tocar
código), tres pasadas de rojos anteriores (`drawer` 24, `metrics` 18,
`color-picker` 25) y **una corrección a la baja** : `context-menu` 90 → 87 %, al
retirarle un token que mentía.
| componente | antes → después | lo que enseñó |
| --- | --- | --- |
| `menubar` | 15 → 88 % | el plano `overlay` GANA donde el componente habla |
| `field` | 73 → 98 % | sus 18 rojos estaban vivos; `::placeholder` sin `placeholder` |
| `onion-menu` | 29 → 84 % | `:global()` en CSS plano ⇒ regla DESCARTADA |
| `button` | 55 → 91 % | la cascada de paleta anula 419 claves del catálogo |
| `callout` | 27 → 79 % | la base óptica deja de copiar las métricas del sistema |
| `empty-state` | 29 → **100 %** | 26/26 sin una sola adjudicación |
| `dropdown-menu` | 57 → 96 % | y la tipografía del gemelo, RETIRADA |
| `checkbox` | 59 → 72 % | un huérfano que el test de huérfanos no puede ver |
| `image` | 60 → 96 % | la página que nunca alcanza `networkidle` |
| `anchor-nav` | 20 → **100 %** | el censo no veía los bordes POR LADO |
| `banner` | 30 → **100 %** | 4/42 → 53/53 al estampar `data-intent` y barrer variantes |
| `date-range-field` | 29 → **100 %** | una clave pública que giraba OTRA cosa |
| `time-range-field` | 29 → **100 %** | el gemelo con el MISMO defecto copiado |
| `tooltip` | 52 → 75 % | el plano le anula las TRES variantes |
| `audio-player` | 37 → 56 % | el instrumento medía CERO nodos |
| cola pequeña | 6 comp. | `section` TAPABA sus propias claves públicas |
**Las cinco leyes que salieron, en una línea cada una:**
1. **El portal es una frontera de cascada** — un privado de la raíz no la cruza
(mató el eje `size` del color-picker).
2. **El plano `overlay` gana donde el componente habla** — y no sólo la
tipografía: en `tooltip` se queda el fondo, el borde y la sombra, y con ellos
las tres variantes.
3. **La cascada de paleta anula los tonos del componente** — el bloque genérico
va el ÚLTIMO y gana por orden: 419 claves en 49 recetas.
4. **Un respaldo escrito a mano envejece contra su token** — `, 1.4` contra un
`--font-line-height-sm` que vale 1.45, en dos componentes.
5. **Donde hay un par, el defecto viene en par** — los dos range-field traían el
mismo nombre equivocado, copiado al duplicar.
**Lo que el instrumento aprendió (todo en `scripts/` , ya commiteado):**
- `openMarker` — no pulsar lo que YA está abierto (onion-menu nace abierto y el
guard lo cerraba: 12 de 20 tokens muertos).
- `sweepAttr` — barrer una variante mientras se mide (banner, tooltip, button).
- El barrido de tono estampa `data-color` **y** `data-intent` (banner).
- `extraNodes` para hooks de CLASE (onion-menu) y para partes de OTRO chasis
(audio-player: 0 → 48 nodos).
- Caída a `load` cuando `networkidle` no llega nunca (image).
- `urls` para un componente sin ruta (surface, audio-player).
- Excepciones por PATRÓN (`SENTINEL_PATTERN_EXCEPTIONS`) para una razón
arquitectónica que afecta a 56 claves de golpe.
- El censo: literal ANOTADO dentro de un privado = ausencia firmada; y los ocho
longhands de borde POR LADO (+30 filas en el catálogo).
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠ **Sonda y centinela filtran por `data-{c}-*`** : un componente que estiliza
HTML crudo (prose) o cuyas partes no llevan atributo se mide sobre UN nodo y el
gate no significa nada. Los dos aceptan ya un selector extra
(`EXTRA_NODES` en la sonda, `extraNodes` en `COMPONENT_OVERRIDES` ).
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(theming): la revisión adversarial §7.7 de los 26 commits — 5 hipótesis, 5 refutadas
Cierra el punto P5 del plan de la revisión: lo ejecutado desde el 22 (33
componentes, dos bloques) por fin tiene su pasada escéptica, con medición propia
y no leída de los commits.
LA BASE, ANTES DE COMPARAR NADA
Worktree en cd6a9f4e3 con dev server propio, node_modules por junction y
`server: { fs: { allow: [...] } }` — sin eso Vite responde 403 a /@fs/… , la
página NO hidrata y se compara contra una base muerta (la trampa que el handoff
registra). Comprobado que los componentes MONTAN e hidratan antes de medir.
H1 · «el default es idéntico» — 33 de 33
31 con 0 diffs, ~48.000 valores computados en 7-8 estados por componente.
`surface` daba 0 valores por una URL mía equivocada: en su ruta real
(/temas/gradientes) 0 diffs sobre 896. Y los dos con diffs son RUIDO DEL
INSTRUMENTO, probado corriendo dos veces el MISMO código: `image` reproduce su
único diff y `audio-player` da ONCE (más que la comparación base↔HEAD). Las dos
propiedades son estado vivo — la opacity de un <img> con animación de entrada
(la sonda congela transition, nunca animation) y el ancho del rango buffered de
un audio. En §13, con la recomendación de excluirlas del snapshot.
H2 · «el velo cae donde debe» — verde en los cuatro que tocaron :hover
Píxel hacia arriba: dropdown-menu y context-menu pintan el velo en su item
(radio 4px, el nodo CON forma) y el list-surface de debajo queda limpio;
menubar pinta el abierto en su propio <button> sin derramar al contenedor, y la
fila de su panel en el item; anchor-nav no tiene velo en ninguna capa, que es lo
correcto — su hover es sólo tinta. Medido sobre un enlace NO activo: el primero
que casa el selector lleva data-active y pinta otra cosa.
H3 · «no hay doble animación» — no aplica
Ningún commit de los 26 toca animation, @keyframes, data-event ni motion-* en
components/. No hay sello movido que pueda duplicarse.
H4 · «cada token alcanza» — rehecho, y destapó float-panel
El barrido del centinela sobre los 59 con ledger: 0 STALE, 0 errores, un solo
rojo (float-panel), ya arreglado en 233ef989b.
H5 · «el contrato no tiene duplicados ni huérfanos» — limpio
144 bloques sin duplicados, sin claves repetidas dentro de un bloque, y el test
oficial de huérfanos en verde.
⚠ Y aquí mintió mi propio instrumento: un guard estricto de un solo uso reportó
185 huérfanos —los pasos de escala por talla y todos los tonos— porque excluía
`generated/`, que es exactamente donde el TSC emite el nombre resuelto y el
forward de paleta lee los tonos. Un guard de huérfanos que no mira el CSS
GENERADO ve huérfano todo lo que el generador resuelve. En §13.
VEREDICTO: 0 hallazgos nuevos. Los reales de esta revisión salieron del análisis
ESTÁTICO (E1-E5) y ya estaban arreglados antes de esta pasada.
El handoff abre ahora con las cuatro lecciones que cambian cómo se trabaja:
correr el guard sobre el ledger entero · el nombre de un token no es el de la
propiedad · si un paso del protocolo no está en el commit, no se hizo · y
comprobar que la base MONTA antes de comparar contra ella.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## LA REVISIÓN DE LOS 26 (2026-08-23) — lo primero que hay que saber
Todo lo ejecutado desde la revisión del 22 pasó por fin su análisis:
[`REVIEW-theming-2026-08-23.md` ](./REVIEW-theming-2026-08-23.md ). **33
componentes, 5 errores reales, 5 desviaciones, y la §7.7 con 5 hipótesis y 5
refutaciones.** Arreglado todo (`233ef989b` · `bfe7727b0` · `e522e04e6` ·
`2f243e1c0` ). Las cuatro lecciones que cambian cómo se trabaja:
1. **Corre el guard sobre el ledger ENTERO, no sobre lo que tocas.** Así salió
que `float-panel` llevaba DOCE rojos sin adjudicar desde el 22 —escritos como
«lo rojo que queda» en su propio commit— mientras el handoff daba el bloque
viejo por cerrado. Un componente cuyo commit dice «lo que queda» NO está
cerrado.
2. **El nombre de un token no es el de la propiedad.** `badge` acuñó
`min-block-size-{k}` donde la ranura es `height` : 24 componentes dimensionan
por `…-height-{k}` y era el único. R-5.3 no guarda el vocabulario
DIMENSIONAL (§13) — mientras no lo haga, **cuenta el nombre en el catálogo
antes de acuñarlo**, también para las dimensiones.
3. **Los pasos 8 y 9 del protocolo (README «Talla y tema» + pestaña `Tokens` ) se
saltaron en 22 componentes de una tanda entera** y nadie lo notó hasta
revisar los `git show --stat` . Si no está en el commit, no se hizo.
4. **Antes de comparar contra una base, comprueba que la base MONTA.** El
worktree necesita `server: { fs: { allow: [...] } }` cuando su `node_modules`
es una junction; sin eso Vite responde 403, la página no hidrata y el diff
sale limpio contra la nada.
## LO QUE DEJÓ LA TANDA DE SIETE (2026-08-23) — léelo antes de seguir
**El instrumento tiene TRES caras del mismo punto ciego, y ninguna se detecta
sola.** El filtro es `data-{c}-*` , así que no ve: (1) HTML crudo estilado por
descendencia (`prose`), (2) partes que compone el CONSUMIDOR — los `<a>` desnudos
de un mega-menú (`navigation-menu`: 10 nodos, ninguno era el panel), y (3) partes
de un componente COMPUESTO — el playhead de `waveform` ES el thumb de un Slider
embebido (4 nodos, ninguno era él). Añade una cuarta forma: **las capas OPT-IN**
(`background` medía 2 de 37 tokens; `badge` , 2 nodos de 5 porque dot / icon /
remove nacen apagados). **Cuenta los nodos SIEMPRE, y si el número es pequeño,
sospecha antes de creerte el gate.**
**Un guard puede cerrar lo que mide, y montar más puede medir menos.**
`navigation-menu` abre por `pointerenter` , y el aparcado del puntero en (0,0)
que el guard hace tras el clic es exactamente el gesto que lo cierra: daba
no-determinismo y las dos caras del error a la vez (falso negativo en las filas,
falso POSITIVO en el token que ensancha el panel). Y en `background` , encender
el foco puntual y el paralaje **bajó** la corrida de 17 a 9 tokens, porque los
dos repintan la capa donde se miden los patrones. Nace `prepareWith` (enciende
TODOS los controles que se le den, al contrario que `openWith` ), y con él la
regla: **enciende sólo lo que no tapa, y compruébalo corriendo el guard antes y
después de cada control**.
**Subir un privado al contrato lo somete a reglas que en el CSS no se le
aplicaban.** Dos veces la misma tarde: `badge.min-block-size-*` y
`cropper.zoom-btn-font-size` copiaban el primitivo CRUDO que el CSS usaba, y
`recipe-css-contract` exige la coordenada del BUNDLE. La suite lo caza en el
acto — pero sólo DESPUÉS de escribirlo, así que escribe el bundle desde el
principio.
**Lo que el componente escribe INLINE no es tema, nunca.** `s-text-virtual-list`
se queda en 70 % porque su triple tipográfico lo escribe él en cada render desde
props resueltas (y tiene que ser exacto: el canvas que mide el texto lee
`getComputedStyle` ). Igual el `--_background-gradient-image` y el rect del
indicador de nav-menu. Un público encima MIENTE.
**La mitad del trabajo que queda es adjudicar, no acuñar.** `color-field` tenía
13 tokens que nunca se habían medido y `background` 19; los dos con contrato
sano. Un componente sin veredicto §5 no es un componente sin tokens: es uno sin
MEDIR. Y hay dos atajos legítimos: la excepción POR PATRÓN cuando la razón es
arquitectónica (las 40 claves de tono de `badge` , la cascada de paleta) y la
clase «sólo el paso en vigor pinta» para toda escala resuelta por atributo.
**Dos trampas de medición que costaron tiempo:**
- **Congela `transition` en TODA medición a mano.** Una propiedad transicionada
devuelve el valor VIEJO si la lees en el acto — pasó con `color` en
`navigation-menu` , y ya había pasado con el cuentagotas del color-picker.
- **Mide el nodo que PINTA, no el primero que casa el selector.** En
`color-field` sospeché del `@media (prefers-reduced-motion)` durante tres
diagnósticos: la causa era que el primer `[data-color-field-segment]` es un
`literal` , que declara `transition: none` de su propia cosecha.
## LO QUE DEJÓ `navigation-menu` (2026-08-23) — el detalle
**Tres cosas que se repetirán en la cola, y cuestan una medición cada una:**
1. **Cuenta los nodos ANTES de creerte el gate — otra vez, y por una causa
nueva.** Las filas de su mega-menú son los `<a>` **desnudos del consumidor** ,
que la receta estiliza por DESCENDENCIA
(`[data-navigation-menu-content] :is(a, …)`). Sonda y centinela filtran por
`data-{c}-*` : veían 10 nodos y **ninguno era el panel ni una fila** — 9 de
sus 19 knobs quedaban fuera del diff. Es la clase de `prose` y `onion-menu` ,
pero por **composición del consumidor** . Los dos instrumentos aceptan ya el
selector extra para este componente, y el paso `open` de la sonda —que NO
honraba `EXTRA_NODES` — ahora sí.
2. **Un panel de HOVER lo cierra el propio guard.** Abre con `pointerenter` y
`pointerleave` PROGRAMA el cierre; el guard abre con clic y luego aparca el
puntero en (0,0), que es justo el gesto que lo cierra. Daba
**no-determinismo** (dos corridas del mismo código discrepando) y las **dos
caras del error a la vez**: falso negativo en los tokens de la fila y falso
POSITIVO en `content-link-padding-inline` , que leía «vivo» porque ensancha
el panel que sí se medía. Se arregla con `openBy: 'hover'` . **Regla: antes
de creer un «no effect», comprueba que la superficie seguía abierta.**
3. ** `color` puede estar EN TRANSICIÓN.** Forzar `data-disabled` y leer en el
acto devuelve el valor VIEJO: tres diagnósticos falsos («ni el inline lo
mueve») hasta congelar. Es la trampa del cuentagotas del color-picker, en
otro componente y sobre otra propiedad. **Toda medición a mano congela
`transition` — el guard ya lo hace, tu script de un solo uso no.**
**Y dos de doctrina:**
- **El catálogo decide el nombre, no la §4.** Aquí falló de CINCO maneras (las
cuatro conocidas más una nueva: un aviso de capa compartida disparado por
**homonimia** — `menu-indicator` es el check de los CheckboxItem, no el
subrayado de esta barra). Contar en `base.ts` resolvió los 19 nombres.
- **Un nombre de parte que existe en OTRO sitio del mismo componente miente.**
Los gemelos llaman `item-*` a la fila del panel; aquí `item` es el `<li>` de
la barra y el `Link` de barra viste el cromo del trigger, así que ni `item-*`
ni `link-*` valen: `content-link-*` nombra el nodo por donde vive.
**Contabilidad**: el censo decide el eje `size` grepeando `data-size` en el CSS,
y el protocolo §7.4 ORDENA retirar esos bloques — así que **todo componente que
aplique bien el protocolo aparece «sin eje `size` »**. Ya le pasa a `sidebar` ,
`nav-tree` y ahora a `navigation-menu` . Registrado en §13; no es deuda.
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## LO PRIMERO AL ENTRAR (cinco minutos, en este orden)
1. **Comprueba que el suelo no se ha movido** :
```bash
uix(prose): temable — 1 % → 83 %, la costura por ELEMENTO y dos cegueras del instrumento
35 claves nuevas (2 → 37). Censo prose 1 % → **83 %** con `global` a CERO;
global del eje **59 % → 60 %** (1.064 → 1.021 knobs `global` en el catálogo).
Prose estiliza HTML CRUDO (`h1`, `code`, `table`, `kbd`…) a través de
`:where([data-prose] el)`, así que sus «partes» son elementos y la costura va
POR PARTE, como en `result`: `heading-*` (+ `h1-font-weight`, lo único que
distingue al h1 de sus hermanos), `link-*`, `strong-`/`dt-`/`th-font-weight`,
`mark-*`, `blockquote-*`, `code-*`, `pre-*`, `kbd-*`, `media-radius`, `hr-*`,
`table-*`, más `fg`, `fg-muted` y el eje `font-size-{sm,md,lg}`. Los valores
siguen siendo los del canon; lo que faltaba era el knob (PLAN §2-A).
LA ESCALA EDITORIAL NO ENTRA, Y ES DOCTRINA FIRMADA: los `2.25em`, `1.5em`,
`0.9em`, sus interlineados y su tracking son `em`-relativos a propósito —un
`font-size` raíz re-deriva encabezados y márgenes, por eso NO hay una escala
duplicada por talla como en tailwind-typography (su README: «No 5× duplicated
scale»)— y van anotados `/* literal: */`, la válvula de recipe-contract §3. Son
las 21 excepciones firmadas que el censo aprendió a leer esta misma sesión.
Dos literales se cambiaron por su paso de escala, con el mismo valor: el `3px`
del borde-acento del blockquote ES `--border-width-thick`, y los `1px` de kbd,
`hr` y la tabla son `--border-width`.
EL INSTRUMENTO ESTABA CIEGO DE DOS MANERAS, arregladas ANTES de medir:
1. **Sonda y centinela filtran por `data-{c}-*`** y aquí NINGUNA parte lo lleva:
la sonda medía **1 nodo** y el guard daba **27 de 37** tokens por muertos.
Los dos ganan un selector de nodos extra (`EXTRA_NODES` en la sonda,
`extraNodes` en `COMPONENT_OVERRIDES`) — con él, 63 nodos y un gate que
significa algo.
2. **El centinela no leía el color de un borde que no fuera el de arriba.** El
blockquote tiñe su `border-inline-start` y la tabla sus bordes de bloque:
tres tokens vivos leían muertos. Añadidos los cuatro lados lógicos y
`borderBottomColor`.
OCHO ADJUDICACIONES, TODAS MEDIDAS: cinco las tapa el harness de la
documentación —`[data-uix-docs] code|pre` (0,2,0) gana a `:where(…)` (0,0,0),
que es la incidencia ya escrita para `code-block` un piso más arriba— y tres son
elementos que el HTML de ejemplo no usa (`<mark>`, `<dl>`), montados DENTRO del
contenedor real: un `<mark>` a pelo es exactamente lo que esta receta estiliza,
así que el nodo es fiel (la lección de `drag-drop` cumplida).
Gates: sonda antes/después **0 diffs en 11.910 valores** (63 nodos × 7 estados) ·
centinela 29/37 con las ocho adjudicadas · censo --only 83 % · `--names` 37/37
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados. Componentes del ledger re-verificados tras
tocar el guard (text-gradient, chart, result, tree-view, textarea): sin
regresiones ni STALE.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
node --import tsx/esm scripts/theming-census.ts # 162 · 5.137 · 2.770 (60 %) · 24 sin contrato
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
node --import tsx/esm scripts/theming-census.ts --names # DESVIADAS 0 — la gramática se mantiene
```
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca
código y es la que importa.
1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré
como «declaraciones muertas» apoyándome en los precedentes de
`table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el
mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el
plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es
neutral — **fija el empate a favor del plano** y con él su 1.25 donde la
receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9
tiene pendiente para VEINTE componentes. Un empate por orden de carga se
registra, no se resuelve dentro de un commit de tokenización.
Y la medición era más débil de lo que el commit daba a entender: estable en
cinco recargas **en DEV**, sin verificar en un bundle de producción.
Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5
tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa
razón. §12.9 y el README dicen ahora que el par se deja declarado A
PROPÓSITO.
2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al
100 % o excepción escrita», y la válvula que `component-audit` lee es esa
marca (`readmeException`), no la prosa. Tenía la razón documentada en
veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2,
los 16 habrían dado error. Una marca por clase medida — forward de paleta
THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de
layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan.
3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por
grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el
protocolo lo pide por componente: una sesión nueva habría arrancado con el
mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la
revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8
firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus
seis lecciones, y actualizada la memoria del eje.
4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el
bloque, cada una nombrando la forma en que el instrumento mentía, más la
lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso
— `picker-shell` medía CERO y reportaba éxito.
5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`,
`virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md
(md→sm); los valores eran correctos (0 diffs), el texto no.
Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B
sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la
medición de quien los escribió, y el plan la exige antes de cerrar un bloque.
El handoff nombra las dos hipótesis concretas que hay que atacar.
Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves ·
`component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno
con un commit de esta sesión en su código) · R-5.4 verde en los 22 ·
suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero
limpio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
El segundo cubre componentes que `component:audit` NO ve (p. ej.
`picker-shell` , eidos-only sin morfo): córrelo siempre, no te fíes del audit
para la gramática.
2. **Arranca el dev server ANTES de medir nada** : `preview_start` con la config
`dev` de `.claude/launch.json` (puerto **5180** ). Las sondas se ejecutan con
`node` , no con `tsx` , desde la raíz, y **su default es 5173** : pásales
siempre la URL como tercer argumento.
3. **Lee el veredicto §5 de la ficha** (`docs/audit/theming/{c}.md`). Si está
vacío — lo están ** ~130 de 171** — lo escribes TÚ midiendo, y luego
ejecutas: ése fue el flujo de todo F2-B. La §4 generada **no se sigue a
ciegas**; ver «Lo que F2-B enseñó».
## QUÉ HACER AHORA
uix(theming): revisión adversarial de F2-B — 4 hipótesis, 3 refutadas, 1 token que mentía
El plan (§7.7) exige una revisión escéptica antes de cerrar un bloque, y F2-B
no la tenía. Molde F2-A: worktree en la base del bloque (`8400e5bdd`) con su
propio dev server, medición independiente.
**REFUTADA \u2014 «el default cambió en algún sitio que la demo no mira».** 77 casos
FORZADOS (variantes, formas, tallas y estados que las demos NO montan, en los
21 componentes) comparados base vs HEAD: **0 diferencias**. Era la sospecha más
fuerte, porque cuatro componentes miden UN nodo (`link`, `code`, `skeleton`,
`link-preview`) y sus tokens viven justo en las variantes que la demo no
renderiza.
**REFUTADA \u2014 «hay tokens huérfanos».** 339 públicos de los 21 bloques, 0 sin
consumo. El primer extractor daba «SIN BLOQUE» en los 21 \u2014 el mismo antipatrón
que audita este eje \u2014 y se rehízo contando llaves; muta-prueba: un token falso
inyectado sale detectado y el árbol se restaura.
**REFUTADA \u2014 «el gate de 0 diffs pasó sobre casi nada».** Contados los nodos que
ve cada sonda; los cuatro de un nodo se cubrieron forzando sus variantes arriba.
**HALLAZGO REAL \u2014 `drag-drop.preview-z` mentía, y lo escondía una adjudicación
mía sobre un nodo SINTÉTICO.** El ledger lo daba por vivo («forzado → alcanza,
100 → 4321»), pero ese nodo lo había creado yo con JS. El preview REAL que soma
monta durante un arrastre lleva `z-index: 9999` **INLINE**
(`drag-drop-provider.svelte.ts:663,671`): el token resuelve a 4321 y el nodo
computa 9999. Ninguna cascada puede ganarle. **Retirado con 0 diffs** contra el
snapshot original (1.827 valores × 7 estados), misma clase que el `item-gap*`
de carousel que retiró la revisión de F2-A. Era el único público que drag-drop
tenía antes del eje; su alcance se mantiene en 89 %.
**La lección que generaliza, y va al protocolo**: una adjudicación «forzado →
alcanza» vale lo que valga el nodo que se forzó \u2014 si lo creaste tú, no lleva lo
que soma le pone. Re-verificado el resto de la misma clase contra nodos reales:
`clipboard` (indicador tras un clic real) y `picker-shell` (pie real) coinciden
con lo adjudicado y no llevan inline; el inline de `skeleton-line` es de
`inline-size`, no del eje tokenizado.
DOS HALLAZGOS DE INSTRUMENTO en la propia revisión (→ §13):
- **El orden de carga NO es el mismo en dev que en producción.** Medido con
`npm run build` + preview y CDP: en dev la receta de `link-preview` va ANTES
del plano `overlay`; en producción queda EN MEDIO de sus dos reglas. El
ganador coincide por casualidad. La fragilidad de §12.9 queda medida en los
dos entornos, y confirma que restaurar el par fue lo correcto.
- **Un worktree cuyo `node_modules` es una junction fuera del root NO HIDRATA**:
Vite responde 403 a `@fs/…` y SvelteKit no arranca, así que la página SSR se
ve pero ningún componente monta. La primera pasada de esta revisión comparó
contra una base MUERTA y devolvió «77 casos, 1 diferencia» sin que nada lo
delatara. Se arregla con `server: { fs: { allow: [...] } }`; queda escrito en
el handoff junto a la regla: **comprueba que un componente monta antes de
comparar**.
Gates: censo global 50 % · `--names` DESVIADAS 0 · drag-drop 89 % ·
component:audit PASS · eidos-lint 0 invalid · R-5.4 verde · suite eidos sin
rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio.
Worktree eliminado quitando la junction ANTES del `remove --force`, con el
`node_modules` real verificado intacto (memoria
`git-worktree-remove-recurses-into-junctions`).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
### 1. F2-B está CERRADO — su revisión adversarial (§7.7) se hizo el 2026-08-22
**4 hipótesis · 3 refutadas · 1 hallazgo real.** Detalle en `PLAN §8` . Lo que
hay que recordar de ella:
- **`drag-drop.preview-z` mentió y se retiró**: soma escribe su `z-index`
INLINE, y la adjudicación que lo daba por vivo se había medido sobre un nodo
creado a mano. **Una adjudicación «forzado → alcanza» vale lo que valga el
nodo que se forzó** — si lo creaste tú, no lleva lo que soma le pone.
- **El orden de carga NO es el mismo en dev que en producción** (medido con
build + CDP). El empate de §12.9 sigue abierto, ahora con las dos medidas.
- **Un worktree cuyo `node_modules` es una junction fuera del root no hidrata**:
Vite responde 403 a `@fs/…` . La primera pasada comparó contra una base muerta
sin que nada lo delatara — añade `server: { fs: { allow: [...] } }` a su
`vite.config.ts` y **comprueba que un componente monta antes de comparar** .
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca
código y es la que importa.
1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré
como «declaraciones muertas» apoyándome en los precedentes de
`table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el
mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el
plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es
neutral — **fija el empate a favor del plano** y con él su 1.25 donde la
receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9
tiene pendiente para VEINTE componentes. Un empate por orden de carga se
registra, no se resuelve dentro de un commit de tokenización.
Y la medición era más débil de lo que el commit daba a entender: estable en
cinco recargas **en DEV**, sin verificar en un bundle de producción.
Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5
tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa
razón. §12.9 y el README dicen ahora que el par se deja declarado A
PROPÓSITO.
2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al
100 % o excepción escrita», y la válvula que `component-audit` lee es esa
marca (`readmeException`), no la prosa. Tenía la razón documentada en
veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2,
los 16 habrían dado error. Una marca por clase medida — forward de paleta
THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de
layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan.
3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por
grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el
protocolo lo pide por componente: una sesión nueva habría arrancado con el
mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la
revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8
firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus
seis lecciones, y actualizada la memoria del eje.
4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el
bloque, cada una nombrando la forma en que el instrumento mentía, más la
lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso
— `picker-shell` medía CERO y reportaba éxito.
5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`,
`virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md
(md→sm); los valores eran correctos (0 diffs), el texto no.
Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B
sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la
medición de quien los escribió, y el plan la exige antes de cerrar un bloque.
El handoff nombra las dos hipótesis concretas que hay que atacar.
Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves ·
`component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno
con un commit de esta sesión en su código) · R-5.4 verde en los 22 ·
suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero
limpio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
uix(theming): el censo aprende que un privado DERIVADO sí alcanza — 50 % → 56 %
Seis puntos de alcance sin tocar una línea de componente: **la medición estaba
mal, no el código**.
EL DEFECTO. F0 encargaba «detección "privado que deriva de público" (leer
`--_c-x: var(--c-y)` en la misma receta y reclasificar)». Se implementó a
medias: el censo CALCULA `derives` y lo imprime en la columna «¿deriva de un
público?» de la §3 de cada ficha, pero **el contador nunca lo usó** — esos
knobs seguían puntuando como deuda. Medido: **240 privados en 59 componentes**
estaban en ese estado, es decir, haciendo exactamente lo que la doctrina
prescribe («privados sólo si derivan de públicos») y penalizados por ello.
Lo destapó tokenizar `avatar`: sus 17 privados YA leían públicos
(`--_avatar-size: var(--avatar-size-md)`), así que no había nada que tokenizar
— había que arreglar el instrumento.
LA CORRECCIÓN. Segunda pasada tras recoger privados y knobs: un knob que lee
`var(--_c-x)` pasa a `public` si ese privado alcanza un público. El cierre es
**TRANSITIVO** (`--_a: calc(var(--_b) * .3)` alcanza si `--_b` alcanza) con
conjunto de visitados para que un ciclo no lo cuelgue.
**Muta-prueba** (obligatoria, memoria `a-guard-that-inspects-nothing-passes`):
apuntar `--_avatar-radius` al primitivo crudo baja avatar de 75 % a 72 % y el
knob vuelve a `private`; revertirlo lo devuelve a 75 % y deja el árbol
idéntico.
EFECTO MEDIDO:
- Global **50 % → 56 %** · privados 625 → 341 · al 100 % 10 → 14 · <20 % 22 → 20.
- `avatar` 36 % → **75 %**, `picker-shell` 76 % → **95 %**, `menu-dial` 25 % →
38 %, y otras 51 fichas con cifras nuevas — **ninguna por cambio de código**.
- Los READMEs de `picker-shell` y `menu-dial` se actualizan con la cifra nueva
y con la razón, para que nadie crea que el componente cambió.
⚠ **Cualquier cifra anterior a este commit no es comparable con las de ahora.**
Queda escrito en el handoff.
Y un hueco de F0 que sale al hacerlo, registrado en §13: **el test del SUELO
que el plan pedía NO EXISTE** («alcance global ≥ el de hoy y literales ≤ 614 —
el número sube o el test falla»). Hoy nada impide que el alcance BAJE entre
sesiones: sólo se vería mirando la cifra a mano. Con el censo ya endurecido, es
el momento de escribirlo.
Gates: `component:audit` 162 PASS / 4 NEEDS-WORK (preexistentes) · `--names`
DESVIADAS 0 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · el
censo compila.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
### 2. El censo cuenta distinto desde el 2026-08-22 — léelo antes de comparar cifras
**Un privado que DERIVA de un público ya cuenta como alcanzable.** Es lo que F0
encargaba («leer `--_c-x: var(--c-y)` y reclasificar») y sólo se había
implementado para el INFORME: la columna «¿deriva de un público?» de la §3 lo
decía, pero el contador lo seguía puntuando como deuda. Medido: **240 privados
en 59 componentes** estaban en ese estado, haciendo exactamente lo que la
doctrina prescribe y penalizados por ello.
El cierre es TRANSITIVO (`--_a: calc(var(--_b) * .3)` alcanza si `--_b`
alcanza) y tiene muta-prueba: apuntar un privado a un primitivo crudo baja la
cifra, revertirlo la sube. **Global 50 % → 56 %** , privados 625 → 341, al 100 %
10 → 14. `avatar` pasó de 36 % a 75 % y `picker-shell` de 76 % a 95 % **sin
tocar una línea de su código**.
Consecuencia: **cualquier cifra anterior al 2026-08-22 no es comparable con las
de ahora.** Las de este handoff ya son las nuevas.
fix(theming): el slot de tinta es `fg` — R-5.3 me cazó tres claves, y el handoff de mañana
Los guards globales, corridos antes de cerrar la sesión, encontraron una
regresión MÍA: `--names` daba **3 desviadas en 2 componentes** y
`component:audit` había pasado de 4 a **6 NEEDS-WORK**.
La causa: en `text-circular` y `text-focus` nombré tres claves con el slot
`color` (`color`, `border-color`, `glow-color`) cuando la gramática firmada el
2026-08-20 dice que **el slot de tinta es `fg` y `color` como slot MUERE**.
R-5.3 existe justamente para eso y funcionó — pero después de que yo lo
escribiera, porque el guard es de catálogo y yo verificaba `--only`.
Renombradas a `fg`, `border-fg` y `glow-fg`, con los destinos que el propio
censo indica en su salida `--names`. Value-preserving verificado: **0 diffs**
en text-circular (5.916 valores) y en text-focus (1.769), guards 5/6 y 8/8,
`--names` **DESVIADAS 0**, audit de vuelta a **162 PASS / 4 NEEDS-WORK** (los
cuatro preexistentes y ajenos al eje).
La lección para el protocolo, y va al handoff: **la propuesta §4 generada usa
el slot `color`**, así que es la cuarta manera en que falla — y como el paso 7
corre los guards con `--only`, la desviación de gramática sólo aparece al
correr `--names` GLOBAL. Ese comando ya estaba en el paso 1 del handoff; ahora
también se explica por qué no basta con el audit.
Y el HANDOFF para mañana: cifras nuevas (56 %, sin contrato 25, al 100 % 16),
la lista de los 24 componentes de F2-B con su alcance, las tres cosas que el
bloque enseñó y hay que tener delante al seguir (las cuatro maneras en que
falla la propuesta · declarar un público «de facto» puede MATAR una escala si
detrás hay un privado por talla · cuenta los nodos que ve la sonda antes de
creerte un gate verde), y la cola actualizada — con `mockup` marcado como SIN
DEMO (404) y `text-scramble` como «0 % estructural, escribe el veredicto, no
tokens».
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
### 3. Lo que dejó la sesión del 22 (24 componentes en F2-B, todos con 0 diffs)
`grid-list` 85 · `textarea` 80 · `tree-view` 92 · `code-block` 81 ·
`card-group` 90 · `spinner` 70 · `picker-shell` 95 · `link-preview` 100 ·
`drag-drop` 89 · `kbd` 86 · `link` 36 · `code` 100 · `virtual-list` 67 ·
`virtual-grid` 73 · `skeleton` 45 · `label` 100 · `announce` 88 ·
`clipboard` 63 · `scroll-frames` 33 · `mark` 60 · `menu-dial` 38 · `knob` 75 ·
`skin-media-player` 22 · `text-circular` 100 · `text-focus` 100. Más cinco
adjudicados como **0 % estructural** (`aspect-ratio`, `text-blur` , `cascade` ,
`motion` , `date-picker` ), la revisión adversarial §7.7, el arreglo del censo y
el test del suelo.
**Tres cosas que enseñó y conviene tener delante al seguir:**
1. **La propuesta §4 generada falla de cuatro maneras.** Hereda el
incumplimiento del CSS de partida (si ya violaba `recipe-css-contract` , lo
repite); infla hasta 4× (71 tokens para 23 knobs en `spinner` ); nombra por
el primer selector de la regla y no por el nodo pintado (llamaba `root-bg` a
una guía de indentación); y **usa el slot `color` donde la gramática firmada
exige `fg` ** — R-5.3 lo caza, pero después de escribirlo.
2. **Declarar un público «de facto» puede MATAR una escala.** Varios
componentes consumen `var(--c-x, <default>)` sin declarar `--c-x` . Si detrás
del fallback hay un privado por talla (`knob`), declarar el público lo mata:
el público va primero y gana siempre. Hay que subir la escala al TSC. Si no
lo hay (`text-circular`, `text-focus` ), declarar es seguro.
3. **Cuenta los nodos que ve la sonda antes de creerte un gate verde.** Cuatro
componentes miden UN nodo, `picker-shell` medía CERO. Y el centinela tiene
tres puntos ciegos ya medidos: congela transiciones, su valor grande se capa
contra `min()` , y no ve lo que la demo no monta.
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 3.bis Lo último ejecutado — `text-gradient` (2026-08-22)
**67 % → 100 %**, 7 claves. Detalle y porqués en `PLAN §8` y en el veredicto
§5 de su ficha. Lo que conviene tener delante al seguir con la cola:
- **La ficha §4 falla también contra el CATÁLOGO, no sólo contra la doctrina.**
Proponía conservar `weight` (77 claves del catálogo dicen `font-weight` ), y
marcaba `width` /`height` con «⚠ eje físico» cuando el `calc(100% - 2px)`
era UN knob —el trazo del marco— del que el hueco deriva. **Antes de acuñar
un nombre, cuéntalo en `base.ts` **: el catálogo es el que habla.
- **Un literal igual a un paso de escala no se congela: se nombra.**
`1px` → `var(--border-width)` , `blur(4px)` → `var(--blur-sm)` . Y ojo con
`blur` : es familia MÉTRICA del eje `scaling` (theming §23), así que un
literal es ciego al zoom global aunque el computed coincida a scaling 100.
- **Los dos instrumentos ya saben encender una VARIANTE.** La sonda tiene
`DEMO_VARIANTS` (chips que se re-pulsan tras CADA recarga — la sonda recarga
una vez por talla) y el centinela acepta `openWith` apuntando a un chip, no
sólo a un trigger de panel. Sin eso, esta demo daba 2 nodos y los tres tokens
del marco no se medían. **Cuenta los nodos antes de creerte el gate.**
docs(theming): las demos quedan FUERA del eje — sólo los componentes
Decisión del autor (2026-08-22): «las demos de los componentes no son
importantes y no deben formar parte del plan, solo los componentes». Y sobre la
escala: «las escalas tipográficas son las que están definidas en el módulo
tipografía, esos son los valores canónicos» — prohibido tocar sus valores.
Se retira del registro del eje (PLAN §8 · CONTINUE §3.bis · next-features §13)
todo lo que hablaba de demos o del harness del sitio: los escenarios de
text-gradient/text-blur, la tabla de tokens a mano de la pestaña API, las
pestañas Tokens que faltan, las 37 referencias `--uix-font-size-*`. Nada de eso
es trabajo del eje: la demo se toca sólo como INSTRUMENTO para que la sonda vea
los nodos, y lo mínimo.
Queda lo que sí es del componente: `text-focus.word-size` referencia
`--font-size-4xl`, un paso que la escala canónica (`xxs..xxxl`,
`lib/primitives/typography.ts`) no tiene y que entró como idioma Tailwind con el
import de julio. El módulo de tipografía no se toca; el fix va en el consumidor,
a un paso o estilo EXISTENTE, y espera firma porque `3rem` cae entre `xxl` y
`xxxl` y mueve el default.
docs:check 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Las demos NO forman parte del eje** (autor, 2026-08-22): sólo los
componentes. Un hallazgo de demo o del harness del sitio no se registra ni se
mide; la demo se toca únicamente como INSTRUMENTO (encender una variante para
que la sonda vea los nodos), y lo mínimo.
uix(text-gradient): temable — 67 % → 100 %, y la ficha se equivocaba en las TRES
7 claves en una entrada NUEVA de `recipes/base.ts`. Censo 67 % → **100 %**
(10 knobs, 10 públicos, 0 literales). Global 2.634 → 2.638 públicos.
Tercero de la familia text-* con la forma de text-circular / text-focus: cuatro
públicos «de facto» consumidos con fallback y **ninguno declarado**, más tres
literales. Sin eje `size` ni privados propios, así que declarar no puede matar
una escala.
LO QUE LA PROPUESTA §4 NO ACERTABA — y se resolvió midiendo contra el CATÁLOGO,
no contra el CSS de partida:
- **`weight` era deriva de nombre.** El catálogo tiene 77 claves `font-weight`
contra 4 `weight` a secas — y dos de esas cuatro las escribí ayer en esta
misma familia. Pasa a `font-weight`, y su valor al paso de escala que ya
pintaba: `500` ES `var(--font-weight-medium)`.
- **El `calc(100% - 2px)` del hueco no son dos knobs de eje físico** (la ficha
los marcaba con ⚠ «pártelo en ejes lógicos») sino UNO: los 2 px son el trazo
del marco asomando a cada lado. El knob es `border-width` —con
`var(--border-width)`, el paso `thin`, no un literal `1px` igual a un paso de
la escala— y el hueco DERIVA de él.
- **`blur(4px)` va a la escala de blur.** `blur` es familia MÉTRICA del eje
`scaling` (theming §23): un literal es ciego al zoom global. `--blur-sm` es
`calc(4px * var(--scaling))` — el mismo píxel al 100 y el correcto al 90/110.
Precedente: `dialog`/`drawer.overlay-blur`, también backdrop-filter.
Y el shorthand físico `padding: var(--space-1) var(--space-2)` se parte en ejes
lógicos (`border-padding-block` / `-inline`), que es la normalización firmada el
2026-07-06; el público de facto `border-padding` era un knob con dos ejes dentro.
FUERA DEL CONTRATO POR NATURALEZA: `--text-gradient-duration` y
`--_text-gradient-play-direction` los escribe el wrapper INLINE desde
`animationSpeed` y `yoyo`. Ningún token gana a un estilo inline, así que
declararlos sería acuñar dos nombres que mienten — misma clase que los cuatro
ausentes de `knob`, el `item-gap` de `carousel` y el `preview-z` de `drag-drop`.
INSTRUMENTO — dos puntos ciegos arreglados ANTES de medir (la lección de F2-B
aplicada por adelantado, no después):
- La demo arranca con `showBorder=false`, así que sonda y centinela veían **2
nodos** y NINGUNO de los tres tokens del marco. La sonda gana un mapa
`DEMO_VARIANTS` (chips de variante re-pulsados tras CADA recarga — recarga una
vez por talla) y el centinela una entrada `openWith` que no abre un panel sino
que ENCIENDE UNA VARIANTE: uso nuevo del mismo gancho, sin tocar su lógica.
- La sonda no leía `backdropFilter`, que `KNOB_PROPS` del censo sí cuenta y el
centinela ya leía: un token de fondo podía moverse entre las dos corridas sin
que el diff lo viera. Con la propiedad y la variante: **4 nodos**.
Hover: 0 nodos medidos, y es correcto — las cuatro partes son `<span>` y el
único efecto de hover es `animation-play-state`, que no es knob.
LO QUE ABRE (→ next-features §13): **la escala de `font-size` no tiene
`2xl`/`3xl`/`4xl`** —es `xxs..xxxl`— y tres sitios los referencian: el token
`text-focus.word-size` que subí ayer (`var(--font-size-4xl, 3rem)`, pintando el
fallback: segundo fantasma de la clase `--radius-xs`, y en el contrato) y los
escenarios de las demos de `text-gradient` y `text-blur`, que sin fallback dejan
la declaración INVÁLIDA y enseñan un efecto tipográfico a 14 px. Y
`--uix-font-size-*` no existe: 37 referencias en el harness del sitio, cero
declaraciones. Ninguno se toca aquí: se miden, se anotan y van a su commit.
Demo: pestaña **Tokens** (`TokensPanel`, contrato vivo) y fuera la tabla de
tokens escrita a mano de la pestaña API — era una segunda fuente de verdad y
este renombrado la dejaba obsoleta al instante.
Gates: sonda antes/después **0 diffs** en 720 valores × 7 estados (4 nodos) ·
centinela **7/7 sin una sola excepción** · censo --only 100 % · --names 7/7
conformes · component-audit PASS · eidos-lint 0 invalid · suite eidos con el
único rojo conocido (`skin-media-player`, lint.test.ts) · rtl:check 0 ·
docs:check 0 · `check` con 72 errores globales y **0 en los ficheros tocados**.
Prettier: los seis ficheros editados ya estaban sucios en HEAD (el repo tiene
2.392), no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
uix(theming): text-scramble no tiene contrato que escribir — y el barrido de fantasmas, hecho
Sin cambios de código: su veredicto §5 y el registro.
Su 50 % no es ni deuda ni logro, es la suma de dos cosas que no son knobs:
- **Los dos literales son la técnica sr-only** (`width`/`height: 1px` en
`[data-text-scramble-sr]`), idéntica a `text-blur` y al resto del catálogo:
existe para que el lector de pantalla lea el texto entero mientras la versión
animada se parte en caracteres. Moverlos rompe la técnica.
- **Los dos «públicos» son tipografía que el componente no debería acuñar**
(`--text-scramble-font` / `-size`, con fallback y sin declarar): es la firma
1.bis pendiente. Escribirles contrato ahora sería acuñar exactamente lo que
esa firma propone retirar. Con esto, 1.bis son **7 claves en 4 de los 5**
componentes de la familia; `text-blur` es el único limpio: hereda.
Y el `font` apunta a un FANTASMA, medido en navegador: `var(--font-mono, …)` no
existe —el canónico es `--font-family-mono`— así que pinta `ui-monospace` e
**ignora la mono del tema** (`Azeret Mono`, que está ahí al lado).
EL BARRIDO MECÁNICO QUE PEDÍAN `--radius-xs` Y `--font-size-4xl`, HECHO:
5.793 custom properties declaradas en todo `src/uix/eidos` (fundación + capas +
recetas + `generated/`) contra los `var(--x, fallback)` de las recetas cuyo `--x`
sea vocabulario de SISTEMA → **9 referencias fantasma**. (Las que van sin
fallback ya las guarda `recipe-css-contract`; el hueco eran justo las que
«funcionan por accidente».) Tabla completa en next-features §13:
- `--color-content-tertiary` ×3 (float-panel, proof-of-human clock y
rotate-align) — **es el caso histórico** que `recipe-contract` §1 cita como
origen de su propia regla, y sigue vivo en tres recetas.
- `--style-{body,prose,label,caption}-font-variation-settings` ×4 (`text.css`) —
los estilos con nombre emiten 6 claves y ésta no está: **el eje de fuente
variable no llega nunca al primitivo `Text`**.
- `--font-family-sans` (palabras, track WIP) y `--font-mono` (text-scramble).
Ninguna se arregla aquí. El barrido debería ser un guard: misma lógica que el
test de fantasmas sin fallback que ya existe, con el filtro de vocabulario de
sistema encima.
Guards: censo `--only` sin cambio (50 %, es el veredicto lo que cambia) ·
component-audit PASS · docs:check 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 3.ter `text-scramble` ADJUDICADO (2026-08-22) — sin contrato, y por qué
Su 50 % no es deuda ni logro: **dos literales son la técnica sr-only** (como
`text-blur` ) y **los dos «públicos» son tipografía que no debería acuñar** , o
sea la firma 1.bis. Escribirle un contrato ahora sería acuñar justo lo que esa
firma propone retirar. Veredicto §5 escrito, cero cambios de código.
De paso salió el **barrido mecánico** que `--radius-xs` y `--font-size-4xl`
pedían: **9 referencias fantasma con fallback** en el catálogo (5.793 nombres
declarados). Tabla en next-features §13. La más grave no es de esta familia:
`--color-content-tertiary` sigue vivo en TRES recetas —es el caso histórico que
`recipe-contract` §1 cita como origen de la regla— y los cuatro
`--style-*-font-variation-settings` de `text.css` significan que **el eje de
fuente variable no llega nunca al primitivo `Text` **. Ninguna se arregla aquí.
tooling(theming): el censo aprende a leer la válvula del canon — clase `exception`
Global 58 % → **59 %** sin tocar una línea de CSS: 54 knobs que eran deuda
resultan ser desviaciones que el canon ya había firmado.
`recipe-contract` §3 dice que una desviación anotada `/* literal: <razón> */`
EN SU PROPIA DECLARACIÓN es válida, y `component-audit` la honra desde siempre
(`declarationWindow` + `/literal:/i` en R-2.1, R-2.6 y R-2.7). El censo era el
único instrumento que no: su `strip()` blanquea los comentarios ANTES de
clasificar, así que las **81 anotaciones del catálogo** contaban como literales
sin excusa. Dos instrumentos, un canon, dos respuestas — y la que mandaba era la
del que no sabía leerlo.
Ahora un literal anotado cae en la clase **`exception`, fuera del ratio** como
`system`, y por la misma razón: no es que un tema no lo alcance, es que el canon
ya aceptó por escrito que ahí no va un token.
**54 knobs en 12 componentes**: `prose` 21 (su escala editorial em-relativa, que
su README documenta como decisión — «No 5× duplicated scale»), `proof-of-human`
16 (la escena de tono fijo), `palabras` 3, `timeline` 2 (73 % → **77 %**),
`result` 1 (86 % → **90 %**), y siete más con una cada uno.
Detalles que costaron medición:
- **La anotación vale para la DECLARACIÓN entera**, no sólo para su primera
línea: un valor partido en varias líneas lleva la nota al final. Se comprueban
todas las líneas que abarca la declaración.
- **`strip()` blanquea en el sitio** (sustituye por espacios, conserva los
saltos), así que el cuerpo despojado y el crudo quedan alineados línea a línea
y basta con guardar el crudo al lado.
- Muta-prueba: retirar una anotación de `prose` mueve el knob de `exception` a
`literal` (21 → 20) y el conteo vuelve al restaurarla.
Efecto colateral bueno: cada ficha gana una **§1.4 «Excepciones firmadas»** que
las LISTA con su razón. Estaban escritas en el CSS y no se leían desde ninguna
parte; ahora la ficha del componente las enseña, que es donde se decide si una
sigue siendo cierta.
Las 163 fichas cambian porque la plantilla cambia (sección nueva + la línea de
reparto); el README de la auditoría gana la fila de la clase y la nota de que
`system` y `exception` quedan fuera del denominador.
Guards: `--names` 4.105 claves, DESVIADAS 0 · component-audit PASS · docs:check
0 · `check` con 72 errores globales y 0 en los ficheros tocados.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 3.ante LA VÁLVULA DEL CANON ya se lee (2026-08-22)
`recipe-contract` §3: un literal con `/* literal: <razón> */` **en su propia
declaración** es una desviación FIRMADA. `component-audit` la honra desde
siempre; el censo no, porque `strip()` blanquea los comentarios antes de
clasificar — 81 anotaciones contaban como deuda. Ahora caen en la clase
**`exception`, fuera del ratio** como `system` : **54 knobs** en 12 componentes
(prose 21 · proof-of-human 16 · palabras 3 · timeline 2 · result 1 …). Global
58 % → **59 %** .
**Consecuencia práctica al tokenizar**: antes de acuñar un literal, mira si ya
lleva su anotación — si la lleva, el canon ya decidió que ahí no va un token, y
la ficha lo lista ahora en su ** §1.4** con la razón escrita. Y si vas a dejar un
literal fuera, ANÓTALO: es la única forma de que no vuelva a contarse como
deuda.
uix(theming): tres techos que no son deuda — el PUENTE DE PALETA no se acuña
Sin cambios de código: los veredictos §5 de `tag-group` (65 %), `stepper` (79 %)
y `timeline` (73 %), y la clase registrada.
Los tres tienen `global` a CERO. Lo único fuera de alcance son sus privados
`--_{c}-palette-*`: el puente THM-2 que la capa compartida alimenta POR
INSTANCIA desde `[data-color]`. **Un público encima del puente
(`--tag-group-selected-bg: var(--_tag-group-palette-surface)`) dejaría que un
tema lo fijara y matara en silencio el `color=` de cada instancia** — la misma
clase de daño que «declarar un público de facto mata una escala» (`knob`). Y no
hace falta: los componentes ya exponen sus nueve roles × variante como claves
públicas (91 en `tag-group`). Ésa ES su superficie de color, y está completa.
`timeline` suma una segunda razón, también firmada: sus `--_timeline-hue-*` son
un CONMUTADOR —cada `data-intent` los re-apunta a las ranuras de rol y el
intent por defecto al puente—, y aplanarlo obligaría a duplicar cada regla por
intent (doctrina F2-B, cinco precedentes).
MEDIDO, para no adjudicar de oído: de las **687** declaraciones del catálogo que
leen un privado, **130 leen un `--_{c}-palette-*`**, y son las que dominan la
columna `private` de todo componente con paleta — tag-group 14/14, stepper
11/11, radio-group 10, checkbox 8, file-upload 8, calendar / editable / los tres
grids 7 cada uno.
Consecuencia que queda escrita en §13: **el techo de un componente con paleta no
es el 100 %**, y su cifra no compara con la de uno sin ella, porque el
denominador incluye un puente que por diseño no se acuña. Si algún día se quiere
comparabilidad, la salida es una clase `bridge` en el censo — no acuñar los
tokens. Los otros seis heredan la razón cuando les toque, pero ojo: ésos tienen
ADEMÁS knobs `global` y sí les toca trabajo real.
Los cuatro literales de los tres son identidad anotada: el `line-height: 1` del
botón de quitar y el del glifo del marcador, el `100%` de layout del stepper y
los dos `1em` que hacen que título y descripción del timeline hereden el tamaño
escalado del item en vez del tamaño UA del encabezado.
docs:check 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 3.pre EL PUENTE DE PALETA no es deuda (2026-08-22)
De las **687** declaraciones del catálogo que leen un privado, **130 leen un
`--_{c}-palette-*` **: el puente THM-2 que la capa compartida alimenta por
instancia desde `[data-color]` . **No se acuña** : un público encima dejaría que
un tema lo fijara y matara en silencio el `color=` de cada instancia. Domina la
columna `private` de todo componente con paleta, así que **el techo de ésos no
es el 100 %**. Tres ya adjudicados (`tag-group` 65 %, `stepper` 79 %,
`timeline` 73 %, éste además con el CONMUTADOR por `data-intent` ); los demás
heredan la razón: radio-group 10, checkbox 8, file-upload 8, calendar /
editable / los tres grids 7 — pero ojo, esos tienen ADEMÁS `global` y sí les
toca trabajo real.
uix(chart): la COSTURA del texto — 49 % → 89 %, y `global` a cero
Seis claves. El valor sigue siendo el del canon; lo que faltaba era el knob.
CORRIGE MI LECTURA DE HACE DOS HORAS. Al tokenizar chart di por doctrina que
«el texto no recibe tokens del componente» porque su valor viene de la capa de
estilos con nombre, y dejé el CSS leyendo `var(--style-caption-font-size)` y
`var(--color-content-*)` A PELO. Eso es media doctrina: PLAN §2-A pide que TODO
knob de apariencia lea `--{c}-{slot}`. Sin la costura, un tema no puede aclarar
las anotaciones de un gráfico denso sin mover `caption` en toda la app, y
`getRecipeTokens()` / `/temas` no ven esa superficie.
El molde ya estaba escrito en la vertebración tipográfica
(`--accordion-trigger-font-family: var(--style-label-font-family)`), y D-TH.2
aclara que sólo los SEIS primitivos quedan fuera: «un componente que sólo LEE un
named style para un eje no es un primitivo y no está en el conjunto».
POR ROL, NO POR PARTE — y se decidió midiendo:
--chart-caption-font-size var(--style-caption-font-size)
--chart-caption-fg var(--style-caption-color)
--chart-label-font-size var(--style-label-font-size)
--chart-label-fg var(--style-label-color)
--chart-label-font-weight var(--style-label-font-weight)
--chart-gauge-label-font-size var(--size-xl-font-size)
Dos roles × tres ejes = 6 claves para 19 nodos de texto; nombrarlo por parte
habrían sido ~30 claves con dos valores. **Tamaño y tinta son ortogonales a
propósito**: `empty` y `bar-list-value` son tamaño `label` con tinta `caption`, y
el CSS lo dice. El readout del gauge no tiene rol en el canon —un `h2` es un
encabezado, no un dato— así que su costura toma el bundle de talla; con eso se
cierra la escotilla que dejé abierta en el commit anterior.
Tres nombres de mi primera propuesta no aguantaron la revisión y no entran:
`label-font-size` a secas chocaba con las seis partes `*-label` del componente
(se acepta el choque, pero nombrando por el ROL del canon, que dice la verdad:
las etiquetas de eje SON captions), `emphasis-*` inventaba vocabulario fuera de
§1/§6.7, y `fg-muted` se apoyaba en un único precedente. La tinta lee el color
DEL ROL (`var(--style-caption-color)`), no la ranura a pelo.
Y RETIRA UNA NOTA EQUIVOCADA DE §13: escribí que el censo penalizaba consumir la
capa tipográfica cuando no eres un primitivo. El censo medía bien; faltaba la
costura. Con ella, `global` cae a CERO y el alcance a 89 % — el techo, porque lo
que queda son los diez literales de identidad (nueve `100%` + el `max-content`
del tooltip). La lección queda escrita: cuando la métrica y la doctrina
discrepan, sospecha de la lectura antes que del instrumento. `listbox` (68 %,
ritmo de fila prestado de `list-surface`) es la misma pregunta un piso más
arriba y queda pendiente de revisar con este molde.
Gates: sonda antes/después **0 diffs en 161.850 valores computados** (16 rutas ×
7 estados) · centinela **43/45**, las dos de transición adjudicadas · censo
--only **89 %** con `global` 36 → 0 · --names 45/45 conformes · component-audit
PASS · eidos-lint 0 invalid · suite eidos con el único rojo conocido · rtl:check
0 · docs:check 0 · `check` con 72 errores globales y 0 en los ficheros tocados.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 3.quater LA COSTURA (2026-08-22) — lo más importante de la sesión
**El valor es del sistema; el knob es del componente.** Tokenizando `chart` y
`result` di por doctrina que «el texto no recibe tokens del componente» porque
su valor viene del canon, y dejé el CSS leyendo `var(--style-caption-font-size)`
y `var(--color-content-*)` A PELO. Es media doctrina: PLAN §2-A pide que TODO
knob de apariencia lea `--{c}-{slot}` . Sin la costura, un tema no puede aclarar
las anotaciones de un gráfico denso sin mover `caption` en toda la app, y
`getRecipeTokens()` / `/temas` no ven esa superficie. El molde ya estaba
escrito: `--accordion-trigger-font-family: var(--style-label-font-family)`
(§Vertebración tipográfica), y D-TH.2 aclara que **sólo los seis PRIMITIVOS**
quedan fuera. Resultado: chart 49 % → **89 %** , result 23 % → **86 %** , y
`global` a CERO en los dos.
**Dos formas, y se eligen midiendo**: por ROL cuando un rol se repite sobre
muchos nodos (chart: 2 roles × 3 ejes = 6 claves para 19 nodos de texto; por
parte habrían sido ~30 con dos valores) y por PARTE cuando cada parte tiene
tipografía propia y ningún rol la cubre (result: 15). Agrupa las filas por valor
ANTES de decidir.
**Y una nota de §13 retirada por equivocada**: escribí que el censo penalizaba
consumir la capa tipográfica. El censo medía bien; faltaba la costura. **Cuando
la métrica y la doctrina discrepan, sospecha de la lectura antes que del
instrumento.** `listbox` (68 %, ritmo de fila prestado de `list-surface` ) es la
misma pregunta un piso más arriba: pendiente de revisar con este molde.
### 3.quinquies `chart` — el instrumento, tres veces ciego
uix(chart): temable — 9 % → 49 %, y la ficha pedía 71 claves de las que 20 llevaban el mismo valor
22 claves nuevas fusionadas en el bloque existente (17 → 39). Censo chart
9 % → **49 %**; global **56 % → 57 %** (2.638 → 2.675 públicos; <20 % 19 → 18).
LO QUE DECIDIÓ LA MEDICIÓN, no la ficha:
Las 84 filas fuera de alcance colapsaban a **26 valores distintos** — 9×
`content-secondary`, 9× `content-primary`, 9× `100%`, 6× `font-size-sm`, 6×
`font-size-xs`, 6× `font-weight-medium`, 5× `surface-default`, 4× `radius-sm`.
Nombrar por parte habría dado cinco claves para el pelo que separa marcas y
nueve para la tinta de anotación: la inflación de `spinner` con otra cara.
**El texto no recibe tokens de chart.** Toma su ROL DE TAMAÑO de los estilos con
nombre del canon —`caption` (xs) para las anotaciones, `label` (sm) para el
texto de cromo— y su tinta y su peso de las ranuras del sistema. Acuñar
`--chart-label-font-size` sería tipografía por componente, prohibido el mismo
día para text-effects. Precedente de consumir la capa: `code-block`, `kbd`,
`announce`. Doce declaraciones cambian de `var(--font-size-xs|sm)` a
`var(--style-caption|label-font-size)`, mismo valor.
**La receta sólo posee la tinta de lo que NO es texto**, cinco claves y cada una
un concepto que el CSS repite: `axis-fg` (eje + rejilla smith + conector del
funnel), `grid-fg` (rejilla + radar), `separator-fg` (el pelo de superficie
entre marcas contiguas: porción, punto activo, punto smith, pétalo, segmento),
`smith-boundary-fg` y `track-bg` (raíl del bar-list y del gauge). Más 17 de
geometría de cromo (gap, los pares row/column-gap, swatch, track, bar-segment).
**Incumplimiento heredado, corregido**: el CSS leía la coordenada CRUDA
`var(--control-height-sm, var(--space-7))` —lo que `recipe-css-contract`
prohíbe— con un respaldo muerto. El contrato guarda el bundle
`var(--size-sm-control-height)`, 1:1 con él.
**Identidad fuera de contrato**: los nueve `100%` («ocupa a tu padre») y el
`min-inline-size: max-content` del tooltip, misma clase ya adjudicada en
`date-picker`. Por eso el techo es 49 %, y está escrito en el veredicto §5.
EL INSTRUMENTO ESTABA CIEGO DE TRES MANERAS, arregladas ANTES de medir:
1. **La superficie de chart vive en DIECISÉIS rutas de demo**, una por tipo:
`/chart` monta 58 nodos de los 302 de la página y el resto vive en rutas
hermanas. El guard gana `urls`: un token está VIVO si ALGUNA superficie del
componente lo sigue, y cada URL sólo re-prueba lo pendiente (el caso de una
sola ruta cuesta exactamente lo que costaba). De paso `picker-shell` recibe
la suya: su ruta propia es un 404 y se mide dentro del date-picker — pasa de
0/31 con seis sin adjudicar a 6/31 sin tener que saberlo.
2. **El guard no leía NINGUNA propiedad SVG.** Sin `fill` / `stroke` /
`strokeWidth` / `fillOpacity` / `r` / `rx`, doce de las 39 claves de un
componente que dibuja en SVG leían muertas estando vivas. Misma clase que el
hueco de `filter` / `backdrop-filter` de ayer.
3. **El valor centinela se elegía por SUBCADENA**: `slice-stroke-width` recibía
`rgb(1, 2, 3)` por contener «stroke» —inválido para una longitud— y leía
muerta. La dimensión se decide ahora por el FINAL del nombre.
Los 28 componentes con ledger re-verificados tras los tres cambios: cero
regresiones, cero STALE. (Ojo: doce a la vez contra el mismo dev server dan
falsos exit=1 por timeout; repetir a solas antes de creerse una regresión.)
Gates: sonda **0 diffs en 161.850 valores computados** (16 rutas × 7 estados,
892 nodos en reposo) · centinela **37/39**, con `transition-duration` y `-ease`
adjudicadas midiéndolas sin la congelación (0,12s → 11,5s · cubic-bezier →
steps(4)) · censo --only 49 % · --names 39/39 conformes · component-audit PASS ·
eidos-lint 0 invalid · suite eidos con el único rojo conocido
(`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados.
Abre (→ next-features §13): el censo **penaliza consumir la capa tipográfica**
si no eres un primitivo —las doce declaraciones correctas siguen contando
`global`—, que es la nota de `listbox` con una segunda ocurrencia; y el número
del gauge no tiene estilo con nombre que lo represente (un readout de dato no es
un `h2`), así que sigue leyendo `--font-size-xl`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Lo que hay que llevarse de aquí:
- **La ficha pedía 71 claves; ~20 habrían llevado el mismo valor.** Antes de
aceptar una propuesta larga, **agrupa las filas por VALOR** : las 84 de chart
colapsaban a 26. Nombrar por parte lo que es un concepto es la inflación de
`spinner` con otra cara.
- **El texto de un componente no recibe tokens propios**: rol de tamaño de los
estilos con nombre (`caption` / `label` ), tinta y peso de las ranuras del
sistema. Sólo se acuña la tinta de lo que NO es texto.
- **El guard ya sabe medir en VARIAS rutas** (`urls` en `COMPONENT_OVERRIDES` ):
un token vive si alguna superficie del componente lo sigue. Chart tiene 16;
`picker-shell` ya lleva la del date-picker (su ruta propia es 404).
- **El guard ya lee SVG** (`fill`, `stroke` , `strokeWidth` , `fillOpacity` , `r` ,
`rx` …) y **elige el valor centinela por el FINAL del nombre** , no por
subcadena — `slice-stroke-width` recibía un color por contener «stroke».
- Tras cualquier cambio del guard: **re-verificar los 28 componentes con
ledger** (se hizo: cero regresiones, cero STALE). Y ojo, correr doce a la vez
contra el mismo dev server da falsos exit=1 por timeout: repite el que falle
a solas antes de creerte una regresión.
fix(theming): el slot de tinta es `fg` — R-5.3 me cazó tres claves, y el handoff de mañana
Los guards globales, corridos antes de cerrar la sesión, encontraron una
regresión MÍA: `--names` daba **3 desviadas en 2 componentes** y
`component:audit` había pasado de 4 a **6 NEEDS-WORK**.
La causa: en `text-circular` y `text-focus` nombré tres claves con el slot
`color` (`color`, `border-color`, `glow-color`) cuando la gramática firmada el
2026-08-20 dice que **el slot de tinta es `fg` y `color` como slot MUERE**.
R-5.3 existe justamente para eso y funcionó — pero después de que yo lo
escribiera, porque el guard es de catálogo y yo verificaba `--only`.
Renombradas a `fg`, `border-fg` y `glow-fg`, con los destinos que el propio
censo indica en su salida `--names`. Value-preserving verificado: **0 diffs**
en text-circular (5.916 valores) y en text-focus (1.769), guards 5/6 y 8/8,
`--names` **DESVIADAS 0**, audit de vuelta a **162 PASS / 4 NEEDS-WORK** (los
cuatro preexistentes y ajenos al eje).
La lección para el protocolo, y va al handoff: **la propuesta §4 generada usa
el slot `color`**, así que es la cuarta manera en que falla — y como el paso 7
corre los guards con `--only`, la desviación de gramática sólo aparece al
correr `--names` GLOBAL. Ese comando ya estaba en el paso 1 del handoff; ahora
también se explica por qué no basta con el audit.
Y el HANDOFF para mañana: cifras nuevas (56 %, sin contrato 25, al 100 % 16),
la lista de los 24 componentes de F2-B con su alcance, las tres cosas que el
bloque enseñó y hay que tener delante al seguir (las cuatro maneras en que
falla la propuesta · declarar un público «de facto» puede MATAR una escala si
detrás hay un privado por talla · cuenta los nodos que ve la sonda antes de
creerte un gate verde), y la cola actualizada — con `mockup` marcado como SIN
DEMO (404) y `text-scramble` como «0 % estructural, escribe el veredicto, no
tokens».
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
### 4. La cola que queda, por alcance
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca
código y es la que importa.
1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré
como «declaraciones muertas» apoyándome en los precedentes de
`table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el
mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el
plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es
neutral — **fija el empate a favor del plano** y con él su 1.25 donde la
receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9
tiene pendiente para VEINTE componentes. Un empate por orden de carga se
registra, no se resuelve dentro de un commit de tokenización.
Y la medición era más débil de lo que el commit daba a entender: estable en
cinco recargas **en DEV**, sin verificar en un bundle de producción.
Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5
tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa
razón. §12.9 y el README dicen ahora que el par se deja declarado A
PROPÓSITO.
2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al
100 % o excepción escrita», y la válvula que `component-audit` lee es esa
marca (`readmeException`), no la prosa. Tenía la razón documentada en
veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2,
los 16 habrían dado error. Una marca por clase medida — forward de paleta
THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de
layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan.
3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por
grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el
protocolo lo pide por componente: una sesión nueva habría arrancado con el
mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la
revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8
firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus
seis lecciones, y actualizada la memoria del eje.
4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el
bloque, cada una nombrando la forma en que el instrumento mentía, más la
lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso
— `picker-shell` medía CERO y reportaba éxito.
5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`,
`virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md
(md→sm); los valores eran correctos (0 diffs), el texto no.
Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B
sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la
medición de quien los escribió, y el plan la exige antes de cerrar un bloque.
El handoff nombra las dos hipótesis concretas que hay que atacar.
Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves ·
`component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno
con un commit de esta sesión en su código) · R-5.4 verde en los 22 ·
suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero
limpio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| componente | knobs | nota |
| --- | ---: | --- |
fix(theming): el slot de tinta es `fg` — R-5.3 me cazó tres claves, y el handoff de mañana
Los guards globales, corridos antes de cerrar la sesión, encontraron una
regresión MÍA: `--names` daba **3 desviadas en 2 componentes** y
`component:audit` había pasado de 4 a **6 NEEDS-WORK**.
La causa: en `text-circular` y `text-focus` nombré tres claves con el slot
`color` (`color`, `border-color`, `glow-color`) cuando la gramática firmada el
2026-08-20 dice que **el slot de tinta es `fg` y `color` como slot MUERE**.
R-5.3 existe justamente para eso y funcionó — pero después de que yo lo
escribiera, porque el guard es de catálogo y yo verificaba `--only`.
Renombradas a `fg`, `border-fg` y `glow-fg`, con los destinos que el propio
censo indica en su salida `--names`. Value-preserving verificado: **0 diffs**
en text-circular (5.916 valores) y en text-focus (1.769), guards 5/6 y 8/8,
`--names` **DESVIADAS 0**, audit de vuelta a **162 PASS / 4 NEEDS-WORK** (los
cuatro preexistentes y ajenos al eje).
La lección para el protocolo, y va al handoff: **la propuesta §4 generada usa
el slot `color`**, así que es la cuarta manera en que falla — y como el paso 7
corre los guards con `--only`, la desviación de gramática sólo aparece al
correr `--names` GLOBAL. Ese comando ya estaba en el paso 1 del handoff; ahora
también se explica por qué no basta con el audit.
Y el HANDOFF para mañana: cifras nuevas (56 %, sin contrato 25, al 100 % 16),
la lista de los 24 componentes de F2-B con su alcance, las tres cosas que el
bloque enseñó y hay que tener delante al seguir (las cuatro maneras en que
falla la propuesta · declarar un público «de facto» puede MATAR una escala si
detrás hay un privado por talla · cuenta los nodos que ve la sonda antes de
creerte un gate verde), y la cola actualizada — con `mockup` marcado como SIN
DEMO (404) y `text-scramble` como «0 % estructural, escribe el veredicto, no
tokens».
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `palabras` | 471 (22 %) | **el mayor del catálogo con diferencia** , sin tocar; D-TH.3 decide si entra |
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca
código y es la que importa.
1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré
como «declaraciones muertas» apoyándome en los precedentes de
`table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el
mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el
plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es
neutral — **fija el empate a favor del plano** y con él su 1.25 donde la
receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9
tiene pendiente para VEINTE componentes. Un empate por orden de carga se
registra, no se resuelve dentro de un commit de tokenización.
Y la medición era más débil de lo que el commit daba a entender: estable en
cinco recargas **en DEV**, sin verificar en un bundle de producción.
Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5
tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa
razón. §12.9 y el README dicen ahora que el par se deja declarado A
PROPÓSITO.
2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al
100 % o excepción escrita», y la válvula que `component-audit` lee es esa
marca (`readmeException`), no la prosa. Tenía la razón documentada en
veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2,
los 16 habrían dado error. Una marca por clase medida — forward de paleta
THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de
layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan.
3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por
grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el
protocolo lo pide por componente: una sesión nueva habría arrancado con el
mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la
revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8
firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus
seis lecciones, y actualizada la memoria del eje.
4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el
bloque, cada una nombrando la forma en que el instrumento mentía, más la
lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso
— `picker-shell` medía CERO y reportaba éxito.
5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`,
`virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md
(md→sm); los valores eran correctos (0 diffs), el texto no.
Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B
sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la
medición de quien los escribió, y el plan la exige antes de cerrar un bloque.
El handoff nombra las dos hipótesis concretas que hay que atacar.
Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves ·
`component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno
con un commit de esta sesión en su código) · R-5.4 verde en los 22 ·
suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero
limpio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `field-langs` | 41 | espera el **mandato Field** (firma 2), que NO es tokenización: manda que los x-field incorporen el wrapper Field — cambia composición y mueve píxel |
fix(theming): el slot de tinta es `fg` — R-5.3 me cazó tres claves, y el handoff de mañana
Los guards globales, corridos antes de cerrar la sesión, encontraron una
regresión MÍA: `--names` daba **3 desviadas en 2 componentes** y
`component:audit` había pasado de 4 a **6 NEEDS-WORK**.
La causa: en `text-circular` y `text-focus` nombré tres claves con el slot
`color` (`color`, `border-color`, `glow-color`) cuando la gramática firmada el
2026-08-20 dice que **el slot de tinta es `fg` y `color` como slot MUERE**.
R-5.3 existe justamente para eso y funcionó — pero después de que yo lo
escribiera, porque el guard es de catálogo y yo verificaba `--only`.
Renombradas a `fg`, `border-fg` y `glow-fg`, con los destinos que el propio
censo indica en su salida `--names`. Value-preserving verificado: **0 diffs**
en text-circular (5.916 valores) y en text-focus (1.769), guards 5/6 y 8/8,
`--names` **DESVIADAS 0**, audit de vuelta a **162 PASS / 4 NEEDS-WORK** (los
cuatro preexistentes y ajenos al eje).
La lección para el protocolo, y va al handoff: **la propuesta §4 generada usa
el slot `color`**, así que es la cuarta manera en que falla — y como el paso 7
corre los guards con `--only`, la desviación de gramática sólo aparece al
correr `--names` GLOBAL. Ese comando ya estaba en el paso 1 del handoff; ahora
también se explica por qué no basta con el audit.
Y el HANDOFF para mañana: cifras nuevas (56 %, sin contrato 25, al 100 % 16),
la lista de los 24 componentes de F2-B con su alcance, las tres cosas que el
bloque enseñó y hay que tener delante al seguir (las cuatro maneras en que
falla la propuesta · declarar un público «de facto» puede MATAR una escala si
detrás hay un privado por talla · cuenta los nodos que ve la sonda antes de
creerte un gate verde), y la cola actualizada — con `mockup` marcado como SIN
DEMO (404) y `text-scramble` como «0 % estructural, escribe el veredicto, no
tokens».
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| `mockup` | 29 (38 %) | ⚠ **sin ruta de demo (404)** , como `picker-shell` : sin sonda ni guard. Y sale NEEDS-WORK en el audit, preexistente |
| `chronos` | 245 (1 %) | el segundo mayor; sin abrir |
uix(chart): temable — 9 % → 49 %, y la ficha pedía 71 claves de las que 20 llevaban el mismo valor
22 claves nuevas fusionadas en el bloque existente (17 → 39). Censo chart
9 % → **49 %**; global **56 % → 57 %** (2.638 → 2.675 públicos; <20 % 19 → 18).
LO QUE DECIDIÓ LA MEDICIÓN, no la ficha:
Las 84 filas fuera de alcance colapsaban a **26 valores distintos** — 9×
`content-secondary`, 9× `content-primary`, 9× `100%`, 6× `font-size-sm`, 6×
`font-size-xs`, 6× `font-weight-medium`, 5× `surface-default`, 4× `radius-sm`.
Nombrar por parte habría dado cinco claves para el pelo que separa marcas y
nueve para la tinta de anotación: la inflación de `spinner` con otra cara.
**El texto no recibe tokens de chart.** Toma su ROL DE TAMAÑO de los estilos con
nombre del canon —`caption` (xs) para las anotaciones, `label` (sm) para el
texto de cromo— y su tinta y su peso de las ranuras del sistema. Acuñar
`--chart-label-font-size` sería tipografía por componente, prohibido el mismo
día para text-effects. Precedente de consumir la capa: `code-block`, `kbd`,
`announce`. Doce declaraciones cambian de `var(--font-size-xs|sm)` a
`var(--style-caption|label-font-size)`, mismo valor.
**La receta sólo posee la tinta de lo que NO es texto**, cinco claves y cada una
un concepto que el CSS repite: `axis-fg` (eje + rejilla smith + conector del
funnel), `grid-fg` (rejilla + radar), `separator-fg` (el pelo de superficie
entre marcas contiguas: porción, punto activo, punto smith, pétalo, segmento),
`smith-boundary-fg` y `track-bg` (raíl del bar-list y del gauge). Más 17 de
geometría de cromo (gap, los pares row/column-gap, swatch, track, bar-segment).
**Incumplimiento heredado, corregido**: el CSS leía la coordenada CRUDA
`var(--control-height-sm, var(--space-7))` —lo que `recipe-css-contract`
prohíbe— con un respaldo muerto. El contrato guarda el bundle
`var(--size-sm-control-height)`, 1:1 con él.
**Identidad fuera de contrato**: los nueve `100%` («ocupa a tu padre») y el
`min-inline-size: max-content` del tooltip, misma clase ya adjudicada en
`date-picker`. Por eso el techo es 49 %, y está escrito en el veredicto §5.
EL INSTRUMENTO ESTABA CIEGO DE TRES MANERAS, arregladas ANTES de medir:
1. **La superficie de chart vive en DIECISÉIS rutas de demo**, una por tipo:
`/chart` monta 58 nodos de los 302 de la página y el resto vive en rutas
hermanas. El guard gana `urls`: un token está VIVO si ALGUNA superficie del
componente lo sigue, y cada URL sólo re-prueba lo pendiente (el caso de una
sola ruta cuesta exactamente lo que costaba). De paso `picker-shell` recibe
la suya: su ruta propia es un 404 y se mide dentro del date-picker — pasa de
0/31 con seis sin adjudicar a 6/31 sin tener que saberlo.
2. **El guard no leía NINGUNA propiedad SVG.** Sin `fill` / `stroke` /
`strokeWidth` / `fillOpacity` / `r` / `rx`, doce de las 39 claves de un
componente que dibuja en SVG leían muertas estando vivas. Misma clase que el
hueco de `filter` / `backdrop-filter` de ayer.
3. **El valor centinela se elegía por SUBCADENA**: `slice-stroke-width` recibía
`rgb(1, 2, 3)` por contener «stroke» —inválido para una longitud— y leía
muerta. La dimensión se decide ahora por el FINAL del nombre.
Los 28 componentes con ledger re-verificados tras los tres cambios: cero
regresiones, cero STALE. (Ojo: doce a la vez contra el mismo dev server dan
falsos exit=1 por timeout; repetir a solas antes de creerse una regresión.)
Gates: sonda **0 diffs en 161.850 valores computados** (16 rutas × 7 estados,
892 nodos en reposo) · centinela **37/39**, con `transition-duration` y `-ease`
adjudicadas midiéndolas sin la congelación (0,12s → 11,5s · cubic-bezier →
steps(4)) · censo --only 49 % · --names 39/39 conformes · component-audit PASS ·
eidos-lint 0 invalid · suite eidos con el único rojo conocido
(`skin-media-player`) · rtl:check 0 · docs:check 0 · `check` con 72 errores
globales y 0 en los ficheros tocados.
Abre (→ next-features §13): el censo **penaliza consumir la capa tipográfica**
si no eres un primitivo —las doce declaraciones correctas siguen contando
`global`—, que es la nota de `listbox` con una segunda ocurrencia; y el número
del gauge no tiene estilo con nombre que lo represente (un readout de dato no es
un `h2`), así que sigue leyendo `--font-size-xl`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `proof-of-human` | 95 (15 %) | escena de tono fijo firmada; lo demás son hooks de clase (eje aparte) |
| `prose` | 74 (1 %) | su superficie es la capa tipográfica: mismo caso que chart, un piso más arriba |
| `nav-tree` · `banner` · … | varios | ver el censo, `reach < 20 %` = 12 |
**Cerrados el 2026-08-23 (siete)**: `navigation-menu` 100 % · `background` 95 % ·
`cropper` 94 % · `color-field` 93 % · `badge` 75 % · `s-text-virtual-list` 70 % ·
`waveform` 86 %. **El siguiente por alcance entre los medibles y sin bloqueo es
`emoji-picker` (61 %)**, y luego `meter` / `spin-field` (64 %), `pin-input`
(65 %), `dialog` (67 %, ⚠ overlay: no acuñes tipografía hasta §12.9),
`progress` (69 %), `color-swatch` (70 %), `form` (71 %)… El mayor no bloqueado
sigue siendo `chronos` (1 %, carril WIP de D-TH.3, y «tiempo» es el ÚLTIMO de
D-TH.4).
fix(theming): el slot de tinta es `fg` — R-5.3 me cazó tres claves, y el handoff de mañana
Los guards globales, corridos antes de cerrar la sesión, encontraron una
regresión MÍA: `--names` daba **3 desviadas en 2 componentes** y
`component:audit` había pasado de 4 a **6 NEEDS-WORK**.
La causa: en `text-circular` y `text-focus` nombré tres claves con el slot
`color` (`color`, `border-color`, `glow-color`) cuando la gramática firmada el
2026-08-20 dice que **el slot de tinta es `fg` y `color` como slot MUERE**.
R-5.3 existe justamente para eso y funcionó — pero después de que yo lo
escribiera, porque el guard es de catálogo y yo verificaba `--only`.
Renombradas a `fg`, `border-fg` y `glow-fg`, con los destinos que el propio
censo indica en su salida `--names`. Value-preserving verificado: **0 diffs**
en text-circular (5.916 valores) y en text-focus (1.769), guards 5/6 y 8/8,
`--names` **DESVIADAS 0**, audit de vuelta a **162 PASS / 4 NEEDS-WORK** (los
cuatro preexistentes y ajenos al eje).
La lección para el protocolo, y va al handoff: **la propuesta §4 generada usa
el slot `color`**, así que es la cuarta manera en que falla — y como el paso 7
corre los guards con `--only`, la desviación de gramática sólo aparece al
correr `--names` GLOBAL. Ese comando ya estaba en el paso 1 del handoff; ahora
también se explica por qué no basta con el audit.
Y el HANDOFF para mañana: cifras nuevas (56 %, sin contrato 25, al 100 % 16),
la lista de los 24 componentes de F2-B con su alcance, las tres cosas que el
bloque enseñó y hay que tener delante al seguir (las cuatro maneras en que
falla la propuesta · declarar un público «de facto» puede MATAR una escala si
detrás hay un privado por talla · cuenta los nodos que ve la sonda antes de
creerte un gate verde), y la cola actualizada — con `mockup` marcado como SIN
DEMO (404) y `text-scramble` como «0 % estructural, escribe el veredicto, no
tokens».
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
`avatar` ya está al **75 %** y `knob` al 75 % (ambos hechos). `heading` /
`text` / `display` son primitivos tipográficos: su superficie es `--style-*` y
el censo los saca del ratio. `range-calendar` / `month-grid` / `year-grid`
están a 0 % **honesto** (consumen `calendar-surface` ).
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca
código y es la que importa.
1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré
como «declaraciones muertas» apoyándome en los precedentes de
`table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el
mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el
plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es
neutral — **fija el empate a favor del plano** y con él su 1.25 donde la
receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9
tiene pendiente para VEINTE componentes. Un empate por orden de carga se
registra, no se resuelve dentro de un commit de tokenización.
Y la medición era más débil de lo que el commit daba a entender: estable en
cinco recargas **en DEV**, sin verificar en un bundle de producción.
Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5
tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa
razón. §12.9 y el README dicen ahora que el par se deja declarado A
PROPÓSITO.
2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al
100 % o excepción escrita», y la válvula que `component-audit` lee es esa
marca (`readmeException`), no la prosa. Tenía la razón documentada en
veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2,
los 16 habrían dado error. Una marca por clase medida — forward de paleta
THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de
layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan.
3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por
grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el
protocolo lo pide por componente: una sesión nueva habría arrancado con el
mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la
revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8
firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus
seis lecciones, y actualizada la memoria del eje.
4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el
bloque, cada una nombrando la forma en que el instrumento mentía, más la
lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso
— `picker-shell` medía CERO y reportaba éxito.
5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`,
`virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md
(md→sm); los valores eran correctos (0 diffs), el texto no.
Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B
sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la
medición de quien los escribió, y el plan la exige antes de cerrar un bloque.
El handoff nombra las dos hipótesis concretas que hay que atacar.
Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves ·
`component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno
con un commit de esta sesión en su código) · R-5.4 verde en los 22 ·
suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero
limpio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
`heading` / `text` / `display` son primitivos tipográficos: su superficie es
`--style-*` y el censo ya los saca del ratio. `range-calendar` / `month-grid` /
`year-grid` están a 0 % **honesto** (consumen `calendar-surface` ).
`alert-dialog` , `css-field` , `mask-field` , `number-field` , `highlight` , `stack` ,
`wrap` , `auto-grid` tienen **cero knobs** : no hay nada que tokenizar.
fix(theming): el slot de tinta es `fg` — R-5.3 me cazó tres claves, y el handoff de mañana
Los guards globales, corridos antes de cerrar la sesión, encontraron una
regresión MÍA: `--names` daba **3 desviadas en 2 componentes** y
`component:audit` había pasado de 4 a **6 NEEDS-WORK**.
La causa: en `text-circular` y `text-focus` nombré tres claves con el slot
`color` (`color`, `border-color`, `glow-color`) cuando la gramática firmada el
2026-08-20 dice que **el slot de tinta es `fg` y `color` como slot MUERE**.
R-5.3 existe justamente para eso y funcionó — pero después de que yo lo
escribiera, porque el guard es de catálogo y yo verificaba `--only`.
Renombradas a `fg`, `border-fg` y `glow-fg`, con los destinos que el propio
censo indica en su salida `--names`. Value-preserving verificado: **0 diffs**
en text-circular (5.916 valores) y en text-focus (1.769), guards 5/6 y 8/8,
`--names` **DESVIADAS 0**, audit de vuelta a **162 PASS / 4 NEEDS-WORK** (los
cuatro preexistentes y ajenos al eje).
La lección para el protocolo, y va al handoff: **la propuesta §4 generada usa
el slot `color`**, así que es la cuarta manera en que falla — y como el paso 7
corre los guards con `--only`, la desviación de gramática sólo aparece al
correr `--names` GLOBAL. Ese comando ya estaba en el paso 1 del handoff; ahora
también se explica por qué no basta con el audit.
Y el HANDOFF para mañana: cifras nuevas (56 %, sin contrato 25, al 100 % 16),
la lista de los 24 componentes de F2-B con su alcance, las tres cosas que el
bloque enseñó y hay que tener delante al seguir (las cuatro maneras en que
falla la propuesta · declarar un público «de facto» puede MATAR una escala si
detrás hay un privado por talla · cuenta los nodos que ve la sonda antes de
creerte un gate verde), y la cola actualizada — con `mockup` marcado como SIN
DEMO (404) y `text-scramble` como «0 % estructural, escribe el veredicto, no
tokens».
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
### 5. Lo que espera TU FIRMA (todo medido, nada bloquea la cola)
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca
código y es la que importa.
1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré
como «declaraciones muertas» apoyándome en los precedentes de
`table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el
mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el
plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es
neutral — **fija el empate a favor del plano** y con él su 1.25 donde la
receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9
tiene pendiente para VEINTE componentes. Un empate por orden de carga se
registra, no se resuelve dentro de un commit de tokenización.
Y la medición era más débil de lo que el commit daba a entender: estable en
cinco recargas **en DEV**, sin verificar en un bundle de producción.
Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5
tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa
razón. §12.9 y el README dicen ahora que el par se deja declarado A
PROPÓSITO.
2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al
100 % o excepción escrita», y la válvula que `component-audit` lee es esa
marca (`readmeException`), no la prosa. Tenía la razón documentada en
veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2,
los 16 habrían dado error. Una marca por clase medida — forward de paleta
THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de
layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan.
3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por
grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el
protocolo lo pide por componente: una sesión nueva habría arrancado con el
mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la
revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8
firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus
seis lecciones, y actualizada la memoria del eje.
4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el
bloque, cada una nombrando la forma en que el instrumento mentía, más la
lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso
— `picker-shell` medía CERO y reportaba éxito.
5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`,
`virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md
(md→sm); los valores eran correctos (0 diffs), el texto no.
Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B
sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la
medición de quien los escribió, y el plan la exige antes de cerrar un bloque.
El handoff nombra las dos hipótesis concretas que hay que atacar.
Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves ·
`component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno
con un commit de esta sesión en su código) · R-5.4 verde en los 22 ·
suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero
limpio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
docs(theming): el handoff recoge la sesión entera del 23 — 65 %, 16 componentes
Cabecera al día (65 % global, 25 componentes al 100 %, <20 % baja de 14 a 12) y
una sección nueva con la tabla de los dieciséis, las CINCO LEYES que salieron y
todo lo que aprendió el instrumento.
Las leyes, que es lo que hay que leer antes de seguir la cola:
1. El portal es una frontera de cascada — un privado de la raíz no la cruza.
2. El plano `overlay` gana donde el componente habla, y en `tooltip` se queda
también el fondo, el borde y la sombra: sus tres variantes computan lo mismo.
3. La cascada de paleta anula los tonos del componente — 419 claves, 49 recetas.
4. Un respaldo escrito a mano envejece contra su token.
5. Donde hay un par, el defecto viene en par.
Firmas actualizadas: la 1 (§12.9) deja de ser sólo tipografía y suma la
superficie del tooltip; la 7 pasa de UN canónico sin demo a CUATRO
(picker-shell, mockup, surface, audio-player) con la nota de que el guard sobre
una página vacía miente en verde-rojo; y entra la 11, las dos reglas con
`:global()` que el navegador descarta.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
1. **El plano `overlay` impone tipografía a VEINTE componentes — y en
`tooltip` se queda además el FONDO, el BORDE y la SOMBRA**, con lo que sus
tres variantes computan lo mismo (medido 2026-08-23: `solid` , `outline` y
`ghost` idénticas). Ya no es una pregunta sobre tipografía: es sobre qué
manda, el plano o la receta. Cuatro componentes han tenido que RETIRAR o
ADJUDICAR claves por esto (menubar, dropdown-menu, context-menu, tooltip;
`combobox` sigue con la suya, registrada).
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca
código y es la que importa.
1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré
como «declaraciones muertas» apoyándome en los precedentes de
`table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el
mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el
plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es
neutral — **fija el empate a favor del plano** y con él su 1.25 donde la
receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9
tiene pendiente para VEINTE componentes. Un empate por orden de carga se
registra, no se resuelve dentro de un commit de tokenización.
Y la medición era más débil de lo que el commit daba a entender: estable en
cinco recargas **en DEV**, sin verificar en un bundle de producción.
Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5
tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa
razón. §12.9 y el README dicen ahora que el par se deja declarado A
PROPÓSITO.
2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al
100 % o excepción escrita», y la válvula que `component-audit` lee es esa
marca (`readmeException`), no la prosa. Tenía la razón documentada en
veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2,
los 16 habrían dado error. Una marca por clase medida — forward de paleta
THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de
layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan.
3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por
grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el
protocolo lo pide por componente: una sesión nueva habría arrancado con el
mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la
revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8
firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus
seis lecciones, y actualizada la memoria del eje.
4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el
bloque, cada una nombrando la forma en que el instrumento mentía, más la
lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso
— `picker-shell` medía CERO y reportaba éxito.
5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`,
`virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md
(md→sm); los valores eran correctos (0 diffs), el texto no.
Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B
sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la
medición de quien los escribió, y el plan la exige antes de cerrar un bloque.
El handoff nombra las dos hipótesis concretas que hay que atacar.
Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves ·
`component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno
con un commit de esta sesión en su código) · R-5.4 verde en los 22 ·
suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero
limpio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
(`font-family` + `line-height` junto a superficie/borde/sombra). ¿Un plano
de profundidad manda sobre la tipografía o sólo sobre la superficie?
— §12.9. **Es la que más urge: cada overlay que se tokenice la arrastra.**
**Y ya tiene MECANISMO** (menubar, 2026-08-23): el plano no sólo impone
donde el componente calla — **GANA donde el componente habla** . Declara
`font-family` y `line-height` con la misma especificidad (0,1,0) y más tarde
en la cascada, así que dos claves acuñadas sobre declaraciones que la receta
YA tenía salieron muertas en el centinela, mientras `color` y `font-size`
del mismo bloque alcanzaban. Traducción operativa: **hasta que firmes, no
acuñes `font-family` ni `line-height` en ninguna superficie `overlay` ** —
miente.
1.bis **La familia text-effects ACUÑA tipografía propia contra el canon**
(autor, 2026-08-22: «¿qué sentido tiene que text-effects introduzca
diferentes nombres de tipografía cuando ya hay un canon establecido?»).
uix(theming): text-scramble no tiene contrato que escribir — y el barrido de fantasmas, hecho
Sin cambios de código: su veredicto §5 y el registro.
Su 50 % no es ni deuda ni logro, es la suma de dos cosas que no son knobs:
- **Los dos literales son la técnica sr-only** (`width`/`height: 1px` en
`[data-text-scramble-sr]`), idéntica a `text-blur` y al resto del catálogo:
existe para que el lector de pantalla lea el texto entero mientras la versión
animada se parte en caracteres. Moverlos rompe la técnica.
- **Los dos «públicos» son tipografía que el componente no debería acuñar**
(`--text-scramble-font` / `-size`, con fallback y sin declarar): es la firma
1.bis pendiente. Escribirles contrato ahora sería acuñar exactamente lo que
esa firma propone retirar. Con esto, 1.bis son **7 claves en 4 de los 5**
componentes de la familia; `text-blur` es el único limpio: hereda.
Y el `font` apunta a un FANTASMA, medido en navegador: `var(--font-mono, …)` no
existe —el canónico es `--font-family-mono`— así que pinta `ui-monospace` e
**ignora la mono del tema** (`Azeret Mono`, que está ahí al lado).
EL BARRIDO MECÁNICO QUE PEDÍAN `--radius-xs` Y `--font-size-4xl`, HECHO:
5.793 custom properties declaradas en todo `src/uix/eidos` (fundación + capas +
recetas + `generated/`) contra los `var(--x, fallback)` de las recetas cuyo `--x`
sea vocabulario de SISTEMA → **9 referencias fantasma**. (Las que van sin
fallback ya las guarda `recipe-css-contract`; el hueco eran justo las que
«funcionan por accidente».) Tabla completa en next-features §13:
- `--color-content-tertiary` ×3 (float-panel, proof-of-human clock y
rotate-align) — **es el caso histórico** que `recipe-contract` §1 cita como
origen de su propia regla, y sigue vivo en tres recetas.
- `--style-{body,prose,label,caption}-font-variation-settings` ×4 (`text.css`) —
los estilos con nombre emiten 6 claves y ésta no está: **el eje de fuente
variable no llega nunca al primitivo `Text`**.
- `--font-family-sans` (palabras, track WIP) y `--font-mono` (text-scramble).
Ninguna se arregla aquí. El barrido debería ser un guard: misma lógica que el
test de fantasmas sin fallback que ya existe, con el filtro de vocabulario de
sistema encima.
Guards: censo `--only` sin cambio (50 %, es el veredicto lo que cambia) ·
component-audit PASS · docs:check 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Siete claves en CUATRO de los cinco** (medido al adjudicar
`text-scramble` ): `text-focus.word-size` (3rem, vía el fantasma
`--font-size-4xl` ) y `word-weight` (900) · `text-circular.weight` (900) y
uix(theming): text-scramble no tiene contrato que escribir — y el barrido de fantasmas, hecho
Sin cambios de código: su veredicto §5 y el registro.
Su 50 % no es ni deuda ni logro, es la suma de dos cosas que no son knobs:
- **Los dos literales son la técnica sr-only** (`width`/`height: 1px` en
`[data-text-scramble-sr]`), idéntica a `text-blur` y al resto del catálogo:
existe para que el lector de pantalla lea el texto entero mientras la versión
animada se parte en caracteres. Moverlos rompe la técnica.
- **Los dos «públicos» son tipografía que el componente no debería acuñar**
(`--text-scramble-font` / `-size`, con fallback y sin declarar): es la firma
1.bis pendiente. Escribirles contrato ahora sería acuñar exactamente lo que
esa firma propone retirar. Con esto, 1.bis son **7 claves en 4 de los 5**
componentes de la familia; `text-blur` es el único limpio: hereda.
Y el `font` apunta a un FANTASMA, medido en navegador: `var(--font-mono, …)` no
existe —el canónico es `--font-family-mono`— así que pinta `ui-monospace` e
**ignora la mono del tema** (`Azeret Mono`, que está ahí al lado).
EL BARRIDO MECÁNICO QUE PEDÍAN `--radius-xs` Y `--font-size-4xl`, HECHO:
5.793 custom properties declaradas en todo `src/uix/eidos` (fundación + capas +
recetas + `generated/`) contra los `var(--x, fallback)` de las recetas cuyo `--x`
sea vocabulario de SISTEMA → **9 referencias fantasma**. (Las que van sin
fallback ya las guarda `recipe-css-contract`; el hueco eran justo las que
«funcionan por accidente».) Tabla completa en next-features §13:
- `--color-content-tertiary` ×3 (float-panel, proof-of-human clock y
rotate-align) — **es el caso histórico** que `recipe-contract` §1 cita como
origen de su propia regla, y sigue vivo en tres recetas.
- `--style-{body,prose,label,caption}-font-variation-settings` ×4 (`text.css`) —
los estilos con nombre emiten 6 claves y ésta no está: **el eje de fuente
variable no llega nunca al primitivo `Text`**.
- `--font-family-sans` (palabras, track WIP) y `--font-mono` (text-scramble).
Ninguna se arregla aquí. El barrido debería ser un guard: misma lógica que el
test de fantasmas sin fallback que ya existe, con el filtro de vocabulario de
sistema encima.
Guards: censo `--only` sin cambio (50 %, es el veredicto lo que cambia) ·
component-audit PASS · docs:check 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`font-size` (1.5rem) · `text-gradient.font-weight` (500, subida el 22) ·
`text-scramble.font` y `.size` (sin declarar). La de `text-scramble`
apunta además a `--font-mono` , que NO existe: pinta `ui-monospace` e
**ignora la mono del tema** . `text-blur` es el único limpio: hereda.
Son opiniones del seed react-bits convertidas en contrato por «valor
verbatim». Doctrina F2-B regla 2: una receta CONSUME la capa tipográfica
(`--style-*`) o HEREDA (`link` → `inherit` ); un tratamiento de pintura
sobre texto real no tiene tipografía propia (un TextGradient dentro de un
`h1` ES un h1). **Resolución propuesta** : retirar las cinco claves y
heredar; mueve defaults (TextFocus deja de imponer 3rem/900, TextGradient
deja de forzar 500) → firma. Con ello muere el fantasma `4xl` . El módulo
de tipografía NO se toca. Registrado en next-features §13.
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca
código y es la que importa.
1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré
como «declaraciones muertas» apoyándome en los precedentes de
`table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el
mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el
plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es
neutral — **fija el empate a favor del plano** y con él su 1.25 donde la
receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9
tiene pendiente para VEINTE componentes. Un empate por orden de carga se
registra, no se resuelve dentro de un commit de tokenización.
Y la medición era más débil de lo que el commit daba a entender: estable en
cinco recargas **en DEV**, sin verificar en un bundle de producción.
Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5
tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa
razón. §12.9 y el README dicen ahora que el par se deja declarado A
PROPÓSITO.
2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al
100 % o excepción escrita», y la válvula que `component-audit` lee es esa
marca (`readmeException`), no la prosa. Tenía la razón documentada en
veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2,
los 16 habrían dado error. Una marca por clase medida — forward de paleta
THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de
layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan.
3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por
grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el
protocolo lo pide por componente: una sesión nueva habría arrancado con el
mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la
revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8
firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus
seis lecciones, y actualizada la memoria del eje.
4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el
bloque, cada una nombrando la forma en que el instrumento mentía, más la
lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso
— `picker-shell` medía CERO y reportaba éxito.
5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`,
`virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md
(md→sm); los valores eran correctos (0 diffs), el texto no.
Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B
sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la
medición de quien los escribió, y el plan la exige antes de cerrar un bloque.
El handoff nombra las dos hipótesis concretas que hay que atacar.
Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves ·
`component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno
con un commit de esta sesión en su código) · R-5.4 verde en los 22 ·
suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero
limpio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
2. **El harness del sitio tapa a `code-block` y `code`** : `[data-uix-docs] pre`
pisa SIETE propiedades del `<pre>` , y `[data-uix-docs] code` el radio del
inline. Acotarlo toca el CSS que sirve a ~162 páginas — §13.
3. **El censo no distingue «0 % por deuda» de «0 % POR NATURALEZA»** (cinco
componentes ya). Sin una clase `structural` , **el gate de F3 es
inalcanzable por construcción** — §13.
4. **El velo derrama sobre el subárbol entero en `tree-view`** (`archetype:
'item'` en el `<li>` branch: 336 px velados en vez de 36) — §12.8, morfo.
5. **La selección de fila de `grid-list` nunca ha pintado** (soma estampa
`data-state` , no `data-selected` ) — §13, morfo.
6. **El borde de foco de `textarea` sólo se ve con Tab** : hover (0,4,0) >
foco (0,3,0) > invalid (0,2,0) — §13.
docs(theming): el handoff recoge la sesión entera del 23 — 65 %, 16 componentes
Cabecera al día (65 % global, 25 componentes al 100 %, <20 % baja de 14 a 12) y
una sección nueva con la tabla de los dieciséis, las CINCO LEYES que salieron y
todo lo que aprendió el instrumento.
Las leyes, que es lo que hay que leer antes de seguir la cola:
1. El portal es una frontera de cascada — un privado de la raíz no la cruza.
2. El plano `overlay` gana donde el componente habla, y en `tooltip` se queda
también el fondo, el borde y la sombra: sus tres variantes computan lo mismo.
3. La cascada de paleta anula los tonos del componente — 419 claves, 49 recetas.
4. Un respaldo escrito a mano envejece contra su token.
5. Donde hay un par, el defecto viene en par.
Firmas actualizadas: la 1 (§12.9) deja de ser sólo tipografía y suma la
superficie del tooltip; la 7 pasa de UN canónico sin demo a CUATRO
(picker-shell, mockup, surface, audio-player) con la nota de que el guard sobre
una página vacía miente en verde-rojo; y entra la 11, las dos reglas con
`:global()` que el navegador descarta.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
7. **CUATRO canónicos sin demo propia** (404): `picker-shell` , `mockup` ,
`surface` y `audio-player` . Sin ruta no hay sonda ni guard, y el guard
**miente en verde-rojo** : sobre una página vacía reportó 0/25 para surface,
incluido un `radius` vivísimo. Los tres medibles se apuntaron a la ruta donde
SÍ se renderizan; `mockup` sigue sin poder medirse — §13.
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca
código y es la que importa.
1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré
como «declaraciones muertas» apoyándome en los precedentes de
`table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el
mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el
plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es
neutral — **fija el empate a favor del plano** y con él su 1.25 donde la
receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9
tiene pendiente para VEINTE componentes. Un empate por orden de carga se
registra, no se resuelve dentro de un commit de tokenización.
Y la medición era más débil de lo que el commit daba a entender: estable en
cinco recargas **en DEV**, sin verificar en un bundle de producción.
Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5
tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa
razón. §12.9 y el README dicen ahora que el par se deja declarado A
PROPÓSITO.
2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al
100 % o excepción escrita», y la válvula que `component-audit` lee es esa
marca (`readmeException`), no la prosa. Tenía la razón documentada en
veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2,
los 16 habrían dado error. Una marca por clase medida — forward de paleta
THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de
layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan.
3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por
grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el
protocolo lo pide por componente: una sesión nueva habría arrancado con el
mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la
revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8
firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus
seis lecciones, y actualizada la memoria del eje.
4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el
bloque, cada una nombrando la forma en que el instrumento mentía, más la
lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso
— `picker-shell` medía CERO y reportaba éxito.
5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`,
`virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md
(md→sm); los valores eran correctos (0 diffs), el texto no.
Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B
sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la
medición de quien los escribió, y el plan la exige antes de cerrar un bloque.
El handoff nombra las dos hipótesis concretas que hay que atacar.
Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves ·
`component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno
con un commit de esta sesión en su código) · R-5.4 verde en los 22 ·
suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero
limpio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
8. Extender la clase `system` del censo a las **capas compartidas** (viene de
antes de esta sesión).
docs(theming): el handoff recoge la sesión entera del 23 — 65 %, 16 componentes
Cabecera al día (65 % global, 25 componentes al 100 %, <20 % baja de 14 a 12) y
una sección nueva con la tabla de los dieciséis, las CINCO LEYES que salieron y
todo lo que aprendió el instrumento.
Las leyes, que es lo que hay que leer antes de seguir la cola:
1. El portal es una frontera de cascada — un privado de la raíz no la cruza.
2. El plano `overlay` gana donde el componente habla, y en `tooltip` se queda
también el fondo, el borde y la sombra: sus tres variantes computan lo mismo.
3. La cascada de paleta anula los tonos del componente — 419 claves, 49 recetas.
4. Un respaldo escrito a mano envejece contra su token.
5. Donde hay un par, el defecto viene en par.
Firmas actualizadas: la 1 (§12.9) deja de ser sólo tipografía y suma la
superficie del tooltip; la 7 pasa de UN canónico sin demo a CUATRO
(picker-shell, mockup, surface, audio-player) con la nota de que el guard sobre
una página vacía miente en verde-rojo; y entra la 11, las dos reglas con
`:global()` que el navegador descarta.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
11. **Dos reglas que el navegador DESCARTA** : `onion-menu.css` y
`timeline.css` escriben `:global(svg)` en un CSS PLANO, donde el selector es
inválido. El glifo del onion computa 14px en vez del 70 % que la regla cree
pintar. Arreglarlo mueve píxel en los dos — §13.
10. ** ⚠⚠ LA CASCADA DE PALETA ANULA LOS TONOS DEL COMPONENTE — 419 claves
públicas** (medido 2026-08-23 en `button` , `badge` y `callout` ). El forward
emite un bloque por tono y, AL FINAL, uno genérico `[data-{c}][data-color]`
que resuelve desde el `--palette-*` global; misma especificidad (0,2,0), gana
el último. `--{c}-risk-solid` no mueve nada; `--palette-solid` y
`--color-risk-solid` en el nodo sí. **49 recetas** emiten ese bloque. El
arreglo cabe en el ORDEN DE EMISIÓN y no movería un píxel, pero cambia el
contrato de la jaula del color → §13. **Es la más gorda del eje.**
9. **El eje `size` del `color-picker` muere en el portal** (2026-08-23): la
anchura del panel está cableada al paso `md`
(`--_color-picker-content-width` se declara tres veces y no lo consume
nadie) y el tamaño de las muestras DENTRO del panel también. Un picker
`sm` y uno `lg` abren el mismo panel de 344 px. El arreglo es una escala
por talla en el ámbito del CONTENIDO —que sí lleva su `data-size` —; mueve
píxel en `sm` y `lg` → §13. **Ley general: el portal es una frontera de
cascada; un privado declarado en la raíz no la cruza.**
feat(calendar-surface): la capa que ya existía, con nombre, casa y su agujero tapado
Firma 1 del acta, diseño presentado y firmado. **La medición desmontó el
encargo**: el handoff la vendía como una capa NUEVA de ~220 knobs, y la capa ya
existía de hecho, sin nombre. `--calendar-*` se emite en `:root` (76 claves) y
sus consumidores no acuñan NADA — medido: `range-calendar` 114 referencias
prestadas y 0 propias, `month-grid` 77/0, `year-grid` 77/0, y lo único ajeno
que leen es sistema puro (`--focus-ring-*`, `--state-hover`). Su 0 % era el
artefacto de `listbox` (§13), pero total.
**`lib/calendar-surface.css`** (hook `data-calendar-surface`):
- cuatro coordenadas por talla — `padding`, `control-size`, `day-size`,
`font-size` — xs..lg, porque la familia NO tiene xl, y con la celda DOS pasos
por debajo del bundle de control. Esa desviación estaba escondida en cuatro
bloques `[data-size]` idénticos, uno por receta, cada uno puenteando a un
privado con otro nombre; ahora se lee en un sitio.
- la FORMA del anillo de evento y de la marca de festivo.
**Capa HÍBRIDA, y es lo que la distingue de sus hermanas**: `list-surface` y
`viewport-placement` componen primitivos del sistema, así que declaran sus
públicos en el fichero y no tienen entrada de receta. Ésta no puede: su
vocabulario son 76 claves SEMÁNTICAS que un tema alcanza una a una por config,
así que la entrada `calendar` de `recipes/base.ts` pasa a ser la de la FAMILIA
y la capa posee sólo lo que una entrada de receta no sabe expresar.
**El defecto que la justificaba, medido**: `--calendar-event-shadow` y
`--calendar-day-holiday-shadow` se emitían con ámbito `[data-calendar]`
(audit B.2 los host-scopeó por buenas razones) mientras `range-calendar`,
`month-grid` y `year-grid` los leían desde hosts que nunca llevan ese atributo:
variable VACÍA, `box-shadow` inválido en computed, **el anillo sema de
`commit-select` / `commit-set` no pintaba jamás en tres componentes**. Un token
prestado cuyo ÁMBITO no te cubre no es un préstamo, es un agujero silencioso, y
ningún guard lo veía. Ahora la forma vive en la capa y el acento entra por
`--_calendar-surface-accent`, que cada superficie alimenta con su propio
forward de paleta THM-2.
**Siete wrappers estampan, no cuatro** — y esto casi se me cuela: `DatePicker`
y `DateRangePicker` renderizan la superficie soma por sus PROPIOS wrappers
(`date-picker-calendar`, `-month-view`, `-year-view`,
`date-range-picker-calendar`) y un panel portalado no hereda nada del root del
picker. Con sólo los cuatro standalone sellando, ambos quedaban con
`--calendar-padding` VACÍA y el panel a padding 0 (medido). La tentación era
enganchar la capa a las cuatro identidades de componente: eso viola la regla 1
de capas compartidas, y la respuesta correcta es un sello por wrapper.
computed 0 diffs en range-calendar (19.285 valores) · month-grid (3.451) ·
year-grid (3.451) · date-picker (464) · date-range-picker (406).
`calendar` da 12, y son del INSTRUMENTO: dos corridas del MISMO
código dan 24 en los mismos nodos y las mismas dos propiedades.
Los «missing node» son el propio sello entrando en la clave.
**Una incidencia nueva, medida y NO arreglada aquí** (§13): el font-size de los
selectores month/year es una moneda al aire —
`[data-calendar-month-select][data-button]` (0,2,0) empata con
`[data-popover-trigger]:not([data-archetype='field-trigger'])` (0,2,0), la
MISMA regla de popover que dejó muerto el cromo de `gradient-picker`, y gana la
hoja que cargue después: 16px o 14px según la recarga. Arreglarlo fija el píxel
en un lado ⇒ decisión.
De paso, `calendar-select.css` deja de puentear un privado que sólo
`[data-calendar]` declaraba: en range / date-range corría SIEMPRE por el
fallback, clavado a md fuera cual fuera la talla.
**El censo deja de penalizar hacer lo correcto**: `LAYER_VOCABULARY` en
`theming-census.ts`, mismo precedente que D-TH.2-b con `--style-*`. Global
43 % → **45 %**, `calendar` 75 % → **84 %**. `list-surface` NO se registra: sus
consumidores puentean por privados, otra forma, y mueve diez componentes de
golpe. Y aparece el techo de debajo, anotado: a los tres consumidores sólo les
quedan los forwards de paleta THM-2 —que el censo cuenta como `private` en TODO
el catálogo— así que siguen leyendo 0 %.
`recipe-css-contract` aprende que una CAPA también declara públicos (antes sólo
miraba la receta, y una capa que comparte prefijo con un componente la hacía
fallar). Sin debilitarla: un nombre que no declara nadie sigue en rojo.
eidos-lint 0 invalid (calendar 29/8 · range-calendar 41/12 · los grids 23/5) ·
audit --only calendar PASS · vitest eidos 434/435 (el rojo conocido) ·
rtl 0/181 · docs 0/813 · check 0 errores en tocados · prettier: revertido el
reformateo en masa que se coló en cuatro README, el test y el censo (churn
ajeno, no mío)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## EL PROTOCOLO, EN CORTO (el largo está en PLAN-theming.md §7)
Un componente = un commit. Por componente:
1. Leer entero: receta, su bloque en `recipes/base.ts` , README de eidos, morfo,
y el veredicto §5 de su ficha.
2. **Sonda ANTES** (`__theming-probe.ts {c} antes.json < url > `).
3. Escribir el contrato en `recipes/base.ts` — **fusionando en el bloque
existente si ya lo hay** (los forwards de paleta THM-2 ya ocupan bloque en
muchos componentes; un segundo bloque con el mismo nombre se descarta EN
SILENCIO).
4. La receta consume los nombres resueltos; **retirar los bloques `[data-size]`
del CSS** — los emite el TSC, y dejarlos vivos hace que el diff dé 0 por la
ruta vieja.
5. `npm run generate:eidos-css` , sonda DESPUÉS, **diff = 0** .
uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4
Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree
con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba
más dura que la del autor), sonda x2 por componente para fijar el suelo de
ruido. 34 hipótesis · 26 refutadas · 8 reales.
Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs;
command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 ·
listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen
idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens
huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano»
de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación;
eidos-lint 0 invalid.
Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command
8.091 y carousel 2.842 valores, 0 diffs):
1. command: el re-point de `--command-radius` dentro del Dialog era una
declaración muerta con comentario falso — la misma regla pone el radio a 0
y el input lee `--command-input-radius`, nunca este token (medido:
`--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px`
movía la paleta inline y no la del dialog). Retirado; comentarios y README
reescritos con lo medido.
2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo
mientras la horizontal leía `active-indicator-scale` — el token alcanzaba
media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora
lo leen las dos.
3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap`
INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por
CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y
las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es
la prueba. Canal de valor de soma, como --gp-current-gradient. Censo
carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto
(5.190 · 2.102).
4. table: `striped-row-bg` no alcanza NADA en la demo publicada —
`:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos
quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel →
PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`);
adjudicado en el ledger mientras tanto.
El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas
medidas, y la cuarta era de la sonda:
- el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input
de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el
token de reposo leía muerto (era el «falso negativo sin causa» de §13);
- el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de
`{c}-root` no lo recibían;
- `::before`/`::after` eran invisibles (el aro de buffering, el spinner);
- la no-determinación de feed no era una animación sin localizar: era la demo
aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma
`commit-settle` anima box-shadow sobre el nodo medido. Con la espera de
asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas.
Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y
que carousel convirtió en patrón — un estilo inline de otra capa es invisible
para todo análisis estático): `npm run theming:sentinel -- <c> <url>`
(scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en
todos los nodos del componente, pseudos, pase de hover, settle) + ledger
scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto
sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en
verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 ·
gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46
excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías
salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró;
y dos muertos nuevos los produjeron los propios arreglos (el blur apaga
focus-input-border; el settle desmonta el spinner de feed) — adjudicados con
su porqué. Doctrina en recipe-contract §4.
También: tres cifras de especificidad de next-features §12 recontadas (la
banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0);
y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el
velo en la celda), el comentario de listbox que mandaba pisar el privado
`--_listbox-max-height` apunta ahora al público, y quedan registrados en §13
los dos `header-z` con literal '2' y el spinner de media-player a 720ms
mientras el gemelo de feed lleva tokens.
Guards: censo global 43 % intacto · audit --only command+carousel PASS ·
eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest
eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs
0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier
limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en
HEAD y no se tocan).
Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el
arquetipo en fila+celda, y que soma lea el gap de un token.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
6. Guard R-5.4 (`npm run theming:sentinel -- {c} < url > `) y **adjudicar cada
«no effect» uno a uno EN EL LEDGER**
(`scripts/theming-sentinel-exceptions.ts`, una razón medida por token) —
el guard falla con un muerto sin adjudicar, y avisa de excepciones STALE.
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
7. Guards: censo `--only {c}` · `component-audit --only {c}` · `eidos-lint {c}`
· `vitest run src/uix/eidos` (comparar POR FICHERO: el rojo conocido es
`skin-media-player` ) · `rtl:check` · `docs:check` · `npm run check`
atribuido POR FICHERO (73 errores globales son de otras sesiones).
8. README del componente con su sección «Talla y tema».
9. **Tab `Tokens` en la demo** — una línea:
`<TokensPanel component="x" stage={stageRef ?? undefined} />` + su botón.
10. Commit con las cifras y los artefactos en el mensaje.
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca
código y es la que importa.
1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré
como «declaraciones muertas» apoyándome en los precedentes de
`table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el
mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el
plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es
neutral — **fija el empate a favor del plano** y con él su 1.25 donde la
receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9
tiene pendiente para VEINTE componentes. Un empate por orden de carga se
registra, no se resuelve dentro de un commit de tokenización.
Y la medición era más débil de lo que el commit daba a entender: estable en
cinco recargas **en DEV**, sin verificar en un bundle de producción.
Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5
tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa
razón. §12.9 y el README dicen ahora que el par se deja declarado A
PROPÓSITO.
2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al
100 % o excepción escrita», y la válvula que `component-audit` lee es esa
marca (`readmeException`), no la prosa. Tenía la razón documentada en
veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2,
los 16 habrían dado error. Una marca por clase medida — forward de paleta
THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de
layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan.
3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por
grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el
protocolo lo pide por componente: una sesión nueva habría arrancado con el
mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la
revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8
firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus
seis lecciones, y actualizada la memoria del eje.
4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el
bloque, cada una nombrando la forma en que el instrumento mentía, más la
lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso
— `picker-shell` medía CERO y reportaba éxito.
5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`,
`virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md
(md→sm); los valores eran correctos (0 diffs), el texto no.
Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B
sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la
medición de quien los escribió, y el plan la exige antes de cerrar un bloque.
El handoff nombra las dos hipótesis concretas que hay que atacar.
Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves ·
`component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno
con un commit de esta sesión en su código) · R-5.4 verde en los 22 ·
suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero
limpio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
## LO QUE F2-B ENSEÑÓ (2026-08-22 — léelo antes de tocar nada)
**Un alcance bajo puede ser doctrina bien aplicada, no deuda.** `menu-dial`
25 % porque sus ejes de colocación son de la capa `viewport-placement` y la
receta escribe en sus RANURAS DE OVERRIDE; `link` 36 % porque sus escotillas
caen en `inherit` , que es semántico (el enlace toma la tipografía del párrafo);
`scroll-frames` 33 % porque es layout puro. **El % no es la métrica de
calidad** — lo que importa es que lo que queda fuera esté MEDIDO y escrito.
**Cuatro clases que se repiten, con su veredicto ya fijado:**
1. **Un privado con DOS fuentes es un conmutador, no deuda.** Cinco casos
(`textarea`, `spinner` , `skeleton` , `code` , `label` ): aplanarlo obligaría a
duplicar cada regla por color. Se queda privado y se adjudica.
2. **Lo que la capa tipográfica posee NO se acuña** (`--style-*`): cinco casos
(`code-block`, `kbd` , `announce` , `code` , `label` ).
3. **Un forward de paleta THM-2 leído a pelo** no admite público sin duplicar
la regla.
4. **Identidad ≠ knob** : `100%` , `50%` de un círculo, `line-height: 1` de una
tecla, `transparent` de una variante ghost.
**La propuesta §4 generada FALLA de tres maneras distintas**, y las tres
costaron medición:
- **Hereda el incumplimiento del CSS de partida**: copia el valor verbatim, así
que si ya violaba `recipe-css-contract` (primitivo crudo en vez del bundle),
la propuesta lo repite. Lo cazó la suite en `code-block` .
- **Infla hasta 4× **: en `spinner` pedía **71 tokens para 23 knobs** ,
multiplicando UNA coordenada de talla por variante × parte × dimensión —
veinte claves con el mismo valor.
- **Nombra por el primer selector de la regla**, no por el nodo pintado: en
`tree-view` llamaba `root-width` / `root-bg` a la GUÍA de indentación, y
fundía en un solo nombre el `padding-inline` de la fila y el paso de
profundidad, que se SUMAN en el mismo `calc` .
**El instrumento estándar no ve tres clases de componente**, y una sonda que
compara pocos nodos pasa en falso: panel portalado que abre en hover
(`link-preview`: 1 nodo), componente sin demo propia y con partes de nombre
genérico (`picker-shell`: **0 nodos** ), y parte que sólo existe durante una
interacción (el fantasma de `drag-drop` , el indicador de `clipboard` , el rótulo
de `scroll-frames` ). **Cuenta siempre los nodos que ve la sonda antes de creerte
un gate en verde.**
**El guard R-5.4 ganó SEIS capacidades en este bloque**, todas nacidas de una
medición y con los del ledger re-verificados sin regresión tras cada una:
puntero parqueado tras el blur (`reopen()` corre antes de CADA token), lectura
de `::placeholder` (la nota de §13 que decía que no se podía era falsa),
`COMPONENT_OVERRIDES` de prefijo de atributo y selector de apertura, apertura
por `hover` , y `text-decoration-thickness` / `-underline-offset` en la lista de
propiedades.
**Y dos errores de proceso que costaron tiempo:**
- **El guard de claves duplicadas del handoff inspeccionaba el VACÍO**:
`grep -E` lee ` ` como una `t` literal — 0 coincidencias sobre 130 bloques.
Corregido más abajo con una versión que CUENTA.
- **`$?` tras una tubería es el del último comando**, no el del guard: un
fichero de excepciones con sintaxis inválida pasó por bueno. Comprueba el
exit REAL.
## LO QUE F2-A ENSEÑÓ (léelo antes de tocar nada)
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Sobre los veredictos.** Tres de ocho tenían un error de lectura que sólo
apareció midiendo: el título de `feed` escala por `aria-level` , **no por
talla**; `--gp-current-gradient` lo estampa **soma** , no el wrapper de eidos; y
el trigger de `gradient-picker` no había que tokenizarlo sino **borrarlo** . El
veredicto orienta; la medición decide.
**Un token que no mueve nada es un token que miente.** Ocurrió tres veces:
`table.selected-row-fg` y la tinta de `listbox` (el arquetipo las gana por
especificidad) y **el cromo ENTERO del trigger de `gradient-picker`** (36 de 45
tokens sin efecto — lo pinta `popover.css` , que gana 0,2,0 contra 0,1,0). En
los tres casos la acción correcta fue **retirar la declaración muerta** , y en
los tres retirarla dio 0 diffs, que es la prueba de que estaba muerta.
**Un alias puro no se renombra: se borra.** Los dieciséis `--_mp-*` de
media-player eran alias de su propia fuente; el veredicto pedía renombrarlos y
lo que procedía era eliminar la capa entera.
**Lo que la capa posee, el consumidor no lo acuña.** `listbox` se queda en 68 %
a propósito: su ritmo de fila es de `list-surface` . La métrica penaliza hacer lo
correcto — registrado en `next-features.md` §13.
**Antes de acuñar un `hover-*` , mide contra la capa de estado.** En `listbox` el
`highlighted` pinta DOS veces (plano + velo); se dejó sin token para no
bendecir un duplicado condenado.
**La sonda miente de tres maneras distintas**, y todas costaron tiempo aquí:
uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4
Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree
con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba
más dura que la del autor), sonda x2 por componente para fijar el suelo de
ruido. 34 hipótesis · 26 refutadas · 8 reales.
Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs;
command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 ·
listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen
idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens
huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano»
de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación;
eidos-lint 0 invalid.
Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command
8.091 y carousel 2.842 valores, 0 diffs):
1. command: el re-point de `--command-radius` dentro del Dialog era una
declaración muerta con comentario falso — la misma regla pone el radio a 0
y el input lee `--command-input-radius`, nunca este token (medido:
`--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px`
movía la paleta inline y no la del dialog). Retirado; comentarios y README
reescritos con lo medido.
2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo
mientras la horizontal leía `active-indicator-scale` — el token alcanzaba
media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora
lo leen las dos.
3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap`
INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por
CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y
las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es
la prueba. Canal de valor de soma, como --gp-current-gradient. Censo
carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto
(5.190 · 2.102).
4. table: `striped-row-bg` no alcanza NADA en la demo publicada —
`:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos
quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel →
PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`);
adjudicado en el ledger mientras tanto.
El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas
medidas, y la cuarta era de la sonda:
- el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input
de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el
token de reposo leía muerto (era el «falso negativo sin causa» de §13);
- el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de
`{c}-root` no lo recibían;
- `::before`/`::after` eran invisibles (el aro de buffering, el spinner);
- la no-determinación de feed no era una animación sin localizar: era la demo
aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma
`commit-settle` anima box-shadow sobre el nodo medido. Con la espera de
asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas.
Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y
que carousel convirtió en patrón — un estilo inline de otra capa es invisible
para todo análisis estático): `npm run theming:sentinel -- <c> <url>`
(scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en
todos los nodos del componente, pseudos, pase de hover, settle) + ledger
scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto
sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en
verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 ·
gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46
excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías
salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró;
y dos muertos nuevos los produjeron los propios arreglos (el blur apaga
focus-input-border; el settle desmonta el spinner de feed) — adjudicados con
su porqué. Doctrina en recipe-contract §4.
También: tres cifras de especificidad de next-features §12 recontadas (la
banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0);
y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el
velo en la celda), el comentario de listbox que mandaba pisar el privado
`--_listbox-max-height` apunta ahora al público, y quedan registrados en §13
los dos `header-z` con literal '2' y el spinner de media-player a 720ms
mientras el gemelo de feed lleva tokens.
Guards: censo global 43 % intacto · audit --only command+carousel PASS ·
eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest
eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs
0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier
limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en
HEAD y no se tocan).
Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el
arquetipo en fila+celda, y que soma lea el gap de un token.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
congela `transition` pero **nunca `animation`** ; el estado `hover` se mide
**después** de forzar tallas, así que arrastra la última; y un empate de
especificidad **resuelto por orden de carga** hace que `tree-grid` dé 0 ó 3
diffs según la recarga. **Ante un diff inesperado, lo primero es correr la
sonda dos veces sobre el MISMO código.** La revisión adversarial encontró y
arregló la causa del caso `feed` (2026-08-21): no era una animación sin
localizar sino la demo aún CARGANDO — el auto load-more mantiene `[data-busy]`
~3 s y la firma sema `commit-settle` anima `box-shadow` sobre el nodo medido.
Sonda y guard esperan ahora a que `[data-busy]` caiga; con eso, dos corridas
del mismo código dan 0 diffs. Y el «falso negativo sin causa» de
`command.input-border` también tenía causa: el centinela ABRÍA haciendo clic
en el input, y un clic de ratón sobre un input de texto SÍ casa
`:focus-visible` — la regla de foco pintaba el borde y el token de reposo
leía muerto. El instrumento viejo acumulaba **22 falsos negativos de 26** ;
las tres causas están arregladas en `theming-sentinel.ts` .
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## LAS INCIDENCIAS NO SE ARREGLAN AQUÍ
Todo lo que este eje destapa y no le toca arreglar está en
[`docs/next-features.md` ](../next-features.md ) ** §12** (el contrato de cascada
del velo de estado: 131 declaraciones-atajo en 45 componentes, la prop
`hoverable` que no suprime nada, el empate por orden de carga, la banda que
mata el hover, el token de tinta que no puede ganar al arquetipo, el thumb de
`scroll-area` sin velo) y ** §13** (huecos de instrumento y de demo, más los
cuatro que salieron de `gradient-picker` y `listbox` ).
**Regla**: si una incidencia mueve píxel o toca morfo, se MIDE, se anota ahí y
se sigue. No se arregla dentro del commit del componente.
## PENDIENTE DE FIRMA (nada bloquea la cola)
- **Diseño de `calendar-surface` ** — la firma 1 aprobó el PATRÓN, no un diseño
concreto; ese se presenta.
- **`scroll-area.thumb-bg-hover`** — único knob de la firma 3 sin resolver: su
thumb lleva `archetype: 'thumb'` , que no recibe velo. Cambiarlo es morfo.
- **Extender la clase `system` del censo a las capas compartidas**, como se
hizo con `--style-*` para los primitivos tipográficos (§13 del registro).
fix(table): el striped cuenta filas de DATOS — la banda vuelve a existir
Firmado por el autor tras la revisión adversarial: el hallazgo 4 (679dfdb29)
midió que `:nth-of-type(even)` cuenta los <tr> hermanos, y con un RowDetail
intercalado tras cada fila las filas de datos quedan todas impares — la demo
publicada no bandeaba NADA (diez tr inmunes al token, medido uno a uno).
El selector pasa a `:nth-child(even of [data-table-row])`, con dos decisiones
de peso dentro:
- **conserva el (0,6,0) del viejo**: el pseudo más el argumento `of` pesan
exactamente lo que pesaba `[data-table-row]:nth-of-type()`, así que el hover
—posterior en el fichero— sigue ganando su empate y la banda NO mata el
hover. Subirlo de peso habría importado a table el defecto §12.4 de
tree-grid.
- **`:where(:not([data-selected]))` a peso CERO**: la fila seleccionada
siempre estuvo prometida al acento («Overrides hover + striped», dice la
regla de al lado a (0,3,0)) pero la banda vieja, de haber casado, se la
habría comido por especificidad. El :where excluye sin pesar.
Medido (sonda antes/después, 13.195 valores en 7 estados): **12 diffs
exactos** — 2 filas pares × 6 estados, backgroundColor 0.9911 → 0.9551 — y
nada más se movió. Interacciones verificadas en vivo: selected par conserva
el acento (0.9588 con croma) · hover sobre par pinta su tinte (0.931).
El ledger de R-5.4 pierde la excepción de `striped-row-bg` (era «genuinely
unreachable, pending signature»): el guard adjudica ahora table 42/45 con 3
excepciones, exit 0, sin STALE.
eidos-lint 0 invalid · audit --only table PASS · censo table 86 % intacto ·
vitest eidos 434/435 (el rojo conocido) · rtl 0 · docs 0 · check 0 en
tocados · prettier limpio en lo tocado (el wrap de la regla del hover ya
estaba desviado en HEAD y no se toca)
Incidencia operativa, reparada y anotada: al retirar el worktree de medición
de la revisión, `git worktree remove --force` recursó A TRAVÉS de la junction
de node_modules y borró parte del real (node_modules/.bin incluido) antes de
fallar; `npm install` lo reconstruyó y la suite volvió a 434/435. El árbol
git nunca se tocó.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- ~~El `striped` de `table` inerte con RowDetail~~ — **FIRMADO Y EJECUTADO
2026-08-21**: `:nth-child(even of [data-table-row])` con
`:where(:not([data-selected]))` , mismo (0,6,0) para no matar el hover.
12 diffs exactos (2 filas × 6 estados); selected y hover verificados.
uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4
Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree
con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba
más dura que la del autor), sonda x2 por componente para fijar el suelo de
ruido. 34 hipótesis · 26 refutadas · 8 reales.
Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs;
command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 ·
listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen
idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens
huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano»
de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación;
eidos-lint 0 invalid.
Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command
8.091 y carousel 2.842 valores, 0 diffs):
1. command: el re-point de `--command-radius` dentro del Dialog era una
declaración muerta con comentario falso — la misma regla pone el radio a 0
y el input lee `--command-input-radius`, nunca este token (medido:
`--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px`
movía la paleta inline y no la del dialog). Retirado; comentarios y README
reescritos con lo medido.
2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo
mientras la horizontal leía `active-indicator-scale` — el token alcanzaba
media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora
lo leen las dos.
3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap`
INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por
CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y
las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es
la prueba. Canal de valor de soma, como --gp-current-gradient. Censo
carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto
(5.190 · 2.102).
4. table: `striped-row-bg` no alcanza NADA en la demo publicada —
`:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos
quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel →
PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`);
adjudicado en el ledger mientras tanto.
El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas
medidas, y la cuarta era de la sonda:
- el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input
de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el
token de reposo leía muerto (era el «falso negativo sin causa» de §13);
- el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de
`{c}-root` no lo recibían;
- `::before`/`::after` eran invisibles (el aro de buffering, el spinner);
- la no-determinación de feed no era una animación sin localizar: era la demo
aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma
`commit-settle` anima box-shadow sobre el nodo medido. Con la espera de
asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas.
Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y
que carousel convirtió en patrón — un estilo inline de otra capa es invisible
para todo análisis estático): `npm run theming:sentinel -- <c> <url>`
(scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en
todos los nodos del componente, pseudos, pase de hover, settle) + ledger
scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto
sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en
verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 ·
gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46
excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías
salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró;
y dos muertos nuevos los produjeron los propios arreglos (el blur apaga
focus-input-border; el settle desmonta el spinner de feed) — adjudicados con
su porqué. Doctrina en recipe-contract §4.
También: tres cifras de especificidad de next-features §12 recontadas (la
banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0);
y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el
velo en la celda), el comentario de listbox que mandaba pisar el privado
`--_listbox-max-height` apunta ahora al público, y quedan registrados en §13
los dos `header-z` con literal '2' y el spinner de media-player a 720ms
mientras el gemelo de feed lleva tokens.
Guards: censo global 43 % intacto · audit --only command+carousel PASS ·
eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest
eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs
0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier
limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en
HEAD y no se tocan).
Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el
arquetipo en fila+celda, y que soma lea el gap de un token.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **El arquetipo `item` de `table` vive en la fila Y en la celda** — el velo
cae en la celda bajo el puntero (`elementsFromPoint`, 2026-08-21). La
decisión de morfo del `hoverable` (§12.2) debe contemplar los dos
portadores.
- **Que soma lea de un token el gap entre diapositivas de `carousel` ** — hoy
es canal de valor inline y el trío `item-gap*` se retiró muerto; darle
superficie de tema toca soma (§13).
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
---
# REGISTRO DE LA SESIÓN DEL 2026-08-20/21 (histórico — no es la agenda)
feat(calendar-surface): la capa que ya existía, con nombre, casa y su agujero tapado
Firma 1 del acta, diseño presentado y firmado. **La medición desmontó el
encargo**: el handoff la vendía como una capa NUEVA de ~220 knobs, y la capa ya
existía de hecho, sin nombre. `--calendar-*` se emite en `:root` (76 claves) y
sus consumidores no acuñan NADA — medido: `range-calendar` 114 referencias
prestadas y 0 propias, `month-grid` 77/0, `year-grid` 77/0, y lo único ajeno
que leen es sistema puro (`--focus-ring-*`, `--state-hover`). Su 0 % era el
artefacto de `listbox` (§13), pero total.
**`lib/calendar-surface.css`** (hook `data-calendar-surface`):
- cuatro coordenadas por talla — `padding`, `control-size`, `day-size`,
`font-size` — xs..lg, porque la familia NO tiene xl, y con la celda DOS pasos
por debajo del bundle de control. Esa desviación estaba escondida en cuatro
bloques `[data-size]` idénticos, uno por receta, cada uno puenteando a un
privado con otro nombre; ahora se lee en un sitio.
- la FORMA del anillo de evento y de la marca de festivo.
**Capa HÍBRIDA, y es lo que la distingue de sus hermanas**: `list-surface` y
`viewport-placement` componen primitivos del sistema, así que declaran sus
públicos en el fichero y no tienen entrada de receta. Ésta no puede: su
vocabulario son 76 claves SEMÁNTICAS que un tema alcanza una a una por config,
así que la entrada `calendar` de `recipes/base.ts` pasa a ser la de la FAMILIA
y la capa posee sólo lo que una entrada de receta no sabe expresar.
**El defecto que la justificaba, medido**: `--calendar-event-shadow` y
`--calendar-day-holiday-shadow` se emitían con ámbito `[data-calendar]`
(audit B.2 los host-scopeó por buenas razones) mientras `range-calendar`,
`month-grid` y `year-grid` los leían desde hosts que nunca llevan ese atributo:
variable VACÍA, `box-shadow` inválido en computed, **el anillo sema de
`commit-select` / `commit-set` no pintaba jamás en tres componentes**. Un token
prestado cuyo ÁMBITO no te cubre no es un préstamo, es un agujero silencioso, y
ningún guard lo veía. Ahora la forma vive en la capa y el acento entra por
`--_calendar-surface-accent`, que cada superficie alimenta con su propio
forward de paleta THM-2.
**Siete wrappers estampan, no cuatro** — y esto casi se me cuela: `DatePicker`
y `DateRangePicker` renderizan la superficie soma por sus PROPIOS wrappers
(`date-picker-calendar`, `-month-view`, `-year-view`,
`date-range-picker-calendar`) y un panel portalado no hereda nada del root del
picker. Con sólo los cuatro standalone sellando, ambos quedaban con
`--calendar-padding` VACÍA y el panel a padding 0 (medido). La tentación era
enganchar la capa a las cuatro identidades de componente: eso viola la regla 1
de capas compartidas, y la respuesta correcta es un sello por wrapper.
computed 0 diffs en range-calendar (19.285 valores) · month-grid (3.451) ·
year-grid (3.451) · date-picker (464) · date-range-picker (406).
`calendar` da 12, y son del INSTRUMENTO: dos corridas del MISMO
código dan 24 en los mismos nodos y las mismas dos propiedades.
Los «missing node» son el propio sello entrando en la clave.
**Una incidencia nueva, medida y NO arreglada aquí** (§13): el font-size de los
selectores month/year es una moneda al aire —
`[data-calendar-month-select][data-button]` (0,2,0) empata con
`[data-popover-trigger]:not([data-archetype='field-trigger'])` (0,2,0), la
MISMA regla de popover que dejó muerto el cromo de `gradient-picker`, y gana la
hoja que cargue después: 16px o 14px según la recarga. Arreglarlo fija el píxel
en un lado ⇒ decisión.
De paso, `calendar-select.css` deja de puentear un privado que sólo
`[data-calendar]` declaraba: en range / date-range corría SIEMPRE por el
fallback, clavado a md fuera cual fuera la talla.
**El censo deja de penalizar hacer lo correcto**: `LAYER_VOCABULARY` en
`theming-census.ts`, mismo precedente que D-TH.2-b con `--style-*`. Global
43 % → **45 %**, `calendar` 75 % → **84 %**. `list-surface` NO se registra: sus
consumidores puentean por privados, otra forma, y mueve diez componentes de
golpe. Y aparece el techo de debajo, anotado: a los tres consumidores sólo les
quedan los forwards de paleta THM-2 —que el censo cuenta como `private` en TODO
el catálogo— así que siguen leyendo 0 %.
`recipe-css-contract` aprende que una CAPA también declara públicos (antes sólo
miraba la receta, y una capa que comparte prefijo con un componente la hacía
fallar). Sin debilitarla: un nombre que no declara nadie sigue en rojo.
eidos-lint 0 invalid (calendar 29/8 · range-calendar 41/12 · los grids 23/5) ·
audit --only calendar PASS · vitest eidos 434/435 (el rojo conocido) ·
rtl 0/181 · docs 0/813 · check 0 errores en tocados · prettier: revertido el
reformateo en masa que se coló en cuatro README, el test y el censo (churn
ajeno, no mío)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## EJECUTADO 2026-08-21 — la capa `calendar-surface` (firmada y medida)
**La medición cambió el encargo.** El handoff la vendía como «una capa nueva,
~220 knobs, 43 % → ~48 %». No lo era: la capa **ya existía de hecho** , sin
nombre ni casa. `--calendar-*` se emite en `:root` (76 claves) y sus
consumidores **no acuñan NADA** — `range-calendar` 114 referencias prestadas y
0 propias, `month-grid` 77/0, `year-grid` 77/0, y lo único ajeno que leen es
sistema puro (`--focus-ring-*`, `--state-hover` ). Su 0 % era el artefacto de
`listbox` (§13) pero TOTAL.
**Lo que se escribió**: `lib/calendar-surface.css` con el hook
`data-calendar-surface` , cuatro coordenadas por talla (`padding`,
`control-size` , `day-size` , `font-size` , xs..lg — la familia **no tiene xl** , y
la celda va DOS pasos por debajo del bundle de control, deviación que ahora se
lee en un sitio en vez de esconderse en cuatro bloques `[data-size]` idénticos)
y la FORMA del anillo de evento. El vocabulario **se queda en la entrada
`calendar` de la receta**, que pasa a ser la de la FAMILIA: ésta es una capa
HÍBRIDA y es lo que la distingue de `list-surface` / `viewport-placement` , que
componen primitivos y no tienen entrada de receta (76 claves semánticas tienen
que seguir siendo alcanzables una a una por config).
**El defecto que la justificó, medido**: `--calendar-event-shadow` y
`--calendar-day-holiday-shadow` se emitían con ámbito `[data-calendar]` y los
otros tres los leían desde hosts que nunca llevan ese atributo → variable
VACÍA, `box-shadow` inválido en computed, **el anillo sema no pintaba jamás en
tres componentes**. Ahora la forma vive en la capa y el acento entra por
`--_calendar-surface-accent` , que cada superficie alimenta con su forward de
paleta THM-2.
⚠️ **Lo que casi se me cuela, y la lección** : estampar el hook sólo en los
cuatro wrappers standalone dejaba a `DatePicker` y `DateRangePicker` con
`--calendar-padding` VACÍA y el panel a padding 0 — renderizan la superficie
soma por sus PROPIOS wrappers (`date-picker-calendar`, `-month-view` ,
`-year-view` , `date-range-picker-calendar` ) y un panel portalado no hereda
nada. **Son SIETE wrappers, no cuatro.** La tentación era enganchar la capa a
las cuatro identidades de componente; eso viola la regla 1 de capas
compartidas, y la respuesta correcta es un sello por wrapper.
**El censo aprendió a no penalizar**: `LAYER_VOCABULARY` en
`theming-census.ts` (mismo precedente que D-TH.2-b con `--style-*` ). Global
43 % → **45 %** , `calendar` 75 % → **84 %** . Los tres consumidores **siguen
leyendo 0 %**, y es honesto: con el vocabulario de la capa fuera del
denominador sólo les quedan los forwards de paleta THM-2 (que el censo cuenta
como `private` en TODO el catálogo) y literales de layout. Reclasificar el
forward de paleta es la misma pregunta un piso más abajo — anotada en §13.
`list-surface` NO se registró: sus consumidores puentean por privados, otra
forma, y mueve diez componentes de golpe.
uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4
Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree
con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba
más dura que la del autor), sonda x2 por componente para fijar el suelo de
ruido. 34 hipótesis · 26 refutadas · 8 reales.
Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs;
command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 ·
listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen
idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens
huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano»
de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación;
eidos-lint 0 invalid.
Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command
8.091 y carousel 2.842 valores, 0 diffs):
1. command: el re-point de `--command-radius` dentro del Dialog era una
declaración muerta con comentario falso — la misma regla pone el radio a 0
y el input lee `--command-input-radius`, nunca este token (medido:
`--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px`
movía la paleta inline y no la del dialog). Retirado; comentarios y README
reescritos con lo medido.
2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo
mientras la horizontal leía `active-indicator-scale` — el token alcanzaba
media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora
lo leen las dos.
3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap`
INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por
CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y
las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es
la prueba. Canal de valor de soma, como --gp-current-gradient. Censo
carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto
(5.190 · 2.102).
4. table: `striped-row-bg` no alcanza NADA en la demo publicada —
`:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos
quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel →
PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`);
adjudicado en el ledger mientras tanto.
El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas
medidas, y la cuarta era de la sonda:
- el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input
de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el
token de reposo leía muerto (era el «falso negativo sin causa» de §13);
- el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de
`{c}-root` no lo recibían;
- `::before`/`::after` eran invisibles (el aro de buffering, el spinner);
- la no-determinación de feed no era una animación sin localizar: era la demo
aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma
`commit-settle` anima box-shadow sobre el nodo medido. Con la espera de
asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas.
Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y
que carousel convirtió en patrón — un estilo inline de otra capa es invisible
para todo análisis estático): `npm run theming:sentinel -- <c> <url>`
(scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en
todos los nodos del componente, pseudos, pase de hover, settle) + ledger
scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto
sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en
verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 ·
gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46
excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías
salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró;
y dos muertos nuevos los produjeron los propios arreglos (el blur apaga
focus-input-border; el settle desmonta el spinner de feed) — adjudicados con
su porqué. Doctrina en recipe-contract §4.
También: tres cifras de especificidad de next-features §12 recontadas (la
banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0);
y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el
velo en la celda), el comentario de listbox que mandaba pisar el privado
`--_listbox-max-height` apunta ahora al público, y quedan registrados en §13
los dos `header-z` con literal '2' y el spinner de media-player a 720ms
mientras el gemelo de feed lleva tokens.
Guards: censo global 43 % intacto · audit --only command+carousel PASS ·
eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest
eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs
0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier
limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en
HEAD y no se tocan).
Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el
arquetipo en fila+celda, y que soma lea el gap de un token.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## EJECUTADO 2026-08-21 — revisión adversarial de F2-A (§7.7) + guard R-5.4
Molde Sidebar, medición propia contra worktree con solo el CSS revertido a la
base del bloque. **34 hipótesis · 26 refutadas · 8 reales.** Refutado: el
«default idéntico» aguanta en los ocho (0 diffs; los 3 de tree-grid y los 5 de
feed son del instrumento, idénticos corriendo dos veces el mismo código), 0
tokens huérfanos de 336, el bundle ES 1:1 con los primitivos, el «verificado a
mano» de gradient-picker era verdad. Los 8 reales: ** (1)** el re-point de
`--command-radius` en el Dialog era declaración muerta con comentario falso —
retirado, 0 diffs; ** (2)** el `2.25` vertical del carrusel iba a pelo y
`active-indicator-scale` solo alcanzaba la horizontal — tokenizado, 0 diffs;
**(3)** el trío `item-gap*` de carousel no podía ganar al `gap` INLINE de soma
— retirado, 0 diffs (canal de valor, como `--gp-current-gradient` ); ** (4)** el
`striped` de table es inerte con RowDetail (parity de `:nth-of-type` ) —
PENDIENTE DE FIRMA; ** (5-7)** el instrumento tenía 22 falsos negativos de 26
(clic-foco en el input · override solo en `[data-{c}]` · pseudos invisibles) y
la no-determinación de feed era la demo cargando (`commit-settle` sobre
`[data-busy]` ) — las cuatro causas arregladas en `theming-sentinel.ts` y la
sonda; ** (8)** tres cifras de especificidad del registro §12 estaban desviadas
en uno y el arquetipo de la fila de table vive TAMBIÉN en la celda —
corregidas. **R-5.4 nace** : `npm run theming:sentinel -- <c> <url>` , ledger
`theming-sentinel-exceptions.ts` con una razón medida por token (46
excepciones en los ocho, cinco entradas mías salieron STALE y las borró el
propio guard), doctrina en recipe-contract §4. Dos hallazgos los produjeron
los propios arreglos: el blur apaga `focus-input-border` (adjudicado) y la
espera de asentado desmonta el spinner de feed (adjudicado). Censo tras la
retirada: carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 %
intacto.
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Lo que sigue es el detalle de cómo se llegó aquí: las firmas, el codemod, el
guard, y el bloque componente a componente. Se conserva porque cada decisión
lleva su porqué medido, pero **la agenda es lo de arriba** .
docs(theming): el plan del eje theme-reach — medir qué alcanza un tema, y corregir componente a componente
El autor, al ver que el radio del trigger del nav vivía en un privado clavado a
--radius-default: «¿los componentes son themables? si no lo son, es un error
como framework». Lo es. La doctrina ya exige que cada receta declare sus knobs
en recipes/base.ts (recipe-contract §1, theming §6), pero R-1…R-4 sólo
comprueban «sin literales», no «alcanzable por un tema»: una receta con todo en
var(--radius-md) y privados pasa component:audit en PASS y sólo se puede temar
moviendo el sistema entero.
Medido, no opinado — scripts/theming-census.ts (instrumento, NO guard): de 5.205
knobs de apariencia en 162 recetas, 1.621 (33 %) pasan por un token público del
componente; 1.880 atan directo a un primitivo global, 856 a privados, 614 son
literales; 62 componentes no tienen una sola entrada en el contrato; 59 tienen
alcance < 20 %; 6 al 100 %. navigation-menu, tras todo el día de hoy, 44 %.
El plan (PLAN-theming.md): §1 el censo por familia y por componente (tabla
regenerable, no editable) · §2 los cuatro ejes de «personalizable» (tokens ·
talla · color/variante · estados) · §3 la regla R-5 «alcance de tema» para
component-audit, con su válvula de excepción · §4 ocho decisiones D-TH para el
autor (R-5 dura · perímetro de knob · WIP · orden · DEFAULT IDÉNTICO · normalizar
nombres de slot, que hoy incumplen tabs y el propio nav · cuándo gradúa a error ·
panel de temas) · §5 fases F0–F4 con gates · §6 deuda transversal · §7 el
PROTOCOLO DE VERIFICACIÓN por componente, porque «lo ejecutará Opus, y Opus falla
mucho»: cinco preguntas, medir ANTES (computed por parte/estado/talla, sonda
headless desde la raíz, fuera de callbacks de MutationObserver), editar sólo la
forma firmada, medir DESPUÉS (diff de computed = 0, prueba de CENTINELA por cada
token nuevo, desde el píxel hacia arriba, registro de animationstart/end),
guards por fichero, un componente = un commit con sus artefactos, y revisión
adversarial por bloque. Cada paso tiene un artefacto; sin artefacto no está hecho.
El instrumento se probó por mutación antes de creerle, y falló la primera vez:
no contaba una regla de una sola línea (`[x] { padding-inline: 8px; }`), así que
meter un literal no movía la cifra. Regex endurecido; ahora 6→7→8 con una y dos
mutaciones. Las cifras del plan son las del instrumento final, y el handoff
(CONTINUE-theming.md) obliga a reproducirlas antes de seguir.
Nada firmado, nada construido. Gates del commit: docs:check 0/642 · prettier del
script limpio · tsc del script sin errores · el plan cita ficheros que existen
(los once, comprobados).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## EJECUTADO 2026-08-20 — vocabulario de tokens: D-TH.6 (codemod) + R-5.3 (guard)
docs(theming): mañana lo primero — el vocabulario de tokens: D-TH.6 (codemod) y R-5.3 (guard de gramática)
La conversación de hoy destapó que el backfill está escribiendo canon sobre un
catálogo que habla al revés: el vocabulario de nombres existe (theming §6.7 +
recipe-contract §1) pero no tiene guard, y la medición fundacional del
2026-07-01 ya dijo lo que le pasa a un canon defendido por prosa. Medido ahora
con `scripts/__names-inventory.ts` (semilla del `--names` del censo): sobre
3.333 claves públicas hay 370 desviadas en 68 componentes — 125 con el
modificador detrás, 215 con `color` como slot o segmento, 30 con ambas. Y dos
falsos amigos que NO se renombran de oficio: `*-focus-ring-color` espeja la
familia del sistema, y los `orb-color-*` de aura usan color como sustantivo.
El handoff pone el bloque como primera tarea, con el orden que evita el error
clásico: primero la FIRMA (D-TH.6, una decisión con el inventario delante),
luego el codemod value-preserving con el triple muro del precedente px/py
(renombres 1:1 en generated, censo idéntico, computed intacto en tres sondas),
y sólo entonces el guard — R-5.3 como gramática y no como lista, porque el
vocabulario de tokens es compositivo donde el de eventos era cerrado: la talla
contra las siete canónicas, el modificador cerrado y delante, el slot contra
sus tres fuentes, y la parte contra el morfo compilado como ya hace eidos-lint.
En `error` directo: tras el codemod no hay deuda que tolerar, y la rampa warn
es como estos guards mueren. Con muta-prueba antes de darlo por bueno.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Por qué antes que nada** (conversación 2026-08-20): el canon de nombres
existe (theming §6.7 slots + recipe-contract §1 dimensionales) pero **no tiene
guard**, y la medición del 2026-07-01 ya demostró que canon sin guard deriva
30-85 %. Está derivando: el backfill de ayer escribió la forma DOCUMENTADA
(modificador delante, 36 claves) mientras el catálogo habla al revés — cada
componente que se corrija sin firmar esto ensancha la brecha. El guard de
eventos (`eidos-event-vocabulary.ts`) es el precedente: nació de un
`commit-resize` muerto tres meses en una receta; R-4.4 es el otro (una regla de
nombres ya guardada, deuda muerta «en el mismo pass, sin allowlist»).
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**FIRMADO 2026-08-20 — el slot de tinta es `fg` ; `color` como slot MUERE.**
La sesión del 20 leyó lo que la del 19 no había leído (`arts/color`,
`architecture/eidos.md` entero, motion §17, §25/§38) y encontró que la
pregunta central no era «normalizar hacia lo documentado» sino una
CONTRADICCIÓN entre dos doctrinas: theming §6.7 r7 (`fg`) contra el principio
de plataforma del px/py («el token se llama como la propiedad»: `color` ). El
autor adjudicó ** `fg` **: el principio de plataforma gobierna los ejes
DIMENSIONALES, no la pareja `bg` /`fg` (si la gobernara, `bg` sería
`background-color` ); `color` es la palabra más sobrecargada del sistema
(`--color-*`, `data-color` , 9 roles, `arts/color` ); `on-fg` compone; Chakra
v3/Panda hablan la pareja.
**Inventario CORREGIDO 2026-08-20** (instrumental: los `scripts/__names-*.ts`
de esta sesión — `census` , `slots` , `owners` , `audit7` , `audit7b` ; el exacto y
regenerable lo produce `--names` en el paso 1). Sobre **3.333 claves públicas** ,
**301 desviadas en 66 componentes** — 193 con `color` como slot, 78 con el
modificador DETRÁS a nivel de receta, 30 con ambas. La semilla
`__names-inventory.ts` decía 370 porque contaba como desviadas **47 claves
`{rol}-{slot-de-rol}` que son CANÓNICAS** (`button.primary-solid-hover`,
`toggle.palette-hover` … — `COLOR_ROLE_SLOTS` pone el modificador detrás POR
CONSTRUCCIÓN) — un codemod sobre las 370 las habría roto. Adopción viva:
196 `-color` contra 55 `-fg` (las `fg` son mayormente las del backfill de este
eje). Peores: tag-group 22 · toast 15 · field 13 · calendar 13 · tabs 12.
**Tres familias, tres gramáticas** (el guard codifica las tres): rol/paleta =
modificador DETRÁS (canon) · sistema (`--state-hover`, `--opacity-hover` ) =
detrás, fuera del alcance del guard · recipe-level = §6.7 r7 (delante:
`hover-bg` , 13 claves conformes contra 22 `bg-hover` ).
**Falsos amigos (22) — FIRMADOS en el acta**: `*-focus-ring-color` (3, espeja
la familia del SISTEMA) · `aura.orb-color-*` (6, color como sustantivo del
orbe) · `gradient-builder.stop-color-*` (4, **stop-color ES la parte** —
verificado: `gradient-builder-stop-color.svelte` + parts DOM) → **se quedan** ·
los 7 con modificador «fuera de vocabulario» resultaron ser DOS clases que el
morfo ya resuelve (valores de `data-state` /ejes declarados: `active` , `partial` ,
`read` , `failed` ; y `current` = aria, que entra al vocabulario universal) más
una de pseudo-partes (`played`/`buffered`) → **se renombran** (destinos en el
acta) · `background.scrim-color-on-{dark,light}` (2, chocaban con el prefijo
`on-` ) → ** `scrim-fg-over-{dark,light}` **.
**Hovers neutros — firmado: NO se renombran, MIGRAN**: §38 + R-4.3 deprecan el
hover neutro por componente (es la capa `--state-*` ). `dropdown-menu.item-bg-hover` ,
`context-menu.item-bg-hover` , `scroll-area.track/thumb-bg-hover` ,
`splitter.handle-bg-hover` … la firma 3 del acta ordena su migración a la capa
de estado (captura + diff explicado por componente). El codemod los EXCLUYE y
el `--names` los lista aparte como cola de esa migración.
**LOS CUATRO PASOS ESTÁN HECHOS** (`f09e04fab` acta · `bd916ef3f` codemod ·
`7781d6e4c` guard + doctrina, sin pushear). Lo que queda del bloque, y sólo
esto:
- **El tercer muro espera a la firma 3.** El tipo en `defineRecipes` (molde
`PhysicalAxisKey` ) está escrito y probado: dispara sobre **17 claves** , que
son los hovers neutros con `color` en cola de migración. Meterlo hoy rompe
`npm run check` a todo el mundo. Entra cuando la migración las vacíe — dos
líneas: una rama `ColorSlotKey` y las tres excepciones firmadas
(`*focus-ring-color`, `orb-color-*` , `stop-color-*` ) deletreadas.
- **`__names-inventory.ts` quedó superado** por `theming-census --names`
(contaba 370 porque metía las 47 role-slot). No se borra sin que lo digas.
El registro de los pasos, para quien audite después:
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Los pasos, en orden y con su gate (**el paso 0 murió el 2026-08-20: D-TH.6
está firmada COMPLETA** — ver §«Firmas del 2026-08-20»; la gramática ejecutable
es: slot `fg` · delante lo interactivo, detrás lo dimensional/contextual ·
modificador ∈ universal (+`current`) ∪ `data-state` /ejes del morfo · rol/paleta
detrás · hovers neutros excluidos · renombres nominales de los ex-falsos
amigos en el acta):
docs(theming): mañana lo primero — el vocabulario de tokens: D-TH.6 (codemod) y R-5.3 (guard de gramática)
La conversación de hoy destapó que el backfill está escribiendo canon sobre un
catálogo que habla al revés: el vocabulario de nombres existe (theming §6.7 +
recipe-contract §1) pero no tiene guard, y la medición fundacional del
2026-07-01 ya dijo lo que le pasa a un canon defendido por prosa. Medido ahora
con `scripts/__names-inventory.ts` (semilla del `--names` del censo): sobre
3.333 claves públicas hay 370 desviadas en 68 componentes — 125 con el
modificador detrás, 215 con `color` como slot o segmento, 30 con ambas. Y dos
falsos amigos que NO se renombran de oficio: `*-focus-ring-color` espeja la
familia del sistema, y los `orb-color-*` de aura usan color como sustantivo.
El handoff pone el bloque como primera tarea, con el orden que evita el error
clásico: primero la FIRMA (D-TH.6, una decisión con el inventario delante),
luego el codemod value-preserving con el triple muro del precedente px/py
(renombres 1:1 en generated, censo idéntico, computed intacto en tres sondas),
y sólo entonces el guard — R-5.3 como gramática y no como lista, porque el
vocabulario de tokens es compositivo donde el de eventos era cerrado: la talla
contra las siete canónicas, el modificador cerrado y delante, el slot contra
sus tres fuentes, y la parte contra el morfo compilado como ya hace eidos-lint.
En `error` directo: tras el codemod no hay deuda que tolerar, y la rampa warn
es como estos guards mueren. Con muta-prueba antes de darlo por bueno.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
1. ** `--names` en el censo**: el inventario exacto por clase de desviación,
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
regenerable, con las 47 role-slot reconocidas como canónicas, los falsos
amigos resueltos por el acta (los 3 grupos que se quedan excluidos; los 4
renombrados contados como desviación con su destino) y los hovers neutros
listados APARTE (van a la firma 3, no al codemod). Muta-prueba del
instrumento: 3 desviadas conocidas salen, 3 role-slot NO salen.
docs(theming): mañana lo primero — el vocabulario de tokens: D-TH.6 (codemod) y R-5.3 (guard de gramática)
La conversación de hoy destapó que el backfill está escribiendo canon sobre un
catálogo que habla al revés: el vocabulario de nombres existe (theming §6.7 +
recipe-contract §1) pero no tiene guard, y la medición fundacional del
2026-07-01 ya dijo lo que le pasa a un canon defendido por prosa. Medido ahora
con `scripts/__names-inventory.ts` (semilla del `--names` del censo): sobre
3.333 claves públicas hay 370 desviadas en 68 componentes — 125 con el
modificador detrás, 215 con `color` como slot o segmento, 30 con ambas. Y dos
falsos amigos que NO se renombran de oficio: `*-focus-ring-color` espeja la
familia del sistema, y los `orb-color-*` de aura usan color como sustantivo.
El handoff pone el bloque como primera tarea, con el orden que evita el error
clásico: primero la FIRMA (D-TH.6, una decisión con el inventario delante),
luego el codemod value-preserving con el triple muro del precedente px/py
(renombres 1:1 en generated, censo idéntico, computed intacto en tres sondas),
y sólo entonces el guard — R-5.3 como gramática y no como lista, porque el
vocabulario de tokens es compositivo donde el de eventos era cerrado: la talla
contra las siete canónicas, el modificador cerrado y delante, el slot contra
sus tres fuentes, y la parte contra el morfo compilado como ya hace eidos-lint.
En `error` directo: tras el codemod no hay deuda que tolerar, y la rampa warn
es como estos guards mueren. Con muta-prueba antes de darlo por bueno.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
2. **Codemod value-preserving** (molde: px/py del 2026-07-06 y su triple muro):
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`-color` → `-fg` (196 + 49 mediales, menos los 3 grupos que el acta deja
quedarse y los hovers neutros que migran aparte), los renombres nominales
del acta (rating-group · chat-message · breadcrumb · waveform ·
`scrim-fg-over-*` ), y modificador detrás → delante a nivel receta
(`bg-hover` → `hover-bg` , 22 claves); renombra la clave
en `recipes/base.ts` Y todos los consumidores (`var(--{c}-{clave})` en
css/svelte/ts/md — con `git ls-files` , no de memoria; los .md de HISTORIA
— changelog, errores-toxico, PLAN-affix/background — NO se reescriben),
regenera, y verifica: diff de `generated/` = **renombres 1:1** ,
docs(theming): mañana lo primero — el vocabulario de tokens: D-TH.6 (codemod) y R-5.3 (guard de gramática)
La conversación de hoy destapó que el backfill está escribiendo canon sobre un
catálogo que habla al revés: el vocabulario de nombres existe (theming §6.7 +
recipe-contract §1) pero no tiene guard, y la medición fundacional del
2026-07-01 ya dijo lo que le pasa a un canon defendido por prosa. Medido ahora
con `scripts/__names-inventory.ts` (semilla del `--names` del censo): sobre
3.333 claves públicas hay 370 desviadas en 68 componentes — 125 con el
modificador detrás, 215 con `color` como slot o segmento, 30 con ambas. Y dos
falsos amigos que NO se renombran de oficio: `*-focus-ring-color` espeja la
familia del sistema, y los `orb-color-*` de aura usan color como sustantivo.
El handoff pone el bloque como primera tarea, con el orden que evita el error
clásico: primero la FIRMA (D-TH.6, una decisión con el inventario delante),
luego el codemod value-preserving con el triple muro del precedente px/py
(renombres 1:1 en generated, censo idéntico, computed intacto en tres sondas),
y sólo entonces el guard — R-5.3 como gramática y no como lista, porque el
vocabulario de tokens es compositivo donde el de eventos era cerrado: la talla
contra las siete canónicas, el modificador cerrado y delante, el slot contra
sus tres fuentes, y la parte contra el morfo compilado como ya hace eidos-lint.
En `error` directo: tras el codemod no hay deuda que tolerar, y la rampa warn
es como estos guards mueren. Con muta-prueba antes de darlo por bueno.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
censo global IDÉNTICO (un rename no cambia alcance), sonda de computed en 3
componentes renombrados = **0 diffs** . Un commit, script commiteado como
registro.
3. **Guard R-5.3 en `component-audit`** — de **GRAMÁTICA** , no de lista (a
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
diferencia del de eventos, que valida pertenencia a un vocabulario cerrado),
y POR FAMILIA: `{rol|palette}-{slot-de-rol}` con modificador detrás
(`COLOR_ROLE_SLOTS`) ∪ recipe-level
docs(theming): mañana lo primero — el vocabulario de tokens: D-TH.6 (codemod) y R-5.3 (guard de gramática)
La conversación de hoy destapó que el backfill está escribiendo canon sobre un
catálogo que habla al revés: el vocabulario de nombres existe (theming §6.7 +
recipe-contract §1) pero no tiene guard, y la medición fundacional del
2026-07-01 ya dijo lo que le pasa a un canon defendido por prosa. Medido ahora
con `scripts/__names-inventory.ts` (semilla del `--names` del censo): sobre
3.333 claves públicas hay 370 desviadas en 68 componentes — 125 con el
modificador detrás, 215 con `color` como slot o segmento, 30 con ambas. Y dos
falsos amigos que NO se renombran de oficio: `*-focus-ring-color` espeja la
familia del sistema, y los `orb-color-*` de aura usan color como sustantivo.
El handoff pone el bloque como primera tarea, con el orden que evita el error
clásico: primero la FIRMA (D-TH.6, una decisión con el inventario delante),
luego el codemod value-preserving con el triple muro del precedente px/py
(renombres 1:1 en generated, censo idéntico, computed intacto en tres sondas),
y sólo entonces el guard — R-5.3 como gramática y no como lista, porque el
vocabulario de tokens es compositivo donde el de eventos era cerrado: la talla
contra las siete canónicas, el modificador cerrado y delante, el slot contra
sus tres fuentes, y la parte contra el morfo compilado como ya hace eidos-lint.
En `error` directo: tras el codemod no hay deuda que tolerar, y la rampa warn
es como estos guards mueren. Con muta-prueba antes de darlo por bueno.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`[variante-]?[modificador-]?[parte-]?[slot][-talla]?` donde talla ∈ las 7
canónicas, modificador ∈ vocabulario cerrado y DELANTE, slot ∈ (§6.7
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
recipe-level ∪ ejes dimensionales de recipe-contract §1), y la PARTE contra
docs(theming): mañana lo primero — el vocabulario de tokens: D-TH.6 (codemod) y R-5.3 (guard de gramática)
La conversación de hoy destapó que el backfill está escribiendo canon sobre un
catálogo que habla al revés: el vocabulario de nombres existe (theming §6.7 +
recipe-contract §1) pero no tiene guard, y la medición fundacional del
2026-07-01 ya dijo lo que le pasa a un canon defendido por prosa. Medido ahora
con `scripts/__names-inventory.ts` (semilla del `--names` del censo): sobre
3.333 claves públicas hay 370 desviadas en 68 componentes — 125 con el
modificador detrás, 215 con `color` como slot o segmento, 30 con ambas. Y dos
falsos amigos que NO se renombran de oficio: `*-focus-ring-color` espeja la
familia del sistema, y los `orb-color-*` de aura usan color como sustantivo.
El handoff pone el bloque como primera tarea, con el orden que evita el error
clásico: primero la FIRMA (D-TH.6, una decisión con el inventario delante),
luego el codemod value-preserving con el triple muro del precedente px/py
(renombres 1:1 en generated, censo idéntico, computed intacto en tres sondas),
y sólo entonces el guard — R-5.3 como gramática y no como lista, porque el
vocabulario de tokens es compositivo donde el de eventos era cerrado: la talla
contra las siete canónicas, el modificador cerrado y delante, el slot contra
sus tres fuentes, y la parte contra el morfo compilado como ya hace eidos-lint.
En `error` directo: tras el codemod no hay deuda que tolerar, y la rampa warn
es como estos guards mueren. Con muta-prueba antes de darlo por bueno.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`compileMorfo(morfo).parts` + la allowlist eidos-only (el mismo criterio que
`eidos-lint` ). Severidad ** `error` directo**: tras el codemod no hay deuda
que tolerar, y la rampa `warn` es como estos guards mueren. **Muta-prueba
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
obligatoria de tres caras** antes de darlo por bueno: `-bg-hover` rojo ·
`trigger-color` rojo · `primary-solid-hover` VERDE (memoria
`a-guard-that-inspects-nothing-passes` ).
docs(theming): mañana lo primero — el vocabulario de tokens: D-TH.6 (codemod) y R-5.3 (guard de gramática)
La conversación de hoy destapó que el backfill está escribiendo canon sobre un
catálogo que habla al revés: el vocabulario de nombres existe (theming §6.7 +
recipe-contract §1) pero no tiene guard, y la medición fundacional del
2026-07-01 ya dijo lo que le pasa a un canon defendido por prosa. Medido ahora
con `scripts/__names-inventory.ts` (semilla del `--names` del censo): sobre
3.333 claves públicas hay 370 desviadas en 68 componentes — 125 con el
modificador detrás, 215 con `color` como slot o segmento, 30 con ambas. Y dos
falsos amigos que NO se renombran de oficio: `*-focus-ring-color` espeja la
familia del sistema, y los `orb-color-*` de aura usan color como sustantivo.
El handoff pone el bloque como primera tarea, con el orden que evita el error
clásico: primero la FIRMA (D-TH.6, una decisión con el inventario delante),
luego el codemod value-preserving con el triple muro del precedente px/py
(renombres 1:1 en generated, censo idéntico, computed intacto en tres sondas),
y sólo entonces el guard — R-5.3 como gramática y no como lista, porque el
vocabulario de tokens es compositivo donde el de eventos era cerrado: la talla
contra las siete canónicas, el modificador cerrado y delante, el slot contra
sus tres fuentes, y la parte contra el morfo compilado como ya hace eidos-lint.
En `error` directo: tras el codemod no hay deuda que tolerar, y la rampa warn
es como estos guards mueren. Con muta-prueba antes de darlo por bueno.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
4. **Docs en el mismo pass** : recipe-contract §1 gana la fila del modificador
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
(hoy sólo la insinúa §6.7) y §4 la fila R-5.3; theming §6.7 nota fechada
con la firma de `fg` y el acotamiento del principio de plataforma a los
ejes dimensionales; T-TH.2 del plan se cierra.
docs(theming): mañana lo primero — el vocabulario de tokens: D-TH.6 (codemod) y R-5.3 (guard de gramática)
La conversación de hoy destapó que el backfill está escribiendo canon sobre un
catálogo que habla al revés: el vocabulario de nombres existe (theming §6.7 +
recipe-contract §1) pero no tiene guard, y la medición fundacional del
2026-07-01 ya dijo lo que le pasa a un canon defendido por prosa. Medido ahora
con `scripts/__names-inventory.ts` (semilla del `--names` del censo): sobre
3.333 claves públicas hay 370 desviadas en 68 componentes — 125 con el
modificador detrás, 215 con `color` como slot o segmento, 30 con ambas. Y dos
falsos amigos que NO se renombran de oficio: `*-focus-ring-color` espeja la
familia del sistema, y los `orb-color-*` de aura usan color como sustantivo.
El handoff pone el bloque como primera tarea, con el orden que evita el error
clásico: primero la FIRMA (D-TH.6, una decisión con el inventario delante),
luego el codemod value-preserving con el triple muro del precedente px/py
(renombres 1:1 en generated, censo idéntico, computed intacto en tres sondas),
y sólo entonces el guard — R-5.3 como gramática y no como lista, porque el
vocabulario de tokens es compositivo donde el de eventos era cerrado: la talla
contra las siete canónicas, el modificador cerrado y delante, el slot contra
sus tres fuentes, y la parte contra el morfo compilado como ya hace eidos-lint.
En `error` directo: tras el codemod no hay deuda que tolerar, y la rampa warn
es como estos guards mueren. Con muta-prueba antes de darlo por bueno.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Gates del bloque entero: censo global idéntico antes/después del codemod ·
suite eidos sin rojos nuevos · `component:audit` sin fallos nuevos fuera de
R-5.3 · `docs:check` 0 · `rtl:check` 0.
## Después — por dónde seguir
docs(theming): el plan del eje theme-reach — medir qué alcanza un tema, y corregir componente a componente
El autor, al ver que el radio del trigger del nav vivía en un privado clavado a
--radius-default: «¿los componentes son themables? si no lo son, es un error
como framework». Lo es. La doctrina ya exige que cada receta declare sus knobs
en recipes/base.ts (recipe-contract §1, theming §6), pero R-1…R-4 sólo
comprueban «sin literales», no «alcanzable por un tema»: una receta con todo en
var(--radius-md) y privados pasa component:audit en PASS y sólo se puede temar
moviendo el sistema entero.
Medido, no opinado — scripts/theming-census.ts (instrumento, NO guard): de 5.205
knobs de apariencia en 162 recetas, 1.621 (33 %) pasan por un token público del
componente; 1.880 atan directo a un primitivo global, 856 a privados, 614 son
literales; 62 componentes no tienen una sola entrada en el contrato; 59 tienen
alcance < 20 %; 6 al 100 %. navigation-menu, tras todo el día de hoy, 44 %.
El plan (PLAN-theming.md): §1 el censo por familia y por componente (tabla
regenerable, no editable) · §2 los cuatro ejes de «personalizable» (tokens ·
talla · color/variante · estados) · §3 la regla R-5 «alcance de tema» para
component-audit, con su válvula de excepción · §4 ocho decisiones D-TH para el
autor (R-5 dura · perímetro de knob · WIP · orden · DEFAULT IDÉNTICO · normalizar
nombres de slot, que hoy incumplen tabs y el propio nav · cuándo gradúa a error ·
panel de temas) · §5 fases F0–F4 con gates · §6 deuda transversal · §7 el
PROTOCOLO DE VERIFICACIÓN por componente, porque «lo ejecutará Opus, y Opus falla
mucho»: cinco preguntas, medir ANTES (computed por parte/estado/talla, sonda
headless desde la raíz, fuera de callbacks de MutationObserver), editar sólo la
forma firmada, medir DESPUÉS (diff de computed = 0, prueba de CENTINELA por cada
token nuevo, desde el píxel hacia arriba, registro de animationstart/end),
guards por fichero, un componente = un commit con sus artefactos, y revisión
adversarial por bloque. Cada paso tiene un artefacto; sin artefacto no está hecho.
El instrumento se probó por mutación antes de creerle, y falló la primera vez:
no contaba una regla de una sola línea (`[x] { padding-inline: 8px; }`), así que
meter un literal no movía la cifra. Regex endurecido; ahora 6→7→8 con una y dos
mutaciones. Las cifras del plan son las del instrumento final, y el handoff
(CONTINUE-theming.md) obliga a reproducirlas antes de seguir.
Nada firmado, nada construido. Gates del commit: docs:check 0/642 · prettier del
script limpio · tsc del script sin errores · el plan cita ficheros que existen
(los once, comprobados).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
1. `node --import tsx/esm scripts/theming-census.ts` — debe dar **162 recetas ·
docs(theming): mañana lo primero — el vocabulario de tokens: D-TH.6 (codemod) y R-5.3 (guard de gramática)
La conversación de hoy destapó que el backfill está escribiendo canon sobre un
catálogo que habla al revés: el vocabulario de nombres existe (theming §6.7 +
recipe-contract §1) pero no tiene guard, y la medición fundacional del
2026-07-01 ya dijo lo que le pasa a un canon defendido por prosa. Medido ahora
con `scripts/__names-inventory.ts` (semilla del `--names` del censo): sobre
3.333 claves públicas hay 370 desviadas en 68 componentes — 125 con el
modificador detrás, 215 con `color` como slot o segmento, 30 con ambas. Y dos
falsos amigos que NO se renombran de oficio: `*-focus-ring-color` espeja la
familia del sistema, y los `orb-color-*` de aura usan color como sustantivo.
El handoff pone el bloque como primera tarea, con el orden que evita el error
clásico: primero la FIRMA (D-TH.6, una decisión con el inventario delante),
luego el codemod value-preserving con el triple muro del precedente px/py
(renombres 1:1 en generated, censo idéntico, computed intacto en tres sondas),
y sólo entonces el guard — R-5.3 como gramática y no como lista, porque el
vocabulario de tokens es compositivo donde el de eventos era cerrado: la talla
contra las siete canónicas, el modificador cerrado y delante, el slot contra
sus tres fuentes, y la parte contra el morfo compilado como ya hace eidos-lint.
En `error` directo: tras el codemod no hay deuda que tolerar, y la rampa warn
es como estos guards mueren. Con muta-prueba antes de darlo por bueno.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
5.203 knobs · 1.841 públicos (37 %) · 56 sin contrato** (antes del codemod;
tras él, el MISMO alcance con nombres nuevos). Si no cuadra, alguien tocó
recetas: regenerar el informe (`--report`) antes de nada.
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
2. Abrir la ficha del componente que toque y leer su ** §5 Veredicto**: dice qué
de la propuesta es correcto, qué está mal y qué espera firma. Está verificado
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
contra el CSS; la §4 generada NO se sigue a ciegas. **Ojo** : los veredictos
se escribieron ANTES del acta del 2026-08-20 — sus «espera firma» se cruzan
con §«Firmas del 2026-08-20» (la mayoría ya están resueltos: calendar,
Field, hover→estado, D-TH.2) y sus nombres propuestos se pasan por la
gramática firmada (p. ej. el `guide-color` de la fila tree-grid de la cola
es `guide-fg` ).
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
3. Ejecutar con el protocolo §7 entero. **Un componente = un commit.**
docs(theming): el plan del eje theme-reach — medir qué alcanza un tema, y corregir componente a componente
El autor, al ver que el radio del trigger del nav vivía en un privado clavado a
--radius-default: «¿los componentes son themables? si no lo son, es un error
como framework». Lo es. La doctrina ya exige que cada receta declare sus knobs
en recipes/base.ts (recipe-contract §1, theming §6), pero R-1…R-4 sólo
comprueban «sin literales», no «alcanzable por un tema»: una receta con todo en
var(--radius-md) y privados pasa component:audit en PASS y sólo se puede temar
moviendo el sistema entero.
Medido, no opinado — scripts/theming-census.ts (instrumento, NO guard): de 5.205
knobs de apariencia en 162 recetas, 1.621 (33 %) pasan por un token público del
componente; 1.880 atan directo a un primitivo global, 856 a privados, 614 son
literales; 62 componentes no tienen una sola entrada en el contrato; 59 tienen
alcance < 20 %; 6 al 100 %. navigation-menu, tras todo el día de hoy, 44 %.
El plan (PLAN-theming.md): §1 el censo por familia y por componente (tabla
regenerable, no editable) · §2 los cuatro ejes de «personalizable» (tokens ·
talla · color/variante · estados) · §3 la regla R-5 «alcance de tema» para
component-audit, con su válvula de excepción · §4 ocho decisiones D-TH para el
autor (R-5 dura · perímetro de knob · WIP · orden · DEFAULT IDÉNTICO · normalizar
nombres de slot, que hoy incumplen tabs y el propio nav · cuándo gradúa a error ·
panel de temas) · §5 fases F0–F4 con gates · §6 deuda transversal · §7 el
PROTOCOLO DE VERIFICACIÓN por componente, porque «lo ejecutará Opus, y Opus falla
mucho»: cinco preguntas, medir ANTES (computed por parte/estado/talla, sonda
headless desde la raíz, fuera de callbacks de MutationObserver), editar sólo la
forma firmada, medir DESPUÉS (diff de computed = 0, prueba de CENTINELA por cada
token nuevo, desde el píxel hacia arriba, registro de animationstart/end),
guards por fichero, un componente = un commit con sus artefactos, y revisión
adversarial por bloque. Cada paso tiene un artefacto; sin artefacto no está hecho.
El instrumento se probó por mutación antes de creerle, y falló la primera vez:
no contaba una regla de una sola línea (`[x] { padding-inline: 8px; }`), así que
meter un literal no movía la cifra. Regex endurecido; ahora 6→7→8 con una y dos
mutaciones. Las cifras del plan son las del instrumento final, y el handoff
(CONTINUE-theming.md) obliga a reproducirlas antes de seguir.
Nada firmado, nada construido. Gates del commit: docs:check 0/642 · prettier del
script limpio · tsc del script sin errores · el plan cita ficheros que existen
(los once, comprobados).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## PRIMERA POSICIÓN — repaso de los 7 ya corregidos contra la gramática nueva
Encargo del autor (2026-08-20): revisar lo ya ejecutado por si incumple las
reglas nuevas. **Auditados los 7 con `scripts/__names-audit7.ts` y
`__names-audit7b.ts` ** (claves públicas + privados + consumo en css/README).
Resultado: **6 de 7 limpios, 1 hallazgo real** .
| componente | claves | veredicto |
| --------------------- | -----: | ----------------------------------------------------------------- |
| `combobox` | 106 | ✅ limpio — ya habla `fg` , sin modificador detrás, privados sanos |
| `natural-time-picker` | 62 | ✅ limpio |
| `date-range-picker` | 24 | ✅ limpio |
| `time-range-picker` | 22 | ✅ limpio |
| `proof-of-human` | 20 | ✅ limpio |
| `time-picker` | 16 | ✅ limpio |
| `gradient-builder` | 72 | ⚠ **1 corrección** (abajo) |
Que los 6 salgan limpios NO es casualidad ni suerte: el backfill de este eje
venía escribiendo `fg` (55 de las ~55 claves `-fg` del catálogo son suyas),
que es exactamente lo que la firma ratificó. La firma **valida** el trabajo
hecho, no lo invalida.
**La corrección — `gradient-builder.checker-color` → `checker-fg` ** (1 clave,
consumida 4 veces en `gradient-builder.css:29-32` ). Es el color de los cuadros
del damero de transparencia: `color` ahí es **slot** , no sustantivo — cae de
lleno en la regla firmada. Las otras 4 claves que el audit marca
(`stop-color-title-font-size`, `-font-weight` , `-fg` , `stop-color-sliders-gap` )
son **falso amigo verificado** : `stop-color` es la PARTE
(`gradient-builder-stop-color.svelte`, `[data-gradient-builder-stop-color-*]` ),
y una de ellas ya termina en `-fg` correctamente. **No se tocan.**
Ejecución: va DENTRO del codemod del paso 2 (misma mecánica, mismos gates), no
como commit aparte — es una clave, y sacarla del codemod duplicaría la
verificación. Si el codemod se retrasa por las firmas pendientes, se ejecuta
sola con el protocolo §7.
docs(theming): el handoff, reescrito para que otra sesión arranque sin arqueología
La sesión llega llena. El handoff había crecido por acumulación —cada bloque
añadía su sección— y para saber qué hacer había que leerlo entero y deducirlo.
Ahora la AGENDA va arriba y el registro histórico abajo, separado por su propio
encabezado.
Arriba: qué comprobar en los primeros cinco minutos (las dos cifras que deben
cuadrar, el dev server antes de medir, leer el veredicto §5); tres opciones con
recomendación —revisión adversarial de F2-A, el diseño de `calendar-surface`, o
seguir la cola por alcance, con la cola ya recalculada—; el protocolo en diez
pasos; y **lo que este bloque enseñó**, que es lo que evita repetir el día:
el veredicto orienta pero la medición decide (tres de ocho tenían un error de
lectura) · un token que no mueve nada miente, y lo que procede es retirar la
declaración muerta · un alias puro se borra, no se renombra · lo que la capa
posee el consumidor no lo acuña · y la sonda miente de tres maneras
distintas, así que ante un diff inesperado se corre DOS VECES sobre el mismo
código antes de sospechar del cambio.
El plan §8 gana la entrada de la sesión con las cifras y los commits, y su
cabecera de estado pasa a 43 %.
Estado que hereda la sesión siguiente: alcance global 43 % (era 33 % al abrir el
eje), 15 componentes con contrato, 49 sin él, 7 al 100 %, gramática con 0
desviadas y guard en `error`. 29 commits, sin pushear.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## BLOQUE F2-A — CERRADO 2026-08-21 (preparado el 20, ejecutado el 21)
**Los ocho, con su commit y su alcance final:**
| componente | antes → después | commit |
| ----------------- | --------------: | ----------- |
| pieza 0 (censo) | 37 % → 38 % | `bd032534b` |
| `command` | 0 % → 98 % | `4ddea7fe2` |
| `table` | 0 % → 86 % | `564133b48` |
| `media-player` | 0 % → 88 % | `b7a4cef08` |
| `tree-grid` | 0 % → 95 % | `9748733ad` |
| `gradient-picker` | 0 % → 88 % | `d177ee331` |
| `listbox` | 0 % → 68 % | `3b325c439` |
| `carousel` | 0 % → 77 % | `4cab77667` |
| `feed` | 0 % → 94 % | `34a95a550` |
Global **37 % → 43 %** ; sin contrato **56 → 49** ; al 100 % **6 → 7** . Más
`90aa6dc5f` (el `TokensPanel` que las demos enseñan) y `8324e2ced` (el registro
de incidencias).
El plan del bloque, tal como se preparó:
El primer bloque del backfill bajo TODAS las firmas. Ocho componentes con
veredicto §5 verificado + una pieza de instrumento que va primero. Suma **330
knobs hoy a 0 %**; al cerrar, el global debe rondar **37 % → ~42 %** . Cada
componente: protocolo ** §7 entero**, un componente = un commit, con la
gramática firmada (¡el guard R-5.3 y el muro de tipos ya vigilan!).
**Pieza 0 — el instrumento ANTES del bloque (D-TH.2-b, firmada).** La familia
tipográfica B5 mide su superficie por `--style-*` como sistema transversal: el
censo añade `--style-*` a la clase `system` PARA los primitivos tipográficos
(heading, text, display, code, s-text…), con gate: las cifras de TODOS los
demás componentes quedan idénticas, y `heading` pasa de «36 privados» a su
verdad (consume la capa semántica). Va primero porque cambia el suelo del
censo — hacerla a mitad de bloque falsearía los antes/después.
| # | componente | knobs | defectos medidos (censo + ficha) | corrección firmada por el veredicto |
| ---- | ----------------- | ----: | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 1 ✅ | `command` | 52 | SIN bloque en `base.ts` ; 35 globales · 9 privados sin derivar · 6 literales | contrato entero con talla resuelta (patrón Sidebar); `radius` con la adaptación al Dialog como CONTEXTO (lee un público de dialog, legítimo — no partir en dos); `list-padding-inline` + `scrollbar-inset` (patrón combobox); sonda con el palette ABIERTO |
| 2 | `table` | 46 | 23 privados · 14 globales · 5 literales | `root-height-{k}` es la **fila** → `row-height-{k}` al bundle; el prefijo `root-` sobra en el resto; talla |
| 3 | `media-player` | 45 | 37 globales · 8 literales; privados `--_mp-*` ABREVIADOS (§6 r5 los prohíbe) | renombrar `--_mp-*` al nombre completo (⚠ prettier: la anotación `/* literal: */` en la MISMA línea — trampa de natural-time-picker) + tokens; su acento theme-stable está FIRMADO en `base.ts` — no tocarlo; el ⚠ de `bg` son DOS knobs (superficie y velo) |
| 4 | `tree-grid` | 42 | 29 privados · 8 globales | `root-bg-image` son las **guías de indentación** : el knob es la tinta (`guide-fg` — era `guide-color` pre-acta), los 5 gradientes se quedan en la receta; talla |
| 5 | `gradient-picker` | 38 | privados `--gp-*` ABREVIADOS · 23 globales | renombrar `--gp-*` + tokens; `content-width` es **por talla** (20/18/22rem), no un solo knob |
| 6 | `listbox` | 38 | 23 globales · 9 privados; una fila FALSA en la propuesta | tokens; **retirar** la fila `font-size = var(--list-font-size)` : es público de la capa `list-surface` — un consumidor no acuña lo que la capa posee |
| 7 | `carousel` | 36 | 12 globales · 14 privados · 5 literales | tokens + talla; los `indicator-width-{k}` son geometría propia (rem), ni bundle ni desviación |
| 8 | `feed` | 33 | 16 globales · 13 privados | tokens + talla; el título es **por talla** y el feed tipa por debajo del 1:1 (md → sm), verbatim — no «corregirlo» al 1:1 |
**Cada componente engancha su tab `Tokens` en el MISMO commit** (firmado
2026-08-20, a raíz de que el autor viera que la demo de `command` no enseñaba su
superficie de tema — y resultó que ninguna lo hacía). Es una línea:
`<TokensPanel component="x" stage={stageRef} />` más el botón del tab; el panel
(`web/routes/uix/lib/TokensPanel.svelte`) lee el contrato vivo con
`eidos.getRecipeTokens()` , así que no hay tabla que mantener. Un componente
temable cuya demo esconde sus tokens está a medio entregar.
Gates de cada componente (§7.4/7.5, sin excepciones): censo `--only {c}` al
**100 %** o excepción escrita · sonda antes/después = **0 diffs** · centinela
por token nuevo · `component:audit` PASS (R-5.3 incluida) · `eidos-lint` 0
invalid · suite eidos sin rojos nuevos · `rtl:check` 0 · `docs:check` 0 ·
`check` por fichero · README del componente con la tabla «Talla y tema»
(molde `navigation-menu` ). Al cerrar el bloque: **revisión adversarial §7.7**
(molde Sidebar: refutar «idéntico», «alcanza», «píxel arriba» con medición
propia).
**Al cerrar F2-A, lo desbloqueado por las firmas espera en este orden**:
1. **Diseño de la capa `calendar-surface`** (firma 1) — se PRESENTA antes de
escribirla (nombre, ejes, qué posee; molde `list-surface` y sus 4 reglas).
Desbloquea los tres gordos del catálogo: `range-calendar` (98) +
`month-grid` (61) + `year-grid` (61) y media `date-range-picker` — 220
knobs, el salto de ~42 % a ~47 %.
2. **Mandato Field ejecutable** (firma 2) — `field-langs` (41) + las mitades
de `time-picker` / `time-range-picker` / `date-range-picker` .
3. El resto del orden B1-B8 de D-TH.4 (`grid-list` 32 · `textarea` 28 · …).
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(theming): partir recipes/base.ts, al terminar el eje entero
Pregunta del autor: por qué los tokens de 128 componentes viven en un fichero
de 6.223 líneas y no junto a su componente.
La respuesta medida: NO es un fichero de tokens, es el valor del campo
`recipes` de `EidosConfig` —serializable, que un tema hidrata—, y por eso los
valores no pueden mudarse a `components/{x}/`: ya se intentó y se retiró («The
old `tokens/components/*` were retired»). Lo que sí puede repartirse es la
AUTORÍA, con un fichero por componente que `base.ts` compone.
Verificado antes de proponerlo: el muro de tipos de `defineRecipes` sigue
disparando cuando las claves llegan por spread desde un fichero suelto —
probado con `trigger-color` y `padding-x`, ambas siguen sin compilar. Y el
único consumidor sensible a la forma (`eidos-purge`, que hace `Object.keys()`)
es indiferente.
Va al final de TODO el themeable, no al cerrar el bloque: mientras quede un
componente por tokenizar, ese fichero se toca en cada commit, y mover 6.000
líneas en medio garantiza conflicto con cualquier sesión que esté trabajando.
Los tres costes que justifican hacerlo se midieron hoy: casi entra un SEGUNDO
bloque `table` que el catálogo habría descartado en silencio, una coma perdida
rompió el catálogo entero dos veces, y es el punto de conflicto de todas las
sesiones concurrentes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
---
## AL TERMINAR EL EJE ENTERO — partir `recipes/base.ts` por componente
Firmado 2026-08-20, a raíz de la pregunta del autor «¿por qué todos los tokens
viven en un fichero?». **Va al final de TODO el themeable** , no al cerrar un
bloque: mientras quede un componente por tokenizar, ese fichero se toca en cada
commit.
`recipes/base.ts` son **6.223 líneas y 128 componentes** , y NO es un fichero de
tokens: es el valor del campo `recipes` de `EidosConfig` , serializable, que un
tema hidrata. Por eso los valores no pueden mudarse a `components/{x}/` — se
intentó y se retiró (`architecture/eidos.md`: «The old `tokens/components/*`
were retired»). Lo que sí puede repartirse es la AUTORÍA:
```ts
// lib/recipes/table.ts
export const tableRecipe = { 'row-height-md': '…', … };
// lib/recipes/base.ts — el valor sigue siendo UNO
export const THEME_BASE_RECIPE_TOKENS = defineRecipes({ table: tableRecipe, … });
```
**Verificado antes de proponerlo, no supuesto**: el muro de tipos de
`defineRecipes` SIGUE disparando cuando las claves llegan por spread desde un
fichero suelto — probado con `trigger-color` (slot `color` ) y `padding-x` (eje
físico), ambas dan error de compilación igual que inline. El único consumidor
sensible a la forma es `eidos-purge.ts` , que hace `Object.keys()` y es
indiferente. `recipe-css-contract` , el censo, R-5.3 y `getRecipeTokens()` leen
el objeto compuesto.
Los tres costes que paga el fichero único, todos medidos en la sesión del
2026-08-20: **casi entra un SEGUNDO bloque `table`** que el catálogo habría
descartado en silencio (la trampa está anotada abajo); **una coma perdida
rompió el catálogo entero dos veces**; y es el punto de conflicto de todas las
sesiones concurrentes. Repartido, un error afecta a un componente.
**Por qué al final y no antes**: son ~6.000 líneas movidas en el fichero que
cada commit del backfill toca. Hacerlo con componentes pendientes garantiza
conflicto con toda sesión que esté tokenizando; con el eje cerrado es un commit
mecánico y aislado.
Gate: `THEME_BASE_RECIPE_TOKENS` **idéntico** antes/después (comparación
ESTRUCTURAL del objeto, no del fichero) · censo global idéntico ·
`generated/base.css` sin un solo cambio · el muro de tipos con su muta-prueba
(las dos claves malas siguen sin compilar).
## FIRMA 3 en ejecución — hover → capa de estado (act. 2026-08-20)
**El diagnóstico cambió al empezar.** La firma decía «migrar los hovers neutros
a la capa de estado». Al hacerlo salió que el velo del sistema **no llegaba a
ninguno**, y no por el hover: por la regla BASE. `archetypes.css` pinta el velo
con `:where(...)` , peso ** (0,0,0)**; cualquier receta que declare el ATAJO
`background:` sobre ese mismo nodo fija `background-image: none` con ** (0,1,0)**
y lo cancela SIEMPRE — ni en hover ni nunca. El hover propio no era un
capricho: era la cicatriz de un velo que no llegaba.
Así que cada migración son DOS cambios: `background:` → `background-color:` en
la base, y fuera el hover propio.
| componente | commit | medido |
| ------------------- | ----------- | -------------------------------------------------------------- |
| `checkbox` | `b35855c20` | 8 diffs, todos en hover: velo + fondo base (2.436 valores) |
| `splitter` | `c66b73810` | 2 diffs en el asa (812 valores) |
| `switch` | `3219a19c3` | 2 diffs en el track off (377); el swap del checked, verificado |
| `date-range-picker` | `0c80a8efb` | **sin medir el pintado** — la demo no monta `kind` month/año |
**Los 6 knobs de la cola eran 47 hasta que se midió la PROPIEDAD**: el velo es
`background-image` , así que un hover de borde (22) o de tinta (19) no es la
capa de estado, sea cual sea su valor. Esos 41 eran deuda de nombre y se
renombraron (`93017975c`).
docs(next-features): el registro de incidencias del eje theme-reach
Encargo del autor: anotar todas las incidencias de esta clase para resolverlas
después. Van al registro canónico (`next-features.md`), no a un sitio nuevo, y
con su MEDICIÓN — no como impresión.
**§12 — El contrato de cascada del velo de estado.** Seis incidencias que
resultaron ser la misma: nadie fijó nunca cómo compone el velo de
`archetypes.css` con las reglas de una receta. Y la raíz explica por qué se
manifiestan de formas tan distintas: el velo se pinta con DOS pesos según el
arquetipo — `:where()` (0,0,0) para `trigger`, especificidad plena (0,5,0) para
`item`/`option`.
131 declaraciones-atajo en 45 componentes cancelan el velo (66 BASE ·
32 ACENTO · 23 HOVER · 10 OTRA; cero valores con gradiente, así que el paso a
longhand no tiene riesgo técnico; 32 nodos velados que hoy no reaccionan al
ratón pasarían a hacerlo) · la prop `hoverable` de table no suprime nada · en
tree-grid el empate (0,5,0) lo decide el ORDEN DE CARGA y varía entre
recargas · la banda de tree-grid mata el hover en las filas pares · un token
de tinta no puede ganar al arquetipo (`selected-row-fg` se retiró por eso) ·
el thumb de scroll-area no tiene velo al que migrar.
Esto explica de paso la adopción 21/135 que midió la auditoría del 2026-07-01:
el velo estaba escrito y estructuralmente derrotado.
**§13 — Huecos de instrumento y de demo.** Lo que hizo que una medición
mintiera o no existiera, que importa porque el eje entero se apoya en ellas:
falsos negativos del centinela sobre propiedades transicionadas, pseudo-elementos
y componentes compuestos que no ve, la sonda que no pasa el ratón por un `<tr>`,
y la lección general —**una sonda sobre una parte que la demo no monta compara
CERO valores y pasa**—, con la lista de partes condicionales afectadas.
El handoff gana la regla para las sesiones del eje: si una incidencia mueve
píxel o toca morfo, se mide, se anota ahí y se sigue; no se arregla dentro del
commit del componente.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### Las incidencias van al registro, no al eje
Todo lo que este eje destapa y NO le toca arreglar está registrado en
[`docs/next-features.md` ](../next-features.md ) §12 y §13 — con su medición, no
como impresión:
- **§12 · El contrato de cascada del velo de estado.** Seis incidencias que son
la misma: nadie fijó cómo compone el velo de `archetypes.css` con las reglas
de una receta. Incluye las 131 declaraciones-atajo en 45 componentes, la prop
`hoverable` que no suprime nada, el empate (0,5,0) que resuelve el orden de
carga, la banda de `tree-grid` que mata el hover, el token de tinta que no
puede ganar al arquetipo, y el thumb de `scroll-area` sin velo al que migrar.
- **§13 · Huecos de instrumento y de demo.** Lo que hizo que una medición
mintiera o no existiera: falsos negativos del centinela, pseudo-elementos y
componentes compuestos que no ve, la sonda que no pasa el ratón por un `<tr>` ,
y la lección general — **una sonda sobre una parte que la demo no monta compara
CERO valores y pasa**.
**Regla para las sesiones de este eje**: si una incidencia mueve píxel o toca
morfo, se MIDE, se anota ahí y se sigue; no se arregla dentro del commit del
componente.
### Lo que queda de la firma 3, y por qué no lo he hecho
1. ** `scroll-area.thumb-bg-hover` — pide DECISIÓN de morfo.** El thumb lleva
`archetype: 'thumb'` , que NO recibe velo. Migrarlo exige cambiar su
arquetipo, y un arquetipo es morfo: se presenta, no se toca de oficio
(§7.3-9). La alternativa es dejar su hover como excepción anotada.
2. **El hallazgo sistémico: 141 declaraciones en 45 componentes** cancelan el
velo del mismo modo, medido con `scripts/__statelayer-shorthand.ts` (que
comprueba contra el morfo que el atajo cae sobre el nodo VELADO, no sobre
cualquiera). Peores: radio-group 12 · tag-group 8 · checkbox 7 · table 7 ·
combobox 6 · tabs 6. Esto explica la adopción 21/135 que midió la auditoría
del 2026-07-01: el velo estaba escrito y estructuralmente derrotado. **Es un
barrido de catálogo que mueve píxel en 45 componentes: no entra en la firma
3, que se firmó sobre unos knobs concretos.**
3. **Hueco de demo** : `date-range-picker` no expone `kind='month'` /`'year'`
(norma N-6), así que la mitad de su API no se ve ni se mide.
---
docs(theming): el acta — las catorce decisiones que faltaban, firmadas
El eje llevaba desde el 19 ejecutando sólo lo que no dependía de una firma.
Hoy se presentaron las catorce con recomendación fundada y el autor las firmó
en bloque. Quedan escritas donde se ejecutan: §4 del plan fila a fila, y una
sección de acta en el handoff con el QUÉ ejecutable de cada una.
La que cambió de sentido al presentarla fue D-TH.6. La pregunta no era
«normalizar hacia lo documentado» sino una CONTRADICCIÓN entre dos doctrinas
firmadas: theming §6.7 r7 dice que el slot de tinta es `fg`; el principio de
plataforma del codemod px/py («el token se llama como la propiedad») dice
`color`. Se adjudicó `fg`, y con una razón que acota el principio en vez de
romperlo: gobierna los ejes DIMENSIONALES, no la pareja `bg`/`fg` — si la
gobernara, `bg` tendría que llamarse `background-color`, y nadie lo propone.
De la misma lectura salió que el inventario heredado estaba inflado: de las
370 claves «desviadas», 47 son `{rol}-{slot-de-rol}` (`primary-solid-hover`,
`palette-hover`) donde COLOR_ROLE_SLOTS pone el modificador detrás POR
CONSTRUCCIÓN. Un codemod sobre las 370 las habría roto — `button` entero.
El inventario real es 301, y la gramática es POR FAMILIA, no única.
Los 22 «falsos amigos» resultaron ser tres cosas distintas: los que se quedan
(la familia del sistema `--focus-ring-*`, el color como sustantivo de `aura`,
y `stop-color` que ES una parte de gradient-builder), los que el morfo ya
resuelve (`partial`, `read`, `failed` son valores declarados de `data-state` y
`data-delivery`), y los dos `scrim-color-on-*`, que chocaban con el prefijo
canónico `on-` del acento y pasan a `scrim-fg-over-*`.
Y una que no era limpieza sino decisión: los hovers neutros NO se renombran,
MIGRAN a la capa de estado (§38 + R-4.3). Renombrarlos habría presumido que
sobreviven.
Con las firmas, la revisión de los 7 componentes ya corregidos contra la
gramática nueva: 6 limpios y una corrección (`gradient-builder.checker-color`
→ `checker-fg`), que entra en el codemod. Que salgan limpios no es suerte —
el backfill de este eje ya venía escribiendo `fg`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Firmas del 2026-08-20 — el acta (las 14, «FIRMO TODAS»)
Presentadas con recomendación fundada y firmadas en bloque por el autor. El
detalle razonado de cada una vive en la conversación del 2026-08-20 y en la
fila correspondiente del plan §4; aquí el QUÉ ejecutable:
1. **Familia calendar = capa compartida** (molde `lib/list-surface.css` : attr
de capa, un eje = token público + ranura privada `var(--_x, var(--x))` ,
guardada por `shared-layer-contract.test.ts` + `layer:check` ). NUNCA ~150
alias `--calendar-*` . Desbloquea `range-calendar` (98), `month-grid` (61),
`year-grid` (61) y media `date-range-picker` . El diseño de la capa
(nombre, ejes, qué posee) se presenta antes de escribirla.
2. **Mandato Field: ejecutable.** Los x-field/pickers componen el wrapper
Field; las alturas de segmento salen del eje size a nivel familia
(`--field-control-height-{k}`); muere la re-duplicación `height-{xs..xl}`
por componente (theming-audit §2-B: computaban `auto` desde su nacimiento).
3. **hover → capa de estado, donde reaparezca** (empezando por los 3 knobs de
`combobox` ). Mueve píxel hacia el canon §38/R-4.3 ⇒ cada migración lleva
captura antes/después y su diff explicado en el commit. Desbloquea la poda
D-2 (changelog §38 ◇: los `--{x}-bg-hover` huérfanos, incluido
`pagination.selected-bg-hover` = capa sobre acento).
4. **D-TH.6 completa** — slot `fg` + modificador DELANTE con la regla:
**delante lo interactivo, detrás lo dimensional y contextual** ; modificador
válido ∈ vocabulario universal (+`current`) ∪ valores `data-state` /ejes del
morfo del componente; `waveform.played/buffered` = pseudo-partes;
`scrim-color-on-*` → `scrim-fg-over-{dark,light}` ; hovers neutros FUERA del
codemod (migran por la firma 3). Renombres nominales de los ex-falsos
amigos: `item-fg` /`active-item-fg`/`partial-item-fg` (rating-group),
`read-status-fg` /`failed-status-fg` (chat-message), `current-link-fg`
(breadcrumb), `played-fg` /`buffered-fg` (waveform). Se quedan:
`*-focus-ring-color` (sistema), `aura.orb-color-*` (sustantivo),
`gradient-builder.stop-color-*` (parte).
5. **D-TH.1** R-5 dura · **D-TH.3** tracks WIP en censo, `error` sólo fuera de
carril · **D-TH.5** el default no cambia (única excepción: la firma 3, con
captura).
6. **D-TH.2** con la opción (b) de `heading` : la familia tipográfica B5 mide
por `--style-*` como sistema transversal — no se acuñan `--{c}-*`
tipográficos. La lista `KNOB_PROPS` es el perímetro; cambios = firma.
7. **D-TH.4** con enmienda: la cola revisada de este CONTINUE prioriza sobre
el orden de familias B1-B8.
8. **D-TH.7** con enmienda: **R-5.3 a `error` directo tras el codemod** ;
R-5.1/5.2 esperan F3.
9. **D-TH.8** : panel de tokens en `/temas` , en F4.
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Lo ejecutado (censo antes → después)
**Bloque del vocabulario, 2026-08-20** (tres commits, sin pushear):
| commit | qué |
| ----------- | --------------------------------------------------------------------------------------------- |
| `f09e04fab` | el acta de las 14 firmas + la revisión de los 7 ya corregidos |
| `bd916ef3f` | codemod: 269 claves · 793 referencias · 101 ficheros · alcance IDÉNTICO · 0 diffs de computed |
| `7781d6e4c` | R-5.3 en `error` (muta-prueba de 3 caras) + recipe-contract §1/§4 + theming §6.7 + checklist |
**Lo que el bloque enseñó** (más caro de lo que parece):
- **El plan del codemod se escribe ANTES de tocar nada.** Releer el
clasificador después da CERO desviaciones —ya están renombradas— y el
verificador del diff pasa sobre el vacío. Costó dos vueltas.
- **Un valor puede cambiar de texto sin cambiar de significado**: 22 privados
reapuntan a nombres nuevos. El gate normaliza por el plan antes de comparar,
o los cuenta como cambio de valor y da rojo en falso.
- **No pasar prettier sobre lo que el codemod tocó.** El árbol tiene CRLF
(`autocrlf=true`) y 88 de 101 ficheros ya salían «sucios» ANTES; un
`--write` en masa reformateó 300 ficheros de deriva ajena. Se midió lo que
importaba —¿alarga el renombrado alguna línea?— y la respuesta fue no en
todos, así que prettier no hacía falta.
- **Clasificar un hover por el NOMBRE es clasificarlo mal**:
`dropdown-menu.item-bg-hover` lee `var(--color-primary-element)` — es el
palette swap con valencia de recipe-contract §2, no el hover bespoke que §38
deprecó. Lo decide el VALOR. Yo lo había listado mal en este mismo handoff.
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| componente | alcance | commit |
| --------------------------- | -------------: | ----------- |
| `gradient-builder` (piloto) | 0 % → **80 %** | `3cdb5b5f0` |
| `combobox` | 0 % → **76 %** | `cef2d32f1` |
| `natural-time-picker` | 0 % → **61 %** | `e774ca7e8` |
| `date-range-picker` | 0 % → **42 %** | `07778b597` |
| `time-range-picker` | 0 % → **19 %** | `68eb8af26` |
| `time-picker` | 0 % → **18 %** | `e4fcdd62e` |
| `proof-of-human` | 0 % → **14 %** | `ae91573c3` |
Global del catálogo: **33 % → 37 %** (1.621 → 1.841 knobs públicos).
Informe + instrumento: `2591ec2f0` ; revisión de las fichas 11-20: `3bfe0d413` .
## El instrumental (vive en `scripts/`, prefijo `__` = temporal del eje)
docs(theming): el plan del eje theme-reach — medir qué alcanza un tema, y corregir componente a componente
El autor, al ver que el radio del trigger del nav vivía en un privado clavado a
--radius-default: «¿los componentes son themables? si no lo son, es un error
como framework». Lo es. La doctrina ya exige que cada receta declare sus knobs
en recipes/base.ts (recipe-contract §1, theming §6), pero R-1…R-4 sólo
comprueban «sin literales», no «alcanzable por un tema»: una receta con todo en
var(--radius-md) y privados pasa component:audit en PASS y sólo se puede temar
moviendo el sistema entero.
Medido, no opinado — scripts/theming-census.ts (instrumento, NO guard): de 5.205
knobs de apariencia en 162 recetas, 1.621 (33 %) pasan por un token público del
componente; 1.880 atan directo a un primitivo global, 856 a privados, 614 son
literales; 62 componentes no tienen una sola entrada en el contrato; 59 tienen
alcance < 20 %; 6 al 100 %. navigation-menu, tras todo el día de hoy, 44 %.
El plan (PLAN-theming.md): §1 el censo por familia y por componente (tabla
regenerable, no editable) · §2 los cuatro ejes de «personalizable» (tokens ·
talla · color/variante · estados) · §3 la regla R-5 «alcance de tema» para
component-audit, con su válvula de excepción · §4 ocho decisiones D-TH para el
autor (R-5 dura · perímetro de knob · WIP · orden · DEFAULT IDÉNTICO · normalizar
nombres de slot, que hoy incumplen tabs y el propio nav · cuándo gradúa a error ·
panel de temas) · §5 fases F0–F4 con gates · §6 deuda transversal · §7 el
PROTOCOLO DE VERIFICACIÓN por componente, porque «lo ejecutará Opus, y Opus falla
mucho»: cinco preguntas, medir ANTES (computed por parte/estado/talla, sonda
headless desde la raíz, fuera de callbacks de MutationObserver), editar sólo la
forma firmada, medir DESPUÉS (diff de computed = 0, prueba de CENTINELA por cada
token nuevo, desde el píxel hacia arriba, registro de animationstart/end),
guards por fichero, un componente = un commit con sus artefactos, y revisión
adversarial por bloque. Cada paso tiene un artefacto; sin artefacto no está hecho.
El instrumento se probó por mutación antes de creerle, y falló la primera vez:
no contaba una regla de una sola línea (`[x] { padding-inline: 8px; }`), así que
meter un literal no movía la cifra. Regex endurecido; ahora 6→7→8 con una y dos
mutaciones. Las cifras del plan son las del instrumento final, y el handoff
(CONTINUE-theming.md) obliga a reproducirlas antes de seguir.
Nada firmado, nada construido. Gates del commit: docs:check 0/642 · prettier del
script limpio · tsc del script sin errores · el plan cita ficheros que existen
(los once, comprobados).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
```bash
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
node scripts/__theming-probe.ts < componente > < salida.json > # sonda antes/después
node scripts/__theming-diff.ts < antes.json > < despu é s . json > # el gate: diff VACÍO
uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4
Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree
con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba
más dura que la del autor), sonda x2 por componente para fijar el suelo de
ruido. 34 hipótesis · 26 refutadas · 8 reales.
Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs;
command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 ·
listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen
idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens
huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano»
de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación;
eidos-lint 0 invalid.
Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command
8.091 y carousel 2.842 valores, 0 diffs):
1. command: el re-point de `--command-radius` dentro del Dialog era una
declaración muerta con comentario falso — la misma regla pone el radio a 0
y el input lee `--command-input-radius`, nunca este token (medido:
`--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px`
movía la paleta inline y no la del dialog). Retirado; comentarios y README
reescritos con lo medido.
2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo
mientras la horizontal leía `active-indicator-scale` — el token alcanzaba
media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora
lo leen las dos.
3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap`
INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por
CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y
las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es
la prueba. Canal de valor de soma, como --gp-current-gradient. Censo
carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto
(5.190 · 2.102).
4. table: `striped-row-bg` no alcanza NADA en la demo publicada —
`:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos
quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel →
PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`);
adjudicado en el ledger mientras tanto.
El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas
medidas, y la cuarta era de la sonda:
- el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input
de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el
token de reposo leía muerto (era el «falso negativo sin causa» de §13);
- el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de
`{c}-root` no lo recibían;
- `::before`/`::after` eran invisibles (el aro de buffering, el spinner);
- la no-determinación de feed no era una animación sin localizar: era la demo
aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma
`commit-settle` anima box-shadow sobre el nodo medido. Con la espera de
asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas.
Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y
que carousel convirtió en patrón — un estilo inline de otra capa es invisible
para todo análisis estático): `npm run theming:sentinel -- <c> <url>`
(scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en
todos los nodos del componente, pseudos, pase de hover, settle) + ledger
scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto
sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en
verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 ·
gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46
excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías
salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró;
y dos muertos nuevos los produjeron los propios arreglos (el blur apaga
focus-input-border; el settle desmonta el spinner de feed) — adjudicados con
su porqué. Doctrina en recipe-contract §4.
También: tres cifras de especificidad de next-features §12 recontadas (la
banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0);
y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el
velo en la celda), el comentario de listbox que mandaba pisar el privado
`--_listbox-max-height` apunta ahora al público, y quedan registrados en §13
los dos `header-z` con literal '2' y el spinner de media-player a 720ms
mientras el gemelo de feed lleva tokens.
Guards: censo global 43 % intacto · audit --only command+carousel PASS ·
eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest
eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs
0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier
limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en
HEAD y no se tocan).
Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el
arquetipo en fila+celda, y que soma lea el gap de un token.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
npm run theming:sentinel -- < componente > < url > # guard R-5.4: ¿alcanza cada token? (ya no es `__` )
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
node scripts/__shot.ts < componente > < salida.png > # captura 2× del stage
docs(theming): el plan del eje theme-reach — medir qué alcanza un tema, y corregir componente a componente
El autor, al ver que el radio del trigger del nav vivía en un privado clavado a
--radius-default: «¿los componentes son themables? si no lo son, es un error
como framework». Lo es. La doctrina ya exige que cada receta declare sus knobs
en recipes/base.ts (recipe-contract §1, theming §6), pero R-1…R-4 sólo
comprueban «sin literales», no «alcanzable por un tema»: una receta con todo en
var(--radius-md) y privados pasa component:audit en PASS y sólo se puede temar
moviendo el sistema entero.
Medido, no opinado — scripts/theming-census.ts (instrumento, NO guard): de 5.205
knobs de apariencia en 162 recetas, 1.621 (33 %) pasan por un token público del
componente; 1.880 atan directo a un primitivo global, 856 a privados, 614 son
literales; 62 componentes no tienen una sola entrada en el contrato; 59 tienen
alcance < 20 %; 6 al 100 %. navigation-menu, tras todo el día de hoy, 44 %.
El plan (PLAN-theming.md): §1 el censo por familia y por componente (tabla
regenerable, no editable) · §2 los cuatro ejes de «personalizable» (tokens ·
talla · color/variante · estados) · §3 la regla R-5 «alcance de tema» para
component-audit, con su válvula de excepción · §4 ocho decisiones D-TH para el
autor (R-5 dura · perímetro de knob · WIP · orden · DEFAULT IDÉNTICO · normalizar
nombres de slot, que hoy incumplen tabs y el propio nav · cuándo gradúa a error ·
panel de temas) · §5 fases F0–F4 con gates · §6 deuda transversal · §7 el
PROTOCOLO DE VERIFICACIÓN por componente, porque «lo ejecutará Opus, y Opus falla
mucho»: cinco preguntas, medir ANTES (computed por parte/estado/talla, sonda
headless desde la raíz, fuera de callbacks de MutationObserver), editar sólo la
forma firmada, medir DESPUÉS (diff de computed = 0, prueba de CENTINELA por cada
token nuevo, desde el píxel hacia arriba, registro de animationstart/end),
guards por fichero, un componente = un commit con sus artefactos, y revisión
adversarial por bloque. Cada paso tiene un artefacto; sin artefacto no está hecho.
El instrumento se probó por mutación antes de creerle, y falló la primera vez:
no contaba una regla de una sola línea (`[x] { padding-inline: 8px; }`), así que
meter un literal no movía la cifra. Regex endurecido; ahora 6→7→8 con una y dos
mutaciones. Las cifras del plan son las del instrumento final, y el handoff
(CONTINUE-theming.md) obliga a reproducirlas antes de seguir.
Nada firmado, nada construido. Gates del commit: docs:check 0/642 · prettier del
script limpio · tsc del script sin errores · el plan cita ficheros que existen
(los once, comprobados).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
```
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Se ejecutan **con `node`, no con `tsx`** (tsx inyecta helpers que rompen
`page.evaluate` ) y **desde la raíz** del repo, contra el dev server en
`localhost:5173` . Los `scripts/__dbg*.ts` y `__sentinel-targeted*.ts` son de un
solo uso (verificaciones dirigidas de ayer); no se commitean.
## Lo que el instrumento aprendió a fuerza de mentir
- **La sonda congela `transition` , NUNCA `animation` **: una propiedad
transicionada devuelve su valor INICIAL justo tras escribir el token (un token
vivo parecía muerto), pero congelar `animation` impide que Presence monte el
panel — y entonces mides un popup que no existe.
- **Un token RESUELTO no se mueve desde `:root` **: se declara en `[data-{c}]` o
en su parte, así que el tema mueve la **coordenada** . El centinela escribe en
`:root` **y** en el host, y aun así los resueltos salen «muertos» por diseño.
- **Un panel portalado no ve el ámbito del componente**: sus tokens se emiten en
`:root` (o con `parts` ), y un override scoped no lo alcanza.
- **La demo puede tapar el componente**: `proof-of-human` declara su propio
`min-block-size` y fondo sobre el stage — ahí el centinela no sirve, y se dice.
- **Un valor centinela igual al real lee como «no efecto»** (`9999px` contra un
`--radius-full` que ya era 9999px).
- **Los tokens que SON la transición no se pueden medir congelando** (2026-08-23):
`transition-duration` / `transition-ease` salen muertos SIEMPRE, en cualquier
componente, porque el congelado es el arreglo que hace medible todo lo demás.
Se miden en una pasada aparte, sin congelar (color-picker: 0.12s → 11.5s).
- **Ni `!important` en línea mueve una propiedad EN TRANSICIÓN si lees en el
acto** (2026-08-23): la lectura devuelve el valor viejo y parece un token
imposible de mover. Pasó con el fondo del cuentagotas: tres diagnósticos
falsos hasta congelar.
fix(eidos): el eje size de form LLEGA a sus acciones - contexto A-112
<Form size="xs"> renderizaba acciones md: la talla moria en el provider
(form-submit/reset con default 'md', nada la propagaba) y del eje entero solo
sobrevivia el row-gap. Contexto de eidos calcado 1:1 de toolbar/context.ts
(el precedente A-112): form provee su size resuelto; Submit/Reset lo
consumen como default (su prop explicita gana; md standalone).
El eje va VERBATIM, no tapado en md - la bifurcacion de doctrina queda
RESUELTA Y ESCRITA (next-features 13 "Anchura vs densidad"):
reference.md:590 (tapar en md, precedente Dialog.Close) gobierna ejes de
ANCHURA; el de form es DENSIDAD declarada cuya receta ya escribio los cinco
peldanos.
- 5 ficheros de codigo, solo eidos (context.ts NUEVO); los dos costes
avisados NO se tocan, verificado con linea: la excepcion A11 de
form-auto-fields y el duck type CompatibleFormProvider quedan intactos
(el puente es setContext/getContext con Simbolo propio, disjunto).
- Medido: 84 diffs y NI UNO fuera - submit 40, reset 40, form 4 (su panel);
CERO en array/widget/error-summary; CERO en md. Alto -10/-6/0/+8/+16 px;
la letra lg/xl difiere de la prediccion (+4/+12 vs +2/+8) por causa MEDIDA:
--font-size-lg/xl son clamp() fluidos que saturan desde ~1200px - ningun
valor fuera de la escalera. Capturas xs/md/xl revisadas por el supervisor.
- Los botones del array siguen POR HERENCIA CSS, intactos (0 diffs) -
respuesta para E1: E2 ahorra el contexto, no la lectura (E1 debera pasar
size al Button que inyecte o sigue siendo la regresion medida).
- Dos mentiras NUEVAS del instrumento, registradas: la sonda estandar fuerza
data-size sobre el nodo compuesto y SE PISA (su 0 es por construccion) -
y los clamp() fluidos no son comparables sin declarar viewport.
- Registro: 13 cierra E2 (diagnostico original conservado tachado - era
exacto) y abre alert-dialog (mismo agujero; a el le toca la norma TAPADA
por ser eje de anchura), error-summary con data-size que nadie lee, la
escalera de fuente 3-sobre-5 que viola el 1:1 (E1, su carril), y la cita
colgada de dialog/context.ts:9. Pendiente dicho: el parrafo de doctrina
querria vivir tambien en reference.md (fuera del alcance liberado).
- Gates: eidos 443+1 ajeno - check 0 atribuibles - docs-check 0/0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
- **La sonda es CIEGA a un puente de talla por contexto** (2026-08-25, `form` ):
fuerza la talla **ESCRIBIENDO `data-size` sobre cada nodo casado que ya lo
lleva** (`__theming-probe.ts:279-281`) — y una parte que COMPONE el `Button`
lleva `data-{c}-…` **y** `data-size` . Se lo pisa DESPUÉS del render, así que
mide el mismo atributo forzado antes y después: **el diff sale 0 por
construcción**, no por ausencia de efecto. Medido: 0 diffs sobre 832 valores
mientras el botón pasaba de 36 px fijos a 26/30/36/44/52. Para esta clase de
firma el instrumento tiene que mover el **chip REAL de la demo** (el prop),
nunca el atributo. La sonda estándar sigue valiendo como gate de «no se movió
nada COLATERAL» — que no es poco, pero no es la prueba.
- **`--font-size-lg` / `-xl` son `clamp()` FLUIDOS** (18→20 y 24→28): una medida
de letra en esas dos tallas **no es comparable entre informes si el viewport
no viaja con ella**. Medido: a 900 px dan 19,05 / 26,10 y desde ~1200 px
saturan en 20 / 28. Costó una desviación aparente de +2 px contra la cifra de
un expediente que no declaraba su ancho. **Declara el viewport en toda medida
de fuente `lg` / `xl` .**
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Trampas que costaron un commit cada una (no repetirlas)
- **Clave duplicada en `recipes/base.ts` **: añadir un bloque que ya existía lo
uix(code-block): temable — 0 % → 81 %, y la demo que no enseña el componente
20 claves en una entrada NUEVA de `recipes/base.ts` (no tenía). Censo 0 % →
81 %. Global 46 % → 47 %, sin contrato 46 → 45.
El handoff lo llamaba «el más mecánico de los que quedan». No lo es: sus 26
knobs se parten en dos grupos con doctrinas distintas.
1. **El nodo del código NO acuña nada, y la §4 pedía que lo hiciera.**
`[data-code-block-code]` consume la capa tipográfica `--style-code-*` en sus
cinco declaraciones, y las dos que pasan por privado usan la forma canónica
de la escotilla por instancia
(`var(--_code-block-font-size, var(--style-code-font-size))`, escrita por el
wrapper desde la prop `size` y sólo si llega). Es el patrón que D-TH.2-b
fijó para heading/text/code. Acuñar `code-font-family` y compañía sería el
vocabulario paralelo que la regla 2 de capas prohíbe. Todo lo que entra al
contrato es el CASCO alrededor.
2. **Los tres `font-size` iban al primitivo crudo, y lo cazó un guard.** La
propuesta copia el valor del CSS verbatim, y ese valor ya violaba
`recipe-css-contract` («recipes consume the size bundle, not the raw
size-coordinate primitives»): `title/lang/copy-font-size` corregidos a
`var(--size-{k}-font-size)`. Los alias son 1:1 → 0 diffs tras aplicarlo.
Aviso general: cuando el CSS de partida ya incumple el contrato, la
propuesta generada hereda el incumplimiento.
3. Shorthand partidos: los dos `border` y el `border-bottom` de la cabecera
comparten anchura y color → `border-width` + `border`; el `padding` del
`<pre>` → `pre-padding`. Los `transparent` de outline/ghost y el `border: 0`
de ghost son identidad de variante.
El 19 % que falta son esas cinco de la capa, que el censo cuenta como `global`
porque `code-block` no está en `TYPOGRAPHIC_PRIMITIVES` — es un compuesto que
CONTIENE un primitivo tipográfico, no uno de ellos. Extender la clase `system`
del censo a las capas sigue pendiente de tu firma; la métrica penaliza hacer lo
correcto y no se fuerza de oficio.
DOS HALLAZGOS QUE NO SE ARREGLAN AQUÍ (→ next-features §13):
- **La demo de `code-block` no enseña el `code-block`.** `[data-uix-docs] pre`
(`web/routes/uix/uix.css:801`) pesa (0,1,1) contra los (0,1,0) de
`[data-code-block-pre]`, y `[data-uix-docs]` es el shell de TODAS las
páginas. Siete propiedades del `<pre>` las pinta el harness y no la receta:
padding (16px 20px contra 12px), border (1px contra ninguno), radius (8px
contra 0), background (gris contra transparente), font-family, font-size
(13 contra 14) y line-height (18.2 contra 20.3). El fondo, el borde y el
radio que se ven ahí son del sitio. Por eso `pre-padding` lee muerto en el
guard, adjudicado con esa medición. Acotar la regla toca el CSS del SITIO,
que sirve a ~162 páginas: decisión aparte.
- **El guard de claves duplicadas del handoff inspeccionaba el VACÍO.** El
comando documentado usa `grep -oE "^\t…"`, y `grep -E` lee `\t` como una `t`
literal: 0 coincidencias sobre 130 bloques reales, así que salía «vacío = OK»
sin mirar nada — el antipatrón que el proyecto tiene registrado, dentro del
propio handoff. Comprobado con un contador fiable: cero duplicados en el
árbol, así que no hay daño en los commits que confiaron en él. CONTINUE
queda corregido con una versión que CUENTA los bloques y avisa de que «0
bloques» significa guard roto, no fichero limpio.
Artefactos y gates:
- Sonda antes/después = 0 diffs en 1.305 valores × 7 estados (dos veces: tras
la tokenización y tras la corrección del bundle). Determinismo verificado.
- R-5.4: 19/20; `pre-padding` adjudicado con las siete propiedades medidas.
- censo --only 81 % · component:audit PASS · eidos-lint invalid 0, class-hooks
0 · suite eidos de vuelta al único rojo conocido (skin-media-player) tras
corregir el bundle · rtl:check 0 · docs:check 0 · check por fichero limpio.
- README con su «Talla y tema» y tab `Tokens` en la demo (20 claves, en vivo).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
descarta **en silencio** (gana la segunda). Guard antes de generar — y que
**cuente cuántos bloques ve** : la versión con `\t` que vivió aquí hasta el
2026-08-21 no casaba NINGUNO (`grep -E` lee `\t` como una `t` literal) y salía
«vacío = OK» sin haber mirado nada — el antipatrón del guard que inspecciona el
vacío, en el propio handoff.
```bash
node -e "const t=require('fs').readFileSync('src/uix/eidos/lib/recipes/base.ts','utf8').replace(/\r\n/g,'\n');const k=[...t.matchAll(/^\t'?([a-z0-9-]+)'?: \{/gm)].map(m=>m[1]);const d=k.filter((x,i)=>k.indexOf(x)!==i);console.log('bloques',k.length,'| duplicados',d.length?d:'ninguno')"
```
Debe imprimir los ~130 bloques y `duplicados ninguno` . **Si dice 0 bloques el
guard está roto**, no es que el fichero esté limpio.
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Dejar vivos los bloques `[data-…][data-size='…']` del CSS** al emitir la
cascada por el TSC: pisan los tokens nuevos con los valores viejos, y el diff
de computed da 0 **porque la ruta vieja sigue mandando** . Lo cazó el centinela.
- **Correr `component:audit` DESPUÉS de `prettier` , no antes**: al renombrar un
privado a su nombre completo, prettier partió tres declaraciones en varias
líneas y **separó la anotación `/* literal: … */` de su valor** — R-2.1 la
exige en la MISMA línea, así que el guard pasó a ver colores crudos donde
antes veía excepciones anotadas. Se arregla con `/* prettier-ignore */` sobre
la declaración: NO acortando el comentario ni tocando el valor. Regresión
real en `natural-time-picker` , cazada un día tarde por correr el audit antes
del formateo.
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Backticks en `node -e "…"` desde bash**: se ejecutan y vacían el texto. Para
editar markdown con código, usar el editor, no el shell.
- **`prettier --write` sobre un README** no protege de que un Edit se coma un
encabezado: comprobar `grep -c "^## Gaps"` después de insertar secciones.
- Lo de ayer sigue vigente: medir el nodo que el usuario señala (píxel arriba),
el hover es del sistema, el default no cambia, rama compartida sin `stash` ni
`--amend` , `check` **por fichero** .
docs(theming): el plan del eje theme-reach — medir qué alcanza un tema, y corregir componente a componente
El autor, al ver que el radio del trigger del nav vivía en un privado clavado a
--radius-default: «¿los componentes son themables? si no lo son, es un error
como framework». Lo es. La doctrina ya exige que cada receta declare sus knobs
en recipes/base.ts (recipe-contract §1, theming §6), pero R-1…R-4 sólo
comprueban «sin literales», no «alcanzable por un tema»: una receta con todo en
var(--radius-md) y privados pasa component:audit en PASS y sólo se puede temar
moviendo el sistema entero.
Medido, no opinado — scripts/theming-census.ts (instrumento, NO guard): de 5.205
knobs de apariencia en 162 recetas, 1.621 (33 %) pasan por un token público del
componente; 1.880 atan directo a un primitivo global, 856 a privados, 614 son
literales; 62 componentes no tienen una sola entrada en el contrato; 59 tienen
alcance < 20 %; 6 al 100 %. navigation-menu, tras todo el día de hoy, 44 %.
El plan (PLAN-theming.md): §1 el censo por familia y por componente (tabla
regenerable, no editable) · §2 los cuatro ejes de «personalizable» (tokens ·
talla · color/variante · estados) · §3 la regla R-5 «alcance de tema» para
component-audit, con su válvula de excepción · §4 ocho decisiones D-TH para el
autor (R-5 dura · perímetro de knob · WIP · orden · DEFAULT IDÉNTICO · normalizar
nombres de slot, que hoy incumplen tabs y el propio nav · cuándo gradúa a error ·
panel de temas) · §5 fases F0–F4 con gates · §6 deuda transversal · §7 el
PROTOCOLO DE VERIFICACIÓN por componente, porque «lo ejecutará Opus, y Opus falla
mucho»: cinco preguntas, medir ANTES (computed por parte/estado/talla, sonda
headless desde la raíz, fuera de callbacks de MutationObserver), editar sólo la
forma firmada, medir DESPUÉS (diff de computed = 0, prueba de CENTINELA por cada
token nuevo, desde el píxel hacia arriba, registro de animationstart/end),
guards por fichero, un componente = un commit con sus artefactos, y revisión
adversarial por bloque. Cada paso tiene un artefacto; sin artefacto no está hecho.
El instrumento se probó por mutación antes de creerle, y falló la primera vez:
no contaba una regla de una sola línea (`[x] { padding-inline: 8px; }`), así que
meter un literal no movía la cifra. Regex endurecido; ahora 6→7→8 con una y dos
mutaciones. Las cifras del plan son las del instrumento final, y el handoff
(CONTINUE-theming.md) obliga a reproducirlas antes de seguir.
Nada firmado, nada construido. Gates del commit: docs:check 0/642 · prettier del
script limpio · tsc del script sin errores · el plan cita ficheros que existen
(los once, comprobados).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Fuentes
docs(theming): handoff del eje al día — cola revisada, firmas pendientes y el instrumental que las verifica
El eje deja de ser «plan entregado» y pasa a «en ejecución»: siete componentes
corregidos, veinte fichas revisadas y el informe vivo. El handoff y el registro
del plan lo dicen con cifras y commits, para que mañana se entre por la ficha y
no por la memoria de nadie.
`CONTINUE-theming.md` se reescribe con lo que hace falta para continuar: la cola
inmediata de ocho componentes EJECUTABLES sin firma —cada uno con la trampa
concreta que su veredicto ya destapó—, la lista de lo que ESPERA firma (familia
calendar, mandato de Field, el perímetro del knob para la familia tipográfica,
el hover a la capa de estado) y la tabla de lo ejecutado con su censo antes →
después. El plan gana su §8 con el registro completo y corrige su cabecera, que
seguía diciendo que no había nada construido.
Y se commitea el instrumental, porque sin él el protocolo §7 es una intención:
la sonda de computed antes/después, el diff que es el gate (vacío o se para), el
centinela que pregunta si cada token alcanza de verdad, y la captura del stage.
Se ejecutan con `node` a secas —el loader de tsx inyecta helpers que no existen
dentro de `page.evaluate` y toda sonda revienta—, desde la raíz y contra el dev
server.
Lo que el instrumento aprendió a fuerza de mentir queda escrito donde se
consulta: congelar `transition` pero NUNCA `animation` (Presence necesita el
`animationend` para montar el panel, y si lo congelas mides un popup que no
existe); un token resuelto no se mueve desde `:root` por diseño; un panel
portalado no ve el ámbito del componente; la demo puede tapar el componente que
mides; y un valor centinela igual al real se lee como «no efecto».
Igual las cuatro trampas que costaron un commit cada una, con su guard al lado:
la clave duplicada en `recipes/base.ts` que descarta el bloque en silencio, los
bloques `[data-size]` del CSS que sobreviven a la cascada del TSC y hacen que el
diff dé cero por la ruta vieja, los backticks en `node -e` desde bash, y el
encabezado que un Edit se come al insertar una sección.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- Plan y decisiones: [`PLAN-theming.md` ](./PLAN-theming.md ) · informe:
[`docs/audit/theming/README.md` ](../audit/theming/README.md ).
- Auditoría del SISTEMA (fase 1, cerrada): [`theming-audit.md` ](../audit/theming-audit.md )
— §B familia calendar, §5.3-3 mandato de Field.
- Doctrina: `docs/theming/reference.md` (§5 talla, §6 nombres, §38 capa de
estado) · `docs/canon/recipe-contract.md` · `docs/canon/tsc.md` ·
`docs/architecture/eidos.md` (vertebración tipográfica, columna `unused` ) ·
`src/uix/eidos/components/README.md` (capas compartidas).
- Precedente de la forma por talla: [`PLAN-sidebar.md` ](./PLAN-sidebar.md ) §3 +
F3 y el bloque `sidebar` de `recipes/base.ts` .