You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/old-deprecated/fable_audit.md

35 KiB

Auditoría Fable — sistema activeUIX (morfo · soma · sema · eidos)

Fecha: 2026-07-01 · Rama: alpha-0.1-sec-dom · Auditor: Claude Fable 5 Método: lectura directa (sin agentes) de la documentación troncal (docs/README, CANON, active_architecture, READMEs de capa, GUIA_IMPLEMENTACION_SEMAUIX, LIBRO_VARIACIONES, TSC, THEMING_NOTES, comparison, decisions, active-uix) y del código fuente núcleo de las 4 capas (morfo: types/compile/schema/resolver/selectors · sema: types/engine/resolver/sema-map/ stamp/projection/durations/chans · soma: runtime.svelte.ts · eidos: active-eidos.svelte.ts + lib/types), más verificaciones puntuales por grep sobre los 136 morfos, 48 packs sema y package.json. Se excluyeron pendientes, CONTINUEs y auditorías previas, según encargo.

Cada hallazgo indica dónde se verificó. Severidades: P0 corrección/riesgo real · P1 deuda de diseño con impacto · P2 mejora clara · P3 higiene.


1. Resumen ejecutivo

El sistema de cuatro capas es arquitectónicamente sólido y genuinamente original: el contrato declarativo (morfo) consumido por compilación tipada, la capa perceptiva (sema) con cascada CSS-like sobre tokens data-event-*, el runtime headless (soma) que transcribe el morfo, y la capa visual (eidos) con el Token Scope Contract validado en generación. Ninguna librería mainstream tiene ese conjunto. Las fronteras de capa se respetan casi siempre en el código real (verificado: 188 usos de semaSelector y cero selectores manuscritos en los packs sema; providers migrados a renderProps/syncAttrs; eidos no importa internals de soma).

Los problemas encontrados no son de concepto sino de tres tipos:

  1. Huecos de implementación en la ejecución perceptiva — concurrencia de señales sin gobernar (el regime declarado no lo consume nadie), sequence: 'coincident' sin implementar, precedencia invertida del fallback de reduced-motion, y un default (sequence: 'pre') que ya causó dos clases de incidentes documentados.
  2. Contrato que promete más de lo que ejecuta — eventos declarados que nunca se emiten (los 5 pickers), commits puramente descriptivo, mode/regime/scope muertos. El propio LIBRO_VARIACIONES (D.2) reconoce el problema y propone el flag emission, aún sin implementar.
  3. Drift documental significativo — el corpus es enorme y varias fuentes "autoritativas" contradicen al código (campo translations vs texts, 24 vs 26 archetypes, familia del Dialog, tabla de holds, dependencia de @floating-ui ya retirada, numeración de capas de la cascada). Irónico en un framework cuyo argumento central es "el contrato no drifta".

Valoración global: arquitectura 9/10 · implementación 8/10 · coherencia doc↔código 6.5/10 · madurez de producto 6/10. Detalle en §6.


