|
|
# REVIEW — theming «theme-reach»: lo ejecutado tras la revisión adversarial del 22 (2026-08-23)
|
|
|
|
|
|
**Alcance**: los **26 commits** posteriores a `cd6a9f4e3` (la revisión §7.7 del
|
|
|
bloque de catorce, 2026-08-22), que no han pasado ningún análisis posterior:
|
|
|
`f25f5bb1d` (drawer, rojos) · `27dc6dba3` (metrics + color-picker, rojos) · los 17
|
|
|
de la mañana del 23 (menubar · field · onion-menu · button · callout · empty-state
|
|
|
· dropdown-menu + context-menu · checkbox · image · anchor-nav · banner · surface ·
|
|
|
date-range-field · time-range-field · tooltip · cola pequeña de seis · audio-player)
|
|
|
· los 7 de la tarde (navigation-menu · waveform · color-field · background ·
|
|
|
s-text-virtual-list · badge · cropper). **33 componentes.**
|
|
|
|
|
|
**Qué se ha comprobado aquí, con medición propia** (instrumental en
|
|
|
`scripts/__rv-*.mjs`, un solo uso): gramática de nombres (`--names`) · pureza del
|
|
|
`generated/base.css` commit a commit · equivalencia ESTÁTICA «valor viejo = valor
|
|
|
del contrato» par a par en los 26 commits · `npm run check` atribuido por fichero ·
|
|
|
`prettier --check` en los ficheros tocados (y si la no conformidad era previa) ·
|
|
|
`component:audit` completo · `eidos-lint-all` · sonda ×2 de los siete de la tarde
|
|
|
contra su línea base, con el servidor reiniciado · barrido del centinela sobre
|
|
|
TODOS los componentes con ledger · re-medición dirigida de las adjudicaciones
|
|
|
dudosas · presencia de README «Talla y tema», tab `Tokens` y veredicto §5.
|
|
|
|
|
|
**Qué NO es esto**: la revisión §7.7 completa. Falta la re-medición del «default
|
|
|
idéntico» contra una BASE (worktree en `cd6a9f4e3`) para los 26 de la mañana, el
|
|
|
«píxel hacia arriba» en los hover tocados y el registro de doble animación. Es el
|
|
|
punto P5 del plan.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 1. Errores reales (código o ledger) — 5
|
|
|
|
|
|
| # | dónde | qué | prueba |
|
|
|
| --- | --- | --- | --- |
|
|
|
| E1 | `badge.min-block-size-{xs,sm,md,lg}` + `min-block-size` (`271fcd4df`) | **Nombre fuera de recipe-contract §1**: «Control height per size → `control-height-{size}` (o `{part}-height-{size}`) — inventing a third name per component». El catálogo ya lo dice: `navigation-menu.trigger-height-{k}` se CONSUME como `min-block-size`, `accordion.trigger-min-height-{k}`, `field.control-height-{k}`. R-5.3 no lo caza (guarda tinta y modificador, no el vocabulario dimensional). | `base.ts`: 41 claves `-height-`, 0 precedentes de `min-block-size-{k}`; §1 fila 40 |
|
|
|
| E2 | ledger `background.parallax-travel` (`9bdc5a5d5`) | **Adjudicación MAL CLASIFICADA**: dice «structural — only enters via the scroll-linked keyframes; the measured stage has no scroll timeline». Medido hoy: el escenario SÍ tiene `animation-timeline: view()`; forzando `data-parallax` + speed 1, el `translate` sigue al scroll (−9,7 → 14,6 px) y **el token alcanza** (14,6 → 60,5 px al mismo scroll con `--background-parallax-travel: 400px`). Lee muerto en el guard porque (a) la demo arranca con speed 0 (sin `data-parallax`) y (b) **el guard no fotografía `translate`/`transform`** (tampoco `mask-image`). | `scripts/__bg-parallax.mjs` |
|
|
|
| E3 | README de `cropper` (`f03ee5af4`) | Dice «hueco de composición (el botón de zoom debería componer `IconButton`), **anotado**» — y no está anotado en ningún sitio: ni fila en `## Gaps`, ni next-features §13. | `grep IconButton` sólo en la prosa |
|
|
|
| E4 | `scripts/theming-sentinel-exceptions.ts` | Mis entradas de `color-field` / `background` / `badge` añaden **4 hunks de prettier** (63 preexistentes → 67). Protocolo §7.5.18. | `prettier --check` base vs HEAD |
|
|
|
| E5 | `float-panel` (ledger) + handoff | **12 tokens públicos muertos SIN adjudicar** — `bg`, `border`, `border-width`, `shadow`, `active-shadow`, `font-family`, `line-height`, `resize-size`, `button-size`, `accent`, `transition-duration`, `transition-ease` — y el guard R-5.4 **falla** en él hoy. No es regresión: el commit `b4510fbf8` (08-22) ya lo dejó escrito («lo rojo que queda son 12 tokens anteriores; seis son el plano de profundidad, §12.9») y nadie los midió después. **La afirmación del handoff «desde el 2026-08-23 NO queda ningún rojo del bloque viejo» es FALSA**: `drawer`, `metrics` y `color-picker` se adjudicaron; `float-panel` no. | barrido del centinela, repetido a solas: 17/40, 12 sin adjudicar; ledger idéntico al del 22; ningún commit tocó el componente desde entonces |
|
|
|
|
|
|
## 2. Desviaciones del protocolo — 5
|
|
|
|
|
|
| # | quién | qué | alcance |
|
|
|
| --- | --- | --- | --- |
|
|
|
| D1 | sesión de la mañana | **Ni README «Talla y tema» ni tab `Tokens` en la demo** en NINGUNO de sus commits de tokenización (PLAN §5 F2 «README de eidos con la tabla de tokens»; handoff, protocolo pasos 8 y 9). `git show --stat`: sólo `docs/audit/theming/`, CSS, `base.ts`, ledger. | **20 componentes**: menubar · field · onion-menu · button · callout · empty-state · dropdown-menu · context-menu · checkbox · image · anchor-nav · banner · date-range-field · time-range-field · tooltip · section · sticky · button-group · qr-code · toggle-group · split-button (+ `surface` y `audio-player`, sin demo: sólo README) |
|
|
|
| D2 | yo (tarde) | `waveform` y `cropper`: la tabla de tokens fue a una sección existente (`## Tokens`, `## Recipe tokens`) y no a «Talla y tema» (molde `navigation-menu`). | 2 |
|
|
|
| D3 | las dos sesiones | **Sin capturas 2× antes/después** (§7.2.6, §7.4.13) en ningún commit; **sin «píxel hacia arriba»** (§7.4.12) — relevante sólo donde se tocaron reglas `:hover` (mañana: dropdown/context-menu `hover-item-*`, anchor-nav `hover-link-fg`, menubar; tarde: ninguno). | 33 / los de hover |
|
|
|
| D4 | yo (tarde) | `npm run check` sólo en `navigation-menu`; `prettier --check` en ninguno; guard re-verificado tras cada cambio sobre 3–5 componentes, no sobre el ledger entero. **Subsanado en esta revisión**: check 0 errores en mis ficheros (los 72 globales son ajenos y preexistentes); prettier: los 11 ficheros ya no pasaban ANTES (sólo E4 es mío); barrido completo del ledger abajo. | 6 |
|
|
|
| D5 | las dos sesiones | **Sin revisión adversarial §7.7** de ningún bloque desde el 22: 26 commits, 33 componentes. | todo el alcance |
|
|
|
|
|
|
## 3. Refutado (se comprobó, no hay hallazgo)
|
|
|
|
|
|
- **Gramática**: `--names` → DESVIADAS 0 (3.931 conformes, 447 rol-slot canónicas).
|
|
|
- **Pureza del generado**: 26 commits, cada línea ± de `generated/base.css` es del componente del commit.
|
|
|
- **«El default es idéntico», estáticamente**: los 26 commits, par a par `prop: viejo → prop: var(--c-key)`: cada valor del contrato ES el viejo — o el respaldo que se quitó (`var(--x, V)` → contrato `V`), o el alias de bundle verificado en el generado (`--size-{k}-control-height: var(--control-height-{k})`, `--size-{k}-font-size: var(--font-size-{k})`, `--size-{k}-font-line-height: var(--font-line-height-{k})`). Los tres que parecían cambiar valor eran artefactos del emparejamiento: `anchor-nav` (hover → `hover-link-fg` content-primary; active → `active-link-fg` primary-text, correcto), `dropdown-menu.separator-bg` (el respaldo `--color-border-subtle` era código MUERTO: la clave ya valía `--color-neutral-separator`), `menubar` (`--floating-gap` por talla: `space-1 * 0.5` → `padding-sm = --space-0-5`, misma aritmética; el `font-size` del panel por talla).
|
|
|
- **Sonda ×2 de los siete, servidor reiniciado**: 0 diffs en las 14 corridas salvo `background` corrida 1 — **2 diffs de `inlineSize` del ESCENARIO (870 ↔ 1.350 px)**, el ancho del layout de la demo, no el componente; corrida 2 limpia. Ruido de instrumento, a §13.
|
|
|
- **`component:audit`**: 162 PASS · 4 NEEDS-WORK (`badge` R-1.5 PREEXISTENTE y ya anotado; `gradient-picker`, `mockup`, `motion` ajenos). **`eidos-lint-all`**: 0 invalid, 0 class-hooks.
|
|
|
- **Ledger**: 196 adjudicaciones en alcance; 26 sin medida explícita en su propia línea, de las que 25 son continuaciones «same as…» de una hermana medida y 1 es E2.
|
|
|
- **Barrido del centinela sobre todo el ledger** (59 componentes, tras los cambios del guard de hoy: `extraNodes`, `openBy: 'hover'`, `prepareWith`): **0 STALE, 0 errores de corrida, y un único componente con muertos sin adjudicar — `float-panel` (E5), que ya lo estaba el 22.** Los cambios del guard no han roto nada del ledger. Detalle en §5.
|
|
|
- Mis adjudicaciones de `background.fade-*` («the guard does not snapshot mask-image») son **ciertas**: `maskImage` no está en `PROPS`.
|
|
|
- El barrido de variantes de `badge` (`soft/solid/outline/ghost`) casa con `EIDOS_VARIANTS.chip`.
|
|
|
- `TokensPanel` acepta `stage` opcional (s-text-virtual-list lo omite): sin error de tipos.
|
|
|
|
|
|
## 4. Plan de solución — **FIRMADO Y EJECUTADO 2026-08-23**
|
|
|
|
|
|
| P | estado | commit |
|
|
|
| --- | --- | --- |
|
|
|
| P8 | ✅ `float-panel`: los 12 medidos y adjudicados; guard en verde; frase del handoff corregida | `233ef989b` |
|
|
|
| P2 | ✅ `background.parallax-travel` reescrito; hueco `translate`/`transform` en §13 | `233ef989b` |
|
|
|
| P3 | ✅ `cropper` §Gaps real; «Talla y tema» en cropper y waveform; ledger sin hunks nuevos | `233ef989b` |
|
|
|
| P1 | ✅ `badge.min-block-size-{k}` → `min-height-{k}`; R-5.3 sin vocabulario dimensional, a §13 | `bfe7727b0` |
|
|
|
| P4 | ✅ 22 READMEs «Talla y tema» derivados del contrato + 21 pestañas `Tokens`, verificadas en el navegador | `e522e04e6` |
|
|
|
| P6 | ✅ §13: flicker del escenario de background · `audio-player` sin README · los tres huecos de `PROPS` | `233ef989b` + éste |
|
|
|
| P7 | ✅ PLAN §7: las capturas se exigen DESDE el siguiente componente; píxel-arriba obligatorio si se toca `:hover` | éste |
|
|
|
| P5 | ✅ revisión adversarial §7.7: 5 hipótesis, 5 refutadas, 0 hallazgos nuevos (§6) | éste |
|
|
|
|
|
|
### El plan original
|
|
|
|
|
|
| P | qué | cómo | toca píxel | firma |
|
|
|
| --- | --- | --- | --- | --- |
|
|
|
| **P1** | E1 — renombrar `badge.min-block-size-{xs,sm,md,lg}` → `height-{xs,sm,md,lg}` y el resuelto `min-block-size` → `height` | un commit: `base.ts` + `badge.css` + regenerar + sonda (diff 0 por construcción) + guard (29/71, mismas adjudicaciones) + README + ficha + PLAN §8 («nombre corregido»). El tab `Tokens` sigue en 71. | no | **sí** — renombra una clave pública recién acuñada; el nombre canónico es de §1, pero la decisión de renombrar hoy es tuya |
|
|
|
| **P2** | E2 — reescribir la adjudicación de `background.parallax-travel` («parallax off in the demo (speed 0); forced data-parallax + speed 1 → reaches through the scroll-linked translate (14.6 → 60.5 px at the same scroll); the guard does not snapshot translate») y registrar en §13 el hueco `translate`/`transform` del guard (ya hay precedente en `drawer.handle-active-scale`) | ledger + next-features; un commit docs | no | no |
|
|
|
| **P3** | E3 + D2 + E4 — `cropper` README: fila en `## Gaps` («el botón de zoom compone cromo propio; debería componer `IconButton` — y por eso su hover queda fuera de la capa de estado»); `waveform` / `cropper`: la sección pasa a llamarse «Talla y tema»; ledger: partir mis 4 entradas largas como prettier las quiere (a mano, sin `--write` sobre el fichero entero: tiene 63 hunks ajenos) | un commit docs | no | no |
|
|
|
| **P4** | D1 — los **20 componentes de la mañana**: README «Talla y tema» (tabla de claves públicas + lo adjudicado, molde `navigation-menu`) y tab `Tokens` en la demo (`<TokensPanel component="x" stage={stageRef ?? undefined} />` + su botón con el conteo); `surface` y `audio-player` sólo README (sin demo). | mecánico, sin píxel. Propuesta: **un commit por componente** (el protocolo es «un componente = un commit» y el registro §8 lo referencia así), o un único commit de lote si prefieres cerrar rápido | no | **sí** — por el alcance (20) y por la forma (por componente vs lote) |
|
|
|
| **P5** | D5 — la **revisión adversarial §7.7** de los 26 commits: worktree en `cd6a9f4e3` con `server.fs.allow` (trampa de la junction), comprobar que un componente MONTA antes de comparar, sonda base vs HEAD por componente (33), «píxel hacia arriba» en los que tocaron `:hover` (dropdown-menu, context-menu, anchor-nav, menubar), registro de `animationstart/end` donde se movió un sello (ninguno de los 26, a comprobar), centinela rehecho. Lo estático de esta revisión (§3) entra como hipótesis ya refutadas. | una sesión | no | **sí** — es el guard de bloque del PLAN; decide si antes o después de seguir la cola |
|
|
|
| **P6** | instrumento — registrar en §13: el flicker de `inlineSize` del escenario de `background` (870/1.350) · `translate`/`transform`/`mask-image` fuera de `PROPS` del guard (tres tokens vivos leen muertos: `parallax-travel`, `fade-size`, `fade-at`; y `drawer.handle-active-scale`). Si se añaden a `PROPS`: **re-verificar los ~35 con ledger** antes de commitear (el barrido de §5 es la base de comparación). | docs (+ opcional guard) | no | para tocar `PROPS`, sí |
|
|
|
| **P7** | D3 — capturas 2× antes/después y «píxel arriba» no se recuperan retroactivamente para 33 componentes: se hacen dentro de P5 para los que tocaron hover; para el resto, el diff de computed 0 + el centinela son el artefacto. Anotar en PLAN §7 que las capturas se exigen DESDE el siguiente componente. | docs | no | no |
|
|
|
|
|
|
| **P8** | E5 — `float-panel`: medir los 12 uno a uno con el panel abierto y adjudicar o retirar. Hipótesis ya escrita por el propio commit del 22: los seis de superficie/tipografía son el plano `overlay` (misma clase que `tooltip` / `popover` → adjudicación «SUPERSEDED by the overlay plane», como la de tooltip); `active-shadow` sólo mientras se arrastra; `accent` alimenta un privado que pinta en foco/arrastre (forzar estado); `resize-size` / `button-size` deberían alcanzar (si no, están mal cableados); `transition-*` la ley conocida (pasada sin congelar). Y corregir la frase del handoff. | un commit (ledger + handoff + ficha §5 de float-panel) | no | no — es adjudicar lo medido; si alguno resulta MUERTO de verdad, su retirada sí se presenta |
|
|
|
|
|
|
**Orden propuesto**: **P8 (el guard está en rojo hoy)** → P2 + P3 (docs, diez minutos) → P1 (una clave) → P4 (los 20, mecánico) → P6 → P5 (la revisión de verdad, una sesión). Nada de esto mueve un píxel.
|
|
|
|
|
|
## 6. P5 — la revisión adversarial §7.7, ejecutada (2026-08-23)
|
|
|
|
|
|
**Molde Sidebar: intentar REFUTAR cada afirmación con medición propia, no leer
|
|
|
la del commit.** Base = worktree en `cd6a9f4e3` (`G:/tmp/rv-base`), dev server
|
|
|
propio en 5301, `node_modules` por junction y `server.fs.allow` con las dos
|
|
|
rutas — la trampa que el handoff registra: sin eso Vite responde 403 a `/@fs/…`
|
|
|
y la página NO hidrata, y se compara contra una base muerta. **Comprobado ANTES
|
|
|
de comparar nada**: los diez primeros componentes montan e hidratan en la base
|
|
|
(10, 4, 10, 2, 57, 17, 6, 25, 2 y 1 nodos).
|
|
|
|
|
|
### H1 — «el default es idéntico»: **REFUTADA la duda, 33 de 33**
|
|
|
|
|
|
Sonda del HEAD (la misma en los dos lados, para no comparar instrumentos)
|
|
|
contra base y contra HEAD, componente a componente:
|
|
|
|
|
|
- **31 con 0 diffs**, de 192 a 7.360 valores por componente y de 7 a 8 estados.
|
|
|
Total comparado: **~48.000 valores computados**.
|
|
|
- `surface` daba 0 valores por una URL mía equivocada; en su ruta real
|
|
|
(`/temas/gradientes`, la que su propio override declara) → **0 diffs sobre 896
|
|
|
valores, 4 nodos**.
|
|
|
- `image` (1 diff) y `audio-player` (7 diffs + 1 nodo ausente) son **ruido del
|
|
|
instrumento, probado**: corriendo la sonda DOS VECES contra el MISMO código,
|
|
|
`image` reproduce su diff y `audio-player` da **once** — más que la
|
|
|
comparación base↔HEAD. Las dos propiedades implicadas son estado vivo: la
|
|
|
`opacity` de un `<img>` con animación de entrada (la sonda congela
|
|
|
`transition`, **nunca `animation`** — ley conocida) y el `inline-size` del
|
|
|
rango *buffered* de un audio, que depende de lo que lleve cargado.
|
|
|
|
|
|
### H2 — «el velo cae donde debe»: **verde en los cuatro que tocaron `:hover`**
|
|
|
|
|
|
Píxel hacia arriba (`elementsFromPoint` en el centro del control, pila de
|
|
|
ancestros con `backgroundImage`/`backgroundColor`):
|
|
|
|
|
|
- `dropdown-menu` y `context-menu`: el velo está en `[data-…-item]`, **radio
|
|
|
4px** — el nodo CON forma; el `list-surface` de debajo (radio 6px) limpio.
|
|
|
- `menubar`: la barra pinta el abierto en el propio `<button>` (radio 2px) sin
|
|
|
derramar al `[data-menubar]`; la fila del panel, el velo en su item (4px).
|
|
|
- `anchor-nav`: **sin velo en ninguna capa**, y es correcto — su hover es sólo
|
|
|
tinta (`hover-link-fg`), no capa de estado. Medido sobre un enlace NO activo,
|
|
|
porque el primero que casa el selector lleva `data-active` y pinta otra cosa.
|
|
|
|
|
|
_(El `data-uix-stage-area` sale con velo en varias pilas: es el fondo a cuadros
|
|
|
del harness, y las demos están fuera del eje.)_
|
|
|
|
|
|
### H3 — «no hay doble animación»: **no aplica, y se comprobó**
|
|
|
|
|
|
Ninguno de los 26 commits toca `animation`, `@keyframes`, `data-event` ni
|
|
|
`motion-*` en `src/uix/eidos/components/`. No hay sello movido que pueda
|
|
|
duplicarse.
|
|
|
|
|
|
### H4 — «cada token alcanza»: **rehecho, y destapó E5**
|
|
|
|
|
|
El barrido del centinela sobre los 59 con ledger (§5): 0 STALE, 0 errores, y un
|
|
|
único componente en rojo — `float-panel`, ya arreglado (P8).
|
|
|
|
|
|
### H5 — «el contrato no tiene duplicados ni huérfanos»: **limpio**
|
|
|
|
|
|
144 bloques en `base.ts`, cero duplicados y cero claves repetidas dentro de un
|
|
|
bloque. El test oficial de huérfanos (`recipe-css-contract.test.ts`) pasa.
|
|
|
|
|
|
⚠ **Y aquí mintió mi propio instrumento**: un guard estricto de un solo uso
|
|
|
reportó **185 huérfanos** — los pasos de escala por talla y todas las claves de
|
|
|
tono. Falso: excluía `generated/`, que es exactamente donde el TSC emite el
|
|
|
nombre resuelto y donde 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.
|
|
|
|
|
|
### Veredicto de P5
|
|
|
|
|
|
**5 hipótesis · 5 refutadas · 0 hallazgos nuevos.** Los dos únicos diffs de la
|
|
|
comparación son ruido reproducible del instrumento, no regresiones, y quedan
|
|
|
registrados en §13. Los hallazgos reales de esta revisión estaban en el análisis
|
|
|
ESTÁTICO (E1–E5) y ya están arreglados.
|
|
|
|
|
|
## 5. Barrido del centinela (todo el ledger, tras los cambios del guard de hoy)
|
|
|
|
|
|
`rv-dyn.sh`, 59 componentes con ledger, uno tras otro contra el mismo dev server
|
|
|
(5180), 2026-08-23 por la tarde:
|
|
|
|
|
|
- **0 excepciones STALE** en los 59 (ninguna adjudicación ha empezado a moverse).
|
|
|
- **0 corridas con error** (ninguna ruta 404 ni timeout: los `urls` de
|
|
|
picker-shell / audio-player / surface resuelven).
|
|
|
- **1 componente con muertos sin adjudicar: `float-panel`, 17/40, 12 sin
|
|
|
adjudicar** (E5). Repetido a solas: idéntico, así que no es el falso exit por
|
|
|
lote del que avisa el handoff.
|
|
|
- Los cinco que re-verifiqué a mano durante la tarde (command 51/57 · table 42/45
|
|
|
· tooltip 15/23 · navigation-menu 43/44 · waveform 11/11) dan lo mismo en el
|
|
|
barrido: los cambios del guard son inocuos fuera de sus overrides.
|
|
|
- Sonda ×2 de los siete de la tarde contra su línea base, en la misma corrida:
|
|
|
**0 diffs en las 14**, salvo `background` corrida 1 (2 diffs de `inlineSize`
|
|
|
del ESCENARIO, 870 ↔ 1.350 px; corrida 2 limpia) — ruido del layout de la
|
|
|
demo, a §13 con P6.
|
|
|
|
|
|
Bisección del guard sobre `float-panel` (`scripts/__sentinel-<sha>.ts`, cada
|
|
|
versión de `theming-sentinel.ts` desde `cd6a9f4e3` contra el ledger de hoy,
|
|
|
idéntico para este componente): **la versión del 22 ya da 17/40 con los MISMOS
|
|
|
12 sin adjudicar**, y cada versión intermedia también. No hay regresión del
|
|
|
guard: es un rojo del 22 que quedó sin medir y que el handoff dio por cerrado.
|