Dos claves acuñadas, seis literales FIRMADOS y cuatro knobs adjudicados por
escrito. El default no se mueve: diff de computed 0 sobre 60 configuraciones y
capturas 2x idénticas byte a byte.
Censo: 69 % → 87 % (35 knobs → 30; público 24 → 26, global 3 → 2, literal 6 → 0,
excepción firmada 0 → 6). Contrato 41 → 43 claves. Global 67 % (no baja).
QUÉ ENTRA (2 claves)
row-gap (--space-2) + column-gap (--space-3). Era el ÚNICO knob de apariencia
que iba a un primitivo a pelo, y se parte en dos porque el atajo llevaba DOS
valores distintos: el hueco de fila separa la línea de texto de la barra, el
de columna separa el rótulo del valor. Un gap único habría nombrado un knob
para dos. El catálogo tiene las dos palabras (row-gap x10, column-gap x4) y el
molde exacto es chart.legend-row-gap / -column-gap.
QUÉ SE FIRMA EN VEZ DE ACUÑARSE (6 literales, fuera del ratio)
Cuatro 100 % y dos max-content: la geometría de la barra, no una decisión de
tema — llena la fila que le dan, o se encoge a su propio grosor / diámetro.
Cada uno con su anotación en la declaración (válvula de recipe-contract §3).
QUÉ SE RECHAZA DE LA PROPUESTA §4 (dos de sus tres filas)
indicator-radius — el --radius-full del anillo. Su GEMELO meter ya dejó el
veredicto escrito EN EL CSS: es lo que hace circular a shape='circular', y un
token dejaría que un tema des-redondease una forma que el consumidor pidió por
su nombre. Identidad, no knob; se copia el comentario del gemelo. Son los dos
únicos global que quedan, y el censo no puede sacarlos del ratio: la válvula de
la anotación sólo reclasifica la clase literal, nunca un global (mismo techo
que meter).
width: max-content — la §4 fundía en UN nombre dos nodos distintos (la raíz
vertical y la raíz circular) y los nombraba por el primer selector. Es el
literal de identidad de arriba.
EL TECHO HONESTO ES 87 %, NO 100 %
Los dos knobs private que quedan son el CANAL DE VALOR:
--_progress-value-pct lo escribe soma en el estilo inline del provider en cada
render (0-100 saturado) y la receta lo lee para el ancho del relleno lineal y
el alto del vertical. Un público encima mentiría — un tema no puede fijar el
progreso de una tarea. Misma clase que el z-index inline de drag-drop.
GUARD R-5.4: 40/43, TRES ADJUDICADOS CON SU MEDIDA
indicator-bg-loaded — sólo pinta bajo [data-state='loaded'], y la corrida
mantiene indeterminate encendido para alcanzar los tokens del barrido; forzado
sobre el nodo real: oklch(0.6406 0.1329 157.68) -> rgb(1,2,3).
transition-duration / -ease — los congela el guard por diseño; pasada sin
congelar: 0.18s -> 11.5s y cubic-bezier(0.4, 0, 0.2, 1) -> steps(7).
EL INSTRUMENTO MEDÍA UNA DE SESENTA CARAS
La sonda estándar ve 4 nodos — que son TODAS las partes del morfo — pero una
sola configuración: lineal, horizontal, loading, md. Medio contrato (el anillo,
el eje vertical, el barrido indeterminado, la tinta de completado) queda fuera
del diff, y el gate pasa en verde sin haberlo mirado. El guard lo dijo antes:
22 de 41 en la página por defecto. Con sweepAttr data-shape — el interruptor
que su gemelo meter YA tenía — sube a 34; con el interruptor indeterminate de
la demo, a 37; con el chip vertical, a 38. Cada control se comprobó por
separado, antes y después, porque montar más puede medir menos: aquí ninguno
tapó nada.
Y una trampa NUEVA, medida aquí: una sonda que CACHEA los nodos y luego mide en
bucle da 8.352 falsos diffs si el HMR reemplaza el subárbol a mitad de corrida.
getComputedStyle sobre un nodo DESACOPLADO devuelve la cadena vacía en TODAS
las propiedades, y el diff lee cada vacío como un cambio. Se arregla
re-consultando los nodos en cada instantánea, y se detecta haciendo fallar la
sonda ante un computed vacío. Pariente de hmr-stale-tab-phantom-findings.
ARTEFACTOS
Sonda estándar: 4 nodos, 800 valores x 7 estados -> 0 diffs.
Sonda de variantes (2 formas x 2 orientaciones x 3 estados x 5 tallas, elemento
y ::before): 17.280 valores -> 0 diffs.
Capturas 2x antes/después, lineal y circular: idénticas byte a byte.
Censo --only progress 87 % · component:audit PASS 1/1 · eidos-lint 0 invalid
(13 morfo-backed, 12 eidos-only) · vitest src/uix/eidos 439/440 (el único rojo
es el conocido skin-media-player en lint.test.ts) · rtl:check 0 · docs:check 0
· npm run check sin errores atribuibles a progress · prettier limpio en lo
tocado (progress.css estaba limpio en HEAD y sigue limpio; los dos ficheros del
centinela ya venían sucios de antes y mis líneas no añaden nada).
README de eidos con su sección «Talla y tema» y pestaña Tokens en la demo,
verificada en el navegador: 43 filas resueltas en vivo, 0 errores de consola.
NOTA DE ÁRBOL COMPARTIDO
Otra sesión trabaja sobre form en los mismos ficheros (base.ts,
generated/base.css, los dos del centinela y el índice de fichas). Lo indexado
se construyó a mano desde HEAD + sólo mis hunks, así que el commit no arrastra
su trabajo en curso; docs/audit/theming/README.md lleva sólo el delta de
progress y conserva la fila de form tal como está en HEAD.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
## 2. Sistema transversal (0) — informativo, fuera del ratio
Un tema los alcanza **a nivel de sistema**, por diseño (recipe-contract §2).
@ -68,7 +67,7 @@ Consumidos y **no declarados en el CSS** (vienen de `base.ts` o de un estilo inl
- **Tiene eje `size`**: los tokens dimensionales van por talla (`{part}-{eje}-{k}`) apuntando al bundle `--size-{k}-*`, nunca al primitivo crudo (theming §5; el guard `recipe-css-contract` prohíbe el primitivo).
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (3)
### 4.1 Tokens a declarar en `lib/recipes/base.ts` (2)
Valor **verbatim** del CSS de hoy: el default no se mueve, sólo cambia quién
puede moverlo. Nombres derivados de recipe-contract §1 (ejes lógicos, talla
@ -80,7 +79,6 @@ no distingue lo que debería — se marca `⚠`.
// 2026-08-23. The guard now sweeps `data-shape` (like its twin meter) and
// switches the demo's indeterminate + vertical controls on, which takes it
// from 22/41 to 40/43. What is left needs a state the demo cannot hold at
// the same time as the ones already forced, or a property the guard freezes.
'indicator-bg-loaded':
"only under [data-state='loaded'], and the run holds `indeterminate` to reach the sweep tokens; forced on the real root -> reaches (oklch(0.6406 0.1329 157.68) -> rgb(1,2,3))",
'transition-duration':
'frozen by the guard by design; unfrozen pass -> reaches (0.18s -> 11.5s)',