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 }
8 Commits (b01646cfd8462dcd61e746d89dcc19dd3847ea17)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
b01646cfd8 |
feat(soma)!: fase C2c — el efecto syncAttrs muere; una tubería, cero ambigüedad
Cierre de la fase C del P0: tras C2a (la bolsa resuelve el contrato) y C2b (una sola computación), el efecto era doble-escritura idempotente sin función. Se retira entero: `syncPartAttrs`, el flag del tipo y las ~71 registraciones que lo pasaban (tabs-provider y radio-group-provider viajaron en `8ac23047f` del eje theming con la retirada declarada en su cuerpo — coordinación por canal entre sesiones, historia completa desde ambos lados). El único escritor imperativo sancionado que queda es el prewrite de `trigger` (un commit que el morfo declara). La PRIMERA pasada de la suite completa de la historia (nadie la corría — el hallazgo original del informe demostrándose solo) destapó la cola: ~258 asserts en 34 ficheros de test de provider (jsdom, elementos sueltos) ejercitaban las escrituras DOM del efecto retirado, no el contrato. Todos re-firmados a asserts de bolsa, con tres leyes que salieron del trabajo: - la bolsa entrega valores CRUDOS (número 20, no '20'; booleans donde el getter los produce) — Svelte stringifica al render, el DOM no cambia; - una AUSENCIA se aserta contra la bolsa del PART (`'x' in props === false`), no contra un getter de provider que añada la clave explícita `undefined`; - el prewrite (`data-last-action`) SIGUE siendo assert de DOM — es el escritor imperativo que sobrevive. De la misma pasada: `skin-media-player` entra en `COMPETING_ROOTS` de lint.test (viste el contrato de media-player, clase audio-player — nació sin registrarse y nada lo corría), y los ~10 comentarios que describían el efecto (dialog-001, sticky, knob, field, media-player, editable, anchor-nav) pasan a describir la bolsa, verificados spread a spread antes de tocar nada. Verificación: runtime 49/49 · ssr-contract 6/6 · morfo:check 161/161 post-strip («All routed morfos validate» — el detector definitivo) · los 34 ficheros re-firmados en verde · suite completa con únicos rojos residuales los flaky de carga ya adjudicados (timeouts que pasan en solitario) · svelte-check src/ a 0 (71 = ledger exacto de web/). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
9dffa541ef |
fix(uix): fase A cierre — los seis rojos del censo morfo:check, adjudicados
Cada uno leído antes de tocarlo; tres clases distintas: - combobox.input y gradient-builder.track: el morfo declara el data-* SIN value (soma posee el valor — el idioma que el propio trigger de combobox documenta) y nadie lo escribía. El comentario del input además afirmaba que la bolsa lo resolvía, cosa que una declaración sin fuente no puede hacer. Escritura manual, como sus hermanos. - menu-dial.trigger: componente de scope eidos (contrato espejado a mano); el trigger estampaba marker y aria pero olvidó data-state — la lista de al lado sí lo lleva. Espejo del idioma existente. - calendar (data-calendar-surface) y fab (data-fab-size): attrs visuales de wrapper / hooks compartidos de eidos, sancionados FUERA del morfo por la doctrina firmada (precedente: data-combobox-control). El instrumento no conocía la doctrina: nace scripts/eidos-only-attrs.ts como lista ÚNICA que consumen morfo-check y eidos-lint-all, para que los dos instrumentos no puedan divergir. - palabras.handle: el grip porta el escape del focus-scope a propósito (comentario in situ con la razón); la declaración alcanza a la implementación sancionada. Los otros cuatro rojos del censo previo no eran contrato: accordion, background y link eran timeouts de compilación fría (pasan en caliente) y color-field lo sanó la unificación de la bolsa por sí sola. Verificación: morfo:check 160/161 con los seis en PASS — el único rojo restante (natural-time-picker) es la clase flaky del instrumento «demo que navega bajo el eval» (no falló en ninguna de las dos pasadas previas; la ruta verificada a mano en navegador con su contrato completo) · schema sweep 89/89 · eidos:lint exit 0 · combobox 11/11 · palabras 84/84. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
56a96114f8 |
feat(morfo,soma): la emisión deja de aceptar un elemento anónimo
El defecto que tres auditorías encontraron y ninguna cerró no era que N eventos redirigieran sin declararlo: era que la API de emisión aceptaba un HTMLElement suelto, compensando que el registro de partes perdía la identidad de instancia. Censar y arreglar a mano reproduce el modo de fallo. Esto lo hace inexpresable. F1 — SomaRuntime<M> genérico, SIN default. Nombres de evento, kebabs de parte y claves de events/actions tipados contra la declaración (EventNameOf / PartKebabOf / ActionNameOf, los extractores que semaSelector ya usaba del otro lado). 104 anotaciones migradas + 3 wrappers que devolvían tipado pero tomaban sources ANCHO. SomaRuntime<Morfo> queda sólo en la tabla de contratos. F2 — registro por instancia: Map<part, PartRegistration[]>, pertenencia mantenida por el stream del attachment (poda al desmontar, re-entrada al remontar), resolución liveReg = la instancia VIVA más nueva. Mata de paso la clase "la más nueva muerta ensombrece a una viva". F3 — tres formas legales de destino: el target declarado; el anclaje por instancia (SomaRuntimePart.trigger, tipado por EventNameTargeting, + runtime.partInstance por identidad de referencia); y targetFallback, la cadena por estado de montaje declarada en el morfo y resuelta por resolveEmitTarget — LA resolución única para validación, emit y foco a11y, que ya no pueden discrepar. ~30 componentes migrados; censo de targetOverride 148 -> 89. F4 — A-36 tenía un superviviente. Medido en dropdown-menu: bajo `pre` el `open` no colisionaba con el contact-activate del Button compuesto, se PERDÍA entero porque su content no había montado. Aplicada la receta de float-panel a dropdown-menu Y context-menu. Ahora: contact-activate en trigger, open en content — dos superficies, ambas expresando. Submenús mudos, tres componentes. No era cableado: el morfo no declaraba el evento. onion-menu recibe emerge-expand/emerge-collapse (la forma de TreeView: un nivel revela sus hijos en el sitio); dropdown-menu y context-menu reciben sub-open/sub-close sobre sub-content, distintos del open raíz a propósito porque el sub es su propia superficie flotante. Nacen con la receta A-36 para no repetirla en código nuevo. chronos — declaraba 26 partes y registraba UNA; 17 role= a mano y el ARIA declarado no llegaba nunca al DOM. Se anula la mitad sobre-extendida de la decisión de 29ffe902a: la reutilización sigue viajando por el motor puro, pero la ESTRUCTURA se compone como en Table y Calendar. C1 (las 6 partes que emiten, chronos con cero targetOverride) + C2 (8 singletons) + C3 8/9. Registrar una parte DESTAPA declaraciones falsas, tres veces en un pase: el chip declaraba defaultElement button y ponía type= sobre un div (anida el asa de resize); grid-row declaraba archetype item y pintó la semana entera como fila de lista; y un aria por propRef desaparece en SILENCIO si el provider no publica la fuente. En los tres el arreglo fue la DECLARACIÓN, no el DOM. Verificado: check 74 = línea base medida con stash, DELTA CERO sostenido en cada lote · 458 pasan (chronos+morfo+sema) · navegador limpio en las tres vistas de chronos, con el contrato ARIA vivo por primera vez (aria-labelledby resolviendo a «junio de 2026», aria-readonly/disabled que no se habían emitido nunca). Handoff en docs/process/CONTINUE-perceptual-surface.md. Aparte, y decidido por el autor: docs/process/PLAN-event-name-normalization.md — prefijo de familia siempre; 36 de 252 sin prefijo, cero ambiguos. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
fc84305c22 |
feat(direction): el mecanismo pertenece al morfo — la declaracion exige el cable
El campo obligatorio `dir: SomaRuntimeDir | null` de 4.1 conservaba el gate a
costa de ~116 lineas de ceremonia: 67 `dir: null` en fuente + 47 en tests
obligaban a ~75 componentes SIN direccion a pronunciarse sobre un eje que no
les concierne, y `parts` era un `readonly string[]` sin validar — un typo
estampaba nada, en silencio (fail-open). El usuario lo dijo antes que la
auditoria: "los dir no deben ser obligados de pasar".
Ahora lo declara el MORFO, que es donde viven los contratos:
direction: {} // 46 morfos — estampa en 'provider'
direction: { parts: ['trigger'] } // dropdown-menu (su raiz no renderiza)
direction: { parts: ['content'] } // drawer · float-panel (pintan en portal)
direction: { parts: [...,'input'] } // css-field · number-field (dos caras)
y el TIPO se computa de la declaracion, con el generico que ya existia inerte
en soma.runtime<M>:
morfo declara direction => dir: Active<Direction|undefined> REQUERIDO
no declara => dir?: never PROHIBIDO
Olvidar el cable no compila; cablear un eje a un componente sin direccion
tampoco. Y compileMorfo valida direction.parts contra el arbol declarado —
fail-CLOSED: el typo que antes estampaba nada ahora revienta al registrar.
El colapso: 49 getters `{ get: () => this.opts.dir.current }` -> `dir:
this.opts.dir`; los 67+47 `dir: null` MUEREN. El estampado gana su sitio en el
tipo de la superficie (`SomaRuntimePart.props` incluye `dir?: Direction`), asi
que los casts `(props as Record...).dir` de los tests sobran.
El gate cazo en el acto, y las dos presas eran reales:
- `command`: 4.1 le dejo `dir: null` en el runtime y el estampado manual
inline en el assert (la linea no estaba sola y el barrido no la vio) — un
componente CON direccion que habia quedado fuera del mecanismo.
- 5 runtimes SECUNDARIOS del mismo morfo (accordion item, nav-tree item,
emoji-picker cell, context-menu root-runtime, feed sentinel): mismo morfo,
misma exigencia — reciben la afirmacion del dueno (el estampado solo aterriza
en direction.parts, que esos runtimes no registran).
Guards nuevos:
- compile.test: normalizacion a ['provider'], partes explicitas, y el
fail-closed del typo (4 casos).
- direction-census.test: prop publica `dir?: Direction` <=> morfo.direction,
en ambos sentidos, con las excepciones FIRMADAS y sus razones (field-langs:
LangSpec; waveform: delega en el Slider; popover/tooltip/link-preview:
overlays puros cuya pintura estampa la capa flotante en el wrapper
portalizado — declararles direction seria el atributo inutil contra el que
4.1 avisaba). El propio censo cazo a esos tres: la excepcion quedo escrita
el mismo dia que el guard.
Verificado en Chrome con la fuente nueva (el morfo): dropdown-menu estampa en
el TRIGGER, css-field en raiz E input, drawer con pagina rtl por prefs deja el
content SIN atributo y computa rtl por herencia — el modelo del flip intacto.
check 77 = linea base · morfo+soma+active-uix 1401/1402 (el 1 es
soma-attr-audit, flaky bajo carga, pasa aislado) · rtl:check 1 (palabras) ·
docs:check 0/566.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5983b00d5f |
feat(direction): el estampado pertenece al runtime — y olvidarlo ya no compila
Era la ultima convencion manual del eje: una linea por proveedor, 49 copias de
ella, y 20 de 55 componentes que simplemente la habian olvidado. Una convencion
que hay que repetir 49 veces y que un tercio del catalogo incumple no es una
convencion — es una abstraccion que falta.
VEHICULO A, y el handoff tenia razon desde el principio. Yo habia recomendado B
(un AttrPlan del compilador de morfo) con el argumento de que A deja `dir`
invisible para `contracts.cssSelectors` y `eidos-lint`. Medido: FALSO. El linter
sólo clasifica selectores `[data-*]`, y las recetas leen la direccion con
`:dir()`, una pseudo-clase que no toca ninguno de los dos guards. El coste que
le achacaba a A no existe.
Y B no llegaba donde yo decia. Reparto real de los 49 sitios segun la bolsa que
expanden:
renderProps() 21 un AttrPlan les llegaria
runtimePart.props 27 NO les llegaria
ninguna 1
O sea B aterriza en 21 de 49 y exige migrar 28 componentes de `.props` a
`renderProps()` — que no es cosmetico: `renderProps()` emite TODOS los attrs del
morfo de esa parte. A, en cambio, inyecta en `partPropsForRegistration`, que
incluyen LAS DOS bolsas, y llega a 48 de 49 desde un solo punto. Su precedente
es literal: `id`, el marcador, `data-archetype` y `reg.attachment` ya se
inyectan ahi sin declaracion en morfo.
EL GATE ES DE TIPOS, que es el premio de verdad:
dir: SomaRuntimeDir | null // OBLIGATORIO en SomaRuntimeSources
`null` es la unica salida y dice algo cierto: este runtime no estampa direccion.
Olvidarlo es un error de compilacion, no un defecto que nadie ve hasta que
alguien abre el componente en RTL.
`dir.parts` responde la otra mitad de la pregunta del contrato — QUE elemento
lleva la pintura — por defecto `['provider']`. El censo dice que 44 de 49 son la
raiz; los cinco que no: dropdown-menu ['trigger'] (su raiz no renderiza
elemento), drawer y float-panel ['content'] (pintan en el portal), number-field
y css-field ['provider','input'].
VERIFICADO en Chrome real, pagina en LTR y direccion movida por el control de la
demo:
tabs auto -> ltr prop rtl -> rtl vuelta a auto -> ltr
dropdown-menu el TRIGGER pasa a rtl y el panel portalizado tambien
number-field raiz e input, los dos a rtl
drawer el content portalizado a rtl por la cadena de prefs
accordion sigue la cadena y vuelve, sin una sola linea en su proveedor
check: 77 con mis cambios vs 79 sin ellos (A/B con stash). El -2 esta explicado:
uno era un error preexistente de `date-range-picker-provider.svelte.test.ts` que
indexaba el tipo `{ readonly dir }` de unos props que ahora son mas anchos; el
otro es que `media-player` ya no puede compilar sin el campo (su unica linea
tocada, +1/-1, es mecanica).
Tests: 1271/1278 en `src/uix/soma` + contracts. Los 7 fallos son el conjunto
preexistente, A/B contra arbol limpio: los 6 de `contracts.test.ts` salen
identicos sin mis cambios y `soma-attr-audit` pasa aislado (flaky bajo carga).
⚠️ Un fallo mio que cazaron los tests y conviene no repetir: los proveedores con
la forma de una linea `soma.runtime(morfo, {})` recibieron `dir: null` en vez del
getter, y 12 componentes con direccion se quedaron sin estampar. Lo vieron cinco
tests de "exposes root props". Un barrido con dos formas sintacticas necesita
las dos en el mapa, no una.
Estampados a mano restantes en el catalogo: 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
b3d0e29037 |
feat(gradient): GradientBuilder editor polish + presets; land gradient WIP
GradientBuilder (this session): - Stop color editor uses the canonical ColorField value row (swatch + styled Select), not a native select; rails at 90% width + xl track. - Composable footer: ColorPicker.Cancel / ColorPicker.Close + trash remove-stop, as a sibling of PickerShell.Body. - Surface-agnostic by default (variant='ghost'): no card, adapts to host. - '+' add-stop on the kind-switch row; inserts between the selected stop and the next; rail click-to-add re-enabled (insert at cursor). - GradientBuilder.StopList composable stops list (rendered by default). - presets prop (Gradient[]) rendered below the editor (flex, not tabs); save-to-presets with a maxPresets cap; the action button flips Save <-> Delete when a saved preset is selected (ColorPicker mechanic). Also lands the in-progress gradient tree so HEAD is self-consistent (langs/components/index.ts already imported ./gradient-picker, whose file was untracked). gradient-builder + gradient-picker stay on ACTIVE_DEV_TRACK; the GradientPicker 2-tab redesign is next (see gradient-builder/CONTINUE.md). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
8ddd55309a |
feat(soma): GradientBuilder soma layer — render-ready providers + wrappers (WIP)
Completes the headless layer of the GradientBuilder (still ACTIVE_DEV_TRACK): - Providers expose `.props` (renderProps() + handlers) and register per-part sources for the morfo's value-bound aria (aria-valuenow / valuetext / label on each stop) — every stop is a keyboard-accessible role=slider thumb. - Svelte wrappers: Provider (the editor root, bindable `value: Gradient`), Track (click-empty-to-add drag surface), Stop (the slider thumb) + types + barrel. The eidos composes Preview / AddStop / AngleDial / KindSwitch over these via GradientBuilderProvider.require(). check: 0 new errors, type-clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
c474fc6bae |
feat(eidos): gradient axis (6th builder) + elevation-scaled opacity + GradientBuilder scaffold
Gradient axis — Phase 1 (engine + dogfood):
- $libs/gradient: canonical Gradient model + gradientToCss serializer, pure and
zero-dep, shared by the theming axis and the (WIP) GradientBuilder. Stops
reference color ROLES → a --gradient-{name} re-tints with the seed and flips
light/dark for free. Default `in oklch` interpolation.
- build-gradient: role-derived factories (deepen/sheen/halo/aurora mesh) +
ActiveEidos.applyGradients() (the 6th runtime builder, in ThemeSeed/applyTheme).
- shimmer migrated to `in oklch`. Dogfood: /demos/cristal replaces its ~12
hardcoded gradients with applyGradients role tokens.
Opacity = function of elevation (depth cue `translucency`):
- New translucency depth-plane cue, sibling of shadow/blur: frost opacity now
scales with elevation (foundation overlay 68% / modal 80%; cristal 52→66→80)
via --depth-{plane}-translucency, consumed by the frost rule. base.css regenerated.
GradientBuilder component — Phase 2 (scaffold, WIP):
- morfo (contract) + soma provider state machine over the Gradient model: stops
add/move/remove/recolor, kind, angle, pointer drag; every stop a keyboard-
accessible role=slider thumb. Marked ACTIVE_DEV_TRACK until eidos/picker/demo land.
Docs: $libs/gradient README + THEMING §gradient-axis / §translucency + token table.
Demo cristal: scroll-reveal via uix.motion spring + hover glow; Select z-index
ladder; aurora/title → role-derived tokens.
contracts.test: ACTIVE_DEV_TRACK now filtered uniformly in both soma collectors.
check: 0 new errors. Tests: $libs/gradient + build-gradient + base.css sync green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |