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