2. Fortalezas verificadas (lo que está bien y hay que proteger)

  • Morfo como contrato compilado (compile.ts): pre-resolución de staticAttrs vs dynamicAttrs con AttrPlan discriminado por mode, deps por parte, keyboard parseado, contrato CSS (contracts.cssSelectors) derivado — cache por identidad (WeakMap) con HMR gratis. Diseño de compilador limpio y bien comentado.
  • as const satisfies Morfo como patrón obligatorio: los typos de parte/evento son errores de compilación reales. Verificado que createAttrs y semaSelector explotan los literales.
  • Disciplina del typed builder cumplida al 100%: 47 packs sema, 188 llamadas a semaSelector, 0 strings manuscritos (grep). La defensa anti-drift funciona donde se aplicó.
  • TSC (Token Scope Contract): el álgebra de scopes con validación transitiva y detección de colisiones cross-axis resuelve un bug real de CSS (substitución eager de custom properties) que ningún sistema de referencia cierra estructuralmente. Con v2.2 (multi-part
    • composition) la cobertura es universal (15/15 componentes con data-color). Es la pieza más defendible del framework junto a sema.
  • Contratos ejecutables (src/uix/contracts.ts): la tabla de ownership/degradación es dato + tipos (UIX_TYPE_CONTRACTS con checks Extends<>), no prosa. Rarísimo verlo.
  • Sema ornamental de verdad: eventEngine opcional en el runtime, canales sound/haptic opt-in, errores de canal absorbidos con logger, prepare-time priming del AudioContext dentro del gesto. La degradación SSR/headless está pensada.
  • Persistence + a11ySemantic + polymorphic close: los tres ítems del libro (§6, §9, §5.3) están implementados con tests y consumidores reales — no es vaporware doctrinal.
  • Cobertura de tests: todos los providers soma tienen test directo (guardia NO_MISSING_PROVIDER_TESTS); ~1900 tests verdes según el último hand-off; motores puros extraídos a $libs (datagrid/forms/strings) — buena separación testable.
  • Tooling de contrato: morfo:check, morfo:vocabulary (hard-fail en verbos fuera de canon), translations:check, component:audit, eidos-lint, recipe-css-contract.test.ts (guardias bidireccionales alias↔CSS). La doctrina "cada fix sistémico lleva guard" se cumple.
  • Timers perceptivos gestionados: hold/delay/earcon corren en uix.timers (cancelable, determinista bajo fake-clock), no setTimeout crudo.

3. Hallazgos por capa

3.1 SEMA

S1 · P0 — Race de señales solapadas sobre el mismo target. DomSignalProjector.cleanup() (projection/dom.ts) llama unstampEventAttrs, que borra los cinco data-event-* sin comprobar data-event-id. Si el mismo target emite una segunda señal antes de que expire el hold de la primera (toggle spam, handle-drag continuo, re-warn de validación), el cleanup de la señal vieja borra la proyección de la nueva a mitad de hold: eidos pierde la animación y cualquier cascade que se resuelva después matchea contra un DOM vacío. El mismo defecto afecta a señales persistentes (untilFix) re-emitidas sin clearTarget previo (hoy es convención de provider, no está forzado). Fix mínimo: guard en cleanup — solo unstamp si target.getAttribute('data-event-id') === signal.id. Fix completo: ver S2.

S2 · P1 — regime / mode / scope son contrato muerto. Declarados en MorfoEvent, compilados a ActionPlan (compile.ts:620), y ningún consumidor en runtime (grep exhaustivo). Los overlays declaran regime: 'lock' que no hace nada. El vocabulario replace | collapse | lock | queue es exactamente la política de concurrencia que S1 necesita — implementarlo mataría dos pájaros. Si no se va a implementar a corto plazo, marcar los campos como reserved/no-op en types.ts para que el contrato no mienta.

S3 · P1 — sequence: 'coincident' no está implementado. runtime.svelte.ts:749 trata coincident idéntico a pre (emit awaited con hold completo ANTES del handler). La doctrina (GUIA §5.2) lo define como "señal durante el proceso" (sustain) — que es precisamente el caso donde bloquear el handler ~600ms (hold noticed de sustain) es incorrecto. Es la misma clase de bug que el checkbox-lag, latente en la tercera rama del enum. Propuesta: coincident = fire-and-forget del emit (no await) + handler inmediato.

S4 · P1 — El default sequence: 'pre' es un footgun demostrado. Dos clases de incidente ya documentadas (checkbox 244ms de lag; apertura de overlays gateada tras el hold) provienen del mismo patrón: default 'pre' + estado fijado en el handler. La doctrina correctiva existe pero vive en notas de sesión. Propuesta: lint en morfo:vocabulary — WARN cuando un evento 'pre' (explícito o por default) tiene handler registrado en el provider y no es de familia emerge-close; o cambiar el default por familia (commit → post).

