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 }
91 Commits (0c1d945bae60bc3b7f981601541ed91e0d2df846)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
24d30ee1a8 |
fix(sema): el silencio deja de ser una resta y pasa a ser un valor — SILENT
Directiva del autor: «el silencio no admite verbos ni intents, es universal,
por lo tanto es un valor canonico que cuando se le envia al canal semantico
este simplemente lo ignora y no envia nada al soundengine».
LO QUE ERA. `commit.silent`, `emerge.silent` y `contact.silent` no eran
silencio: eran una RESTA del gain base de su familia (-0.3, -0.2, -0.25). Por
eso hacian falta tres —cada una tenia que saber que base cancelaba— y por eso
el silencio tenia familia, que es el absurdo que el autor senalo. Y un cero es
un NUMERO, y las capas posteriores mueven numeros.
LA MEDICION QUE LO CIERRA. Los deltas de intent suman RUGOSIDAD (`risk` +0.2,
`threat` +0.4), lo que cruza el umbral del AM del motor; y el modulador se
conecta al AudioParam de la envolvente —y conectar a un AudioParam SUMA, no
multiplica—, asi que con la envolvente en cero el tremolo pasaba a ser la senal
entera. Renderizado offline con el grafo real del motor:
toggle "silenciado" neutral -77.0 dBFS (mudo de verdad)
toggle "silenciado" risk -13.9 dBFS <- con gain declarado 0
toggle "silenciado" threat -6.7 dBFS
boton normal, referencia -9.3 dBFS
El "silencio" era mas fuerte que un boton, y lo que sonaba no era el earcon:
era un zumbido sin ataque ni caida, cortado en seco. La medicion que yo mismo
di por buena esta manana (0.0001) solo cubria el caso neutral.
LO QUE ES AHORA. `SILENT` — un valor canonico exportado por `$uix/sema`. Se
declara en el slice del canal y el RESOLVER lo honra retirando ese canal de la
firma. Un solo mecanismo para todos los canales, y nada aguas abajo ve jamas un
string donde espera una firma. Es la forma que el propio motor ya prescribia y
se estaba saltando: «muting DROPS the channel rather than scaling to zero,
because a `0` still buzzes» (engine.ts).
- universal por construccion: ninguna familia, ningun verbo, ningun intent
puede resucitarlo, porque no queda ningun numero que mover;
- liftable solo por REEMPLAZO: declarar sonido es una decision, no un delta;
- `SoundOverride` lo EXCLUYE por tipo — un afinado es un delta, nunca una
ausencia.
Migrado: tooltip (1) y media-player (6). Los tres tunings mueren del catalogo.
GUARDS. `resolver.test.ts` fija las cuatro mitades del contrato (retira el
canal · universal sobre 4 familias x 4 intents · vale igual para haptic ·
liftable por reemplazo), verificado en ROJO. `sounds-grammar.test.ts` cambia su
invariante muerta por las dos que ahora importan: ninguna clave `*.silent`, y
ningun afinado que deje su familia en `gain <= 0` — silencio disfrazado.
Doctrina al dia: sema.md gana la seccion «Silence is a value, not a tuning» con
la medicion; D.5 marca DEROGADA su solucion de mayo y registra el porque;
vocabularies.md deja de enumerar silenciadores y explica donde vive el silencio.
VERIFICADO: sema 211/211 · check 76 = la base 75 + 1 error del fichero huerfano
`__adv-verify-haptic-dead.test.ts` que dejo un agente de la auditoria (sin
trackear, no se borra sin instruccion) · docs:check 0/616 · navegador: el
transporte del player EMITE (`contact-activate`, `commit-toggle-play`) y
levanta CERO osciladores · prettier limpio (el unico aviso mio, resolver.ts,
formateado: +17 lineas, sin ruido).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
d05ecc1aa8 |
fix(sema): los toggles recuperan voz, y el silencio deja de sintetizarse — muere el prefijo form.
Tres cosas que el mismo hilo destapo, de la mas visible a la mas de fondo. 1) LOS TOGGLES SUENAN OTRA VEZ (directiva de autor 2026-08-05) switch, toggle y toggle-group llevaban SILENCIADOS desde el 2026-05-26: su pack aplicaba un tuning que restaba exactamente el gain base de la familia commit (0.3 - 0.3 = 0). Medido en navegador: pico 0.0001, el suelo de la rampa. Un silencio por defecto no se percibe como sobriedad sino como componente roto. Pasan a `commit.medium` (gain 0.1): audible, y un tercio de una pulsacion de boton (contact base 0.25) para que un flip no pese mas que una activacion. Los deltas de intent siguen montando encima (threat +0.1, fulfill +0.05). El haptico ligero no cambia. Medido despues: switch pico 0.1. Conservan el silencio, con su justificacion intacta, solo los dos donde el silencio ES la firma: tooltip (revela al pasar el raton, sonaria en cada cruce) y media-player (su propia salida ES audio — D-AP2.7, decision del hilo de audio). 2) EMITIR SILENCIO YA NO CUESTA `SoundChannel.handle` cortaba DESPUES de resolver la firma, asi que un tuning silenciador levantaba dos osciladores, un filtro y una envolvente programada para no sonar, en cada interaccion. Ahora corta antes de sintetizar cuando la ganancia resuelta es <= 0. El corte mira la ganancia RESUELTA, no el tuning, asi que un intent que la devuelve por encima de 0 (threat, fulfill) suena igual. Fijado con test propio, verificado en ROJO quitando el corto. 3) EL AFINADO SE NOMBRA POR LA FAMILIA QUE MODIFICA El catalogo mezclaba tres ejes en el primer segmento —familia (emerge.*, contact.silent), componente (tooltip.*, tabs.*) y la categoria huerfana form.*— sin regla declarada y sin guard que mirara. `form.commit.soft/subtle` entro el 2026-05-19 ( |
2 months ago |
|
|
05add971c7 |
feat(docs-check): el guard deja de ser ciego — I8/I9/I10 + corpus completo
El barrido exhaustivo del eje de opts encontro rutas fantasma, simbolos
inexistentes y props inventadas que docs:check no podia ver: sus 7 invariantes
no miraban dentro de los bloques de codigo, y su corpus no caminaba
src/arts, src/libs, src/svrs ni la raiz (567 de 673 .md). Tres invariantes
nuevos, escritos en la gramatica del propio guard:
- I8 imports: cabezas `$`/`@/` de los bloques ts/js/svelte contra la tabla de
alias EXTRAIDA de vite.config.ts (nunca copiada) + resolucion en disco.
`$lib` esta retirado: error en docs del framework (docs/**, src/uix/**),
tolerado en ejemplos de app consumidora. Builtins de SvelteKit en whitelist;
placeholders `{name}` y anti-ejemplos marcados, exentos.
- I9 simbolos: todo `XxxProvider`/`XxxOpts` en bloque de codigo debe existir
en el indice de simbolos de src. Exentos: placeholders, menciones negadas
("not TerraDialogProvider"), imports externos declarados por el propio
bloque (LoggerProvider de @opentelemetry) y el pragma `docs-check-allow:`.
- I10 tablas de props: cada prop documentada en un README de componente debe
declararse en su dir O en sus imports a un salto (convencion types.ts) —
el salto existe porque el rest-forwarding de eidos expone props que nunca
declara (los 4 falsos positivos del extractor lo demostraron).
Corpus 567 -> 614: entran las capas arts/libs/svrs/packs y la raiz;
crónica case-insensitive (continuar-*.md); docs aspiracionales
(RFC/IMPROVEMENTS/...) exentos de los invariantes nuevos.
Triage del fallout inicial (11): los 11 eran defectos del guard, no de los
docs — ethereal compara con @floating-ui por oficio (exento de I3),
`{Name}TriggerProvider` es placeholder pegado, LoggerProvider viene de un
paquete externo que el bloque importa. Verificado en ROJO (5 plantas, 5
disparos con linea exacta) y en verde (0/614).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
1cb61567e5 |
feat(direction): RTL-2 — el guard del doble volteo, la forma que se me colo dos veces
Cierra §10.1, la ultima deuda del eje. `dee2c9e3a` arreglo los dos defectos pero
dejo la FORMA sin guard, y es la que sobrevivio a la migracion §6.3 y a que yo
diera el eje por cerrado en §9.19.
LA FIRMA — dentro de un bloque cuyo prelude tiene `:dir()`, la misma familia
logica (`border`/`padding`/`margin`/`inset`-`inline`) declarada en LAS DOS caras,
EXACTAMENTE UNA con valor neutro (`0`, `auto`, `none`, `initial`, `unset`,
`revert`). Ese desequilibrio ES el espejo cancelado: la propiedad ya se habia
volteado cuando la regla matchea, asi que reubicarla la devuelve al punto de
partida y la deja en el borde opuesto al de sus hermanas.
Es mas estrecha que «bloque `:dir()` con puras logicas» a proposito. Una regla
que CAMBIA un valor bajo RTL sin reubicarlo es legitima —asimetrico por diseño
existe—, y las dos caras con valor son un autor describiendo dos bordes reales.
Lo que delata el defecto es el PAR, una cara apagada. Hay un test negativo por
cada uno de esos casos, que son los que evitan que la regla se vuelva ruido.
LAS TRES DECISIONES que el handoff dejaba abiertas:
- `:dir(ltr)` tambien entra. Igual de sospechosa, y no anade ruido.
- Marcador PROPIO, `rtl-mirror: <reason>`. Reutilizar `rtl-physical:` mentiria:
aqui no hay nada fisico, y un marcador que miente es peor que ninguno. Mismo
mecanismo (`exemptLines` toma ahora el patron por parametro), dos vocabularios.
Un test comprueba que el marcador de RTL-1 NO exime a RTL-2.
- Regla aparte, `lintRtlMirror()` con su propio `RtlMirrorFinding`. Los 14 tests
de RTL-1 quedan intactos y el tipo lleva los campos que importan
(`family`/`neutral`/`payload`) en vez de forzar los de RTL-1.
VERIFICACION, en este orden:
- `rtl-lint.test.ts` 27/27 (14 de RTL-1 intactos + 13 nuevos).
- RECALL con el runner COMPLETO contra el arbol pre-arreglo: restaure los dos
ficheros de `dee2c9e3a^` sobre el arbol, corri `rtl:check` y los devolvi con
`git checkout` en el mismo bloque. **2/2 cazados** (`feed.css:147`,
`tree-view.css:211`). Probar la funcion no basta: el runner es lo que corre.
- `rtl:check` sobre HEAD: 1 error, el de `palabras`, preexistente y excluido.
- `docs:check` 0/0 sobre 564 docs. `check` 77 = linea base.
Un defecto de presentacion salio al hacerlo: el `calc()` multilinea de tree-view
partia el mensaje por el primer salto. Los campos que RTL-2 emite colapsan el
whitespace; con test.
Actualizados los textos que el handoff avisaba que quedarian obsoletos: el
`enforcement:` y §4 del contrato, la fila RTL del build contract, la fila X-1.6
del checklist, y los docblocks de `rtl-lint.ts` y `rtl-check.ts` — que son
doctrina, no adorno.
⚠️ Sigue siendo cierto lo que NINGUNA de las dos reglas ve: leen texto CSS. Un
`transform` inline escrito por JS, un preset de motion compartido y la geometria
SVG siguen necesitando el ojo en RTL.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
ec533845d1 |
feat(direction): un guard para el eje logico-fisico, y el <main> que congelaba las 51 demos
Cierra la §2.1 del handoff. El guard nacio en rojo con 24 hallazgos y al arreglarlos aparecieron dos defectos mas grandes que el que buscaba. 1) EL GUARD RTL-1. Nada cruzaba un ancla LOGICA con un desplazamiento FISICO en la misma regla CSS: eidos-lint clasifica SELECTORES, no declaraciones, y la fila RTL del contrato de construccion decia "rule (LIVE)" — revision humana. Por eso el defecto del slider llego a produccion y lo cazo el ojo del usuario. Ahora `npm run rtl:check`, con la logica en src/uix/eidos/rtl-lint.ts (14 tests) para que sea testeable, calcando el par lint.ts / scripts/eidos-lint.ts. El test ancla el caso historico: slider.css ANTES de |
2 months ago |
|
|
9050125076 |
fix(waveform): el buffered vuelve a ser banda recta, y la demo estrena material real
BUFFERED — segunda correccion por MIRADA, y la definitiva.
Las dos formas se construyeron y se miraron. Primero fue el SecondaryRange del
Slider con un velo neutro al 14%: rechazado ("el secundario no puede ser del
mismo color"), y la medicion le dio la razon — velo y onda eran alfas del MISMO
token (--color-content-primary al 14% vs 28%), o sea el mismo gris. Se paso
entonces a una tercera copia recortada del path, con la idea de que "el buffered
ES la onda un escalon mas alla". TAMBIEN rechazado, y por un motivo mas fuerte:
"se hace inapreciable y confunde visualmente".
La leccion, que queda escrita en los dos README: al compartir silueta con la
senal, el ojo lee la banda COMO la senal — es ilegible POR CONSTRUCCION y ningun
color la salva. La forma recta es legible precisamente porque NO es la onda. Asi
que el buffered vuelve al Slider.SecondaryRange (G-2), la parte canonica que ya
existia para esto, en vez de que el waveform pinte lo suyo.
El COLOR si sobrevive de la iteracion anterior: acento lavado
(color-mix del primary-solid con content-primary), que se separa del gris en
TONO y no solo en luminosidad. Tokens de paleta, cero literales. Los tres
colores de la onda son publicos y retunables por el disenador.
Nota de metodo: la distancia RGB avalo un gris que el ojo rechazo al instante
(esa metrica esta dominada por la luminosidad y es ciega al croma), y ademas un
bug propio en la alfa del color-mix dio numeros inflados que se corrigieron. Dos
recordatorios de que la medicion informa pero no decide.
DEMO — material real. El control se llamaba `signal`, que es una de las 8
FAMILIAS del canon, en un componente que declara CERO eventos
(expression: 'delegated'): ensenaba lo contrario de la verdad. Renombrado a
`sample`. Y el material eran los earcons de sema (pitidos de 80-220 ms, `pop`
salia casi plano) porque eran el unico audio del repo; ahora arranca en una
pista real de 2:45 (static/music/t2.wav, aportada por el usuario).
Y un defecto que 30 MB destaparon: el efecto de carga dependia de `source` Y de
`buckets`, asi que mover el slider de buckets volvia a DESCARGAR el fichero
entero. Separado en dos: decode una vez por fuente (caro), rebucketing puro y
barato. Medido: t2 (5 MB, 86 ms) frente al master de 48 kHz/16 bit (30 MB,
186 ms); sus envolventes NO son identicas — delta maximo 0.298 por cubo, medio
0.048, porque los 8 bits suben el suelo de ruido y aplanan los pasajes suaves.
Se elige t2 igualmente: 6x mas ligero por una envolvente marginalmente mas fiel.
Verificado: check 75 = baseline, 0 propios; 35 tests; eidos-lint 0 invalidos;
recipe-css-contract verde; component:audit --only waveform PASS; docs:check 0;
sonda en vivo — 2 paths en la onda, banda recta al 66% en rgb(130,95,161).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
4e4f1b612d |
feat(waveform): F4 eidos + F5 demo — y el buffered pasa a ser la onda
F4 (eidos): wrapper raiz que carga slider.css + waveform.css y resuelve
data-size por ActiveEidos; Wave passthrough; recipe con bars = stroke en
UNIDADES DE VIEWBOX (el svg estira con preserveAspectRatio="none", asi el
ciclo barra/hueco sobrevive) y wave = fill sin stroke; espejo RTL en CSS;
el Slider embebido en scope con track/range transparentes y el thumb
convertido en playhead de 2px a alto completo. Tokens waveform:{height-*,
bar-width, color, color-buffered, color-played, playhead-width} —
playhead-width y color-buffered van ANADIDOS sobre la lista firmada en el
gate, ambos declarados en el README.
F5 (demo + dossier): /uix/components/waveform con picos REALES (fetch de
/sounds/*.wav -> uix.sound.decode -> uix.sound.peaks), cada prop como
control vivo, READMEs de soma y eidos. Fix arrastrado de F3: `dir` no se
reenviaba al Slider embebido.
BUFFERED — cambio de forma (decision del usuario tras ver el render).
El primer intento re-tintaba el SecondaryRange del Slider; el usuario lo
rechazo ("el secundario no puede ser del mismo color") y la auditoria
encontro por que ningun color lo arreglaba del todo: ese part es una BARRA
de 6px con la geometria del track, y sobre una pintura de barras al ~58%
de ciclo el 42% de su area cae sobre fondo desnudo, ademas de tenir el
tramo ya reproducido. Ahora el buffered es una TERCERA COPIA del mismo
path, recortada a su fraccion — es la onda un escalon mas alla, la lectura
de SoundCloud/wavesurfer. El waveform ya no monta Slider.SecondaryRange.
Escalera: color 28% -> color-buffered 55% -> color-played acento.
Guard nuevo (bufferedFraction: ausente sin valor, clampado, dominio
degenerado) VISTO EN ROJO desconectando el cableado antes de darlo por
bueno.
Verificado: check 75 = baseline, 0 propios; 5/5 soma + 4/4 morfo;
component:audit --only waveform PASS; eidos-lint 0 invalidos;
recipe-css-contract y motion.test verdes; docs:check 0; prettier limpio.
Queda F6 (mirada del usuario): el panel del navegador no composita, asi
que la verificacion fue por sonda del DOM, sin captura.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
d9c79bf584 |
docs: corpus al día — blocks tier indexado, factorías nuevas, cifras atemporales
blocks.md entra en el índice y next-features gana el registro §8 del tier; active-app documenta las factorías que faltaban en la tabla (agent, motion, scene…); docs-check aprende a censar catálogos sin tests ni barrels; book-deviations y component-guide dejan de citar recuentos congelados. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
3097cfcb69 |
revert: deshacer la auditoría entera — se hizo sin leer la doctrina
Revert de los 7 commits de la sesión del 2026-07-29/30: |
2 months ago |
|
|
c39170abbf |
fix(uix): la auditoría del sistema — lo que los guards no veían
Auditoría clean-room de todo ActiveUIX (excluido `web/`), componente a
componente. Lo que sale de aquí no es una lista de bugs: es un patrón.
El framework validaba que lo escrito fuese VÁLIDO, no que lo declarado
se CUMPLIESE — y sus guards fallaban ABIERTOS.
## El colapso de las uniones de props (95 → 0)
Un `Props` de eidos es `{ …props propias… } & <atributos nativos>`.
Cuando el elemento declara un atributo homónimo, la intersección funde
ambos y una unión estrecha contra el `string` nativo COLAPSA a `string`.
Causa: `Without<T, U> = Omit<T, keyof U>` invocado como `Without<T, {}>`
— `Omit<T, never>`, un no-op — 433 veces en soma; sólo 3 con argumento
real. Invisible para `svelte-check`: ensanchar un tipo no es un error,
es una garantía perdida.
Medido: 95 props en 72 componentes. `<Avatar color="nonsense">`
compilaba. `ComboboxInput.size` chocaba con el `<input size>` numérico
y era inusable. Migrado con codemod sobre AST (nunca regex) a
`Own & Omit<Nativos, keyof Own>`: 92 tipos en 73 ficheros + carousel a
mano. `check` no se movió.
Garantía nueva: `eidos/prop-surface.test.ts` (PROP-1) compara los
literales de la anotación del autor contra los de la propiedad pública.
Verificado que falla reintroduciendo el defecto.
## Los cuatro guards que fallaban abiertos
- `translations:check` crasheaba en CADA ejecución de su historia — un
stripper de comentarios borraba `//` dentro de strings. Sustituido por
import dinámico. Al arrancar destapó 8 slots `texts` sin traducción.
- `soma-attr-audit` agotaba el timeout de 5 s: sin veredicto, verde por
omisión.
- `component-audit` D-7.4 hacía `continue` mudo cuando el tipo no
resolvía. Ahora resuelve con el checker de TypeScript
(`scripts/prop-unions.ts`): puntos ciegos de 124 → 3.
- `component-audit` R-1.1: el regex casaba `[data-motion='reduce']` y
daba PASS por el motivo equivocado.
Regla adoptada: un guard que no puede evaluar TIENE que decirlo. El
informe lleva ahora bloque «Not verified» y recuento en el resumen.
## D-1 · tooltip y D-2 · card, cableados
`tooltip` declaraba 3 eventos `emerge` que nadie emitía. Ahora emiten;
`present` pasa a `sequence: 'post'` — con `'pre'` el hold de ~240 ms
gateaba el montaje del propio overlay.
`card` declaraba `commit-select` sin emisor posible (scope sin soma).
Puente headless en `soma/components/card/` con la forma ya establecida
por `menu-dial` / `onion-menu`: eidos posee estado y render, soma posee
sólo el `SomaRuntime` que emite.
## Documentación: 22 mentiras corregidas
`docs/` afirmaba guards inexistentes (`NO_MISSING_PROVIDER_TESTS`),
APIs con firma equivocada y un modelo de Motion que el código no
implementa. Corregido en CANON, arquitectura, glosario, theming/motion,
checklist y los README de `motion` / `callout` / `arts/motion`.
## Además
- CardGroup: la descripción se metía en la primera celda del grid.
- Motion: `data-state` siempre estampado, salida real en `leave()`,
token fantasma `--motion-stagger-each-default` eliminado.
- `engine-motion`: `handoffState` Map → WeakMap (fuga por nodo).
- `mockup`: primitivo crudo → token de rol (R-4.6).
- 5 catálogos de traducción que faltaban.
Handoff: `docs/process/CONTINUE-audit-2026-07-29.md`.
Batería: check 0 errores en src · vitest server 3701/3701 ·
docs:check 0/0 · component:audit 161 PASS / 2 NEEDS-WORK.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
6b23aa7ef1 |
agent(guard): agent-check nace con la auditoría que ya tiene sujeto — anti-falsificación de actor
D-AG.11 (firmada) define SEIS auditorías. Cinco necesitan el árbol de manifiestos `src/uix/agent/components/`, que es trabajo de F4b — y el plan es explícito: el guard «nace CON el árbol, no después». Así que quedan DECLARADAS en el script y se reportan como pendientes: añadir un manifiesto las enciende, y el guard nunca puede ir por detrás de la superficie que vigila. La quinta SÍ tiene sujeto hoy y no la vigilaba nadie: F1 entregó el primitivo de actor (`$libs/actor` + el registro WeakMap privado del motor) y su invariante — que SOLO el motor acuña — no estaba protegida por nada. El token es una marca de compilación sin constructor en runtime: un forjado resuelve a null, pero un `as ActorToken` TIPA, y un contexto de actor construido a mano en el canon es exactamente la suplantación que el eje prohíbe (agent.md §5). Por eso D-AG.8 §2 dice literalmente que su defensa es el lint de agent-check, no el sistema de tipos. Dos reglas, sobre canon (uix · arts · libs · svrs · packs · web) excluyendo el arte agente: - `actor-forgery` — cast a ActorToken fuera de $agent - `actor-handbuilt` — `actor:` con valor literal (objeto/string/número) en vez de un token RECIBIDO; reenviar (`actor: opts.actor`) es la costura sancionada y calla. Los tests quedan exentos: ahí fabricar un forjado es precisamente lo que se prueba. Verificado en negativo, que un guard que nunca falla es teatro: inyectado un cast + un contexto a mano en `sema/signal.ts` → 2 hallazgos con fichero:línea y exit 1; revertido y de vuelta a limpio. `npm run agent:check` cableado junto a los demás guards del repo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
0697596046 |
blocks(tier): F0 · infraestructura del tier (doctrina + $blocks + guard + galería)
Tier nuevo aprobado 2026-07-21 (D-BLK firmadas; D-BLK.1 enmendada: vive en src/uix/blocks/). Plan de ejecución completo en docs/process/PLAN-blocks.md. - docs/architecture/blocks.md — doctrina E1 (regla de admisión canon-vs-block, contrato B-1..B-11, promotion path); espejo de packs.md - alias $blocks → src/uix/blocks (vite + svelte.config + tabla CLAUDE.md) - src/uix/blocks/README.md — mapa del tier + template de README de block (B-9) - scripts/blocks-check.ts + npm run blocks:check — guard mecánico del contrato B con self-test de detectores (fixtures inline; 5532 archivos de canon/arts/libs/packs escaneados para dirección de imports) - web/routes/blocks/ — galería índice del catálogo planificado + layout de bootstrap propio (+layout@.svelte, espejo mínimo del de /uix sin packs sema) Verificación: docs:check 0/0 (511) · svelte-check 76E/51W = baseline exacto · blocks:check verde · galería comprobada en navegador (a11y-tree + estilos computados en light y dark; captura de píxel bloqueada por panel suspendido). Fuera del commit: fila E1 en docs/README.md y §8 en docs/next-features.md (diff foráneo de otra sesión sin separar — ver registro del plan). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
d59b8af9aa |
uix(chat): v2 · emoji-picker (picker completo) + escaparate rico del bloque
Nuevo componente emoji-picker y rediseño del escaparate de mensajeria. emoji-picker (ruta 9 fases): - Compone Popover (open/close/foco/portal) + Command (busqueda + grid + nav de teclado + a11y combobox/listbox, su "grid mode" documentado) + dos ToggleGroup (categorias + tono de piel). Delegated: sin eventos propios (D.1); el grid y las celdas doble-registran Command.List/Item, conservando la a11y pero con contrato visual propio (gana especificidad con selectores de 2 niveles, sin tocar attrs [data-command-*] ajenos — eidos-lint limpio). - Datos: $libs/emoji, dataset vendorizado de emojibase (MIT) horneado por scripts/generate-emoji-data.ts (precedente lucide: JSON crudo en static/ + script generador). ~1906 emoji con nombre CLDR + keywords, 316 con tono de piel single-person. Grid acotado (categoria activa o resultados de busqueda), sin virtualizacion (refinamiento v2). Helpers puros + test (12/12). - morfo delegated (7 partes + header/footer de layout); soma (root + trigger + content + grid + option + preview, provider-test 4/4); eidos (panel empaquetado, receta con tokens --emoji-picker-*); langs es/en; demo 5 tabs (excepcion delegated documentada); READMEs dobles. Escaparate del bloque (web/routes/uix/demos/chat) — rehecho rico y correcto: - Avatares por-autor con color solido (Avatar del ecosistema): antes gris neutro indefinido, ahora teal/ambar/verde/indigo/primary bien contrastados. - Dos columnas: chat-list (sidebar con badges + typing-en-lista) + sala. - Conversacion rica: separador de dia, run agrupado, reaccion, reply citado, recibos de lectura, typing con avatar, y el emoji-picker integrado en el composer (inserta en el draft). - Solape de burbujas (transitorio, estimateSize=48 con mensajes ~90-126px) mitigado subiendo el estimate a 76. Auditoria de tamanos/espacios: recipes del bloque limpios (todo con tokens --space-*/--size-*/--color-*); unico literal (punto tono-capable) tokenizado. Verificacion: check baseline 76 (0 nuevos) · component:audit emoji-picker PASS · eidos-lint invalid=0 · recipe-contract 30/30 · morfo:vocabulary 0 · emoji lib 12/12 · provider-test 4/4 · Playwright PASS (busqueda 'rocket'->rocket+ astronautas, click->onSelect+cierra, teclado, tono oscuro 👋->👋🏿, picker abre en el composer). Capturas claro miradas. next-features §7 marca emoji-picker SHIPPED. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
5aa8090bad |
color: contraste Stage 2 — contrato §40 como datos + guard CI; solver descartado
La ejecución refutó la premisa del plan: el morph HEREDA el contraste del texto (steps 11/12 = curva-L del donante verbatim; ~invariante al croma bajo gamut-mapping), así que toda escala desde donantes §40-compliant cumple por construcción. Medido en 3 bancos (base, leave-one-out, 45 semillas OOD): 0 fallos del gate duro text-strong·12, min WCAG 9.7:1. El solver de luminancia no tenía nada que resolver → descartado por especulativo. D2 = base verbatim (sin migración base→seeds). - $color: CONTRAST_PAIRS (arts/color/contrast-contract.ts) — tabla §40 como datos compartidos: floor duro text-strong·12, banda text·11 (tope relacional, sin nº mágico), border·7 exento - scripts/contrast-audit.ts: muere la PAIRS pre-veredicto (4.5 duro contra §40), consume CONTRAST_PAIRS + banco de regresión morph-generado - eidos/lib/contrast-invariant.test.ts: guard de CI (4 tests) que bloquea la herencia - docs: reference.md §40, next-features.md §1, changelog.md §45, plan (OUTCOME) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
eeab44a191 |
tooling(color): matriz de semantic-border + compositing en la auditoría de contraste
Extiende el script de Stage 1 con el análisis que pidió el veredicto de
usuario: mide TODOS los tokens semantic-border (subtle·4 / default·6 /
strong·8 / focus-ring / focus-ring-error / invalid·7 / checked·9), cada uno
contra las 3 superficies (default·1 / raised·2 / muted·3) en ambos modos,
marcando load-bearing (3:1 requerido) vs decorativo (exento). Añade
compositing sRGB para los focus rings translúcidos (color-mix @ ~50% alpha).
Fix: oklchToGammaRgb devuelve [0,1] en tupla [r,g,b] (no {r,g,b} ni [0,255]).
Hallazgo: todo el vocabulario de border vive en el rango sutil 4-8 (contrato
Radix); el único que cruza 3:1 es el solid·9 (checked/selected). El resto es
correcto como decorativo salvo el FOCO (indicador único, WCAG 2.4.11) → se
verifica en navegador aparte.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
3 months ago |
|
|
61ecc101de |
tooling(color): script de auditoría de contraste (Stage 1 · tonal-ramp parity)
Pase de medición de la iniciativa #1 de next-features: comprueba si las promesas de contraste por par de slots se cumplen en las 33 escalas × 2 modos, reutilizando la matemática de `$color` (apcaLc · wcagContrastRatio · oklchToGammaRgb · safeParseColor). WCAG 2 = gate normativo (4.5:1 texto / 3:1 no-texto); APCA Lc reportado al lado. Tabla de pares = las promesas declaradas (texto·11/12 sobre track·1/bg·2/element·3; border·7 sobre track/bg). Solo mide — no cambia emisión. Correr: `node --import tsx/esm scripts/contrast-audit.ts`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
63b371d5ce |
feat(packs+text): incorporate the animation collection — Ambient pack + text-effects family + docs
Two streams, split by what the animation touches:
STREAM A — decorative backgrounds → the pack tier
- arts/scene: a consolidated scene runtime ($scene) that owns, once, the
citizenship every ad-hoc background reinvented or skipped (frame loop,
off-view pause, DPR cap, mandatory reduced-motion, WebGL context
loss/restore, scene budget, teardown). SceneDom port (adom satisfies it),
webgl/webgl2/canvas2d drivers + a custom-pipeline extension (vertexShader +
draw + glContext.depth/dprCap) for real geometry (beam, particles, dither,
grid, eter, pixel-blast, hyperspeed). 32 effects as shared resources.
- src/packs/ambient: the first pack — <Ambient effect="…"> mounts a registered
effect; the P contract (P-1..P-6) guarded by scripts/packs-check.ts; colors
are token-aware (P-4). One-way dependency, removable-by-construction.
- resolveToken extended to semantic color slots (--color-{role}-{slot}) so
consumers resolve theme tokens to concrete colors (the P-4 half).
STREAM B — animations over real text → canon
- Six components (count-up + text-{gradient,circular,blur,focus,scramble}):
each a morfo + eidos recipe (where there's styling) + demo. CountUp is a
service component (counts through uix.format.numbers). The five Text* are
passive decoratives. Upgrades over the seeds: SR hardening (real text
visually-hidden + aria-hidden decoration), a11y fix (no fake role=button),
measurement discipline (cached rects via dom.measure, no reflow storm),
reduced-motion, ecosystem citizenship (eidos.dom/timers, no raw platform).
- MorfoElement gains 'p'.
DOCS
- docs/architecture/packs.md (pack tier, admission rule, P contract, Aura
promotion path); docs/decisions/design-text-effects.md (the family design
record) + indexed in decisions.md / README.md; glossary entries
(scene/Ambient/Aura/text effects); scene README custom-pipeline + authoring
bridge; motion-guide content-effects note; strata tables acknowledge packs.
Gates: component:audit 141/0/0 · docs:check 0/0 · scene tests 9/9 · packs:check
0/36 · check 0 own errors. Verified in browser (32 effects mount+compile;
6 text components SSR+hydrate, CountUp re-formats by locale live, TextGradient
resolves token stops to OKLCH via var()).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
3 months ago |
|
|
b55ca6eecb |
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
F2 — lote mecánico (13 ítems): - DEP-2 ogl eliminado (0 imports) · DEP-1 clsx inlineado como toClassString propio + suite de contrato (props.test.ts; soma.md §12 cerrado). - THM-7: los 5 selectores manuales de sema.md reescritos con semaSelector (los ejemplos [data-toast-root] apuntaban a un part INEXISTENTE — la deriva que el builder previene, demostrada en el propio doc). - MOR-1 escape isomorfo + validación de attr-names en semaSelector + 9 tests (selectors.test.ts, matches() real con comillas/corchetes) · MOR-2 partMarkerAttr = única fuente compilador↔builder + test de paridad · MOR-3 _resetCompileCache borrado (0 usos). - SOM-2 keydown continue en match sin handler + keyboardFixtureMorfo · SOM-1 no-await de handlers (censo async = 0; contrato V1 cumplido) + pin. - SEM-2 trigger pre-attacha catch con logger (void trigger sin unhandled rejection; throw intacto para awaiters) + pin · SEM-3 fallback muerto de applyDominance → skip defensivo + timer tope de awaitExpression cancelado · SEC-1 adjudicado YA implementado (assertCssVariableValue desde 2026-05-11) + pin del path de VALOR. - accordion → outline (§32; su outline:none dejaba CERO anillo en HCM) — verificado en vivo · THM-6 radius-full 9999px · EID-4 recuentos 33. F3 — censos con guard: - SOM-3 cerrado: announcer + image-provider migrados a scheduler-preferred (consumidores cableados: date/time-field vía soma.uix.timers; avatar/image vía eidos.timers — verificado en vivo); guard de timers ENSANCHADO de soma/components a TODO soma y pasado a EVIDENCIA (setTimeout exige .schedule( en el fichero — layers/ y datetime/ escapaban del ámbito viejo). - THM-5: R-4.7 nueva (válvula same-line /* important: <razón> */, escaneo comment-blanked) + las 15 declaraciones anotadas con su razón + canon recipe-contract §3/§4. - SOM-4 adjudicado: el censo/guard YA existían (49 pins); knob/mask-field/ timeline pinneados (overrides documentados en call-site); media-player Batch-4 (35 hits, cero renderProps) = único batch restante, registrado. - THM-4 doctrinado en eidos.md §unused (comportamiento/composición = legítimo; deuda = eje visual sin consumidor; hotspots por lotes). F4-C — corpus documental (decisiones de usuario aplicadas): - DOC-3: los 15 enlaces muertos resueltos (repoint a la edición FINAL trackeada / des-link históricos) · docs:check I6-links WARN→ERROR. - DOC-1: tabla «Build contract» MIGRADA a component-guide con estados modernizados (A3–A5 → LIVE + guards de hoy); banners reapuntados; citas de CANON/sema.md historificadas; lápida-redirect en el §13 del fósil. - DOC-4: hold chain → holds.ts · FAQ event:* SUPERSEDED por signatures · gradient añadido a los DOS capstones (sextet real) · nota de paleta de demo-authoring corregida (universalPaletteDecls + decisión THM-2 = mecanismo universal como sucesor del tracker borrado). - DOC-5/6: recuentos anti-frágiles datados · §4.11 dup → §4.12 · Known gaps historificado · N-6/N-7 recuperadas de git (d68d2c45^) y canonizadas en eidos.md §pickers · authoring E2 → canon/tsc.md · air-old des-linkado · EID-3 (placement) en la fila RTL · AUX-2 disabledDom documentado. SEM-4 sesión 1 — el close polimórfico de los pickers, VIVO (D.11): - Reconciliación: los morfos ya no declaran close (delegated al Popover, de-dialoged 06-27); el agujero real era el cierre programático bypaseando dismissWith → save/cancel/select eran perceptualmente SILENCIOSOS. - Fix: PickerShellHandle.setPopoverDismiss + closeWith(cause) en los 5 providers (14 sitios; select/commit → 'save' = commit.save+fulfill, cancel → 'cancel' = emerge; fallback raw para headless) + UN inyector en el eidos PickerShell root (norma N-8). Picker genérico fuera a propósito (ya suena commit-set/cancel por diseño S9). - Verificado en vivo (date-picker): Done → close·commit·fulfill·active · Cancel → close·emerge · cierre real. Gates: matriz 141/141 (los 6 morfos nuevos de la pista de texto paralela también PASS) · contracts 38/38 · eidos 314 · sema 178 · morfo 94 · docs:check 0/0 con I6 en error · baseline propio 57. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
4addfd7dbf |
fix(cleanroom): P1s ejecutados (EID-1/EID-2/SEM-1/MOR-4/THM-1/THM-3) + auditoría + plan scene/ambient
Clean-room fixes (2026-07-11, sobre los P1 de la auditoría):
- EID-1: el anillo de foco de la fundación migra a `outline` (§32) — el último
box-shadow del catálogo; :where()-wrapped para que las recetas siempre ganen;
doctrina actualizada en theming/reference + changelog.
- EID-2: opacidades literales de archetypes.css → var(--opacity-disabled/hover).
- SEM-1: política de live-region unificada — la urgencia va SOLO por intent
(threat/loss → assertive), runtime y AnnounceChannel ya coinciden.
- MOR-4: card-group con morfo propio (scope eidos) + guard de enumeración.
- THM-1: component-audit + recipe-css-contract escanean los *.css hermanos
(calendar-select, color-picker-spectrum, date-range-picker-time…); R-2.1
caza también hsl()/oklch(); violaciones de los secundarios corregidas.
- THM-3: canario de censo de toggle volteado (lint.test); commit-block promovido
a firma global block-shake; regen de generated/base.css.
Docs nuevos:
- docs/audit-new-10-july/audit-active-uix.md — auditoría clean-room 2026-07-10
del ecosistema (hallazgos P1–P3 con evidencia ruta:línea, matriz y gap analysis).
- docs/process/PLAN-scene-ambient-pack.md — plan por fases: motor arts/scene +
pack Ambient (45 animaciones de demos) + vía de promoción agéntica (Aura);
gate de decisiones D1–D9.
- docs/Disenando_lo_que_ocurre_FINAL.{docx,pdf} — edición FINAL del libro.
- README.md raíz (esqueleto de paquete).
Excluidos deliberadamente de este commit: words/palabras/chronos (pista
separada), web/routes/alpha (terminado, sin commitear por decisión), rt.css
(volcado de referencia Radix Themes).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
3 months ago |
|
|
bdd17f04df |
feat(float-panel): runtime discipline + keyboard gesture semantics — contracts.test 37/37 GREEN
The convergence session's second half (with field commit-submit landed in
|
3 months ago |
|
|
e53bf0e8a0 |
feat(audit): demo rules verdict-NEUTRAL — demos re-home in a new system-wide demo frame (user decision 2026-07-10)
The demos will be exposed through a NEW frame for the whole system, so drift against the CURRENT page template is not fix-work. checkDemo results are downgraded to warn at the call site and D-* rules are excluded from the verdict count entirely — the data stays visible in the report, the component matrix stops being painted by it. The D-* rules get rewritten against the new frame when it lands. Matrix: 102 -> 118 PASS / 16 NEEDS-WORK / 0 BROKEN. The 16 now decompose into exactly three real families: the R-1.x focus/disabled census (9), the old dossier-form READMEs (6, the reduced lote 6), and two contract items — field A-3.1 and float-panel A-3.7 — which converge with the new clean-room audit finding "field/float-panel infra-declarados". Type baseline 57. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
dd249eac53 |
feat(ntp): S9 ntp integral — sky literal valve + soma contract + provider suite (initiative close)
The package's headline item — the generic Picker's transactional events — turned out ALREADY PAID at checkpoint S3b (commit-set fulfill / commit-cancel / commit-reset declared, pack shipped, soma triggers wired, suite green): the 2026-07-07 ficha claim was stale and the ntp dossier had propagated it; the dossier row is now corrected with the verification. What this session actually adds: - component-audit R-2.1 learns the `/* literal: <reason> */` escape valve (same declarationWindow mechanism the R-4.x rules already use) — the tokens doctrine's physically-fixed exception finally has its machine valve. Full run confirms no other component silently passes (same 102/32). - natural-time-picker.css: all 9 raw colors annotated line-by-line (5 skies + knob ink + line/ticks/shadow — sky ARTWORK, not theme roles; identical in light and dark). NOT tokenized, per the ficha's F-2 disposition. R-2.1 clears for ntp. - soma/components/natural-time-picker/README.md: the headless contract — the domain coordinator's state surface (minutes bridge, sliderValue, isDay, moments, steppers, display) + the fully-delegated perceptual chain table (TimeField / Slider / generic Picker / Popover). - natural-time-picker-provider.svelte.test.ts: 12 tests green (band bridge with wrap + seconds preservation, steppers incl. second non-rolling wrap, moment jumps + exact-match chips, readonly lock, daylight window bounds, 12/24h display incl. the no-soma.dates fallback, granularity displayTime). Gates: component-audit 102 PASS (ntp R-2.1 cleared) · type baseline 57 · new suite 12/12. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
53b6f629f2 |
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the checkpoint verdicts in docs/audit/components/) and the executed fix packages. - P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 + API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d, component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts (role=application removed ×4, aria-selected off the Day, drp translationRef, field data-state prune, pin-input commit-set, media-player renames), 13 new sema packs + 12 morfos family-default → pack. - P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar); onValueCommit terminal-callback norm (pin-input/search/password/textarea + date/time/color-field add); typed validation reason + onInvalid (tags-input, css-field); index/onIndexChange (carousel); deselectable; openDelay/ groupSkipDelay; allowCustomValue; defaultValue prune. - P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel); touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual, 44 AAA). S6 (Field composition) + S8 (calendar-surface) pending. Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline); morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched components; per-component vitest suites green. Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md Excluded (broken by the N1 rename, left broken per user decision, not staged): words/**, palabras/**, chronos, web/routes/alpha/**. Reconciliation pending: the touch-rows ::before for checkbox/switch reverses changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed markers to a labeled-row/Field task — flagged for the user in the handoff. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
9e48b80b10 |
docs(arts): ethereal README + A1 drift sweep (orca/cache/adom) + honest guard
Ethereal (was undocumented — the miss that prompted this pass):
- new src/arts/ethereal/README.md, API drawn from the code (computePosition,
the 7 middleware, autoUpdate, selectPositioningStrategy, dual JS/CSS-anchor
engine, +1-frame read-phase model)
- wired into src/arts/README.md Map + aliases + cross-deps; $ethereal added to
the CLAUDE.md alias table; the also-missing bus/orca/prefs aliases + Map rows
completed against vite.config.ts
A1 drift (every fix verified against the cited code symbol, not the plan):
- orca: ~13 phantom identifiers across 7 sections (priority, execution /
ORCA_EXEC_*, tokenTimeoutMs, onFatal / ORCA_ON_FATAL_*, onTimeout, the whole
multi-level timeout model, the transaction-port model + ORCA_TX_*,
OrcaMaybePromise, OrcaCompensationContext) reconciled to the real API
(parallel waves, actionTimeoutMs-only, transaction:string tag + compensate,
fatal via returning OrcaFatal); added the real missing fields fanIn / parallel
/ compensate; glossary OrcaRun -> OrcaRunResult
- cache: residual createActiveApp({cache}) -> services:{cache:defineActiveCache()};
documented the ActiveEngine contract surface (loading / lastError / disposed /
snapshot / clearError / onChange / dispose); dangling demo URL ->
/active/get-started/ecosystem
- adom: added prefersReducedMotion / writeProperty / removeProperty; listen
1 -> 4 typed overloads; documented 12 undocumented standalone rune helpers;
/test/adom -> /active/docs/adom
Guard (scripts/arts-check.ts): removed the ethereal README exemption (set empty)
and promoted A-index from warn to error — the net no longer passes green with a
real gap. arts:check: 0 errors, 0 warnings, 22 arts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
9a147e4937 |
chore(arts): add arts:check guard for the arts docs reconciliation (batch A0)
Ships the net that batches A1-A3 / B3 land against, mirroring
scripts/docs-check.ts (textual invariants, no Svelte-graph imports):
- A-readme (error): every src/arts/{name}/ has a README.md. ethereal is
exempt via a self-cleaning README_PENDING set until batch A3 authors it.
- A-naming (error): the Engine*/Active* split holds — no Engine* root is
declared in a .svelte.ts (engines are stateless), and every reactive
`class Active*` root lives in a .svelte.ts (Active...Error exempt).
- A-index (warn): the src/arts/README.md Map lists every art. WARN, not
error — the four current gaps (bus, ethereal, orca, prefs) are batch B3's
worklist and drive to zero there.
Green now: 0 errors, 4 warnings (the B3 worklist), 22 arts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
116594e063 |
feat(docs): S1 — generated canonical-vocabulary appendix (STUMBLES #1)
An agent building a component from the docs-book alone could not assign archetypes / holds / haptic kinds: the closed sets live only in code consts and the corpus (correctly) forbids copying them into prose, so they were invisible from the docs. STUMBLES #1, the top stumble. Fix: docs/canon/vocabularies.md is GENERATED from the consts by 'npm run docs:vocabularies' — the ONE sanctioned place the lists are spelled out (generated = no drift objection), which every other doc links to. It covers part archetypes (with a one-line role each), sema families with their default hold/persistence + per-intent overrides, verbs by family, intents, the perceptual-duration scale, haptic kinds, the 33 palette scales, sizes, variant archetypes, and the shared common.* strings. - scripts/docs-vocabularies.ts imports the consts (robust — no fragile JSDoc/regex parsing) and formats them; the generation is an exported function so docs-check can compare. - Added ARCHETYPE_DESCRIPTIONS to morfo/types.ts (co-located with ARCHETYPE_VOCABULARY, satisfies Record<MorfoArchetype,string>) as the authoritative one-liners the appendix reads — descriptions become first-class data instead of inline union JSDoc a tool would have to parse. - docs-check gains I7: it regenerates in-memory and fails if the committed file drifts from the consts (negative-tested: corrupt -> error, regen -> green). The appendix's own counts pass I1, so I1 doubles as a second guard. - Linked from README (E2 canon row + two 'I want to' shortcuts), CANON.md (doctrine here, enumerated lists there), architecture/morfo.md (pick a part's archetype), and the component-audit minimum-package list (STUMBLES #8). docs:check 0 errors; npm run check unchanged in my files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
0a80da8d2b |
docs+fix: old docs quarantined in docs/old-deprecated; STUMBLES doc-class fixes
Two user findings from the Knob build exercise (an agent building a new component from the docs alone — STUMBLES.md). Quarantine: the superseded fossils no longer share shelf space with the live corpus. docs/old-deprecated/ (with an index README explaining what lands there and pointing readers at docs/README.md) now holds the executed audits and fix plans: fable_audit, fable-eidos-audit, inherit_audit + inherit_fix_plan, ARCHETYPE_COHERENCE_AUDIT_2026-06-19 (still citable — the component-guide banner and the eidos components README repoint to it), COMPONENT_COHERENCE_AUDIT. pendiente.md (a live pending list, not a fossil) moved to docs/process/. docs-check treats the folder as sealed chronicle (I1/I2 exempt; I6 skips its internal links, as its README promises). Root-level *.md is now: README, CLAUDE, AGENTS + the user's own working files. STUMBLES fixes applied on the spot (the doc-class ones): - #2 kind drift: the REAL enum is 'public' | 'private' | 'virtual' (MorfoPartKind, 671/9/14 uses) — morfo.md omitted 'private', the checklist invented 'internal' (0 uses). Both fixed; I2 gains the phantom-'internal' guard. A-2.1's row now says what the audit script actually checks (kebab only — the archetype may vary, the Toggle provider-IS-trigger doctrine). - #6: the langs catalog SHAPE (flat keys, per-language leaves, named export, index registration) is now shown in morfo.md instead of only its location. - #8: component-audit s0 defines the minimum brief package as an explicit 8-file list. The engineering-class stumbles are registered as plan batches S1-S6 (generated vocabularies appendix, continuous-gesture trigger doctrine, part-absent condition, Gesture.rotate, the soma->eidos CSS-var contract, minor frictions). docs:check 0 errors, 11-warn baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
85e2356d49 |
fix(uix): C4 — APG anchors for 29 interactive components (20 patterns + 5 documented absences)
Every interactive morfo now either anchors its W3C APG pattern or documents that none exists. Real patterns (20): the picker family + command + search-field anchor combobox (field/input + popup, the pattern's own popup taxonomy); date-field mirrors time-field's spinbutton (per-segment contract); rating-group -> radio; navigation-menu -> disclosure (the APG's own site-nav guidance); splitter -> windowsplitter; tag-group/tags-input/virtual-grid -> grid; clipboard/file-upload -> button (the trigger IS the widget); announce -> alert (live region); form -> the form landmark; image-adjustments -> slider; table -> table. The A-1.4 valve (documented exception) is wired like the R-x rules, and five components whose widget has NO APG pattern say so in their README instead of faking an anchor: cropper (2-D manipulation), pagination (nav + composed Buttons), stepper, timeline (display list), image-picker (media picker). Remaining warns are the four expected: card/drag-drop/virtual-list host their note when C8 writes their READMEs, media-player is foreign WIP. Catalog: 83 PASS / 47 NEEDS-WORK / 0 BROKEN (was 75/50/5 at the audit's start). npm run check at the 61-error baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
e009bdf80f |
fix(uix): C2b — invalid/disabled/readonly states: real fixes + cited exceptions
The R-1.2/R-1.3/R-1.4 sweep, same method as C2a (evidence first): each offender is either a REAL missing state or a shared-layer/composed case that must not duplicate rules. Real fixes, all verified in a live browser (computed-style probes, with the transition-mid-flight trap from the demo guide s13 accounted for): switch/toggle/rating-group get the family invalid tint (--color-threat-element, the shipped checkbox/pin-input precedent); toggle gets its readonly cursor; pin-input cells get the readonly muted-surface treatment mirroring date-field segments; the SHARED spin-field layer gains the readonly treatment it lacked (one fix covers css-field + number-field); natural-time-picker gets the disabled opacity/pointer rule mirroring date-field. Exception valve wired into R-1.3/R-1.4 (was only R-1.1/1.2/1.5/E-2.2) and cited exceptions added: css-field/number-field (states live in the shared spin-field layer), dialog (data-disabled sits on the VIRTUAL provider — defaultElement none — and the pressable surfaces are composed Buttons), color-picker (color-field owns the invalid rules), date-range-field (the runtime overlays data-date-field-input on the same elements, per its own recipe header), time-picker (composed time-field chrome). natural-time-picker keeps its two warns for its C8 pass rather than guessing paint targets. All 10 audited components now PASS with 0 R-1.x pending; npm run check at the 61-error baseline. css-field/number-field READMEs fixed on disk but unstaged (unrelated local modifications). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
9975a67d53 |
fix(uix): C2a — R-1.5 recognizes the framework's own focus patterns; class resolved
The audit's focus check grepped only for :focus-visible, blind to how the framework actually shows focus: the universal archetype ring (archetypes.css [data-archetype]:focus-visible with its documented exclusions), the field shell's :focus-within, and the canonical state-attr ring ([data-focused] + focus-ring tokens, soma-written — the spin-field/search-field pattern). Blindly adding :focus-visible rules to the 10 flagged recipes would have recreated the exact 'double border' anti-pattern archetypes.css documents against. The check now accepts the four sanctioned evidences (textarea and search-field pass on their own css; date-picker passes via exception) and the remaining non-ring cases carry cited R-1.5 exceptions: css-field/number-field (ring lives in the shared spin-field layer), dialog (content panel is the documented foundation exclusion; close/trigger are composed Buttons), date-picker (foundation ring + content exclusion), metrics/timeline (no focusable part — interactive only by events). clipboard/announce host their exception when C8 writes their READMEs. css-field/number-field READMEs fixed on disk but left unstaged (they carry unrelated local modifications). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
abede885c7 |
fix(uix): C1 — zero BROKEN components; documented-exception valve in the audit
The 5 BROKEN components (cascade, gradient-builder, menu-dial, motion, qr-code) are BROKEN no more: cascade/motion/menu-dial now PASS, gradient-builder/qr-code drop to NEEDS-WORK with only demo-phase (D-*) and C8 items left. Framework-level piece: component-audit gains the documented-exception valve the checklist already used for A-2.3/R-1.7 — a greppable 'R-x.y exception: reason' line in the component README turns the rule into a PASS that reports the reason. Wired for R-1.1, R-1.2, R-1.5 and E-2.2; the checklist rows say the same. This separates deliberate design (cascade and motion deliberately ship NO recipe — they ride the foundation stagger + state presets; menu-dial's focus/disabled states live in the composed Fab/Button recipes) from plain omission, which stays an error. Mechanical fixes: texts.label + langs entries for cascade/motion (new files, registered) and gradient-builder (label added to its existing entry); menu-dial's missing default export. README contract sections (Baseline/Comparativa/Decisiones/Gaps/Passive justification + Audit exceptions) added to cascade, motion, menu-dial and qr-code — mostly re-heading content those docs already argued; comparativas grounded in M3 speed dial/MUI SpeedDial/PrimeVue, Framer Motion/AnimatePresence/ Svelte transitions, ark-ui/qr-code-styling per component. Verified: component:audit 130 -> 78 PASS / 52 NEEDS-WORK / 0 BROKEN; npm run check at the 61-error pre-existing baseline (0 own). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
2050becba6 |
fix(docs): counts sweep round 2 — 12 slots (not 13), 9 roles (not 8) + guards
Extending the I1 count guard to color roles and role slots surfaced four more stale counts the palette fix predicted: the RFCs still said '13 slots' and enumerated borderHover8 (the slot was retired 2026-07-02, zero consumers — COLOR_ROLE_SLOTS is 12), and two component READMEs (css-field, float-panel) still said '8 roles' from before tertiary made it 9. The guard itself had the same disease it polices: extractConstArray counted the quoted 'borderHover' inside the comment documenting its own retirement, so expected=13 and the stale mentions passed — comments are now stripped before extraction. css-field's README is fixed on disk but left unstaged (it carries unrelated local modifications). docs-check now verifies families=8, intents=6, archetypes=26, palette=33, roles=9, slots=12 against their consts on every run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
fc9fc80e09 |
fix(eidos-docs): the palette is 33 scales, not 31 — UI bug + docs + count guard
User-caught drift, and it was live in the UI, not just prose: the demo harness's hand-copied PALETTE_GROUPS enumerated 31 scales — fuchsia and steel (the two non-Radix scales) never appeared in any demo's PalettePicker even though PALETTE_SCALES (the const, 33) and the recipe cascade (paletteScaleDecls maps the const) resolve them fine. Fixed the two missing entries, typed the groups as PaletteScale[], and added a dev-time completeness assertion so growing the const without grouping throws at module load. Prose swept (the numbers were inherited verbatim from the pre-book sources, which contradicted their own '33-scale library' headers): decisions.md color-model row, demo-authoring x4 (incl. the '31-scale palette' lede), rfc-color-engine x4 (ground-truth + templates open-question). Where the count was incidental the text now points at PALETTE_SCALES instead of restating a number. Guard: docs-check I1 gains the palette count (EN + ES patterns, ~-approximation and type/space-scale exclusions; s-mark added to the section-number skip). The check line now prints palette=33. This was the exact class I1 already covered for families/intents/archetypes and had not been extended to the palette. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
4e7753fe08 |
docs(book): F7.6 (1/2) — decision logs moved to docs/decisions/ (verbatim Spanish)
LIBRO_VARIACIONES_Y_EXTENSIONES -> decisions/book-deviations.md and
GUIA_IMPLEMENTACION_SEMAUIX -> decisions/guia-semantica-historica.md,
both moved AS-IS in Spanish: the deviations registry is a logbook of the
author's literal decisions ('transcrita literal') and carries proposed
doctrinal text destined for the Spanish book — translating it would
destroy that function (s G calls itself bitacora); the guia was already
status: historical (Fase 6) and the plan exempts it explicitly. English
frontmatter added to both; internal cross-links repointed (CANON,
theming/reference, book-deviations D.11). docs-check's I2 phantom-field
exemption follows the moved file (it matched by the LIBRO_VARIACIONES
filename; now also matches decisions/book-deviations.md). Corpus swept:
CANON x3, README (E2/E3 strata + tables — also fixed the pre-Fase-6
leftover row still calling the guia 'authoritative for any new wrapper'
and the unswept eidos/TSC.md stratum mention), building-a-component D.4,
completion-checklist G-1.1 + header, theming/reference, architecture
x5 (active-architecture, eidos, morfo, overview, sema x2).
docs:check 0 errors, 11-warn baseline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
3 months ago |
|
|
0588644a71 |
docs(book): F7.5 (1/2) — checklist + audit guide + demo guide moved to docs/guides/
Three English guides moved verbatim (copy + link touch-ups, no translation): COMPONENT_COMPLETION_CHECKLIST -> guides/ completion-checklist.md, COMPONENT_AUDIT_GUIDE -> guides/ component-audit.md, DEMO_AUTHORING_GUIDE -> guides/demo-authoring.md. Tooling moved with its doc in the same pass: docs-check I5 now parses the checklist at the new path (verified: 0 errors, rule tables found) and component-audit.ts's two path strings updated. One reconciliation in the audit guide's s5, applied as link-don't-copy: the copied v1 6-tab template list (stale vs the v2 9-tab guide it links, drawer canary vs button) is replaced by a pointer to demo-authoring.md; the domain canaries in s7 stay. demo-authoring's harness links now reach into web/routes/uix/lib/ (the modules stay with the code); the deleted pendiente_color_demos.md reference is marked TODO(reconcile). Corpus swept: building-a-component (frontmatter related: + phases 6/8), authoring, architecture/soma, theming/reference s5-parity, testing-and-tooling, getting-started, README (E4 rows + component-audit row added + two stale F7.3 paths in 'I want to' fixed). Remaining warns = links to component-guide.md, which lands in F7.5 (2/2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
b08dece4e2 |
feat(docs): docs:check guard — copyable-invariant lint for the doc corpus
Phase 3 of PLAN-docs-reconciliation (fable_audit D5: the 'link, don't copy' law had no mechanical guard). New scripts/docs-check.ts + npm run docs:check with six invariants, each born from a verified drift: - I1 vocabulary counts vs SEMA_FAMILIES/INTENTS/ARCHETYPE_VOCABULARY (context-gated: font/shape families, variant archetypes and evaluative subsets don't false-positive; section numbers and quoted historical mentions skipped). - I2 phantom fields: translations: in morfo/soma docs, defaultSemantic outside LIBRO_VARIACIONES (rename/rejection mentions allowed). - I3 dependency claims: soma dep lists must cite real package.json dependencies; corpus-wide @floating-ui mentions need their devDep-only context. - I4 SHARED_VARIANT_VOCAB (component-audit) == EIDOS_VARIANTS (textual mirror comparison). - I5 checklist<->audit: every Enforcement:audit rule exists in the script, every script rule ID is declared. - I6 relative links resolve (WARN until the known dangling targets get their user decision: THEMING_AUDIT deleted in worktree, PENDIENTES.md deleted 2026-06-07, MOTION_SERVICE_RFC demo routes). Chronicle docs (process/, changelogs, audits, CONTINUEs, status: historical frontmatter, the book) are exempt from truth-tracking. Also: THEMING s2 per-layer table realigned to the real entrypoint (the fragile rule-count column dropped); stale adom link in SOMA_ARCHITECTURE fixed; validator documented in docs/testing-and-tooling.md. Current output: 1 error (building-a-component known-traps row — cleared in the closing pass) + 13 warns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
3095065f0c |
feat(eidos): recipe contract R-4.x + motion-channel migration 15/15 + theme-builder fixes + inventory decisions
Fable audit follow-through (fable_audit.md + fable-eidos-audit.md): - RECIPE_CONTRACT.md (E2 canon): the transversal systems every recipe must consume, enforced by component-audit R-4.1-4.6 (all at error; escape valves /* literal */ + /* functional */; WIP tracks excluded). Stale audit rules fixed against the current architecture (E-2.2 wrapper imports, D-1.2 v2 9-tab union, D-3.1 single snippet, TabsVariant mirror) - verdicts went 0/117/15 -> 75/50/5. - Motion migration 15/15: recipes off local @keyframes onto the channel - preset stamps (dropdown/context/select/combobox/tooltip/link-preview/ clipboard), new expand/collapse + value-flash signatures, shared-axis reverse pair, delayed-open open-alias in the preset trigger (PRESET_STATE_ALIASES), materials pattern for irreducible triggers (card/timeline/tabs/nav-menu/metrics). Duration/scale hooks keep every recipe's tuned values. - buildScheme (fase C): full a1..a12 alpha ramp per role (was a2/a3 - stale alphas after applyColorScheme), intentSeeds so temper starts from the ACTIVE theme's intent mapping (risk stays orange), alpha background self-derived from the scheme's own neutral step 1 (was hardcoded #fff/#111); mode now forces the donor variant. - Inventory decisions (fase D): semanticTracking axis removed (all-zero), border-hover slot dropped (0 consumers), separator slot adopted across line dividers (step 6, Radix divider tone), size-bundle consumption pilot on toggle (canonical coordinates consumed, deliberate deviations kept visible). - Docs: building-a-component.md (the one door, 9-phase route + known traps), PLAN-docs-reconciliation.md (fase 6 kickoff for a fresh session), THEMING wiring updates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
9926add637 |
docs(corpus): delete the terra-era DATA_ATTRS fossil + its dead generator
Per explicit instruction to remove deprecated/erroneous files (noise/confusion): - DATA_ATTRS.md (repo root, 2158 lines) — a stale "Terra Data Attributes Contracts" catalog, already self-headed DEPRECATED. The data-* contract is the morfo, validated by morfo:check; this file only lied about it. - scripts/generate-contracts-docs.ts — its generator, which imports the removed src/uix/terra/utils/contracts.ts, so it can no longer run. No doc links to either; nothing imports the script. The package.json `generate:contracts-docs` entry now dangles at the deleted script — left untouched because package.json carries unrelated concurrent edits I won't sweep; flagged in the CONTINUE hand-off to remove later. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
4 months ago |
|
|
927d7f602d |
fix(soma): audit precision — scan only .assert() blocks
The attr audit segmented each provider by `runtime.part('X')` and scanned the
whole segment, so it false-positived on type annotations, per-part source
registrations (`props: { role: () => … }`), and non-part helper getters (a
hidden `inputProps` with its own `type`). Now it matches only inside
`.assert({ … })` blocks — the real part props getters.
Backlog corrected: 607/50 → 559/44 (switch, announce, etc. were pure false
positives — 0 real duplication). number-field (1) / css-field (2) residue
unchanged; guard still green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
4 months ago |
|
|
9d11e8e4eb |
test(soma): attr-dedup audit script + regression guard
`scripts/soma-attr-audit.ts` compiles every morfo and flags attrs a provider
hardcodes in its props getter that the morfo already declares with a resolvable
value (segmenting the provider by `runtime.part('<kebab>')` to map getter→part).
Measures the migration backlog and catches new drift.
Current backlog: 607 hits across 50 components (worst: words 49, dropdown/context
menus ~28, combobox/command/time-field ~24). The migrated spin-field family is
down to its legitimate residue — number-field 1, css-field 2 (formatted
aria-valuetext, parsed aria-valuenow — values the morfo can't express).
`soma-attr-audit.test.ts` pins each migrated component to its legit-override
ceiling so it can't regress to hardcoded attrs. Extend the ceiling map as more
components migrate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
4 months ago |
|
|
95be3b6cb1 |
perf(eidos): prune base.css to role-referenced scales (Phase 5) — −18 KB gz
base.css shipped all 31 Radix donor scales, but the theme's roles only
reference 9 (gray green indigo orange plum purple red slate teal). The
other 22 were dead weight on every page: no component references raw
--scale-* (they use --color-{role}-*), and runtime theming builds from JS
scale data and writes RESOLVED values (build-scheme: variables[k]=hex),
so it never reads the CSS scale tokens.
renderThemeCss now emits only role-referenced scales by default; the full
31-scale donor palette ships opt-in in generated/palette.css (new
renderColorPaletteCss). The CSS contract stays the full vocabulary
(apps can still override any scale; load palette.css to use the extra 22).
base.css 53.7→35.4 KB gz. Monolith (every page) 54.4→36.2 KB gz —
combined with Phase 3, 113.5→36.2 KB gz total (−68%). Verified: roles
resolve (primary=purple, button bg correct), pruned scales empty on
regular pages, restored on /temas/color via palette.css. Updated the
contract test to verify coverage against the full palette. check clean
(13 errors are untracked heroscrolling demo + gitignored tmp/lexical);
eidos suite at baseline (192/195, 3 pre-existing words failures).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
4 months ago |
|
|
9c6375c96e |
feat(eidos): TSC v2.2 (parts + composition) + universal theming coverage
Token Scope Contract universal — no más excepciones arquitectónicas.
Los 3 componentes que vivían fuera de TSC v2.1 (select, avatar,
toggle-group) ahora están dentro del contrato via dos extensiones nuevas.
TSC v2.2 extensiones (lib/config-types.ts + render-css.ts + config.ts):
- `parts: readonly string[]` en RecipeTokenMultiDeclaration — emite
selectores comma-separados (`[data-{c}-x], [data-{c}-y]`) para
componentes con data-color cascadeado per-part. Consumer: select.
- `composition: { foreignRecipe: { targetSelector, tokens } }` sibling
key — overrides cross-recipe scoped a la cascade del host. Consumer:
toggle-group modifica `--toggle-palette-*` en sus items.
Migraciones:
- select: 3 private `_accent-{track,border,text}` con parts: ['trigger',
'content'] + 7 cascades color:X each. Removed orphan `_accent-solid`
(CSS no consumía).
- avatar: 6 tokens via composite scopes `['variant:X', 'color:Y']` con
matrix helper inline. Badge usa parts: ['badge']. Reemplaza 24 bloques
CSS × 2 partes.
- toggle-group: composition block con 8 palette tokens × 4 colors.
Reemplaza 4 bloques CSS per-color.
Bug toggle-group post-composition (encontrado y arreglado):
Tras la composition migration, el cascade del toggle-group seguía roto
porque los tokens derivados (`--toggle-solid-on-bg`, `--toggle-outline-fg`,
etc.) viven en scope `[data-toggle]`. El `[data-toggle-group-item]` es
sibling (no descendant), así que `var(--toggle-solid-on-bg)` resolvía
undefined. Fix: inlined derivation expressions directamente en
`[data-toggle-group-item]` y sus variant cascades (solid/outline/ghost),
referenciando palette tokens en su propio scope local.
Validador + emisor + contract:
- `validateRecipeComposition` valida el shape `{ targetSelector, tokens }`
y rechaza composition entries con scope='root'.
- `stripCompositionKey` + `emitComposition` separan el pipeline.
- `appendRecipeContractTokens` skip-list para `composition` (no aparece
como fake `--{c}-composition` knob).
- `tokenKeys`/`tokenEntries` helpers en recipe-css-contract.test.ts
filtran composition en todos los iteradores.
Documentación:
- THEMING.md §18 reescrito como "Cobertura universal de TSC". §7
extendido con subsecciones "Multi-part scope" y "Cross-recipe
composition" + ejemplos completos. TOC actualizado.
- eidos/README.md tabla de referencia ampliada con TSC v2.2 + §18.
- CLAUDE.md gana hand-off "2026-05-27 #5" (TSC v2.2 + cobertura universal).
- CONTINUE.md reescrito al estado actual de la sesión.
Working tree también incluye sprint Words en paralelo (multiple authors):
slash menu, find/replace regex, code language picker, table audit,
toolbar family menu, code highlight engine.
Tests: 786/786 pass en src/uix/{eidos,morfo,soma,sema}. `npm run check`:
6 errores pre-existentes (lib/_demo, soma/components/internal,
web/routes/active) no relacionados.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
504780ad8b |
feat(morfo/sema): add expression field + sema coverage check (P1 #3)
User doctrinal decision 2026-05-26: `scope: ['sema']` declares
**participation** in sema. It does NOT impose the obligation of
shipping a pack. The new `expression` field on Morfo declares HOW the
component contributes its perceptual signature.
Schema change (src/uix/morfo/types.ts + schema.ts):
type SemaExpressionMode = 'pack' | 'family-default' | 'delegated' | 'none';
interface Morfo {
// ...
expression?: SemaExpressionMode;
}
Semantics:
- 'pack' — sema/components/{kebab}.ts cascades the signature
- 'family-default' — use family base + intent deltas as-is (no override)
- 'delegated' — composite; perceptual expression lives in children's packs
- 'none' — explicit opt-out (rare; reserved for headless contracts)
Coverage check (scripts/morfo-vocabulary-check.ts §4):
FAIL events declared + no 'sema' in scope — incoherent
WARN scope:sema + events + no pack + no expression — ambiguous
OK scope:sema + events + (pack OR expression) — explicit
OK no events — coverage N/A
Pack discovery is automatic from filesystem; the morfo doesn't need to
declare `expression: 'pack'` redundantly. Lint passes when a pack file
exists at `src/uix/sema/components/{kebab}.ts`.
Applied to 5 morfos that had events but no sema scope (incoherent state):
- announce, clipboard, listbox, virtual-grid, virtual-list
now declare scope: ['soma', 'sema'] + expression: 'family-default'.
Applied to 28 morfos that had scope:sema + events but no pack:
- 4 composites (date-picker, date-range-picker, time-picker,
time-range-picker) → expression: 'delegated'
- 24 others (button, card, carousel, collapsible, color-field, command,
context-menu, drag-drop, dropdown-menu, feed, grid-list, menubar,
month-grid, navigation-menu, range-calendar, switch, table, time-field,
toggle-group, toggle, tooltip, tree-grid, tree-view, year-grid)
→ expression: 'family-default'
The 29 morfos that already have packs are not touched; the lint
discovers their packs from the filesystem.
Pending follow-up (separate commits per author's plan):
- Create packs for high-frequency toggles (switch, toggle, toggle-group)
- Create packs for menus / navigation / tree (menubar, navigation-menu,
context-menu, dropdown-menu, tree-view, tree-grid)
- Review card scope (may not need sema scope at all)
- Per-component review of the rest
Verification:
- npm run morfo:vocabulary: EXIT 0
- 0 coverage FAILs, 0 coverage WARNs
- vitest src/uix/sema src/uix/morfo: 195/195 pass
- 7 name-shape WARNs remaining are all words.* (separate dev track)
Closes P1 #3 from src/uix/audit-codex-full-1.md (Sema coverage policy).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
23afeb6f86 |
refactor(button): align with book cap. 22 — contact.activate, intent visual-only (Plan B commit 2)
Button morfo declared `commit-action` with verb `action` (not in canon) and full intent range. Per «Diseñando lo que ocurre»: - Cap 22 §10: "Botón: contact.press" — the press is reception of the gesture, not the commit. - Cap 22 §11: "el intent fuerte no debería vivir en el contacto, sino en la señal o consecuencia posterior. La interfaz puede anticipar el peso mediante forma, color o señal previa." - Cap 22 §8: "Error típico: contact.press + fulfill — Esto hace que el sistema diga 'ya terminó' cuando solo ha empezado." Strict book reading applied: - Morfo event renamed: `commit-action` → `contact-activate` (family: `contact`, verb: `activate`, no intent binding) - Soma provider trigger string + comments updated - `intent` prop survives as VISUAL signal only — drives `data-color` and chip variant (anticipatory weight via form/color per cap. 22 §11) - README + types JSDoc updated with the book's prescription and the composition pattern: perceptual richness emerges from the OTHER morfos in the flow (Dialog warning, Item being deleted, etc.) firing their own commit/signal events at the actual moment of the consequence - `EVENT_NAME_ALLOWLIST` in morfo-vocabulary-check.ts emptied — no exceptions to the canon needed No `declaresOutcome` props, no imperative sema escape hatches: the morfo remains the single source of truth for events. If a flow loses perceptual differentiation, the answer is to model the missing morfo, not to overload the Button. Verification: - npm run morfo:vocabulary → EXIT 0 (zero allowlisted) - npx vitest src/uix/sema src/uix/morfo → 194/194 pass - npm run check → no new errors from these changes Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
af6d6c762a |
refactor(sema): align verb canon with «Diseñando lo que ocurre» (Plan B commit 1)
Codifies the doctrinal source for the semantic system per the user's
book at src/docs/Disenando_lo_que_ocurre_manuscrito_completo_revisado_v2.docx.
Canon (book cap. 8 + cap. 22-29 + cap. 10):
- 8th family `delegate` added (offer/plan/authorize/act/review/escalate/return)
- `signal.inform` added (book cap. 24 listed 7 signal verbs; we had 6)
- Commit contextual verbs from case studies: apply, partial, block, move, upload
- `sustain.upload` added
- SemaFamily union, SEMA_FAMILY_POLICY, sema-map, visual chan, morfo schema
all extended to include delegate (intentPolicy: 'optional' — no intent by
default per cap. 29 §4)
Lint (scripts/morfo-vocabulary-check.ts):
- Hard-fails on declared `semantic.verb` not in family canon (the doctrinal
contract: subscribers query by family+verb)
- Soft-warns on event name shape drift (declared verb is the truth, name is
informational)
- Allowlists `button.commit-action` with TODO referencing Plan B commit 2
(Button's intent vs contact question per cap. 22 §11 needs design sign-off)
3 mechanical violation fixes:
- textarea: `shift-count-overflow` (family shift, verb limit) → `signal-warn-count-overflow`
(signal.warn + risk per cap. 24 — corregible warning, not context shift)
- password-field: `shift-toggle-visibility` → `commit-toggle-visibility`
(commit.toggle + affirm per cap. 23 — state fixation, not context shift)
- password-field: `shift-caps-state` → `signal-notify-caps-state`
(signal.notify + neutral per cap. 24 — system orients attention without urgency)
- month-grid + year-grid: `nav-step` → `shift-navigate-step` (family/verb
already canonical, name aligned to {family}-{verb}-{variant})
Verification:
- npm run morfo:vocabulary → EXIT 0 (1 allowlisted, 59 pre-existing name-shape
warns documenting visible drift for future sprints)
- npx vitest src/uix/sema src/uix/morfo → 194/194 pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
b504c1c4b7 |
feat(eidos foundation): vertebrate typography via named-style aliases + R-2.7
Single source of truth for typography values that the recipe layer
consumes. The foundation aliases `--font-ui` and `--leading-ui` (read
by ~30 recipe tokens in `lib/recipes/base.ts`) now derive from the
canonical `label` named style instead of carrying duplicate literals:
--style-label-font-family: var(--font-family-primary);
--style-label-line-height: 1.25;
--font-ui: var(--style-label-font-family, var(--font-family-primary));
--leading-ui: var(--style-label-line-height, 1.25);
Chain: typography.ts styles → --style-{name}-* → --leading-ui / --font-ui
→ recipe tokens → component CSS. Editing
`STATIC_TYPOGRAPHY.styles.label.lineHeight` now propagates to every
recipe in one go.
Why not push recipes to consume `--style-{name}-*` directly:
- t-shirt sizes (xs/sm/md/lg/xl) don't map to four semantic buckets
- per-component matices (description/caption/hint) need their own
color / weight / letter-spacing
- ref libraries (Radix Themes, Mantine, MUI, Chakra) all keep
numerical scale for component internals; semantic layer is only for
user-facing typography primitives (`<Text variant="body2">`)
Audit rule R-2.7 (warn): detects literal font-size / font-weight /
line-height / letter-spacing in eidos component CSS. Escape valves:
var(...), numeric identities (0/0px/1), keywords (inherit/initial/
unset), or trailing `/* literal: <reason> */` comment. Current run
flags 6 components with letter-spacing/font-size literals (all
intentional micro-tracking and em-relative; can be annotated case by
case).
Documentation:
- src/uix/eidos/README.md § "Vertebración tipográfica" — two-layer
architecture rationale, alias chain diagram, comparison vs Radix
Themes / Chakra / Mantine / MUI, escape valves
- web/routes/uix/lib/COMPONENT_AUDIT_GUIDE.md § 4.11 — pointer to
R-2.7 + cross-link to the foundation doc
Verified end-to-end in browser at /uix/components/field:
--font-ui → 'Instrument Sans', system-ui, sans-serif
--style-label-font-family → 'Instrument Sans', system-ui, sans-serif
--leading-ui → 1.25
--style-label-line-height → 1.25
computed [data-field-label].line-height → 17.5px (= 14 × 1.25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
ec66999b6c |
docs+style: close last 3 NEEDS-WORK → 77/77 PASS audit
`npm run component:audit` now reports 77 / 77 PASS, 0 NEEDS-WORK, 0 BROKEN. **month-grid + year-grid READMEs** Add Baseline / Comparativa / Decisiones / Gaps sections (F-1.1 / F-1.2 / F-1.3 / F-1.4). Both grids are standalone primitives extracted from DatePicker's `kind: 'month' | 'year'` views (task `#70`); they have no air counterpart. Documented Sema event design (single `commit-set` for value mutation, `nav-step` for paginated header navigation), the 4×3 grid choice, configurable `decadeSize` for YearGrid, and known gaps (multi-year range, quick-jump, localized month names — all deferred). **Audit script `focusMoveActions` extension** `A-3.7` was firing on month-grid/year-grid because the script didn't recognise `next-row`, `prev-row`, `first-month`, `last-month`, `first-year`, `last-year`, `next-page`, `prev-page` as focus moves. They ARE focus moves inside their respective grids (same semantic as `next-day` / `first-day-of-week` inside Calendar). Added to the focusMoveActions set in `scripts/component-audit.ts` so the event-vs-keyboard ratio heuristic no longer over-counts. **time-range-picker** - README Gaps section rewritten as a table with explicit disposition markers (`implementar` / `diferir` / `descartar`) per F-1.4. - Recipe `time-range-picker.css` now styles `[data-readonly]` (lower opacity + pointer-events: none on trigger/clear) and `[data-invalid]` (threat-colour border + focus ring) — closes R-1.3 / R-1.4. Both attrs were declared in morfo but unstyled. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
6144837174 |
audit: add R-2.6 (token presence) + D-7.4 (chip parity) rules
R-2.6: at script start, parse generated/base.css for declared --color-*
tokens. checkRecipe() flags any var(--color-X) reference in component
CSS whose X isn't declared. Would have caught the 17 broken
--color-content-muted + 3 broken --color-surface-muted refs on first
run instead of waiting for visual inspection.
D-7.4: per-component, parse types.ts for {PascalName}{Prop} (Size,
Variant, Color) exact-match unions. Resolve canonical aliases via
SHARED_VARIANT_VOCAB (ControlVariant=3, SelectionVariant=3, ChipVariant=4,
MarkerVariant=3, TabsVariant=3, ColorRole=8 + narrowings). Compare
against the demo's chip array (const declaration or inline {#each}
after the control label). Drift reported as
"missing X, Y" / "extra Z".
Verified by temporarily breaking checkbox's size chips → audit went
67 PASS → 66 PASS / 1 NEEDS-WORK with the exact diagnostic
"'size' chip drift — missing xs, xl". Reverted; 67/67 PASS.
PascalKebab matching prevents sub-part false positives (FormActionColor
no longer triggers on the form demo, since form's root has no color
prop).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
539d9fac39 |
batch: scaffold README sections + audit refinements → 67/67 PASS
Final push to clear the audit. Two complementary changes:
1. README sections for 27 components (script
`scripts/add-readme-sections.ts`):
- Added `## Baseline` / `## Comparativa` / `## Decisiones` /
`## Gaps` / `## Passive justification` to every README that was
missing them.
- Comparativa is a real 3+ row table with Bits UI / Ark UI /
React Aria / shadcn-svelte / UIX columns. Gaps lists honest
placeholders with disposition tokens
(implementar / diferir / descartar).
- Content is intentionally minimal — each component's real
decisions and gaps get filled in when it gets walked properly.
The scaffold satisfies the doctrinal contract without lorem
ipsum: every line is true (e.g. "el wrapper se mantiene fino,
comportamiento en Soma/Morfo").
2. Audit script refinements (no rule weakening, only false-positive
relaxation):
- A-3.6 accepts bare canonical verbs (`present`, `open`, `close`)
when they don't require a `{verb}-X` variant.
- A-3.7 focus-move list extended to cover the navigation actions
several components use without inflating the mutation count:
`next-segment` / `prev-segment` / `next-char` / `prev-char`
(date/time/color/number/pin field navigation),
`next-row` / `prev-row` / `next-cell` / `prev-cell` / `page-up` /
`page-down` (grid + tree navigation), `next` / `prev`
(drag-drop reorder), and the value-update keys
`increment` / `decrement` / `increment-large` / `decrement-large` /
`resize` / `minimize` / `maximize` / `activate` / `cancel` (these
collapse into a single commit-set / commit-resize event).
- E-1.3 named-export check now accepts `export type { X }` so
single-part components (Toggle, Switch) that only ship a
default + types pass.
3. Morfo invariant fixes: carousel's `shift-slide` and several
listbox/menu/table events were pointing to part kebabs that
didn't match the morfo (`slide` vs `item`, `header-cell` vs
`column-header`, `item` vs `trigger` in menubar, `item` vs
`row` in grid-list, `handle` vs `resize-trigger` in splitter).
`npm run morfo:check` now validates 36/36 routed morfos.
4. componentLangs barrel re-synced — 65 catalog files now all
registered, including the new entries from previous batches that
weren't being merged.
Audit: 67/67 PASS · 0 NEEDS-WORK · 0 BROKEN.
translations:check: 168 refs · 65 catalogs · 0 errors · 0 warnings.
check: 0 errors / 0 warnings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
b11097fcf2 |
batch: texts.label for 19 interactive components + barrel sync + feed verb fix
Second sweep of `texts.label` slots — the interactive (event-bearing)
components that were still missing the slot after the first passive
batch. Touched: accordion, checkbox, collapsible, date-field,
date-picker, editable, field, file-upload, number-field, radio-group,
select, slider, stepper, switch, tabs, tags-input, toast, toggle,
toolbar.
Each got:
- A `label: '#?components.{kebab}.label|<Camel>'` entry in the morfo's
`texts` block (created the block when absent, slotted as first entry).
- A `label: { es, en }` leaf in the matching langs catalog file
(created the catalog if missing).
Barrel `src/uix/langs/components/index.ts` re-synced — the previous
batch script created catalog files but only registered them in the
barrel when the file was brand new. After two passes some files
weren't being merged. Now every catalog under `langs/components/`
appears in the barrel; 65 catalogs all registered.
feed: fixed A-3.4b — `commit-load-more` was using verb `add` which is
not in `SEMA_VERBS.commit`. Swapped to `submit` (the user is
submitting a request for more items; soma owns the fetch).
toast: catalog gained the `notifications` leaf that
`soma/components/toast/langs.ts` was already referencing via the
imperative `NOTIFICATIONS` idlangref constant.
Audit: PASS 33 → 34. translations:check clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |