astra
alpha-0.1-background
alpha-0.1-dir-prefs
alpha-0.1-sec-dom
menubar-v4-safe
active-uix
morfo-runtime
morfo-driven-soma
semantuix
glm-5
main
sium-v1.0
${ noResults }
15 Commits (15eb9c56c94bf14ba9a4f944a29fc5aa8b02bfeb)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
15eb9c56c9 |
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 |
|
|
5e7462a3ff |
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 |
|
|
5b10005ef7 |
docs(theming): apuntar para después — text-effects acuña tipografía propia contra el canon
Pregunta del autor (2026-08-22): «¿qué sentido tiene que text-effects introduzca diferentes nombres de tipografía cuando ya hay un canon establecido?». Ninguno. Queda apuntado como FIRMA PENDIENTE (CONTINUE §5 1.bis · PLAN §8 · next-features §13) para resolverlo después: Cinco claves del contrato acuñan tipografía: `text-focus.word-size` (3rem vía el fantasma `--font-size-4xl`) y `word-weight` (900) · `text-circular.weight` (900) y `font-size` (1.5rem) · `text-gradient.font-weight` (500, subida hoy). Son opiniones del seed react-bits que el protocolo «valor verbatim» convirtió en contrato sin la pregunta previa. La doctrina del propio eje (F2-B regla 2, cinco precedentes) dice que una receta CONSUME la capa tipográfica (`--style-*`) o HEREDA (`link` → `inherit`): un TextGradient dentro de un `h1` ES un h1. Resolución propuesta: retirar las cinco claves y heredar del contexto. Mueve defaults → firma. Con ello muere el fantasma `4xl` sin tocar el módulo de tipografía (canon, prohibido modificar). docs:check 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
652c3411ab |
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 |
|
|
97a6f03d76 |
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 |
|
|
3a47c1a53d |
test(theming): el suelo del alcance, con sus dos muta-pruebas — cierra F0.d
`src/uix/eidos/theming-reach-floor.test.ts`. El plan lo encargaba en F0 («un test que fije el suelo: el número SUBE o el test falla») y nunca se escribió, así que hasta hoy **nada impedía que el alcance BAJARA entre sesiones**: una receta podía cambiar un token público por un primitivo y sólo se vería leyendo el censo a mano. Cuatro trinquetes, medidos el 2026-08-22 tras el endurecimiento del censo: alcance global ≥ **56 %** · literales ≤ **564** · knobs sobre global crudo ≤ **1.156** · componentes al 100 % ≥ **14**. Cuando el eje avanza, se suben en el mismo commit que se lo gana. **LAS DOS MUTA-PRUEBAS** (memoria `a-guard-that-inspects-nothing-passes`: un guard sólo vale cuando lo has VISTO rojo). No se dan por supuestas — se ejecutaron: 1. Inyectar UN literal (`border-radius: 7px` en `mark`) → rojo en `maxLiteral` y en la sonda del clasificador. Revertido, verde, árbol idéntico. 2. Cambiar CINCO públicos de `tree-view` por primitivos crudos (92 % → 73 % en ese componente) → rojo en `maxGlobal`. Revertido, vuelve a 92 %. Y de ahí sale una observación que queda escrita en el propio test: **los techos son el detector FINO y el porcentaje el grueso.** Cinco knobs de ~4.700 no mueven un porcentaje redondeado, pero sí un techo — una regresión demasiado pequeña para esconderse de `reachPct` sigue disparando `maxGlobal`. Lo que el test NO asegura, a propósito: el alcance POR COMPONENTE, que ya gobiernan el censo `--only` y las excepciones R-5.x — un número bajo puede ser doctrina bien aplicada (`menu-dial` paga por consumir bien una capa compartida, `link` por heredar la tipografía ambiente). Y `system`, que es temable a nivel de sistema por diseño y queda fuera del ratio. Gates: los 5 tests en verde · suite eidos 439/440 (el único rojo sigue siendo el conocido `skin-media-player`) · prettier sobre el fichero nuevo · docs:check 0 · check limpio. `PLAN §5 F0.d` y la entrada de §13 quedan cerradas. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
a0fc8f4f1e |
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 |
|
|
43b3e8a501 |
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 |
|
|
8400e5bdd4 |
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 |
|
|
df27351ffc |
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 (
|
2 months ago |
|
|
679dfdb291 |
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 |
|
|
f5f2b5d225 |
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 |
|
|
f09e04fab1 |
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 |
|
|
a9b9711657 |
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 |
|
|
07a99679d7 |
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 |