S5 · P2 — Precedencia del fallback reduced-motion invertida. runtime.svelte.ts:690: opts.channels ?? action.semantic.channels ?? a11yChannelsOverride. Un morfo que declara channels: ['sound'] para silenciar haptic derrota silenciosamente el reducedMotionFallback: 'state' (que fuerza channels: []). El comentario lo declara deliberado ("authors can still force motion"), pero mezcla dos intenciones: afinar canales ≠ anular una preferencia de accesibilidad del usuario. La preferencia del usuario debería ganar (intersección, no fallback): channels = a11ySilence ? [] : (opts ?? morfo).

S6 · P2 — El sound base de contact contradice la doctrina de fatiga. SEMA_MAP.families.contact.base.sound.gain = 0.25 hace audible por defecto la familia más frecuente del sistema. El incidente Palabras (EV-G) se "resolvió" dejando de emitir el evento — perdiendo telemetría — porque el base suena aunque no haya pack. D.7 dice "en eventos frecuentes la prioridad es evitar fatiga; el silencio es una firma válida". Propuesta: contact base gain ≈ 0 (o activeChannels: ['haptic']) y que los packs opt-in suban el sonido — invierte la carga de la prueba y elimina la clase entera de workaround.

S7 · P3 — safeMatches matchea también por closest(). resolver.ts:200: una rule cuyo selector matchea un ancestro del target también aplica. Útil para scoping (#dialog [data-x]), pero significa que una rule sin constraints [data-event-*] (solo state attrs) puede capturar señales de cualquier descendiente. No está documentado en el README de sema; documentarlo o restringir closest a selectores con combinador.

S8 · P3 — Numeración de la cascada inconsistente entre docs. README sema: "cascada de 5 capas" (1–5). engine.ts: capas 1–5 con otra asignación (runtime=4, cascade=5) y luego "Layer 5/6" en comentarios. CLAUDE.md: 6 capas con 5a/5b. resolver.ts: "layers 4 + 6". Elegir UNA numeración canónica (sugerencia: 1 family · 2 intent · 3 morfo · 4 runtime · 5a packs · 5b app-cascade) y barrer.

S9 · P3 — Higiene menor: stamp.ts/durations.ts/projection/dom.ts usan estilo sin punto y coma, distinto del resto (Prettier no lo unifica); cssSpecificity no modela combinadores/:is() (documentado, aceptable); applyOverride clona con structuredClone por rule matcheada — coste O(rules·señal) tolerable pero medible en handle-drag continuo.

3.2 SOMA

SO1 · P1 — Doctrina "handlers síncronos" vs await handler(). Regla dura nº 9 ("los handlers de events son síncronos; async va antes del trigger") vs runtime.svelte.ts:742/752: await handler(). El runtime soporta silenciosamente handlers async, y en post el emit espera a que terminen — comportamiento razonable pero contradictorio con la doctrina escrita. Decidir: o el runtime NO awaita (enforcement), o se actualiza la regla (los hand-offs sugieren que el await de post es deseado).

SO2 · P2 — opts.semantic sobre evento no-polimórfico se ignora en silencio. El JSDoc de TriggerOptions.semantic promete "pass-through warns via logger if present"; la implementación no loguea nada (runtime.svelte.ts:622 — el branch solo entra si isPolymorphicSemantic). Un provider que pasa semantic a un evento concreto cree haber sobreescrito la familia y no lo ha hecho. Implementar el warn (hay sources.logger).

SO3 · P2 — JSDoc desactualizado respecto al diseño aditivo. El mismo JSDoc habla de allowedFamilies + defaultSemantic — defaultSemantic no existe (D.11 eligió el shape aditivo). Igual en morfo/types.ts comentarios. Barrer referencias.

SO4 · P3 — prewrite se aplica antes de validar el target del emit. Si el target no está en DOM, SomaRuntimeTargetError se lanza DESPUÉS de haber escrito los prewrite (data-last-action) — estado a medias sobre el DOM. Reordenar validación o revertir prewrites en el throw.

SO5 · P3 — runA11y recalcula snapshotRootProps()/resolveIntent ya resueltos en runEmit — micro-duplicación; y la indentación de runtime.svelte.ts:667-668 está rota (formato).

SO6 · P3 — Docs de soma citan dependencias retiradas. README §3 y SOMA_ARCHITECTURE §6/§12 declaran dependencia de @floating-ui (hoy devDep; el positioning es el motor propio $ethereal desde 56eb9bd2) y de clsx (no está en package.json). También la tabla de layers omite popper/stacking/manipulation/zoom-pan que existen en layers/. Actualizar — es la puerta de entrada de la capa.

3.3 MORFO

M1 · P1 — Eventos declarados que nunca se emiten (contrato que miente). Los 5 pickers declaran close polimórfico que ningún provider dispara (hallazgo propio de D.11: "eventos inertes"); commits es descriptivo sin validador activo más allá del smoke. El autor ya aceptó la solución (D.2: flag emission: 'runtime' | 'declared-only' | …) pero sigue pendiente. Mientras no exista, la tabla de eventos de los READMEs y el contrato público prometen percepción que no ocurre. Acción: implementar emission en MorfoEvent + lint que exija declared-only explícito donde no haya runtime.trigger correspondiente, o cablear los triggers de pickers.

M2 · P2 — expression cubre solo la mitad del catálogo. 82 morfos declaran events, solo 41 declaran expression (grep). El campo se creó para que "la ausencia de pack nunca se confunda con olvido" — con un WARN de lint y 50% de cobertura, la ambigüedad que quería eliminar sigue viva. Subir a FAIL tras una pasada de anotación.

M3 · P2 — Excepción no-reconocida a la regla 2-de-3. parts[].keyboard es soma-only (la propia tabla del README lo marca "✅ (was already there)"). O se documenta como grandfathered explícito o se argumenta el segundo consumidor (docs lo consume para tablas — sería 2-de-3 si docs cuenta como capa, pero entonces la regla necesita redefinirse). Tal cual, la regla estrella tiene un asterisco silencioso.

M4 · P2 — enumPair infiere mal enums de 3+ valores. compile.ts:508: para data-state-derived, falseLabel = enumValues.find(v => v !== trueLabel) — con ['checked','unchecked','indeterminate'] y stateRef booleano, el false-label depende del ORDEN de declaración. Hoy no muerde (los stateRef booleanos usan enums binarios), pero es una inferencia frágil sin validación en schema. Añadir check: stateRef+enum exige exactamente 2 valores, o mapeo explícito.

M5 · P3 — semaSelector puede tipar state ya. El matcher state/aria acepta strings sueltos "porque el vocabulario data-attr no está derivado del morfo" — pero compiled.contracts.dataAttrsByPart YA contiene attr + enum por parte. La tipificación prometida es implementable hoy sin nueva infraestructura.

M6 · P3 — Higiene: _resetCompileCache() es un no-op vacío con nombre engañoso (eliminar); aliases deprecados IntentExpectedFamily/SemaEventLabel siguen importados por código nuevo (morfo/types.ts importa IntentExpectedFamily, no el canónico IntentRequiredFamily); el doble collectSourceDeps con cast as never (compile.ts:409) merece el helper real.

3.4 EIDOS

E1 · P1 — ActiveEidos es una god-class con apply() de fuerza bruta. 1.254 líneas: 6 builders runtime + persistencia + render + proyección de attrs + resolución de tokens. Cada apply() re-renderiza todo (incluido renderStaticCss() completo, que genera la foundation entera) aunque solo cambió un axis; applyTheme construye cada builder dos veces (una en apply()→#renderXCss, otra para el resultado devuelto). Un theme editor con slider (caso de uso anunciado: "vivacidad P3") paga regeneración total de CSS por evento de input. Acciones: (a) memoizar renderStaticCss por identidad de config + breakpoints; (b) que apply() acepte un scope ('scheme' | 'type' | …) y solo reescriba ese bloque; (c) reutilizar el resultado ya construido en applyTheme. Separar los builders a un EidosRuntimeBuilders colaborador reduciría la clase a su rol de runtime/contexto.

E2 · P2 — createSystemColorSchemeSource viola la regla DOM del propio framework. active-eidos.svelte.ts:1232-1254 usa globalThis.matchMedia + addEventListener crudos. La regla dura ("listeners de document/window pasan por ActiveDom") y el precedente (ActiveDom.prefersReducedMotion como tracker) exigen que el mode-source por defecto viva en adom (p.ej. dom.prefersColorScheme) o al menos use dom.listen.

E3 · P2 — #renderSchemeCss traga errores en silencio. Si #buildSchemeResult() lanza durante un re-derive (cambio de modo con seed inválido para las donor scales), el catch devuelve '' y el bloque scheme desaparece sin log. Al menos logger.warn con la causa; idealmente conservar el bloque anterior (transaccionalidad que setCssVariables sí tiene y aquí falta).

E4 · P2 — El bundle --size-* sigue sin consumidores (63 tokens huérfanos). Reconocido en THEMING_NOTES (⚠️ "canon + guard, no consumo") y en el inventario reference-grade. El guard evita deriva, pero la promesa "map global coordinado" del README es hoy solo emisión. Decidir: refactor de recipes a consumir --size-{k}-* o degradar la promesa en docs.

E5 · P3 — Capa 4 del token stack (component-color) sin veredicto. THEMING_NOTES la marca "candidata a deprecate si en 6 meses nadie la usa" — el plazo va corriendo desde ~2026-05. Revisar consumo y decidir.

E6 · P3 — Pendientes declarados del propio doc: primer caso real de scope: 'event:*' (integración TSC↔sema aún sin consumidor), migración de los 5 palette-consumers a declarations[]. Son las dos costuras donde la "integración con sema" del theming es aspiracional.

3.5 Transversal / documentación

D1 · P1 — morfo.translations → texts: los docs de la capa no migraron. El tipo Morfo solo tiene texts (97 morfos lo usan; 0 usan translations). Pero morfo/README.md (secciones "What morfo contains", Step 4.5, anatomía, pitfalls), SOMA_ARCHITECTURE §7 y soma/README §4 documentan translations: con ejemplos completos que no compilan. Es el drift más grave porque afecta al onboarding directo de la capa contrato. (active_architecture §0.1 sí registra el rename — el barrido quedó a medias.)

D2 · P1 — GUIA_IMPLEMENTACION_SEMAUIX (declarada "autoritativa") diverge del código en al menos 5 puntos: (1) §4.1 Modal/Dialog = shift.enter-mode; el morfo real usa emerge (open y close; allowedFamilies sin shift). (2) §6.2 tabla de holds (contact 120 / emerge 180 / shift 240 / commit por-intent) ≠ SEMA_MAP (emerge 240, shift 600, commit plano 240) ≠ SEMA_HOLDS_BY_INTENT (holds.ts). Tres tablas, tres verdades. (3) §2 declara "sistema de 8 tokens" sin tertiary; eidos tiene 9 roles canónicos. (4) §2.4 usa naming --color-{role}-element pre-actual. (5) §5.3 documenta el shape defaultSemantic que D.11 descartó. Dado que CLAUDE.md la señala como fuente autoritativa "cuando haya dudas", esto produce decisiones incorrectas en cada sesión nueva. Acción: pasada de reconciliación o degradar su autoridad a favor de CANON.md + código (que ya es la regla en CANON §sources).

D3 · P2 — Archetypes: 24 en docs, 26 en código. ARCHETYPE_VOCABULARY tiene 26 (se añadieron field-trigger y footer); active_architecture §6 y morfo/README dicen "24" y listan sin los nuevos. Ejemplo canónico de por qué CANON.md prohíbe copiar listas — estas dos copias sobrevivieron.

D4 · P2 — Doctrina "zero dependence" vs realidad. La doctrina del proyecto (memoria de feedback: "framework depends on NOBODY") convive con runtime deps reales: runed, tabbable, ogl, csstype, esm-env. runed/tabbable son razonables pero contradicen la doctrina enunciada; ogl (WebGL) es pesada y merece justificación explícita o aislamiento en el art que la use. Documentar la política real (p.ej. "cero deps en uix/*; arts pueden declarar deps justificadas") y alinear soma/README.

D5 · P3 — Volumen del corpus como riesgo estructural. El proyecto ya diagnosticó el patrón ("7 families sobrevivió en tres docs") y creó CANON.md. Esta auditoría encontró la misma clase de drift en 6 sitios más (D1–D4, S8, SO6). La regla "link, don't copy" existe pero no hay guard mecánico. Propuesta: docs:check — script que verifique invariantes copiables (conteos de vocabularios, nombres de campos de tipos citados en docs, deps citadas vs package.json) igual que translations:check hace con idlangrefs.


4. Ampliaciones recomendadas (no defectos)

  1. Slots semánticos V2 (GUIA §8.2): hoy una señal por target; las composiciones simultáneas del libro (shift.enter-mode + signal.alert + threat) no son expresables. Con S1/S2 resueltos, data-event-frame / data-event-signal es la evolución natural.
  2. Builder tipado para recipes CSS — el propio eidos/README lo anuncia ("cuando los recipes migren a un builder, el lint podrá retirarse"). Cerraría la última superficie de drift no tipada del sistema. Candidato: generar los selectores de estado desde compiled.contracts.cssSelectors como constantes exportadas por componente.
  3. Aplicación automática de SEMA_HOLDS_BY_INTENT — hoy la tabla canónica es "referencia" y cada morfo re-declara persistence a mano (decisión conservadora razonable en su día). Tras estabilizar, un opt-in holdsPolicy: 'canonical' en el engine evitaría la divergencia silenciosa entre tabla y morfos.
  4. Lint de intentGuidance — el eje doctrinal (discouraged en contact) se declaró "possible lint in the future"; morfo:vocabulary ya tiene el sitio natural.
  5. uix.perf + presupuesto de emit — medir el coste real de resolveSignature (structuredClone por rule) bajo handle-drag continuo; si aparece en LoAF, cachear la signature por (family,intent,channels-hash) cuando no hay cascade dinámica.
  6. Docs: guía de adopción incremental — comparison.md admite "more to learn"; falta el camino "usa solo soma headless sin sema/eidos" como tutorial de primera hora, que es como compiten Radix/Ark.

5. Incoherencias menores registradas (lista rápida)

  • EventEngineEmitter permite fakes sin clear/clearTarget → señales persistentes que "lingeran" en tests: documentado, OK, pero un fake-helper oficial evitaría 40 fakes ad-hoc.
  • partProps() devuelve {} para partes no registradas (silencioso) mientras part() lanza — asimetría de errores razonable pero no documentada.
  • resolveSignature acepta SemaMap | SemaResolveOptions con type-sniffing (isResolveOptions) — API histórica; unificar en options-only en la próxima major.
  • eidos README "Estado actual (2026-05-17)" está congelado (la lista de wrappers migrados es ~20; el catálogo real es 137 dirs) — sección fechada dentro de un doc atemporal, contradice docs/authoring.md.
  • MorfoElement es unión cerrada de ~45 tags: cada elemento nuevo (p.ej. dialog, canvas, picture) exige tocar el tipo; valorar (string & {}) escape con lint.

6. Valoración del framework frente a los existentes

Posicionamiento

El campo se divide en headless (Radix Primitives, Ark UI, bits-ui, React Aria) y styled systems (Mantine, Chakra, Radix Themes, shadcn). activeUIX mantiene la separación estricta de los headless y añade dos capas que nadie más tiene: un contrato declarativo por encima del comportamiento (morfo) y una capa de percepción por debajo de lo visual (sema). Esa lectura de comparison.md es honesta y esta auditoría la confirma contra el código.

Dónde gana (diferenciadores reales, verificados)

Dimensión activeUIX Mejor referencia Veredicto
Contrato estructural único (parts/ARIA/keyboard/events) morfo compilado + tipado literal nadie (disperso en provider+docs+CSS) Único. El rename-rompe-en-compile es real.
Capa perceptiva (familias/intents/verbos + sound/haptic/hold) sema + cascada CSS-like nadie Único. Fundamentado en un libro propio; con packs por componente.
Scope de tokens validado en generación TSC v2.2 (álgebra + colisiones cross-axis) Panda (parcial, build-time) Mejor de clase. Cierra un bug de CSS que los demás dejan al azar.
Motion de dos momentos (--event/--state) integrado con la firma perceptiva Chakra (solo data-state) Único en la integración.
Theme = retintar lo fijo (variants/roles canon) EIDOS_VARIANTS + 9 roles + lint Radix Themes (accents) Más portable; menos libre — trade-off deliberado y coherente.
Builders runtime (color APCA/OKLCH-P3, type, depth, shape, space desde 1 seed) applyTheme atómico Material You (color solo) Muy por delante de las libs de componentes.
Degradación (SSR / sin audio / sin DOM) contratos ejecutables por módulo React Aria (buena) Comparable o mejor, y además verificable (contracts.test).
a11y semántica por evento (live region / focus / reduced-motion fallback) declarada en morfo, honrada por runtime React Aria (imperativa) Enfoque más declarativo; con el matiz S5 a corregir.
Bundle (purged) 13.6 KB gz Tailwind 10 / Panda 12 Competitivo — sorprendente para lo que expresa.

Dónde pierde (costes honestos)

  1. Carga conceptual: 4 capas + 8 familias + 6 intents + verbos + archetypes + TSC + el vocabulario del libro. Radix se aprende en una tarde; esto exige leer un corpus. El glossary/getting-started mitigan, pero el precio existe y comparison.md lo admite.
  2. Ecosistema y battle-testing: un codebase, un autor-equipo, sin comunidad, sin años de issues cerrados. Los headless mainstream llevan ventaja de miles de apps en producción.
  3. Svelte 5 only: el morfo y sema son portables en teoría (TS puro + DOM), pero soma está casado con runes. Frente a Ark (universal via Zag) es una limitación de mercado.
  4. Promesas aún no forzadas: eventos declarados-no-emitidos (M1), regime muerto (S2), holds de referencia no aplicados — el framework vende "contrato = verdad" y en esos puntos todavía no lo es. Es exactamente el flanco que un evaluador externo atacaría.
  5. Coste de mantenimiento documental: el corpus (docenas de docs E0–E5 + READMEs por componente) drifta más rápido de lo que se barre (sección 3.5). Los frameworks de referencia tienen menos doctrina que mantener sincronizada.
  6. La capa sema solo paga si se usa: para un consumidor que quiere "widgets accesibles bonitos", el sistema entrega lo mismo que los demás con más conceptos por delante.

Veredicto

Como arquitectura de investigación aplicada (separar contrato / comportamiento / significado / materia visual), activeUIX está por delante de todo lo publicado: es la única implementación seria de una gramática perceptiva sobre componentes, y el TSC + morfo son contribuciones exportables por sí solas. Como producto adoptable hoy, está en alpha honesta: la ejecución de las 4 capas es de calidad alta (mejor de lo habitual en proyectos de esta ambición), pero la concurrencia perceptiva (S1–S4), el contrato de emisión (M1) y la higiene documental (D1–D2) tienen que cerrarse antes de que la promesa central — "el contrato no puede mentir" — sea cierta sin asteriscos.

Puntuaciones (escala honesta, no de marketing): originalidad 10 · arquitectura 9 · implementación 8 · testing/tooling 8.5 · docs (coherencia) 6.5 · a11y 8 (8.5 tras S5) · rendimiento 7.5 (E1, S9) · adoptabilidad externa 5 · madurez global 7.


7. Plan de acción priorizado

Fase 0 — Corrección (1–2 sesiones)

# Acción Cierra Verificación
0.1 Guard por data-event-id en DomSignalProjector.cleanup (unstamp solo si el id sigue siendo el propio) + test de solape (emit B durante hold de A) S1 test nuevo en projection/dom.test.ts + emit.test.ts
0.2 Precedencia a11y: reducedMotionFallback:'state' interseca (no cede ante) channels de morfo/opts S5 test en runtime.svelte.test
0.3 Warn de logger al pasar opts.semantic a evento no-polimórfico (cumplir el JSDoc) SO2 test
0.4 #renderSchemeCss: log del error + conservar bloque anterior en fallo de re-derive E3 test

Fase 1 — Contrato honesto (2–4 sesiones)

# Acción Cierra
1.1 Implementar emission: 'runtime' | 'declared-only' en MorfoEvent + lint FAIL cuando un evento sin emission no tiene trigger localizable; anotar los 5 pickers (o cablear sus triggers) M1, D.2 del LIBRO
1.2 Decisión sobre regime: implementar replace (mínimo viable: nueva señal sobre el mismo target cancela la anterior — resuelve S1 estructuralmente) y marcar mode/scope/resto de regimes como reserved en types S2, S1
1.3 Implementar coincident (emit no bloqueante) + lint 'pre'-con-handler S3, S4
1.4 Resolver doctrina handlers sync: no-await o actualizar regla escrita SO1
1.5 Subir expression a FAIL tras anotar los ~41 morfos restantes M2

Fase 2 — Barrido documental (1–2 sesiones, mecánico)

# Acción Cierra
2.1 translations: → texts: en morfo/README, SOMA_ARCHITECTURE, soma/README (ejemplos compilables) D1
2.2 Reconciliar GUIA_IMPLEMENTACION con código (dialog/emerge, holds, 9 roles, naming actual, shape polimórfico aditivo) o marcar §§ afectadas como superseded-by-CANON D2
2.3 Archetypes 24→26 en active_architecture + morfo/README; numeración única de la cascada sema en README/engine/CLAUDE.md; retirar @floating-ui/clsx de docs soma; limpiar JSDoc defaultSemantic D3, S8, SO6, SO3
2.4 Documentar política real de dependencias (uix cero-dep; arts justificadas: runed/tabbable/ogl) D4
2.5 Script docs:check para invariantes copiables (conteos de vocabulario, campos citados, deps citadas) D5

Fase 3 — Rendimiento y ergonomía (según demanda)

# Acción Cierra
3.1 Memoizar renderStaticCss; apply(scope?) por bloque; eliminar doble build en applyTheme E1
3.2 Mode-source de eidos vía ActiveDom (dom.prefersColorScheme análogo a prefersReducedMotion) E2
3.3 Tipar matcher state de semaSelector desde dataAttrsByPart M5
3.4 Contact base silencioso + packs opt-in de sonido S6
3.5 Schema check: stateRef+enum exige 2 valores M4
3.6 Limpieza: _resetCompileCache, aliases deprecados, formato stamp/durations, indentación runtime:667 M6, SO5, S9

Fase 4 — Ampliaciones estratégicas (backlog)

  • Slots semánticos V2 (data-event-frame/data-event-signal) — tras 1.2.
  • Builder tipado para recipes CSS → retirar eidos-lint.
  • holdsPolicy: 'canonical' opt-in en el engine.
  • Lint de intentGuidance en morfo:vocabulary.
  • Decisión capa 4 del token stack (deprecate si sigue sin consumers) + consumo real del bundle --size-* + primer caso scope:'event:*' en TSC.
  • Guía "adopción incremental: solo soma" para competir en onboarding con Radix/Ark.

Verificado al cierre: los hallazgos S1–S9, SO1–SO6, M1–M6, E1–E6 y D1–D5 se contrastaron contra el código fuente en la rama alpha-0.1-sec-dom a 2026-07-01. Los conteos (136 morfos, 82 con events, 41 con expression, 48 packs, 188 usos de semaSelector, 97 con texts, 0 con translations) provienen de grep directo. No se ejecutó la suite de tests en esta sesión; las cifras de tests citadas provienen de los hand-offs registrados.

Powered by TurnKey Linux.