libs/logger/test/diagnostics.test.ts no longer imports SILENT_LOGGER from the consuming `$logger` art -- it uses a local no-op Logger fixture (the art exports the identical shape). Removes one of the test-only layer inversions (SU2). The prefs half of SU2 (libs/prefs/test importing dimension constructors from $prefs) is left for a deliberate call: those constructors are pure (import only $libs/prefs + $libs/locale), so the root fix is relocating them to $libs/prefs with arts/prefs re-exporting -- an ~11-file move, disproportionate to force for a BAJA, not-a-build-violation item. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>active-uix
parent
0d66e5a4e7
commit
0b7757d027
@ -1,683 +0,0 @@
|
||||
# Codex full audit - arquitectura y framework
|
||||
|
||||
Fecha: 2026-05-27
|
||||
Repo: `G:\dev\svelte\vicen`
|
||||
Rama observada: `active-uix`
|
||||
|
||||
## Veredicto ejecutivo
|
||||
|
||||
La arquitectura principal esta bien orientada: `ActiveApp` compone servicios,
|
||||
`ActiveUix` actua como raiz UIX, `Morfo/Soma/Sema/Eidos` mantienen una
|
||||
separacion reconocible, y las reglas de alias/runes estan bastante alineadas.
|
||||
Hay buenas barreras: `arts` no importa `uix`, `active-uix` no importa Soma ni
|
||||
Eidos, Soma no importa Eidos, y `active-app`/`active-uix` pasan sus suites
|
||||
propias.
|
||||
|
||||
Pero el sistema no esta contractualmente sano todavia. El `npm test` global
|
||||
falla por `Words`, hay drift real entre docs y codigo, Morfo importa Sema
|
||||
aunque su README lo prohibe, algunos Eidos vuelven a exponer `Provider`
|
||||
publicamente, y el reporte de componentes declara 34/107 componentes como
|
||||
`NEEDS-WORK`. Ademas, la entrada documentada `$active-app/services` no coincide
|
||||
con el alias real ni con el codigo vivo, lo que hace que la documentacion de
|
||||
composicion sea peligrosa para consumidores.
|
||||
|
||||
## Alcance revisado
|
||||
|
||||
Documentacion y contratos revisados:
|
||||
|
||||
- `src/docs/GUIA_IMPLEMENTACION_SEMAUIX.md`
|
||||
- `src/docs/LIBRO_VARIACIONES_Y_EXTENSIONES.md`
|
||||
- `src/uix/active_architecture.md`
|
||||
- `src/uix/README.md`
|
||||
- `src/uix/active-uix/README.md`
|
||||
- `src/uix/morfo/README.md`
|
||||
- `src/uix/sema/README.md`
|
||||
- `src/uix/soma/README.md`
|
||||
- `src/uix/soma/SOMA_ARCHITECTURE.md`
|
||||
- `src/uix/soma/COMPONENT_GUIDE.md`
|
||||
- `src/uix/eidos/README.md`
|
||||
- `src/uix/eidos/components/README.md`
|
||||
- `web/routes/uix/lib/COMPONENT_AUDIT_GUIDE.md`
|
||||
- `web/routes/uix/lib/DEMO_AUTHORING_GUIDE.md`
|
||||
- README de `src/arts/*`, con foco especial en `src/arts/active-app`
|
||||
- README de `src/libs/*` y `src/svrs/*` relevantes
|
||||
- README de `Words` en Morfo/Soma/Sema/Eidos
|
||||
|
||||
Tambien se revisaron configs, import graph, tests y reportes generados.
|
||||
|
||||
## Comandos ejecutados
|
||||
|
||||
- `npm run test` - falla: 1 fichero fallido, 2 tests fallidos en
|
||||
`src/uix/contracts.test.ts`.
|
||||
- `npx vitest run src/uix/contracts.test.ts` - falla con las mismas 2
|
||||
violaciones.
|
||||
- `npx vitest run src/arts/active-app/test` - pasa: 8 ficheros, 54 tests.
|
||||
- `npx vitest run src/uix/active-uix/active-uix.svelte.test.ts` - pasa:
|
||||
1 fichero, 25 tests.
|
||||
- `npm run check` - exit 0, pero con 24 warnings Svelte y errores de carga de
|
||||
configs dentro de `tmp/lexical`.
|
||||
- `npm run build` - exit 0, pero conserva warnings de Svelte/Vite.
|
||||
- `npm run component:audit` - exit 0, 107 componentes: 73 PASS,
|
||||
34 NEEDS-WORK, 0 BROKEN.
|
||||
- `npm run translations:check` - exit 0: 218 refs, 76 catalogos,
|
||||
0 errors, 0 warnings.
|
||||
- `npm run morfo:vocabulary` - exit 0, pero 107 warnings de vocabulario y
|
||||
9 eventos con nombre no canonico.
|
||||
- Escaneos estaticos de imports entre `arts`, `active-app`, `active-uix`,
|
||||
`morfo`, `soma`, `sema` y `eidos`.
|
||||
|
||||
## Hallazgos P0
|
||||
|
||||
### P0-1 - La suite global falla por drift contractual de Words
|
||||
|
||||
Evidencia:
|
||||
|
||||
- `src/uix/contracts.test.ts:537` falla en
|
||||
`guards hardcoded Soma component data attrs with morfo contracts`.
|
||||
- `src/uix/contracts.test.ts:548` falla en
|
||||
`guards component translation namespaces as kebab-case`.
|
||||
- Atributos Soma no declarados en Morfo:
|
||||
- `src/uix/soma/components/words/engine/render.ts`:
|
||||
`data-words-find-match`, `data-words-find-active`, `data-words-indent`
|
||||
- `src/uix/soma/components/words/engine/serialize-html.ts`:
|
||||
`data-language`
|
||||
- `src/uix/soma/components/words/words-provider.svelte.ts`:
|
||||
`data-words-heading-picker`, `data-words-toolbar-family`,
|
||||
`data-words-toolbar-family-panel`, `data-words-code-language-picker`,
|
||||
`data-words-code-language-panel`
|
||||
- Claves i18n no kebab-case:
|
||||
- `components.words.bubbleMenu`
|
||||
- `components.words.slashMenu`
|
||||
- `components.words.linkEditor`
|
||||
- `components.words.findReplace`
|
||||
- Las rutas aparecen en `src/uix/morfo/components/words.ts:14-17`,
|
||||
`:390`, `:413`, `:476`, `:498`, y en
|
||||
`src/uix/soma/components/words/words-provider.svelte.ts:1715`,
|
||||
`:1804`, `:2075`, `:2178`.
|
||||
|
||||
Impacto:
|
||||
|
||||
Morfo deja de ser la fuente de verdad para el DOM y para las rutas de texto.
|
||||
Eso rompe el modelo declarado en `src/uix/README.md`: Morfo declara,
|
||||
Soma transcribe, Sema proyecta, Eidos lee. Tambien bloquea CI porque
|
||||
`npm run test` queda rojo.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
1. Declarar esos `data-*` en `src/uix/morfo/components/words.ts` si son parte
|
||||
publica estable, o retirarlos/renombrarlos en Soma si son internos.
|
||||
2. Normalizar las rutas i18n a kebab-case, por ejemplo
|
||||
`components.words.bubble-menu`, y sincronizar catalogos.
|
||||
3. Revisar el README de Words: hoy afirma que esas claves fueron normalizadas
|
||||
a camelCase, pero el contrato actual exige kebab-case.
|
||||
|
||||
## Hallazgos P1
|
||||
|
||||
### P1-1 - Morfo importa Sema aunque su contrato lo prohibe
|
||||
|
||||
Evidencia:
|
||||
|
||||
- `src/uix/morfo/README.md:824` dice que Morfo es TypeScript declarativo puro,
|
||||
sin imports de `$uix/sema`, `$adom` ni `$libs/reactive`.
|
||||
- Imports reales:
|
||||
- `src/uix/morfo/compile.ts:48-49` importa `../sema/durations` y
|
||||
`../sema/types`.
|
||||
- `src/uix/morfo/types.ts:39-41` importa `../sema/types`,
|
||||
`../sema/channels` y `../sema/durations`.
|
||||
- `src/uix/morfo/selectors.ts:34` importa `../sema/types`.
|
||||
- `src/uix/morfo/schema.ts:31-33` importa `$sium`.
|
||||
|
||||
Impacto:
|
||||
|
||||
La capa declarativa queda acoplada a la capa perceptiva. Si Sema cambia sus
|
||||
tipos/canales/duraciones, Morfo cambia con ella. Eso invierte parte del flujo
|
||||
arquitectonico: Morfo deberia declarar el lenguaje que Sema consume, no
|
||||
depender de Sema para poder describirlo.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Mover los tipos compartidos a un contrato neutro, por ejemplo
|
||||
`src/uix/contracts` o un submodulo `morfo/semantic-contracts.ts`. Sema puede
|
||||
implementar esos contratos, pero Morfo no deberia importar desde Sema.
|
||||
Revisar si `$sium` se acepta como validador puro o si el README debe afinar
|
||||
la regla.
|
||||
|
||||
### P1-2 - Eidos vuelve a exponer `Provider` publicamente en 6 componentes
|
||||
|
||||
Evidencia:
|
||||
|
||||
- `src/uix/eidos/components/README.md:21-27` prohibe
|
||||
`<X.Provider>` y `Provider` publico.
|
||||
- `src/uix/eidos/components/README.md:40` exige asignacion explicita,
|
||||
no `Object.assign`.
|
||||
- Violaciones:
|
||||
- `src/uix/eidos/components/announce/index.ts:12`
|
||||
- `src/uix/eidos/components/clipboard/index.ts:13`
|
||||
- `src/uix/eidos/components/feed/index.ts:19`
|
||||
- `src/uix/eidos/components/drag-drop/index.ts:15`
|
||||
- `src/uix/eidos/components/tree-grid/index.ts:53`
|
||||
- `src/uix/eidos/components/tree-view/index.ts:53`
|
||||
|
||||
Impacto:
|
||||
|
||||
La API publica vuelve a tener dos formas mentales: root visual y Provider.
|
||||
Eso contradice la "disciplined option C" y perpetua el split retirado
|
||||
`flat vs Provider compound`.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Eliminar `.Provider` de los namespaces publicos. El root visual debe ser el
|
||||
provider visual si corresponde, y las partes adjuntas deben ser solo las
|
||||
partes publicas esperadas (`Trigger`, `Content`, `Item`, etc.).
|
||||
|
||||
### P1-3 - La entrada documentada `$active-app/services` no coincide con el codigo
|
||||
|
||||
Evidencia:
|
||||
|
||||
- `src/arts/active-app/README.md:57` documenta `$active-app/services` como
|
||||
path de service factories.
|
||||
- `src/arts/active-app/index.ts:8` repite esa promesa.
|
||||
- `src/arts/active-app/README.md:106-107` dice que
|
||||
`service-factories/` se exporta desde `$active-app/services`.
|
||||
- Config real:
|
||||
- `svelte.config.js:19` y `vite.config.ts:13` solo definen
|
||||
`$active-app -> src/arts/active-app`.
|
||||
- Por tanto `$active-app/services` resuelve a
|
||||
`src/arts/active-app/services.ts`, que es el contrato de schema, no las
|
||||
fabricas.
|
||||
- Codigo vivo:
|
||||
- `src/uix/active-uix/services.ts:24` importa desde
|
||||
`$active-app/service-factories`.
|
||||
- `src/arts/README.md:148` tambien usa `$active-app/service-factories`.
|
||||
- Prueba directa:
|
||||
- Importar `defineActiveLangs` desde `./src/arts/active-app/services.ts`
|
||||
lanza `SyntaxError: ... does not provide an export named
|
||||
'defineActiveLangs'`.
|
||||
|
||||
Impacto:
|
||||
|
||||
La documentacion guia al consumidor a un import path que no funciona. Es una
|
||||
violacion fuerte de API publica, aunque no rompe build porque muchos ejemplos
|
||||
estan dentro de strings de documentacion.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Elegir una sola direccion:
|
||||
|
||||
- O se corrige toda la doc a `$active-app/service-factories`.
|
||||
- O se crea un alias real y estable `$active-app/services` hacia
|
||||
`src/arts/active-app/service-factories`, y se mueve el contrato actual
|
||||
`services.ts` a otro nombre (`schema.ts`, `contracts.ts`, etc.).
|
||||
|
||||
Despues, anadir un test que compile los snippets publicos o al menos valide
|
||||
los import paths documentados.
|
||||
|
||||
### P1-4 - 34 de 107 componentes quedan en NEEDS-WORK
|
||||
|
||||
Evidencia:
|
||||
|
||||
`npm run component:audit` genero `tmp/component-audit.md`:
|
||||
|
||||
- Total: 107 componentes.
|
||||
- PASS: 73.
|
||||
- NEEDS-WORK: 34.
|
||||
- BROKEN: 0.
|
||||
|
||||
Componentes `NEEDS-WORK`:
|
||||
|
||||
`alert-dialog`, `announce`, `avatar-group`, `badge`, `button`, `card`,
|
||||
`clipboard`, `command`, `drag-drop`, `feed`, `format-date`, `format-number`,
|
||||
`grid-list`, `image`, `link-preview`, `listbox`, `menubar`,
|
||||
`navigation-menu`, `password-field`, `range-calendar`, `relative-time`,
|
||||
`s-text`, `s-text-virtual-list`, `search-field`, `skeleton`, `spinner`,
|
||||
`table`, `textarea`, `time-range-field`, `trans`, `tree-grid`, `tree-view`,
|
||||
`virtual-grid`, `virtual-list`.
|
||||
|
||||
Ejemplos de errores:
|
||||
|
||||
- `alert-dialog`: falta selector root `[data-alert-dialog]`.
|
||||
- Muchos Eidos: falta `README.md`.
|
||||
- Varios interactivos: falta `:focus-visible`.
|
||||
- Varias demos: falta `somaSnippet`.
|
||||
- `table`, `textarea`, `tree-grid`: referencias a `--color-*` no declaradas.
|
||||
- Interactivos sin URL APG declarada.
|
||||
|
||||
Impacto:
|
||||
|
||||
El framework no esta en estado de completitud auditada. La auditoria automatica
|
||||
no marca `BROKEN`, pero `NEEDS-WORK` en 34 componentes es suficiente para
|
||||
considerar incompleta la implementacion de la arquitectura de componentes.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Convertir el reporte en backlog cerrado por severidad: primero selectores
|
||||
root/contrato DOM, luego foco/a11y, luego snippets/demo, luego READMEs. Si el
|
||||
estado esperado del repo es "todo auditado", hacer que `component:audit` falle
|
||||
cuando haya `NEEDS-WORK`.
|
||||
|
||||
### P1-5 - Drift doctrinal entre docs: 7 familias vs 8 familias Sema
|
||||
|
||||
Evidencia:
|
||||
|
||||
- `src/docs/GUIA_IMPLEMENTACION_SEMAUIX.md:15`: "7 familias. Sin
|
||||
excepciones."
|
||||
- `src/uix/active_architecture.md:329`: enumera 7 familias.
|
||||
- `src/docs/LIBRO_VARIACIONES_Y_EXTENSIONES.md:673`: dice 8 familias,
|
||||
incluyendo `delegate`.
|
||||
- `src/uix/sema/README.md:576` y `:636-638` documentan `delegate`.
|
||||
|
||||
Impacto:
|
||||
|
||||
Los autores de componentes no tienen una fuente unica para saber si
|
||||
`delegate` es canonico o extension experimental. Esto afecta Morfo,
|
||||
validadores, `morfo:vocabulary`, packs Sema y naming de eventos.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Consolidar la doctrina: si `delegate` es vigente, actualizar la guia base y
|
||||
`active_architecture`. Si es extension, marcarlo como extension con gating y
|
||||
validacion explicita.
|
||||
|
||||
### P1-6 - `npm run check` sale verde con ruido que deberia limpiarse
|
||||
|
||||
Evidencia:
|
||||
|
||||
`npm run check` devuelve exit 0, pero reporta:
|
||||
|
||||
- 24 warnings Svelte en 7 ficheros.
|
||||
- Warnings a11y por elementos con handlers de puntero sin rol.
|
||||
- Variables enlazadas que se actualizan sin `$state(...)`.
|
||||
- `href="#"` invalido en demo de `navigation-menu`.
|
||||
- `table` demo captura solo valores iniciales de `selectionMode` y
|
||||
`multiSort`.
|
||||
- `trans` demo tiene cierre implicito de `<span>`.
|
||||
- Errores de carga de config dentro de `tmp/lexical` por dependencias no
|
||||
instaladas (`svelte-preprocess`, `@sveltejs/adapter-auto`).
|
||||
|
||||
Impacto:
|
||||
|
||||
La senal de `check` queda degradada: el comando dice "0 errors", pero imprime
|
||||
errores de carga externos y warnings que apuntan a bugs reales de demo.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Mover `tmp/lexical` fuera del workspace escaneado o configurar exclusion real
|
||||
para svelte-check. Corregir warnings de rutas UIX y demos. Para CI, definir si
|
||||
warnings Svelte deben fallar.
|
||||
|
||||
### P1-7 - Documentacion de estado obsoleta en `active_architecture`
|
||||
|
||||
Evidencia:
|
||||
|
||||
`src/uix/active_architecture.md` contiene un "Estado actual (2026-05-17)" que
|
||||
presenta partes como pendientes o cerradas con conteos historicos, mientras
|
||||
`src/docs/LIBRO_VARIACIONES_Y_EXTENSIONES.md` documenta cambios posteriores
|
||||
del 2026-05-27: persistencia, `a11ySemantic`, familias permitidas y patrones
|
||||
polimorficos.
|
||||
|
||||
Impacto:
|
||||
|
||||
El documento que deberia orientar la arquitectura activa mezcla estado antiguo
|
||||
con reglas vigentes. Esto multiplica decisiones contradictorias en capas
|
||||
sensibles como Sema y Eidos.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Separar "historial" de "contrato vigente". El contrato vigente debe decir en
|
||||
una pagina corta que docs son canonicos y cuales son libro/historia.
|
||||
|
||||
## Hallazgos P2
|
||||
|
||||
### P2-1 - `morfo:vocabulary` produce demasiado warning estructural
|
||||
|
||||
Evidencia:
|
||||
|
||||
`npm run morfo:vocabulary` reporta:
|
||||
|
||||
- 107 warnings de enums `data-*` divergentes.
|
||||
- 9 eventos de `words` que no siguen la forma `{family}-{verb}[-{variant}]`:
|
||||
`words.commit-content`, `words.commit-format`, `words.commit-link`,
|
||||
`words.commit-unlink`, `words.commit-slash-command`, `words.commit-check`,
|
||||
`words.commit-history`, `words.commit-clear`,
|
||||
`words.signal-invalid-input`.
|
||||
|
||||
Impacto:
|
||||
|
||||
El comando no distingue bien entre vocabularios legitimamente nuevos y drift
|
||||
real. Al ser solo warning, se acumula ruido y el contrato pierde capacidad de
|
||||
bloquear regresiones.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Promover vocabularios recurrentes a `CANONICAL_VOCABULARIES` o marcarlos como
|
||||
extension aceptada con razon. Separar warnings esperados de violaciones reales.
|
||||
|
||||
### P2-2 - `arts` tiene excepciones de dependencia que contradicen la regla amplia
|
||||
|
||||
Evidencia de import graph productivo entre artes, excluyendo `active-app`:
|
||||
|
||||
- `src/arts/auth/client.ts -> $http`
|
||||
- `src/arts/bus/engine-bus.ts -> $logger`
|
||||
- `src/arts/perm/types.ts -> $http`
|
||||
- `src/arts/prefs/dom-projection.ts -> $adom`
|
||||
- `src/arts/session/bus-helpers.ts -> $bus`
|
||||
- `src/arts/session/http-integration.ts -> $http`
|
||||
- `src/arts/session/types.ts -> $storage`
|
||||
- `src/arts/sium/engine-resolver.ts -> $langs`
|
||||
- `src/arts/sium/engine-sium.ts -> $langs`
|
||||
|
||||
Muchas estan documentadas y parecen intencionales. El problema es que
|
||||
`src/arts/active-app/README.md` formula una regla mas dura: los arts no deben
|
||||
conocer sibling arts; ese conocimiento pertenece a `active-app`.
|
||||
|
||||
Impacto:
|
||||
|
||||
La arquitectura real ya tiene una lista de excepciones. Si no se formalizan,
|
||||
las futuras dependencias cruzadas se justificaran por precedente.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Crear una matriz permitida de dependencias entre arts. Diferenciar:
|
||||
|
||||
- Contratos puros aceptados (`$libs/*`).
|
||||
- Infraestructuras core aceptadas (`$logger`, `$bus`, `$timer`).
|
||||
- Bridges opcionales aceptados (`prefs/dom-projection -> adom`).
|
||||
- Dependencias prohibidas.
|
||||
|
||||
### P2-3 - `active-app/service-builder.ts` importa Svelte en un `.ts`
|
||||
|
||||
Evidencia:
|
||||
|
||||
`src/arts/active-app/service-builder.ts` importa `untrack` desde `svelte`.
|
||||
El comentario explica que se usa para construir lazy services dentro de scopes
|
||||
reactivos sin capturar mutaciones.
|
||||
|
||||
Impacto:
|
||||
|
||||
Probablemente es una decision practica correcta, pero hace que el core builder
|
||||
de `active-app` tenga dependencia Svelte aunque no sea `.svelte.ts`. Si la meta
|
||||
es que solo `Active*` reactivos carguen Svelte, esto debe documentarse como
|
||||
excepcion.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Mantener si es necesario, pero documentarlo en `active-app` como parte del
|
||||
contrato del builder. Alternativa: aislar el `untrack` en un adaptador Svelte
|
||||
inyectable si se quiere preservar un builder completamente puro.
|
||||
|
||||
### P2-4 - `src/arts/README.md` promete `sideEffects`, pero `package.json` no lo tiene
|
||||
|
||||
Evidencia:
|
||||
|
||||
- `src/arts/README.md:267` dice que `package.json` declara
|
||||
`"sideEffects": ["**/*.css", "**/*.svelte"]`.
|
||||
- `package.json` no contiene `sideEffects`.
|
||||
|
||||
Impacto:
|
||||
|
||||
La politica de tree-shaking y preservacion de CSS/Svelte no esta codificada.
|
||||
En un paquete privado puede no doler hoy, pero contradice el documento de
|
||||
bundle policy.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Anadir el campo si la politica sigue vigente, o retirar/ajustar la regla del
|
||||
README.
|
||||
|
||||
### P2-5 - Documentacion stale en `format/currency`
|
||||
|
||||
Evidencia:
|
||||
|
||||
`src/arts/format/currency/README.md` usa `$formats/currency` y describe
|
||||
`src/arts/formats/currency/`, pero el alias real es `$format` y la ruta real
|
||||
es `src/arts/format/currency`.
|
||||
|
||||
Impacto:
|
||||
|
||||
Consumidores que copien esos snippets importaran desde un alias inexistente.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Corregir el README y anadir un chequeo simple de aliases en snippets de
|
||||
documentacion publica.
|
||||
|
||||
### P2-6 - Build pasa, pero hay senales de bundle/ruido a vigilar
|
||||
|
||||
Evidencia:
|
||||
|
||||
`npm run build` pasa, pero:
|
||||
|
||||
- Repite warnings de Svelte/Vite ya vistos en `check`.
|
||||
- Un asset CSS de cliente aparece alrededor de 824 kB sin gzip.
|
||||
- Rollup avisa que un comentario `/* @__PURE__ */` en
|
||||
`src/uix/soma/components/command/command-provider.svelte.ts` esta en una
|
||||
posicion que no puede interpretar y sera removido.
|
||||
|
||||
Impacto:
|
||||
|
||||
No bloquea, pero indica que el build no esta limpio y que faltan budgets o
|
||||
umbrales para assets grandes.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Registrar budgets de bundle y limpiar warnings del build. Revisar el origen
|
||||
del CSS grande y el comentario pure en `command-provider`.
|
||||
|
||||
### P2-7 - Demos UIX contienen bugs de reactividad/a11y
|
||||
|
||||
Evidencia:
|
||||
|
||||
`npm run check` y `npm run build` reportan:
|
||||
|
||||
- `web/routes/uix/components/navigation-menu/+page.svelte`: enlaces
|
||||
`href="#"`.
|
||||
- `web/routes/uix/components/table/+page.svelte:104`: `selectionMode` y
|
||||
`multiSort` capturados solo al inicializar.
|
||||
- `web/routes/uix/components/trans/+page.svelte:375`: cierre implicito de
|
||||
`span`.
|
||||
- Rutas de demo genericas en `web/routes/demos/*.svelte`: handlers de puntero
|
||||
sin rol y refs no reactivas.
|
||||
|
||||
Impacto:
|
||||
|
||||
Aunque sean demos, son la superficie de validacion del framework. Bugs ahi
|
||||
pueden ocultar errores del componente o ensenar patrones incorrectos.
|
||||
|
||||
Recomendacion:
|
||||
|
||||
Limpiar las demos antes de usarlas como material de contrato o referencia.
|
||||
|
||||
## Hallazgos P3
|
||||
|
||||
### P3-1 - Muchos README de Eidos faltan por componente
|
||||
|
||||
El reporte de componentes y el inventario indican que varios directorios
|
||||
Eidos no tienen `README.md`: `announce`, `badge`, `button`, `card`,
|
||||
`clipboard`, `command`, `drag-drop`, `feed`, `grid-list`, `image`,
|
||||
`link-preview`, `listbox`, `menubar`, `navigation-menu`, `password-field`,
|
||||
`range-calendar`, `s-text`, `s-text-virtual-list`, `skeleton`, `spinner`,
|
||||
`table`, `textarea`, `time-range-field`, `tree-grid`, `tree-view`,
|
||||
`virtual-grid`, `virtual-list`, entre otros.
|
||||
|
||||
Impacto:
|
||||
|
||||
Reduce trazabilidad por modulo, especialmente porque el usuario pidio auditar
|
||||
README por modulo y porque la guia de componente exige documentar contrato,
|
||||
comparativa y decisiones.
|
||||
|
||||
### P3-2 - AGENTS.md esta parcialmente viejo frente a aliases actuales
|
||||
|
||||
AGENTS.md menciona alias historicos (`@/ling`, `@/logr`, `@/glob`, `@/actx`)
|
||||
como criticos, pero los configs actuales exponen sobre todo aliases de
|
||||
`arts`, `libs`, `svrs` y `uix`. La instruccion general de mantener
|
||||
`svelte.config.js` y `vite.config.ts` sincronizados si se cumple; lo viejo es
|
||||
el inventario concreto.
|
||||
|
||||
Impacto:
|
||||
|
||||
Bajo para runtime, medio para agentes/humanos que usen AGENTS.md como mapa.
|
||||
|
||||
## Evaluacion por capas
|
||||
|
||||
### ActiveApp
|
||||
|
||||
Estado general: solido como composition root, con una deuda de API docs.
|
||||
|
||||
Lo que esta bien:
|
||||
|
||||
- Core: `logger`, `bus`, `timers`, `orca`, `prefs`.
|
||||
- Servicios opt-in con schema y topological builder.
|
||||
- Presets de orca separados.
|
||||
- Dispose en orden razonable.
|
||||
- Suite propia verde: 54 tests.
|
||||
|
||||
Riesgos:
|
||||
|
||||
- Path publico de service factories documentado como `$active-app/services`,
|
||||
pero codigo real usa `$active-app/service-factories`.
|
||||
- `service-builder.ts` depende de `svelte/untrack`; probablemente justificado,
|
||||
pero debe declararse como excepcion de core.
|
||||
- La regla "arts no conocen siblings" necesita matriz de excepciones.
|
||||
|
||||
### ActiveUix
|
||||
|
||||
Estado general: bueno y alineado con la intencion de asentarse sobre
|
||||
`ActiveApp`.
|
||||
|
||||
Lo que esta bien:
|
||||
|
||||
- `createActiveUix(...)` standalone compone servicios locales.
|
||||
- `attachActiveUix(app)` exige `langs` y `dom` y no compensa servicios
|
||||
faltantes.
|
||||
- No importa Soma ni Eidos.
|
||||
- `defineUixServices(...)` crea la slice de servicios necesaria para
|
||||
`ActiveApp`.
|
||||
- Suite propia verde: 25 tests.
|
||||
|
||||
Riesgos:
|
||||
|
||||
- Depende del problema de naming de service factories en `active-app`.
|
||||
- El contrato de `events` esta bien nombrado, pero la doctrina Sema aun esta
|
||||
en drift.
|
||||
|
||||
### Arts
|
||||
|
||||
Estado general: arquitectura razonable, con excepciones de dependencia que
|
||||
necesitan formalizacion.
|
||||
|
||||
Lo que esta bien:
|
||||
|
||||
- Import graph: `arts -> uix` es 0.
|
||||
- Muchos modulos separan engine puro y active wrapper.
|
||||
- `auth/session/perm/cache/http/storage` tienen docs de seguridad bastante
|
||||
claras.
|
||||
- `active-app` centraliza presets y composicion.
|
||||
|
||||
Riesgos:
|
||||
|
||||
- Algunas dependencias sibling son utiles pero no estan expresadas como matriz
|
||||
permitida.
|
||||
- Bundle policy de `sideEffects` no esta codificada.
|
||||
- `format/currency` README tiene alias/ruta vieja.
|
||||
|
||||
### Morfo
|
||||
|
||||
Estado general: el concepto es correcto, la implementacion viola la pureza.
|
||||
|
||||
Lo que esta bien:
|
||||
|
||||
- Define contratos DOM/eventos/partes con bastante cobertura.
|
||||
- `translations:check` esta verde.
|
||||
- `semaSelector` existe y los packs Sema lo usan en general.
|
||||
|
||||
Riesgos:
|
||||
|
||||
- Importa tipos de Sema y `$sium`.
|
||||
- `Words` tiene drift actual contra los tests de contrato.
|
||||
- `morfo:vocabulary` produce demasiado ruido para ser una barrera fuerte.
|
||||
|
||||
### Soma
|
||||
|
||||
Estado general: el headless runtime mantiene buena separacion de Eidos, pero
|
||||
Words se salio del contrato Morfo.
|
||||
|
||||
Lo que esta bien:
|
||||
|
||||
- No se detecto import de Eidos desde Soma.
|
||||
- No se detecto import directo de `$libs/dom` desde Soma/Eidos; se usa `$adom`.
|
||||
- Los tests globales pasan en casi todo salvo el contrato de Words.
|
||||
|
||||
Riesgos:
|
||||
|
||||
- Hardcoded `data-*` en Words no declarados en Morfo.
|
||||
- Warnings en demos de Table apuntan a reactividad incorrecta.
|
||||
|
||||
### Sema
|
||||
|
||||
Estado general: potente, pero la doctrina no esta consolidada.
|
||||
|
||||
Lo que esta bien:
|
||||
|
||||
- Packs usan `semaSelector` en vez de selectores inventados.
|
||||
- Visual/Sound/Haptic estan modelados como canales.
|
||||
- `defineEngineSemantic` encaja con `ActiveUix.events`.
|
||||
|
||||
Riesgos:
|
||||
|
||||
- 7 vs 8 familias no resuelto.
|
||||
- Warnings de nombres de eventos `Words`.
|
||||
- Morfo depende de Sema para tipos.
|
||||
|
||||
### Eidos
|
||||
|
||||
Estado general: wrapper visual bien encaminado, pero con regresiones en API y
|
||||
completitud.
|
||||
|
||||
Lo que esta bien:
|
||||
|
||||
- No se detecto `Object.assign`.
|
||||
- No se detecto Eidos components importando `ActiveUix` directamente.
|
||||
- `ActiveEidos` separa tema/modo/densidad de `prefs`.
|
||||
|
||||
Riesgos:
|
||||
|
||||
- 6 componentes exponen `.Provider`.
|
||||
- 34 componentes NEEDS-WORK afectan Eidos/demos/contratos.
|
||||
- Muchos README por componente faltan.
|
||||
|
||||
## Checks positivos importantes
|
||||
|
||||
- `svelte.config.js` y `vite.config.ts` tienen aliases sincronizados.
|
||||
- Runes mode esta forzado por `dynamicCompileOptions`.
|
||||
- `npm run build` pasa.
|
||||
- `npm run check` no reporta errores TypeScript/Svelte fatales.
|
||||
- `translations:check` pasa sin warnings.
|
||||
- `active-app` y `active-uix` pasan tests focalizados.
|
||||
- No hay `arts -> uix`.
|
||||
- No se encontro `Soma -> Eidos`.
|
||||
- No se encontro `Eidos components -> ActiveUix`.
|
||||
- No se encontro `ActiveUix -> Soma/Eidos`.
|
||||
- No se encontro `$libs/dom` directo desde Soma/Eidos.
|
||||
|
||||
## Orden recomendado de reparacion
|
||||
|
||||
1. Corregir `Words` hasta que `src/uix/contracts.test.ts` pase.
|
||||
2. Resolver el path publico de service factories de `active-app`.
|
||||
3. Sacar imports de Sema desde Morfo.
|
||||
4. Eliminar `.Provider` publico en Eidos.
|
||||
5. Cerrar los 34 `NEEDS-WORK` del component audit por prioridad.
|
||||
6. Consolidar docs canonicas: familias Sema, estado actual, Words i18n,
|
||||
`active-app` service path.
|
||||
7. Limpiar `npm run check` y `npm run build` de warnings conocidos.
|
||||
8. Formalizar matriz de dependencias permitidas entre `arts`.
|
||||
9. Codificar `sideEffects` o retirar esa politica del README.
|
||||
10. Anadir tests de snippets/import paths publicos para que la doc no pueda
|
||||
prometer alias rotos.
|
||||
|
||||
## Cierre
|
||||
|
||||
La arquitectura no necesita una reescritura: necesita cerrar contratos. Las
|
||||
piezas principales estan bien ubicadas, pero ahora mismo los tests y la
|
||||
documentacion muestran que algunas capas estan adelantandose unas a otras.
|
||||
El mayor riesgo no es que falte funcionalidad; es que el contrato escrito,
|
||||
el contrato testeado y el codigo runtime no siempre son el mismo contrato.
|
||||
@ -0,0 +1,188 @@
|
||||
<script>
|
||||
/**
|
||||
* ScrollFrames — secuencia de imágenes sincronizada con el scroll.
|
||||
*
|
||||
* Técnica: un contenedor alto ("track") con un hijo `position: sticky` que
|
||||
* permanece fijo en pantalla mientras se recorre el track. El progreso del
|
||||
* scroll dentro del track (0 → 1) se mapea a un índice de fotograma, y ese
|
||||
* fotograma se dibuja en un <canvas> (sin parpadeos, fluido).
|
||||
*
|
||||
* Props:
|
||||
* - frames: string[] URLs de los fotogramas, EN ORDEN. (obligatorio)
|
||||
* - height: string Altura del track. Más alto = giro más lento. (def "300vh")
|
||||
* - background: string Color de fondo del canvas. (def "transparent")
|
||||
* - class: string Clases extra para el track.
|
||||
*/
|
||||
let {
|
||||
frames,
|
||||
height = '300vh',
|
||||
background = 'transparent',
|
||||
class: className = ''
|
||||
} = $props();
|
||||
|
||||
// --- Estado reactivo (runas) ---
|
||||
let track = $state(null); // contenedor alto (define el recorrido)
|
||||
let canvas = $state(null); // lienzo donde se pinta el fotograma
|
||||
let progress = $state(0); // 0..1 según el scroll dentro del track
|
||||
let loaded = $state(0); // nº de imágenes ya precargadas
|
||||
let size = $state({ w: 0, h: 0 }); // tamaño del canvas en píxeles de dispositivo
|
||||
|
||||
let images = []; // objetos Image (no necesita ser reactivo)
|
||||
|
||||
// Índice de fotograma derivado del progreso. round() reparte cada frame
|
||||
// en una "franja" de scroll de igual tamaño.
|
||||
const frameIndex = $derived(
|
||||
frames.length
|
||||
? Math.min(
|
||||
frames.length - 1,
|
||||
Math.max(0, Math.round(progress * (frames.length - 1)))
|
||||
)
|
||||
: 0
|
||||
);
|
||||
|
||||
// --- 1) Precarga de todas las imágenes ---
|
||||
$effect(() => {
|
||||
let cancelled = false;
|
||||
loaded = 0;
|
||||
images = frames.map((src) => {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
if (!cancelled) loaded += 1; // dispara un redibujado al cargar
|
||||
};
|
||||
img.src = src;
|
||||
return img;
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
});
|
||||
|
||||
// --- 2) Cálculo del progreso al hacer scroll (throttle con rAF) ---
|
||||
$effect(() => {
|
||||
const el = track;
|
||||
if (!el) return;
|
||||
|
||||
let ticking = false;
|
||||
|
||||
function compute() {
|
||||
ticking = false;
|
||||
const rect = el.getBoundingClientRect();
|
||||
const vh = window.innerHeight;
|
||||
const distancia = rect.height - vh; // recorrido útil mientras está sticky
|
||||
const recorrido = -rect.top; // cuánto hemos avanzado dentro del track
|
||||
progress =
|
||||
distancia > 0
|
||||
? Math.min(1, Math.max(0, recorrido / distancia))
|
||||
: 0;
|
||||
}
|
||||
|
||||
function onScroll() {
|
||||
if (!ticking) {
|
||||
ticking = true;
|
||||
requestAnimationFrame(compute);
|
||||
}
|
||||
}
|
||||
|
||||
compute();
|
||||
window.addEventListener('scroll', onScroll, { passive: true });
|
||||
window.addEventListener('resize', onScroll);
|
||||
return () => {
|
||||
window.removeEventListener('scroll', onScroll);
|
||||
window.removeEventListener('resize', onScroll);
|
||||
};
|
||||
});
|
||||
|
||||
// --- 3) Ajuste del canvas al tamaño real (nitidez en pantallas HiDPI) ---
|
||||
$effect(() => {
|
||||
const c = canvas;
|
||||
if (!c) return;
|
||||
|
||||
function resize() {
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const w = Math.round(c.clientWidth * dpr);
|
||||
const h = Math.round(c.clientHeight * dpr);
|
||||
c.width = w;
|
||||
c.height = h;
|
||||
size = { w, h }; // dispara redibujado
|
||||
}
|
||||
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
return () => window.removeEventListener('resize', resize);
|
||||
});
|
||||
|
||||
// --- 4) Dibujar el fotograma actual (cover) ---
|
||||
$effect(() => {
|
||||
// Dependencias reactivas que fuerzan el redibujado:
|
||||
frameIndex;
|
||||
size;
|
||||
loaded;
|
||||
|
||||
const c = canvas;
|
||||
const img = images[frameIndex];
|
||||
if (!c || !img || !img.complete || !img.naturalWidth) return;
|
||||
|
||||
const ctx = c.getContext('2d');
|
||||
const { width: cw, height: ch } = c;
|
||||
const ir = img.naturalWidth / img.naturalHeight;
|
||||
const cr = cw / ch;
|
||||
|
||||
let dw, dh, dx, dy;
|
||||
if (ir > cr) {
|
||||
dh = ch;
|
||||
dw = ch * ir;
|
||||
dx = (cw - dw) / 2;
|
||||
dy = 0;
|
||||
} else {
|
||||
dw = cw;
|
||||
dh = cw / ir;
|
||||
dx = 0;
|
||||
dy = (ch - dh) / 2;
|
||||
}
|
||||
|
||||
ctx.clearRect(0, 0, cw, ch);
|
||||
ctx.drawImage(img, dx, dy, dw, dh);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="sfs-track {className}" bind:this={track} style:height>
|
||||
<div class="sfs-sticky">
|
||||
<canvas
|
||||
class="sfs-canvas"
|
||||
bind:this={canvas}
|
||||
style:background
|
||||
aria-hidden="true"
|
||||
></canvas>
|
||||
|
||||
{#if frames.length && loaded < frames.length}
|
||||
<div class="sfs-loader">{Math.round((loaded / frames.length) * 100)}%</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sfs-track {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.sfs-sticky {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
.sfs-canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
.sfs-loader {
|
||||
position: absolute;
|
||||
bottom: 1.5rem;
|
||||
font: 0.75rem/1 system-ui, sans-serif;
|
||||
letter-spacing: 0.1em;
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in new issue