parent
26166b9e3c
commit
0a014ed9e5
@ -1,362 +0,0 @@
|
|||||||
# Auditoria Arquitectonica UIX — Kimi (2026-05-12)
|
|
||||||
|
|
||||||
## Alcance
|
|
||||||
|
|
||||||
Auditoria de las capas ActiveUix, Morfo, Soma, Sema y Eidos.
|
|
||||||
NO se analizaron los componentes internos de Soma ni Eidos.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Estado Codex 2026-05-14
|
|
||||||
|
|
||||||
Esta auditoria queda parcialmente cerrada por fases en la rama `active-uix`:
|
|
||||||
|
|
||||||
- `ActiveUix` ya no expone ni crea `Eidos`; `ActiveEidos` se crea aparte.
|
|
||||||
- `ActiveEidos` no crea `ActiveDom` propio y falla si necesita DOM real y no
|
|
||||||
se le entrega una superficie valida.
|
|
||||||
- `Provider` abstract class fue eliminada; queda solo el contrato de opciones.
|
|
||||||
- `Morfo.langs` se renombro a `Morfo.translations`.
|
|
||||||
- `VisualChannel` posee la proyeccion `data-event-*`; `EngineSemantic` solo
|
|
||||||
orquesta prepare/handle/cleanup de canales.
|
|
||||||
- `Sema` ya no transporta `motion`, `color` ni `presence` en el mapa canonico.
|
|
||||||
- `SoundChannel` no registra listeners globales en el constructor.
|
|
||||||
- `ActivePrefsDomProjection` escribe `dir`, `data-motion`, `data-sound` y
|
|
||||||
`data-haptic`; `ActiveEidos` escribe `data-theme`, `data-mode` y
|
|
||||||
`data-density`.
|
|
||||||
- La proyeccion cross-modal no vive en `ActiveUix`: existe como
|
|
||||||
`createActivePrefsDomProjection(...)` en `arts/prefs` y debe cablearla el
|
|
||||||
composition root que quiera esos attrs globales.
|
|
||||||
- La ruta `/uix` ya sigue el contrato final: no escribe `prefs.theme`; usa
|
|
||||||
`createActivePrefsDomProjection(...)` para `dir/motion/sound/haptic` y
|
|
||||||
`ActiveEidos.create({ theme:'base', modeSource, applyDom:true })` para
|
|
||||||
`data-theme`, `data-mode` y `data-density`.
|
|
||||||
- La auditoria DOM P1 queda documentada en `src/uix/dom_audit.md`.
|
|
||||||
|
|
||||||
Pendiente vivo: terminar la generacion/retirada de CSS legacy de Eidos.
|
|
||||||
`createAttrs` queda como selector helper, `registerContract` ya no se usa desde
|
|
||||||
Soma, y `arts/frontend` queda como servicio legacy opt-in fuera del boot UIX.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Errores arquitectonicos criticos
|
|
||||||
|
|
||||||
### 1.1. Sema viola su propia frontera: conoce DOM y concerns visuales
|
|
||||||
|
|
||||||
**Archivo:** `src/uix/sema/engine.ts` (lineas 113, 202, 232)
|
|
||||||
|
|
||||||
**Problema:** `EngineSemantic` crea un `DomSignalProjector` por defecto y es el quien escribe
|
|
||||||
`data-event-*` en el DOM durante `emit`. La doctrina dice que Sema es "registry + dispatch"
|
|
||||||
y que `VisualChannel` materializa la senal, pero en el codigo el engine proyecta **antes**
|
|
||||||
de llamar a los canales. El `VisualChannel` solo hace `sleep(hold)`; no controla la proyeccion.
|
|
||||||
|
|
||||||
**Impacto:** El canal visual no es autonomo. El engine esta acoplado a la idea de "escribir en el DOM",
|
|
||||||
lo que rompe la regla _Sema no conoce DOM_.
|
|
||||||
|
|
||||||
**Fix propuesto:** Mover `projector.project()` y `handle.cleanup()` dentro de `VisualChannel.handle()`.
|
|
||||||
El engine solo despacha la senal; el canal visual gestiona su propio plano DOM.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 1.2. Acoplamiento historico de Eidos/Semantic en `ActiveUix`
|
|
||||||
|
|
||||||
**Estado 2026-05-13:** resuelto por retirada de ambos acoplamientos. `ActiveUix`
|
|
||||||
ya no expone `eidos` ni el alias `semantic`; el motor perceptivo se expone como
|
|
||||||
`events?: EngineSemantic` y `ActiveEidos.create(...)` crea el scope visual.
|
|
||||||
`ActiveEidos` solo es necesario para CSS runtime o authoring de configuracion.
|
|
||||||
|
|
||||||
**Archivo:** `src/uix/active-uix/types.ts` (linea 115), `src/uix/active-uix/active-uix.svelte.ts` (lineas 419-425)
|
|
||||||
|
|
||||||
**Problema historico:** En `types.ts`, `semantic: EngineSemantic | undefined`
|
|
||||||
(opcional), pero el bridge visual era obligatorio. Sin embargo,
|
|
||||||
`createActiveUix({ eidos: false })` era valido, lo que hacia que leer el
|
|
||||||
bridge visual fallase en runtime. Esto contradecia la degradacion graceful que
|
|
||||||
se aplicaba al motor perceptivo.
|
|
||||||
|
|
||||||
**Impacto historico:** Un componente que intentaba leer el bridge visual en
|
|
||||||
modo headless (sin CSS) crasheaba; uno que leia el motor perceptivo simplemente
|
|
||||||
saltaba la senal.
|
|
||||||
|
|
||||||
**Fix aplicado:** retirar ambos acoplamientos de `ActiveUix`: `events` queda
|
|
||||||
como motor perceptivo opcional y `ActiveEidos` se crea aparte cuando la app lo
|
|
||||||
necesita.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 1.3. `ActiveEidos` puede crear su propio `ActiveDom` sin permiso de `ActiveUix`
|
|
||||||
|
|
||||||
**Archivo:** `src/uix/eidos/active-eidos.svelte.ts` (lineas 258-263)
|
|
||||||
|
|
||||||
**Problema:** `ActiveEidos.#getDom()` llama `createActiveDom()` si no recibe `dom`.
|
|
||||||
Esto crea un segundo servicio DOM con sus propios listeners de resize/scroll,
|
|
||||||
rompiendo el principio de que _ActiveUix es el unico dueno del DOM_.
|
|
||||||
|
|
||||||
**Impacto:** En modo `dom: false` o attach sin dom, `ActiveEidos` silenciosamente instancia
|
|
||||||
DOM real en lugar de usar el `disabledDom` compartido.
|
|
||||||
|
|
||||||
**Fix propuesto:** `ActiveEidos` debe recibir siempre un `dom` explicito (incluso si es `disabledDom`).
|
|
||||||
Si falta, debe lanzar error o degradar a no-op, nunca crear uno propio.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 1.4. `Provider` abstract class sigue vivo a pesar de que la doctrina dice "dropped"
|
|
||||||
|
|
||||||
**Archivo:** `src/uix/soma/provider/provider.svelte.ts`
|
|
||||||
**Documento:** `src/uix/soma/SOMA_ARCHITECTURE.md` §15
|
|
||||||
|
|
||||||
**Problema:** `SOMA_ARCHITECTURE.md` dice "Provider inheritance dropped", pero
|
|
||||||
`provider.svelte.ts` sigue exportando `abstract class Provider<S>`.
|
|
||||||
Esto genera **dos patrones conviviendo**: el legacy (herencia) y el nuevo (SomaRuntime directo).
|
|
||||||
|
|
||||||
**Impacto:** Confusion para nuevos desarrolladores. Doble mantenimiento.
|
|
||||||
|
|
||||||
**Fix propuesto:** Depreciar/Eliminar `Provider`. Todos los componentes deben migrar a
|
|
||||||
`SomaRuntime` + funciones helper puras.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 1.5. Duplicacion de logica de `prefs` entre `active-uix/prefs.ts` y `eidos/active-eidos.svelte.ts`
|
|
||||||
|
|
||||||
**Archivo:** `src/uix/active-uix/prefs.ts` (lineas 55-69, 71-78)
|
|
||||||
**Archivo:** `src/uix/eidos/active-eidos.svelte.ts` (lineas 364-375)
|
|
||||||
|
|
||||||
**Problema:** `readPrefsSlot`, `createPrefsPreferenceSource`, `readActiveUixPrefsSlot` y
|
|
||||||
`createLocaleSourceFromPrefs` hacen esencialmente lo mismo: leer slots de `ActivePrefs`
|
|
||||||
de forma defensiva.
|
|
||||||
|
|
||||||
**Impacto:** DRY violation. Si cambia la forma de `ActivePrefs`, hay que tocar dos sitios.
|
|
||||||
|
|
||||||
**Fix propuesto:** Extraer un `prefs-bridge.ts` compartido en `$libs/prefs` o `$active-uix`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 1.6. Morfo incluia `langs` — mezcla de contrato estructural con datos de i18n
|
|
||||||
|
|
||||||
**Archivo:** `src/uix/morfo/types.ts` (linea 604), `src/uix/morfo/registry.ts` (lineas 33-47)
|
|
||||||
|
|
||||||
**Actualizacion 2026-05-13:** el campo publico se ha renombrado a
|
|
||||||
`Morfo.translations` y el registro a `connectMorfoTranslations`, para distinguir
|
|
||||||
catalogo declarativo de servicio runtime `langs`.
|
|
||||||
|
|
||||||
**Problema original:** `Morfo.langs` era un catalogo de traducciones embebido en el contrato.
|
|
||||||
Morfo deberia ser "DNA" puramente estructural. Las traducciones son volatiles y no
|
|
||||||
forman parte del contrato DOM.
|
|
||||||
|
|
||||||
**Impacto:** Cada vez que cambia una traduccion, el fingerprint del morfo cambia,
|
|
||||||
disparando re-registros innecesarios en `connectMorfoTranslations`.
|
|
||||||
|
|
||||||
**Fix propuesto:** Separar `MorfoLangCatalog` en un registry aparte. El morfo puede tener
|
|
||||||
una referencia (`langCatalogId`), pero no el arbol de strings.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Optimizaciones identificadas
|
|
||||||
|
|
||||||
### 2.1. `readBindings` en `SomaRuntime` genera garbage objects en cada tick
|
|
||||||
|
|
||||||
**Archivo:** `src/uix/soma/runtime.svelte.ts` (lineas 213-239)
|
|
||||||
|
|
||||||
```ts
|
|
||||||
function readBindings(reg, sources): MorfoBindings {
|
|
||||||
const states = {};
|
|
||||||
const props = {};
|
|
||||||
const parts = {};
|
|
||||||
// ... for-in + asignacion en cada $effect
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
En un `$effect` reactivo, esto corre en cada cambio de estado. Para 20 partes, son ~60 objetos
|
|
||||||
nuevos por frame.
|
|
||||||
|
|
||||||
**Optimizacion:** Usar un objeto de bindings mutable reutilizado (pool) o cambiar `readBindings`
|
|
||||||
a lectura lazy por plan, evaluando solo las fuentes que el `evalAttrPlan` necesita.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2.2. `EngineSemantic` clona `SEMA_MAP` en cada instancia
|
|
||||||
|
|
||||||
**Archivo:** `src/uix/sema/engine.ts` (linea 107)
|
|
||||||
|
|
||||||
```ts
|
|
||||||
this.map = applyMapOverrides(SEMA_MAP, opts.overrides?.runtime);
|
|
||||||
```
|
|
||||||
|
|
||||||
En tests con muchas instancias, deep-clone del mapa perceptivo completo es costoso.
|
|
||||||
|
|
||||||
**Optimizacion:** Hacer `SEMA_MAP` inmutable y aplicar overrides como un layer de proxy/lookup
|
|
||||||
en tiempo de resolucion, no en construccion.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2.3. `SoundChannel` registra listeners globales en el constructor incluso si nunca se usa
|
|
||||||
|
|
||||||
**Archivo:** `src/uix/sema/chans/sound.ts` (eager-init)
|
|
||||||
|
|
||||||
Eager-init de `AudioContext` es correcto para la politica de autoplay, pero registrar un
|
|
||||||
listener `capture-phase` en `document` al crear `EngineSemantic` es side-effect agresivo.
|
|
||||||
|
|
||||||
**Optimizacion:** Mover el registro del listener a la primera llamada a `emit()` que requiera
|
|
||||||
sonido, o usar un singleton lazy para `SoundChannel`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2.4. `stableStringify` en `registerMorfo` para fingerprint de `langs`
|
|
||||||
|
|
||||||
**Archivo:** `src/uix/morfo/registry.ts` (lineas 97-109)
|
|
||||||
|
|
||||||
```ts
|
|
||||||
function fingerprintLangNode(node: LangNode): string {
|
|
||||||
return stableStringify(node); // JSON-like recursivo
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Esto se ejecuta en cada `registerMorfo`. Para catalogos grandes, es `O(n)` en cada registro.
|
|
||||||
|
|
||||||
**Optimizacion:** Usar `WeakMap` + referencia de objeto si los catalogos son estaticos (lo son),
|
|
||||||
o cachear fingerprints por identidad de objeto.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Propuesta de mejor arquitectura
|
|
||||||
|
|
||||||
### 3.1. Contrato minimo tipado por capa
|
|
||||||
|
|
||||||
El documento `active_architecture.md` admite que falta la tabla de contratos.
|
|
||||||
Propongo definirla como tipos en `src/uix/contracts.ts`:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export interface UixServiceContract {
|
|
||||||
langs: ActiveLangs; // obligatorio
|
|
||||||
dom: ActiveDom; // obligatorio (puede ser disabledDom)
|
|
||||||
events?: EventEngineEmitter; // ornamental
|
|
||||||
eidos?: ActiveEidos; // ornamental
|
|
||||||
format?: ActiveFormat; // ornamental
|
|
||||||
prefs: ActivePrefs; // obligatorio
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`ActiveUix` deberia implementar esta interfaz y `createActiveUix` deberia validar contra ella
|
|
||||||
en lugar de logica `if/else` dispersa.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3.2. Sema debe purgarse de dimensions visuales (`motion`, `color`, `presence`)
|
|
||||||
|
|
||||||
La doctrina de Phase 5 del codex refactor es correcta pero incompleta. Propongo:
|
|
||||||
|
|
||||||
- **`SemaChannelSignatures`** solo debe tener: `sound`, `haptic`, y canales futuros (`a11y`, `voice`).
|
|
||||||
- El `hold` visual debe vivir en `VisualChannel` como `hold: number | 'brief' | 'noticed'...`,
|
|
||||||
resuelto desde `SEMA_MAP.families[*].hold` (ya existe), **no** desde `effective.motion.duration`.
|
|
||||||
- `motion`, `color`, `presence` se eliminan del `EffectiveSignature`. Eidos reacciona a
|
|
||||||
`data-event-family` + `data-event-intent` directamente en CSS.
|
|
||||||
|
|
||||||
Esto reduce drasticamente el acoplamiento Sema→Eidos.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3.3. Unificar scopes redundantes
|
|
||||||
|
|
||||||
Estado 2026-05-13: el adaptador `Eidos` ya fue eliminado. `ActiveEidos`
|
|
||||||
queda como scope visual real y no existe un engine visual separado. `Soma`
|
|
||||||
sigue como scope headless mientras se decide si debe conservarse o aplanarse.
|
|
||||||
|
|
||||||
La deuda historica era:
|
|
||||||
|
|
||||||
`Soma` y el antiguo adaptador visual repetian una superficie casi identica:
|
|
||||||
`uix`, `dom`, `events`, `langs` y helpers de capa. Esa duplicacion ya no debe
|
|
||||||
volver.
|
|
||||||
|
|
||||||
**Propuesta viva:** eliminar solo los adaptadores que no aporten contrato
|
|
||||||
propio. Los componentes no deben leer la superficie completa de `ActiveUix`;
|
|
||||||
deben consumir scopes o vistas estrechas:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// En un provider headless
|
|
||||||
const uix = getActiveUix();
|
|
||||||
const runtime = uix.runtime(morfo, sources);
|
|
||||||
|
|
||||||
// En un wrapper visual
|
|
||||||
const uix = getActiveUix();
|
|
||||||
const eidos = ActiveEidos.require();
|
|
||||||
```
|
|
||||||
|
|
||||||
Si se quiere evitar que los componentes toquen `ActiveUix` completo, usar **interfaces de capa**:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export interface SomaServices {
|
|
||||||
dom: ActiveDom;
|
|
||||||
events?: EventEngineEmitter;
|
|
||||||
langs: ActiveLangs;
|
|
||||||
}
|
|
||||||
export interface EidosServices {
|
|
||||||
dom: ActiveDom;
|
|
||||||
eidos?: ActiveEidos;
|
|
||||||
langs: ActiveLangs;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Esto elimina una clase entera de indireccion y la dependencia a `runed/Context` extra.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3.4. `SomaRuntime` desacoplado de Svelte
|
|
||||||
|
|
||||||
> Nota 2026-05-13: la API publica `registerPart` fue eliminada. La superficie
|
|
||||||
> canonica de registro queda en `SomaRuntime.part(...)`; esta observacion queda
|
|
||||||
> como contexto historico de la auditoria.
|
|
||||||
|
|
||||||
`registerPart` usa `$effect` directamente. Para testear el runtime sin un entorno Svelte,
|
|
||||||
o para reutilizarlo en otro framework, propongo inyectar un `Scheduler`:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export interface EffectScheduler {
|
|
||||||
run(fn: () => void): () => void; // return cleanup
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createSomaRuntime(
|
|
||||||
morfo: Morfo,
|
|
||||||
sources: SomaRuntimeSources,
|
|
||||||
scheduler: EffectScheduler = svelteScheduler
|
|
||||||
): SomaRuntime { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
Esto permite testear con `nanostores`, `mobx`, o incluso manual callbacks.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3.5. Eliminar CSS legacy (`contracts/`, `tokens/`, `themes/base/`)
|
|
||||||
|
|
||||||
Estos directorios son deuda de migracion. `ActiveEidos` ya puede generar todo el CSS estatico
|
|
||||||
y de theme desde la configuracion viva. Mantenerlos:
|
|
||||||
|
|
||||||
- Duplica fuentes de verdad (engine vs CSS manual).
|
|
||||||
- Hace que `eidos-lint` sea necesario.
|
|
||||||
- Incrementa bundle size.
|
|
||||||
|
|
||||||
**Estado 2026-05-13:** existe el primer artefacto generado,
|
|
||||||
`src/uix/eidos/generated/base.css`, producido con `npm run generate:eidos-css`
|
|
||||||
desde `EidosConfig` base. `contracts/` ya no se importa desde `index.css`;
|
|
||||||
ni desde `tokens/index.css`; queda como archivo de consulta/tooling. Aun no se
|
|
||||||
borran `tokens/` ni `themes/base/`, pero `themes/base/` tampoco se importa ya
|
|
||||||
en runtime: sus aliases necesarios viven ahora en el CSS generado.
|
|
||||||
`tokens/components/index.css` solo importa tokens de las recipes activas; el
|
|
||||||
resto queda como material legacy. El siguiente paso es separar recipes estables
|
|
||||||
de aliases retirables en `tokens/`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Preguntas para priorizar
|
|
||||||
|
|
||||||
1. **¿Prioridad inmediata?** ¿Cerrar primero la tabla de contratos minimos
|
|
||||||
(`active_architecture.md` §102) antes de cualquier refactor?
|
|
||||||
2. **¿Eliminacion de `Provider` legacy?** ¿Hay componentes que aun no se migraron al patron
|
|
||||||
`SomaRuntime` directo? ¿Se puede deprecar `Provider` abstracto ya?
|
|
||||||
3. **¿Sema visual cleanup?** ¿Aceptar que sea un cambio grande? Implica mover
|
|
||||||
`motion/color/presence` fuera de `SEMA_MAP` y ajustar `VisualChannel`.
|
|
||||||
4. **Eidos opcional:** resuelto. `ActiveUix` no expone el bridge visual;
|
|
||||||
`ActiveEidos` se crea aparte.
|
|
||||||
5. **¿Scopes `Soma`/`Eidos`?** ¿Eliminar ambas clases y dejar que los componentes lean
|
|
||||||
`getActiveUix()` directamente, o mantener la separacion simbolica?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
_Auditoria generada el 2026-05-12. Estado de referencia: rama `active-uix`._
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
# UIX DOM Audit
|
|
||||||
|
|
||||||
Fecha: 2026-05-14. Rama: `active-uix`.
|
|
||||||
|
|
||||||
## Criterio
|
|
||||||
|
|
||||||
La regla arquitectonica queda:
|
|
||||||
|
|
||||||
> Las capas UIX no escriben atributos/estilos mutables directamente. Las
|
|
||||||
> escrituras estructurales y visuales deben pasar por `ActiveDom`
|
|
||||||
> (`dom.apply`, `dom.remove`, `dom.writeStyle`, `dom.removeStyle`,
|
|
||||||
> `dom.writeNode`, `dom.writeText`, `dom.removeNode`) o por un proyector
|
|
||||||
> construido con ese servicio.
|
|
||||||
|
|
||||||
Lecturas DOM (`querySelector`, `dataset`, `textContent` como lectura,
|
|
||||||
`ResizeObserver.observe`) no violan esta regla por si solas.
|
|
||||||
|
|
||||||
## Superficies correctas
|
|
||||||
|
|
||||||
- `ActivePrefsDomProjection` proyecta prefs transversales (`dir`,
|
|
||||||
`data-motion`, `data-sound`, `data-haptic`) con `dom.apply` cuando el
|
|
||||||
composition root lo cablea.
|
|
||||||
- `SomaRuntime` sincroniza attrs derivados de morfo con `dom.apply`.
|
|
||||||
- `events`/`Sema` proyecta `data-event-*` solo desde
|
|
||||||
`VisualChannel.prepare()` usando `DomSignalProjector`, que escribe con
|
|
||||||
`dom.apply`; `EngineSemantic` no escribe attrs directamente.
|
|
||||||
- `ActiveEidos` proyecta `data-theme`, `data-mode`, `data-density` e inserta
|
|
||||||
CSS runtime con `dom.writeStyle` y `dom.removeStyle`.
|
|
||||||
- La shell `/uix` usa `createActivePrefsDomProjection(...)` para attrs
|
|
||||||
cross-modal y `ActiveEidos.create({ applyDom:true, modeSource })` para
|
|
||||||
theme/mode/density. No escribe `prefs.theme`.
|
|
||||||
- `TextSelection` ya no escribe `style.userSelect` directamente; ahora recibe
|
|
||||||
`ActiveDom` y actualiza/restaura solo `user-select` y `-webkit-user-select`
|
|
||||||
mediante `dom.apply`.
|
|
||||||
- Announcers/live regions y descripciones ocultas de date/time ya no crean
|
|
||||||
nodos ni escriben texto directamente; usan nodos gestionados de `ActiveDom`.
|
|
||||||
|
|
||||||
## Escrituras directas restantes
|
|
||||||
|
|
||||||
No quedan escrituras directas de producción detectadas por el barrido P1.
|
|
||||||
Quedan lecturas DOM y fixtures de tests.
|
|
||||||
|
|
||||||
| Archivo | Qué escribe | Estado |
|
|
||||||
| --------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------- |
|
|
||||||
| `src/uix/soma/components/announce/global.svelte.ts` | Crea live regions globales y alterna texto. | Corregido via `ActiveDom.writeNode/writeText` |
|
|
||||||
| `src/uix/soma/datetime/announcer.ts` | Crea live regions para date/time y escribe mensajes. | Corregido via `ActiveDom.writeNode/writeText` |
|
|
||||||
| `src/uix/soma/datetime/helpers.ts` | Crea/elimina descripcion oculta `aria-describedby`. | Corregido via `ActiveDom.writeNode/removeNode` |
|
|
||||||
|
|
||||||
## Lecturas o efectos DOM no clasificadas como violacion
|
|
||||||
|
|
||||||
- `src/uix/soma/datetime/segments.ts` y `helpers.ts`: leen `dataset.segment`.
|
|
||||||
- `src/uix/soma/layers/focus-scope.svelte.ts`: lee/focaliza `document.body`
|
|
||||||
como parte del focus management. Es mutacion de foco, no escritura de attrs.
|
|
||||||
- `src/uix/soma/components/virtual-list/virtual-list-provider.svelte.ts`:
|
|
||||||
observa `document.documentElement` con `ResizeObserver`.
|
|
||||||
- Tests bajo `src/uix/**`: manipulan `document.body` como fixture.
|
|
||||||
|
|
||||||
## Decision cerrada
|
|
||||||
|
|
||||||
Se eligio extender `ActiveDom` con nodos gestionados (`writeNode`,
|
|
||||||
`writeText`, `removeNode`). No se crea una fachada nueva y no quedan islas DOM
|
|
||||||
owned fuera del servicio.
|
|
||||||
|
|
||||||
Los eventos de cierre que apuntan a una parte desmontable deben pasar
|
|
||||||
`fallbackTarget` cuando esa parte pueda no estar registrada. Popover centraliza
|
|
||||||
ese patrón en `triggerClose(...)`: prefiere `content`, cae al botón/trigger que
|
|
||||||
provocó el cierre y evita que `SomaRuntime` emita una señal visual sin target.
|
|
||||||
Loading…
Reference in new issue