|
|
# CONTINUE — eje Theming «theme-reach» (handoff, act. 2026-08-20)
|
|
|
|
|
|
**Estado: EN EJECUCIÓN — bloque del vocabulario CERRADO.** 7 componentes corregidos (auditados
|
|
|
contra la gramática nueva: 6 limpios, 1 corrección), 20 fichas revisadas, el
|
|
|
informe de auditoría vivo y regenerable. **El 2026-08-20 el autor firmó las 14
|
|
|
decisiones pendientes**: las D-TH.1…8 enteras (§4 del plan, con dos enmiendas)
|
|
|
más familia calendar, mandato Field y hover→capa de estado — el acta está en
|
|
|
§«Firmas del 2026-08-20». Y el bloque del vocabulario se ejecutó el mismo día
|
|
|
(tres commits, §«Lo ejecutado»): 269 claves renombradas, R-5.3 en `error`,
|
|
|
doctrina al día. Lo siguiente es la migración a la capa de estado (firma 3).
|
|
|
|
|
|
- Fuente viva del método: [`PLAN-theming.md`](./PLAN-theming.md) (§7 el
|
|
|
protocolo, sin excepciones).
|
|
|
- **Informe por componente**: [`docs/audit/theming/`](../audit/theming/) — un
|
|
|
README de conjunto + 170 fichas (162 recetas + 8 sin receta). Cada ficha lleva
|
|
|
su análisis, su propuesta y, en §5, el **veredicto** escrito a mano, que
|
|
|
sobrevive a la regeneración.
|
|
|
|
|
|
## EJECUTADO 2026-08-20 — vocabulario de tokens: D-TH.6 (codemod) + R-5.3 (guard)
|
|
|
|
|
|
**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»).
|
|
|
|
|
|
**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:
|
|
|
|
|
|
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):
|
|
|
|
|
|
1. **`--names` en el censo**: el inventario exacto por clase de desviación,
|
|
|
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.
|
|
|
2. **Codemod value-preserving** (molde: px/py del 2026-07-06 y su triple muro):
|
|
|
`-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**,
|
|
|
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
|
|
|
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
|
|
|
`[variante-]?[modificador-]?[parte-]?[slot][-talla]?` donde talla ∈ las 7
|
|
|
canónicas, modificador ∈ vocabulario cerrado y DELANTE, slot ∈ (§6.7
|
|
|
recipe-level ∪ ejes dimensionales de recipe-contract §1), y la PARTE contra
|
|
|
`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
|
|
|
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`).
|
|
|
4. **Docs en el mismo pass**: recipe-contract §1 gana la fila del modificador
|
|
|
(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.
|
|
|
|
|
|
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
|
|
|
|
|
|
1. `node --import tsx/esm scripts/theming-census.ts` — debe dar **162 recetas ·
|
|
|
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.
|
|
|
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
|
|
|
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`).
|
|
|
3. Ejecutar con el protocolo §7 entero. **Un componente = un commit.**
|
|
|
|
|
|
## 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.
|
|
|
|
|
|
## BLOQUE F2-A — el próximo grupo: analizar y corregir (preparado 2026-08-20)
|
|
|
|
|
|
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 · …).
|
|
|
|
|
|
---
|
|
|
|
|
|
## 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`).
|
|
|
|
|
|
### 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.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 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.
|
|
|
|
|
|
## 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.
|
|
|
|
|
|
| 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)
|
|
|
|
|
|
```bash
|
|
|
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
|
|
|
node scripts/__theming-sentinel.ts <componente> # ¿alcanza cada token?
|
|
|
node scripts/__shot.ts <componente> <salida.png> # captura 2× del stage
|
|
|
```
|
|
|
|
|
|
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).
|
|
|
|
|
|
## Trampas que costaron un commit cada una (no repetirlas)
|
|
|
|
|
|
- **Clave duplicada en `recipes/base.ts`**: añadir un bloque que ya existía lo
|
|
|
descarta **en silencio** (gana la segunda). Guard antes de generar:
|
|
|
`grep -oE "^\t'?[a-z0-9-]+'?: \{" src/uix/eidos/lib/recipes/base.ts | sed "s/[\t':{ ]//g" | sort | uniq -d`
|
|
|
→ debe salir vacío.
|
|
|
- **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.
|
|
|
- **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**.
|
|
|
|
|
|
## Fuentes
|
|
|
|
|
|
- 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`.
|