104 KiB
| title | type | audience | authority | status |
|---|---|---|---|---|
| UIX — registro de hallazgos estáticos | notes | human + agent | process — evidencia de auditoría; no cambia contratos ni estado del ledger | reviewed |
UIX — registro de hallazgos estáticos
Fecha: 2026-09-19. Este registro desarrolla el plan y las fichas de módulos. Distingue evidencia estática de una reproducción. El ledger vigente conserva el estado oficial de cada fila.
Cola de correcciones tras la auditoría
Este registro es la cola de trabajo para después de cerrar la auditoría, no una
autorización para mezclar correcciones funcionales con las extracciones neutras.
Las filas de la tabla siguiente cubren todos los defectos de comportamiento
confirmados en la tabla de hallazgos de esta auditoría a fecha 2026-09-26.
Q12, Q13, Q17, Q20–Q23 y Q74 se añaden como discrepancias de API o metadatos confirmadas por
lectura, aún sin reproducción de su efecto en consumidores de metadatos ni
decisión de compatibilidad.
Q14–Q16, Q18–Q19, Q24–Q31 y Q33 se reprodujeron en consumidores Eidos montados en Chromium.
Q34 se reprodujo con el proveedor Sticky y geometría real en Chromium.
Q35–Q36 se reprodujeron con el wrapper SkipLink montado en Chromium.
Q37 se confirmó en el DOM de Breadcrumb y en la regla WAI-ARIA de conflictos
del rol presentacional.
Q38 se reprodujo al cambiar reactivamente el href de AnchorNav.Link.
Q39 se reprodujo con pageSize=0 en Pagination y count>0.
Q40 se reprodujo con una colisión entre el sufijo de un ID duplicado de NavTree
y otro ID declarado; Svelte abortó el render por claves iguales.
Q41 se reprodujo al pulsar ArrowDown desde el control de una rama abierta
de TreeView: el foco no avanzó a la hoja.
Q42 ya constaba medido en el README Eidos de TreeView: el hover de una rama
abierta tiñe el subárbol por la ubicación del arquetipo en el contenedor.
Q43 se reprodujo al seleccionar una fila hija de TreeGrid: el clic también
selecciona la fila padre y esta prevalece. Q44 recoge las dos anomalías de
hover de TreeGrid medidas previamente en su README Eidos.
Q45 se reprodujo al pulsar un botón de acción dentro de GridList: la acción
se ejecuta, pero el clic burbujea a la fila y reemplaza la selección múltiple.
Q46 recoge el doble velo de hover medido previamente para GridList. L-027,
la selección de fila sin acento, ya estaba confirmado y diferido en el ledger.
Q47 se reprodujo al pulsar una acción dentro de una fila Table: también se
seleccionó la fila. Q48 y Q49 recogen mediciones previas de hover con
hoverable=false y pinning en RTL. Q50 es una discrepancia de tipos de la
API genérica; Q51 recoge el hover sin respuesta del SortButton ya descrito
en el README Eidos.
Q52 y Q53 se reprodujeron en VirtualGrid Eidos en Chromium: scroll
horizontal RTL con rango vacío y salto a columna que conserva offset 0.
Q54 se reprodujo en su provider: claves únicas por eje generan claves de
celda duplicadas; el efecto sobre el keyed each queda por reproducir.
Q55 y Q56 se reprodujeron en ScrollArea Eidos en Chromium: un mínimo
CSS de thumb mayor que el usado por Soma desborda el track al final;
un style como objeto se descarta y deja la raíz sin altura.
Q57–Q59 se reprodujeron en Splitter Eidos en Chromium: falta enlace del
separador al panel, la orientación ARIA sigue el layout en lugar del
separador físico y expandir restaura defaultSize en lugar del tamaño anterior.
Q60–Q62 se reprodujeron en Knob Eidos: value omitido fuera del rango
declarado, step cero que publica NaN y pivote tomado del root con Label.
Q62 usa geometría real y eventos sintéticos, no captura nativa de puntero.
También se reprodujo el foco ausente al pulsar Label, ya registrado como
L-110; no se crea otro ID ni se cambia su estado oficial.
El estado oficial de los ID L-* sigue en el ledger; esta cola no crea un
segundo estado ni da por reparado un defecto porque el gate general pase.
| Lote posterior | ID | Condición para abordarlo y prueba de cierre |
|---|---|---|
| Anuncios y attach | Q01-a, Q01-b, Q01-c | Fijar ownership del canal y de los temporizadores. Incorporar pruebas permanentes de timeout: 0, attach → dispose → attach y cancelación, que fallen antes y pasen después; comprobar servicios prestados intactos. |
| Arranque de ActiveUix | Q05 | Separar rollback tras constructor fallido de la dirección inicial en targetWindow. Fijar ambos casos con pruebas cliente; comprobar listeners y preferencias en documento global e iframe. |
| Sustitución de raíz Eidos | L-126 | Caracterizar dos raíces sucesivas sobre el mismo DOM; al destruir la antigua, la nueva debe conservar atributos y estilos. Comprobar SSR y aplicación DOM. |
| Foco de overlays | L-138 | Medir document.activeElement al cerrar Dialog y Drawer por Escape y botón, con trigger vivo y desmontado, en Chromium, Firefox y WebKit. |
| Valor visible de Select | L-140 | Fijar etiqueta inicial con portal cerrado, también con children de Select.Value; comprobar selección y registro de etiquetas tras abrir/cerrar. |
| Acento de GridList seleccionado | L-027 | Fijar la apariencia de una fila seleccionada y del checkbox en varios temas y estados; decidir firma visual antes de mover el selector de acento. |
| Referencias enlazadas | L-152 | Clasificar wrappers afectados y añadir pruebas cliente de bind:ref por familia; reparar sólo los casos demostrados. |
| Firma háptica | L-153 | Decidir el contrato para un override parcial sin firma base (rechazar, silenciar o completar); fijar la decisión con prueba del resolver y canal antes de cambiar el runtime. |
| Idiomas | L-141, L-144 | Reproducir fallback con ar y tipado de claves de catálogo de aplicación; completar traducciones y decidir la frontera de tipos en lotes separados. |
| Props de Badge | Q12 | Caracterizar as, visibleFrom y una prop de layout en un consumidor real; decidir si retirar esas props del tipo o implementar su semántica sin romper compatibilidad. |
| Props de carga Eidos | Q13 | Caracterizar as, visibleFrom, width y height en Spinner/Skeleton, incluida la geometría computada de Skeleton; decidir el contrato público y la compatibilidad antes de modificar el runtime. |
| Partes de Avatar | Q14 | Fijar en tests cliente la demora de Avatar.Fallback y el callback de Avatar.Image dentro del root; comparar con el callback y la demora del root antes de corregir cada prop. |
| Herencia de Image.Img | Q15 | Fijar src y alt heredados en composición explícita y atributos propios prioritarios; verificar carga, fallback y SSR al corregir la herencia. |
| Error abreviado de Image | Q16 | Fijar el fallback visual tras error cuando sólo se pasa fallback; conservar la distinción de errorFallback, slot Error explícito y fallbackSrc. |
| Elemento de Code | Q17 | Comprobar consumidores de defaultElement y fijar la expectativa code frente a span; alinear los metadatos sin alterar la salida DOM predeterminada. |
| Estilo de Highlight | Q18 | Probar Highlight importado solo y junto con Mark, con colores por defecto y personalizados; cargar la receta de marca sin duplicar reglas CSS. |
| Consulta de Highlight | Q19 | Fijar en cliente las consultas '', ' ', listas mixtas y términos con espacios significativos; decidir la normalización antes de cambiar el matcher. |
| Elemento de Mark | Q20 | Comprobar consumidores de defaultElement y alinear mark frente a span sin variar el tag renderizado por defecto. |
| Elemento de Kbd | Q21 | Comprobar consumidores de defaultElement y alinear kbd frente a span sin variar el tag renderizado por defecto. |
| Elemento de Heading | Q22 | Comprobar consumidores de defaultElement y alinear el <h2> inicial frente a span sin variar el render ni la relación level/style. |
| Elemento de Display | Q23 | Comprobar consumidores de defaultElement y alinear <h1> frente a span sin variar el tag renderizado por defecto. |
| Marcadores de Prose | Q24 | Añadir prueba cliente permanente de marcadores ul/ol normales e ignorados, incluido tema; aplicar la exclusión a ::marker sin alterar las listas normales. |
Foco de Link sin href |
Q25 | Caracterizar usos reales de Link sin destino y fijar con prueba cliente el foco y rol deseados antes de decidir un cambio de DOM. |
| Props de Link deshabilitado | Q26 | Fijar en prueba cliente qué atributos de ancla deben omitirse del <span> y comprobar que las props comunes siguen pasando. |
| Estilo de Label | Q27 | Añadir prueba cliente permanente que combine style del consumidor con size/weight/color; preservar la asociación for y la precedencia prevista al fusionar estilos. |
| Posición de Box en RTL | Q28 | Fijar en prueba cliente left y right dentro de contenedores LTR/RTL; decidir si el contrato es físico o lógico y conservar los insets explícitos al corregir la receta. |
alignContent de Stack |
Q29 | Caracterizar el uso público de alignContent sin wrap; decidir si se omite del tipo Stack o se expone wrap, con prueba cliente de geometría y compatibilidad. |
grow vertical de Group |
Q30 | Fijar anchos de hijos para Group grow en fila y columna; decidir si grow vertical debe igualar ancho, limitarse a fila o cambiar su descripción, comprobando ButtonGroup vertical. |
| Props de Box en Container | Q31 | Fijar precedencia de size/align frente a width, maxWidth y márgenes heredados; decidir si se admiten overrides o se estrecha el tipo, y comprobar los Blocks consumidores. |
| Elemento de Section | Q32 | Comprobar consumidores de defaultElement y alinear el metadato div con el root section predeterminado, sin alterar el DOM ni la capacidad as de SiteFooter. |
| Props de Box en Section | Q33 | Fijar la precedencia de display y width heredados frente a los valores fijos del wrapper; decidir el contrato con pruebas cliente sobre Section y los Blocks, incluido SiteFooter. |
| Estado de Sticky al terminar sección | Q34 | Fijar en Chromium, Firefox y WebKit la entrada y salida por ambos extremos del contenedor, con edge=top/bottom, offset y scroll-host explícito. Corregir la observación sin lecturas síncronas de layout y comprobar el atributo real. |
onclick de SkipLink |
Q35 | Decidir si componer el callback con la navegación o retirar esa prop de la API; fijar foco, cancelación y llamada del consumidor en prueba cliente antes de cambiar el wrapper. |
| Limpieza de foco de SkipLink | Q36 | Fijar destinos visibles, ocultos, desconectados y con tabindex previo; limpiar sólo el atributo que puso el componente, incluso cuando focus() no lo consigue. |
| Ellipsis decorativo de Breadcrumb | Q37 | Fijar el árbol de accesibilidad del elipsis estático e interactivo en Chromium, Firefox y WebKit; decidir si el estático es decorativo o nombrado y retirar el conflicto sin cambiar el botón. |
| Destino reactivo de AnchorNav | Q38 | Fijar cambio de href con dos destinos reales, registro/observación y atributos del enlace; decidir si el prop es estable por contrato o re-registrarlo sin fugas ni pérdida de duplicados. |
| Rango vacío de Pagination | Q39 | Fijar pageSize=0 y valores negativos con count>0; decidir validación, normalización o rango vacío, protegiendo cálculo de páginas, slice y controles. |
| Claves de NavTree | Q40 | Reproducir sufijo generado frente a ID declarado, además de duplicados ordinarios; reservar claves únicas de todo el árbol y verificar ruta activa, expansión y logger sin cambiar IDs válidos. |
| Teclado y rol de ramas TreeView | Q41 | Alinear la lista de candidatos y el tab stop de rama; fijar ArrowDown/Up, flechas horizontales, Home/End y typeahead en un árbol anidado real, más el foco accesible. |
| Velo hover de ramas TreeView | Q42 | Medir fila y contenedor en abierto/anidado, desplazar el arquetipo a la fila solo con caracterización visual y de eventos, y proteger el resultado en claro/oscuro y RTL. |
| Selección anidada de TreeGrid | Q43 | Fijar selección de hija, padre y hermanas con clic, teclado y expansión; aislar el evento de fila sin perder selección múltiple ni controles interactivos. |
| Hover de filas TreeGrid | Q44 | Medir bandas y filas normales en claro/oscuro, varias órdenes de carga CSS y motores; resolver la precedencia visual en un lote separado. |
| Botones internos de GridList | Q45 | Fijar clic en acción, enlace y checkbox dentro de fila con selección simple y múltiple; conservar ejecución y foco de cada control sin selección accidental. |
| Hover doble de GridList | Q46 | Medir velo de fila y celda en claro/oscuro y estados selected/highlighted; decidir un único portador del hover en lote visual separado. |
| Botones internos de Table | Q47 | Fijar clic en acción, enlace y RowDetailTrigger con selección simple/múltiple; conservar la acción sin seleccionar una fila por burbujeo. |
hoverable de Table |
Q48 | Medir filas en hover con la prop activada y desactivada, y decidir si el arquetipo o la receta es dueño del velo. |
| Pinning de Table en RTL | Q49 | Fijar desplazamiento horizontal y offset de columnas fijadas en LTR/RTL en Chromium, Firefox y WebKit; decidir coordenadas lógicas sin alterar el enum por inferencia. |
| Tipo genérico de Table | Q50 | Reproducir un consumidor TypeScript sin casts con createTable<T>; decidir parametrización pública y compatibilidad de los tipos de partes. |
| Hover de SortButton | Q51 | Medir estados normal, hover, foco y orden asc/desc; decidir precedencia entre receta y arquetipo en lote visual. |
| Rango horizontal RTL de VirtualGrid | Q52 | Normalizar el offset lógico por dirección; cubrir scroll negativo, ambos extremos y resize en Chromium, Firefox y WebKit antes de corregir. |
| Salto RTL de VirtualGrid | Q53 | Fijar scrollToCell con start/center/end/auto por ambos ejes y verificar offset nativo negativo y celda visible; conservar el evento de navegación. |
| Claves compuestas de VirtualGrid | Q54 | Reproducir colisiones con delimitadores y tipos string/number en un consumidor keyed; definir clave inequívoca sin romper estabilidad ni identidad de las celdas. |
| Geometría del thumb de ScrollArea | Q55 | Fijar tamaño pintado y recorrido con mínimos CSS, tracks cortos, padding, ambos ejes y RTL; decidir qué capa posee la geometría antes de corregir drag y offset. |
| Splitter: enlace y eje ARIA | Q57, Q58 | Fijar ID del panel primario, orientación física en ambos ejes y composición de tres paneles; verificar ARIA y teclado en tres motores antes de corregir Morfo. |
| Restauración de Splitter | Q59 | Caracterizar tamaño previo, defaultSize, min/max del vecino, collapse por teclado/doble clic y escrituras externas; decidir contrato sin romper bindings ni callbacks. |
| Knob: valor inicial | Q60 | Caracterizar value omitido, min distinto de cero y valores controlados fuera de rango; decidir seed sin añadir callbacks ni cambiar la semántica de reset. |
| Knob: step no positivo | Q61 | Fijar step cero, negativo y no finito, rejillas decimales y límites; decidir rechazo o fallback antes de impedir la publicación de NaN. |
| Knob: pivote del dial | Q62 | Medir Control y root con Label, ValueText y ValueField; reproducir gesto nativo y captura en tres motores antes de elegir el nodo del pivote. |
| Knob: foco de Label | L-110 | Resolver el Control real mediante ActiveDom y verificar foco al pulsar Label, disabled, readonly y destrucción; mantener el estado oficial del ledger. |
| Gesture: cancel antes del buffer | Q63 | Caracterizar down/cancel/move/unmount y callbacks; fijar limpieza de listeners antes y después del umbral sin cambiar offsets o capture por inferencia. |
| Gesture: segundo puntero | Q64 | Probar dos pointerdown antes del buffer y el gesto siguiente; conservar el primer pointerId y garantizar una sola sesión/listener en eventos sintéticos y multi-touch nativo. |
| Gesture: snaps secuenciales | Q65 | Fijar snap asentado, inicio de gesto, vecinos, wrap, velocidad y entradas externas; decidir estado de referencia para drag y rotate sin cambiar AxialDrag. |
| AxialDrag: cleanup de cancel | Q66 | Fijar down/cancel/down y desmontaje antes/después del buffer; garantizar una sesión y una cleanup sin perder la posición asentada. |
| AxialDrag: identidad del puntero | Q67 | Caracterizar move/up/cancel de otros IDs y captura; verificar multi-touch nativo sin alterar signos, límites, snaps ni callbacks. |
| AxialDrag: progreso controlado | Q68 | Fijar offsetPx/value01 con snap externo inicial y actualizado, antes/durante/después del drag; medir tamaño y progreso en Drawer. |
| ZoomPan: mínimo e inicio | Q69 | Adjudicar escala inicial y reset con minScale distinto de 1; comprobar isZoomed, límites y Cropper montado antes de cambiar el contrato. |
| Cropper: nombre del zoom | Q70 | Nombrar el thumb enfocable mediante el contrato Slider y verificar idiomas y nombre accesible sin cambiar valor o teclado. |
| Cropper: límites de zoom reactivos | Q71 | Adjudicar cambios de minScale/maxScale tras mount; sincronizar controles y motor conservando clamp, anclas y reset. |
| Cropper: disabled con teclado | Q72 | Fijar Tab/Enter en reset y teclado del Slider con disabled; conservar exportación programática y reactivación. |
| Cropper: identidad del puntero | Q73 | Fijar ID de sesión para move/up/cancel y captura en selección, resize y pan; comprobar multi-touch nativo antes de corregir. |
| Cropper: justificación APG | Q74 | Adjudicar el texto apg que afirma keyboard nudge frente al gap diferido; alinear metadatos sin implementar teclado dentro del refactor neutral. |
| Style del root ScrollArea | Q56 | Fijar estilos string/objeto, precedencia con size/radius y autosize; conservar dimensiones y tokens del consumidor sin alterar la geometría Soma. |
Lotes posteriores de ImagePicker e ImageAdjustments:
| Lote posterior | ID | Condición y prueba de cierre |
|---|---|---|
| Payload y objeto URL | Q75 | Adjudicar cuándo emitir select/remove/replace; hacer corresponder file y URL sin cambiar ownership, revocación ni orden de callbacks por inferencia. |
| Notificación de ajustes y bindings | Q76 | Fijar contrato de onChange para teclado, fit y cambios externos; impedir emisiones duplicadas conservando bindings y preview. |
| Nombre de ajustes | Q77 | Nombrar cada thumb en ImageAdjustments mediante el contrato Slider y traducciones; probar nombres, varios ajustes y teclado. |
| Destino perceptual al seleccionar | Q78 | Caracterizar selección y desmontaje de FileUpload; conservar señal y handler sin retrasar arbitrariamente la transición ni introducir un fallback ajeno al contrato. |
Al aparecer otro defecto durante la auditoría se añade aquí y en la tabla de
evidencia de abajo con un ID existente del ledger o un Q* nuevo, reproducción
o límite de la evidencia, consumidor afectado y prueba de cierre. Al terminar
las fases 6 y 7 se concilian los ID con el ledger, se ordenan por impacto y se
ejecutan lotes independientes con prueba antes/después y gate completo.
L-130 es una medición de CSS/primer pintado, no un defecto adjudicado. Q02
requiere decidir si existe una promesa de integración prefs → Sema. Q11 no
se reprodujo en el <SText> real y permanece como señal condicionada.
Ninguno entra en la cola de correcciones confirmadas por inferencia.
Defectos y riesgos de comportamiento
| ID | Área | Evidencia de código | Estado de auditoría | Siguiente prueba, sin cambio de contrato |
|---|---|---|---|---|
| Q01-a | ActiveUix announce | announce() sólo reemplaza el timer si timeout > 0; timeout: 0 conserva el timer anterior |
Reproducido en Vitest client (Chromium) | Corregir en un lote de defectos con prueba permanente |
| Q01-b | ActiveUix attach | La closure de AnnounceChannel captura la primera instancia; el canal prestado sobrevive a dispose() |
Reproducido en Vitest client (Chromium) | Definir ownership del canal antes de corregirlo |
| Q01-c | ActiveUix attach | announce() programa el borrado en app.timers, pero uix.dispose() deja pendiente ese temporizador prestado |
Reproducido en Vitest client (Chromium) | Definir cancelación por instancia junto con Q01-b |
| Q05 | ActiveUix boot | createActiveUix() registra listeners antes de validar Sema y lee la dirección del documento global aunque ActiveDom apunte a otro targetWindow |
Ambos casos reproducidos en Vitest client (Chromium) | Garantizar rollback en error y alinear la lectura inicial de preferencias con el destino configurado |
| L-126 | Eidos lifecycle | dispose() borra IDs de estilo y atributos sin marca de la instancia que escribió después |
Reproducido en Vitest server | Corregir ownership de DOM y estilos en un lote de defectos |
| L-130 | Eidos CSS | apps/base importa index.css, que incluye generated/base.css, y crea ActiveEidos con applyDom:true, que escribe foundation runtime |
Medido en el ledger; la alternativa afecta primer paint | Comparar SSR, hidratación, CSS y first paint antes de variar el entrypoint |
| L-138 | Dialog/Drawer | Dialog construye FocusScope antes de HideOthers. El ledger reproduce el retorno a body mientras el trigger sigue inert; los tests no leen activeElement |
Reproducido en el ledger; estático compatible | Browser test de Escape/Cerrar en Chromium, Firefox y WebKit con trigger vivo y desmontado |
| L-027 | GridList selección | La regla visual para [data-selected] se retiró porque Soma escribe data-state='selected'; una fila seleccionada conserva el velo neutro y el checkbox sí recibe acento. |
Medido en next-features.md §13 y diferido en el ledger |
Decidir firma visual y fijar píxeles en varios estados antes de cambiar el selector. |
| L-140 | Select | getDisplayText() devuelve el value si no hay etiqueta registrada. Los items registran su etiqueta al montarse; con el portal cerrado no hay registro inicial |
Reproducido sin children en Vitest client (Chromium) | Decidir cómo suministrar la etiqueta inicial; probar también children en Value |
| L-152 | Eidos wrappers | Censo previo: wrappers con ref = $bindable reenvían ...rest a Soma sin siempre enlazar bind:ref |
Confirmado por el ledger; no se repite el censo como prueba funcional | Clasificación por familia y prueba cliente de cada contrato bind:ref afectado |
| L-153 | Sema resolver | SemaSignatureOverride permite Partial<HapticSignature>; sin slice base applyOverride() clona ese parcial. Con channels:['haptic'] y sin kind, HapticChannel desreferencia un perfil inexistente antes de la defensa S-31 |
Reproducido en Vitest server | Decidir y fijar rechazo, silencio o completado antes de corregir el comportamiento |
| L-141 | Langs catálogo | El ledger confirma componentes sin traducción ar; con ese locale aparece texto de otro idioma |
Confirmado por el ledger; catálogo estático en boot | Arrancar con ar y comprobar las claves de componente afectadas, antes de completar traducciones |
| L-144 | Langs de aplicación | Una ruta inválida de catálogo de app compila y sólo se detecta en desarrollo; uixLangs no integra ese tipo |
Confirmado por el ledger; requiere decisión de API | Compilar una clave válida e inválida del catálogo app y decidir la frontera de tipo pública |
| Q11 | Eidos canvas-text | FontFace tardía: WebKit pintó 5 líneas a 124 px y layout() contó 4 tras invalidar; Chromium y Firefox coincidieron |
Harness parcial intermitente; <SText> real pasa en tres motores |
Aislar sólo si reaparece en otro consumidor; no modificar el runtime |
| Q12 | Badge API | BadgeProps hereda BoxProps, pero badge.svelte renderiza un <span> y reenvía as, visibleFrom y props de layout mediante ...rest sin resolverlas |
Discrepancia confirmada por lectura; salida DOM aún no caracterizada | Probar las props en cliente y decidir contrato de compatibilidad después de la auditoría |
| Q13 | Spinner/Skeleton API | Ambos tipos heredan BoxProps y afirman componer Box; los wrappers renderizan <div> y reenvían as, visibilidad y medidas mediante ...rest. Skeleton anuncia width/height en su ejemplo, mientras su CSS fija inline-size:100% y block-size:var(--skeleton-size) |
Discrepancia confirmada por lectura; geometría DOM aún no medida | Medir atributos y tamaño en cliente; decidir compatibilidad de props al cerrar la auditoría |
| Q14 | Avatar parts | Avatar.Fallback desestructura delayMs sin usarlo; Avatar.Image sólo conecta onImageStatusChange al provider cuando no hay root padre |
Reproducido en Vitest client (Chromium) | Probar las dos props dentro de un Avatar antes de corregir su cableado |
| Q15 | Image.Img | ImageImgProps promete heredar src y alt del root, pero la part fija defaults null y '' en su <img> sin leer los props del padre |
Reproducido en Vitest client (Chromium) | Probar herencia y precedencia de valores explícitos; cubrir carga y SSR |
| Q16 | Image error | El README promete usar Fallback si no hay Error, pero la ruta abreviada oculta Fallback en error y monta un slot Error sin contenido si falta errorFallback |
Reproducido en Vitest client (Chromium) | Probar error con fallback solo, errorFallback, slot explícito y fallbackSrc |
| Q17 | Code Morfo | codeMorfo declara defaultElement: 'span'; el wrapper Eidos, su tipo y README establecen code por defecto |
Discrepancia estática confirmada; no se midió efecto en consumidores | Inspeccionar consumidores de metadatos y alinear el elemento declarado sin cambiar el render |
| Q18 | Highlight CSS | highlight.svelte importa highlight.css, pero la receta [data-mark] sólo está en mark.css, que importa Mark |
Reproducido en Vitest client (Chromium): amarillo nativo, sin padding | Probar importación aislada y conjunta, tema y color CSS libre antes de cargar la receta |
| Q19 | Highlight query | El filtro usa t.length > 0; una consulta de sólo espacios genera coincidencias aunque el README prometía ignorarla |
Reproducido en Vitest client (Chromium) | Decidir normalización de espacios y fijar casos de lista y término significativo |
| Q20 | Mark Morfo | markMorfo declara defaultElement: 'span'; el wrapper Eidos, su tipo y README establecen mark por defecto |
Discrepancia estática confirmada; no se midió efecto en consumidores | Inspeccionar consumidores de metadatos y alinear el elemento declarado sin cambiar el render |
| Q21 | Kbd Morfo | kbdMorfo declara defaultElement: 'span'; el wrapper Eidos, su tipo y README establecen kbd por defecto |
Discrepancia estática confirmada; no se midió efecto en consumidores | Inspeccionar consumidores de metadatos y alinear el elemento declarado sin cambiar el render |
| Q22 | Heading Morfo | headingMorfo declara defaultElement: 'span'; el wrapper Eidos, su tipo y README establecen <h2> por defecto |
Discrepancia estática confirmada; la sonda montó <h2> en Chromium |
Inspeccionar consumidores de metadatos y alinear el elemento declarado sin cambiar el render |
| Q23 | Display Morfo | displayMorfo declara defaultElement: 'span'; el wrapper Eidos, su tipo y README establecen <h1> por defecto |
Discrepancia estática confirmada; no se midió efecto en consumidores | Inspeccionar consumidores de metadatos y alinear el elemento declarado sin cambiar el render |
| Q24 | Prose CSS | Las reglas ul > li::marker y ol > li::marker omiten el filtro data-prose-ignore; una sonda con color de marcador distinto mostró que también colorean las listas ignoradas |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Fijar listas normales e ignoradas en prueba permanente antes de ajustar los selectores |
| Q25 | Link sin href |
El tipo afirmaba que el <a> sin destino seguía siendo enfocable; al montar Link sin href, focus() no lo convirtió en document.activeElement, mientras que el enlace con destino sí |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Caracterizar consumidores y decidir el contrato de foco y rol sin cambiar navegación por inferencia |
| Q26 | Link deshabilitado | El wrapper afirma descartar atributos de ancla en el <span> deshabilitado, pero target="_blank" y rel="nofollow" pasados por el consumidor permanecen en ese elemento |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Probar filtrado y reenvío de props comunes antes de cambiar la rama deshabilitada |
| Q27 | Label style |
LabelProps hereda style, pero label.svelte escribe style={resolvedStyle} después de ...restProps; una sonda con padding-inline-start: 7px y size="lg" conservó el tamaño, pero perdió el padding |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Probar composición de estilo externo y ejes internos antes de cambiar el wrapper |
| Q28 | Box en RTL | box.css aplica --box-left/right tanto a propiedades físicas como a inset-inline-start/end; en RTL, las declaraciones lógicas posteriores cambian de lado left={10} y right={10} |
Reproducido en Vitest client (Chromium); sonda retirada | Decidir contrato físico o lógico y probar ambos ejes antes de cambiar la receta |
| Q29 | Stack alignContent |
StackProps hereda alignContent de Flex pero omite wrap; el wrapper deja flex-wrap: nowrap, de modo que el prop se acepta y se escribe aunque no mueve los hijos en el uso tipado normal |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Decidir si reducir el tipo o abrir wrap, con prueba de efecto y compatibilidad |
| Q30 | Group grow |
GroupProps.grow promete igualar anchos, pero la receta usa flex: 1 1 0 en cualquier dirección; con direction="column", dos hijos de 30/50 px conservaron anchos distintos, frente a la fila que los igualó |
Reproducido en Vitest client (Chromium), 2/2; sonda retirada | Decidir contrato vertical y proteger también ButtonGroup vertical antes de corregir |
| Q31 | Container props | ContainerProps hereda width, maxWidth y márgenes de Box, pero el wrapper los sobrescribe tras ...restProps; size="sm" conservó 480 px pese a maxWidth={320} y width="50%", y align ganó a marginLeft/marginX |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Decidir precedencia o estrechar la API; probar size, align y Blocks antes de corregir |
| Q32 | Section Morfo | sectionMorfo declara defaultElement: 'div', pero Eidos monta <section> por defecto y as="footer" monta <footer> |
Discrepancia estática y DOM confirmados; efecto en lectores de Morfo pendiente | Alinear metadato tras comprobar sus consumidores, sin cambiar el DOM ni as |
| Q33 | Section props | SectionProps hereda display y width de Box, pero el wrapper escribe display="block" y width="100%" después de ...restProps; la sonda conservó esos valores con display="flex" y width="50%" explícitos |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Decidir precedencia o estrechar API; cubrir los Blocks consumidores antes de corregir |
| Q34 | Sticky data-stuck |
El único centinela queda fuera del scroll-host al salir por arriba; StickyProvider conserva stuck=true aun cuando el límite inferior de la sección obliga al box a dejar de estar pegado y salir de la vista. |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Caracterizar ambos bordes y scroll-hosts; añadir observación del fin de sección y regresión sin cambiar API. |
| Q35 | SkipLink onclick |
SkipLinkProps hereda onclick de HTMLAnchorAttributes, pero el <a> escribe onclick={jump} después de ...restProps; el callback del consumidor no se invoca. |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Decidir composición o estrechar el tipo; proteger foco, fragmento y callback antes de corregir. |
| Q36 | SkipLink tabindex |
Cuando el destino tiene display:none, jump() le añade tabindex="-1", pero focus() falla y no se dispara el blur que lo quitaría. |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Fijar limpieza tras foco fallido y conservación de un tabindex previo antes de corregir. |
| Q37 | Breadcrumb Ellipsis | El Ellipsis no interactivo monta <span role="presentation" aria-label="…">; WAI-ARIA indica que el atributo global aria-label hace ignorar el rol presentacional. |
DOM confirmado en Vitest client (Chromium), 1/1; efecto en lectores pendiente | Decidir si es decorativo o nombrado; medir árbol accesible en tres motores antes de cambiar el Morfo. |
| Q38 | AnchorNav href |
El wrapper actualiza el href del <a> reactivamente, pero AnchorNavLinkProvider.targetId se calcula sólo en el constructor y conserva el registro anterior. |
Reproducido en Vitest client (Chromium), 1/1; sonda retirada | Decidir estabilidad de la prop o re-registro; probar observación y ref-count de destinos duplicados. |
| Q39 | Pagination pageSize |
Con count=95, page=5 y pageSize=0, totalPages=0 y pages=[], pero pageRange={start:1,end:0} contradice el contrato de rango vacío {0,0}. |
Reproducido en Vitest client (Chromium): sonda fallida y retirada | Decidir contrato de entrada y fijar 0, negativos y transición desde tamaño válido antes de corregir. |
| Q40 | NavTree keys | Los IDs a, a#root/2, a generan las claves a, a#root/2, a#root/2; el sufijo de recuperación choca con un ID declarado y el keyed each aborta. |
Reproducido en Vitest client (Chromium): each_key_duplicate; sonda retirada |
Reservar claves únicas en el árbol completo; probar estado y avisos con colisiones sucesivas. |
| Q41 | TreeView teclado | getVisibleItems() enumera [role="treeitem"], pero el tab stop de rama está en BranchControl sin ese rol; ArrowDown calcula índice -1 y enfoca el contenedor no enfocable. |
Reproducido en Vitest client (Chromium): aserción de foco fallida y retirada | Caracterizar las teclas y el árbol accesible; alinear candidato y foco sin cambiar selección por inferencia. |
| Q42 | TreeView hover | El arquetipo item está en el Branch que contiene control e hijos; su regla transversal de hover pinta el contenedor completo cuando está abierto. |
Medido en el README Eidos (2026-08-21); estructura y CSS ratificados en esta auditoría | Medir estados y tema; mover el arquetipo solo en un lote visual separado con canario de píxeles. |
| Q43 | TreeGrid selección | RowChildren anida las filas en el DOM; TreeGridRowProvider.onclick llama a handleRowClick sin detener la propagación. Un clic en index selecciona después al padre src. |
Reproducido en Vitest client (Chromium): se esperaba index, se obtuvo src; sonda retirada |
Caracterizar clic y teclado de filas anidadas antes de aislar el evento. |
| Q44 | TreeGrid hover | La banda striped tiene mayor especificidad que el hover; fuera de ella, el hover de la receta empata con el velo del arquetipo item y depende del orden de carga. |
Medido en README Eidos (2026-08-20): seis cargas, cuatro sin velo y dos con velo | Medir píxeles en cada estado y fijar precedencia visual con regresión. |
| Q45 | GridList acción | GridListRowProvider.onclick procesa el clic de un botón hijo como clic de fila. En selección múltiple, pulsar Open dentro de alpha reemplazó beta,alpha por alpha. |
Reproducido en Vitest client (Chromium): aserción fallida y retirada | Caracterizar controles internos antes de aislar sus eventos. |
| Q46 | GridList hover | Fila y celda declaran el arquetipo item; el fondo de hover de la receta y el velo del arquetipo se apilan bajo el puntero. |
Medido en README Eidos (2026-08-21) y next-features.md §12 |
Medir capas de píxeles y resolver portadores del hover sin cambiar el checkbox. |
| Q47 | Table acción | TableRowProvider.onclick alterna la selección sin comprobar el origen del evento; pulsar Open dentro de Ada también seleccionó Ada. |
Reproducido en Vitest client (Chromium): aserción fallida y retirada | Caracterizar controles internos y selección por teclado antes de aislar clics. |
| Q48 | Table hoverable | La fila usa el arquetipo item; su velo de hover sigue activo aunque el root omita data-hoverable. |
Medido en README Eidos (2026-08-20), antes de tokenización | Medir el efecto visual y decidir qué capa manda en un lote separado. |
| Q49 | Table pinning RTL | buildColumnStyle escribe offsets físicos left/right; con dir=rtl el borde de una columna fijada se desplazó de 350 a 444 px al hacer scroll horizontal. |
Medido en README Eidos (2026-08-17) a 375 px | Reproducir geometría y semántica start/end en los tres motores antes de cambiar el engine. |
| Q50 | Table tipos | TableProps.table es TableInstance<unknown>; createTable<T> produce TableInstance<T> invariante, por lo que un consumidor tipado necesita cast. |
Discrepancia estática confirmada en tipos y README; compilación de consumidor pendiente | Fijar caso TypeScript real y decidir genéricos en Table y partes sin romper inferencia. |
| Q51 | Table SortButton | El velo de hover del SortTrigger pierde ante background: transparent de la receta, de modo que no hay respuesta visual al hover. |
Documentado en README Eidos; medición visual pendiente en esta auditoría | Medir píxeles en hover/foco/sort antes de cambiar la precedencia. |
| Q52 | VirtualGrid rango RTL | El viewport guarda el.scrollLeft negativo; rangeFor lo usa como offset positivo. Con dir=rtl y scrollLeft=-800, una cuadrícula de 1.000 × 200 celdas quedó sin celdas en el DOM. |
Reproducido en Vitest client (Chromium) y captura inspeccionada; sonda retirada | Fijar coordenadas lógicas por dirección y cubrir rango, overscan, extremos y resize en tres motores. |
| Q53 | VirtualGrid salto RTL | scrollToCell(20,10,{rowAlign:'start',columnAlign:'start'}) manda left=800 en un scroller RTL; el navegador conserva scrollLeft=0, aunque la fila avanza a 480 px. |
Reproducido en Vitest client (Chromium): offset esperado -800, obtenido 0; sonda retirada | Cubrir align por eje, celda visible y evento discreto antes de convertir offset lógico a nativo. |
| Q54 | VirtualGrid claves | ${rowKey}|${columnKey} no es inequívoco: filas a|b,a y columnas c,b|c generan dos claves a|b|c, pese a que cada eje tiene claves únicas. |
Reproducido en provider con Chromium: 3 claves únicas para 4 celdas; render pendiente | Fijar consumidor con keyed each y conservar estabilidad de claves con delimitadores y tipos mixtos. |
| Q55 | ScrollArea thumb | El mínimo CSS de 64px pinta un thumb de 64px; Soma calcula 22,4px sobre un track de 112px. Al final, el borde inferior excede el track en 41,59375px. | Reproducido en Chromium con DOM real y captura inspeccionada; sonda retirada | Fijar geometría efectiva de tamaño, offset y drag por eje sin introducir lecturas de layout por cada scroll. |
| Q56 | ScrollArea style | El root conserva style sólo si es string, aunque el tipo acepta objeto. Un objeto con block-size 120px e inline-size 200px deja altura 0px. | Reproducido en Chromium: altura esperada 120, obtenida 0; sonda retirada | Caracterizar precedencia de estilos de consumidor y props visuales antes de fusionar ambos formatos. |
| Q57 | Splitter enlace ARIA | El separador no emite aria-controls aunque el panel primario tiene ID. | Reproducido en Chromium: atributo null; sonda retirada | Caracterizar identificación de paneles y enlace ARIA sin romper composición ni IDs. |
| Q58 | Splitter eje ARIA | En layout horizontal, el separador físico vertical anuncia aria-orientation horizontal. | Reproducido en Chromium con DOM y captura inspeccionada; sonda retirada | Separar orientación del layout, teclado y geometría ARIA para ambos ejes. |
| Q59 | Splitter restauración | Tras escribir 40/35/25 y colapsar con Enter a 0/75/25, expandir da 25/50/25 (defaultSize), no 40/35/25. | Reproducido en Chromium con teclado nativo; sonda retirada | Fijar historial de tamaño, límites vecinos y cambios externos antes de alterar expansión. |
| Q60 | Knob valor inicial | Con min 20, max 100 y value omitido, aria-valuenow es 0 pese al default min del tipo; ambos wrappers inicializan a cero. | Reproducido en Chromium: valor esperado 20, obtenido 0; sonda retirada | Caracterizar defaults y escrituras controladas antes de ajustar el seed. |
| Q61 | Knob step cero | Con value 20 y step 0, ArrowRight produce NaN y lo publica como aria-valuenow. | Reproducido con teclado nativo en Chromium; sonda retirada | Decidir validación o fallback de step con rangos y callbacks preservados. |
| Q62 | Knob pivote | Gesture.rotate usa el root que incluye Label. Al mover al punto derecho del dial sm, la posición fue 75 en lugar de 85. | Reproducido con DOM real, eventos sintéticos y captura inspeccionada; sonda retirada | Caracterizar composición y gesto nativo antes de mover el pivote a Control. |
| L-110 | Knob foco de Label | El onclick de Label sigue vacío. Pulsar su span deja el foco en body en lugar del Control. | Reproducido con Playwright en Chromium; ya diferido en ledger | Enlazar foco mediante ActiveDom sin alterar disabled ni readonly. |
| Q63 | Gesture cancel | cancel() retorna si isDragging es false aunque pointerdown ya enlazó listeners. Tras down/cancel/move 20px, onDrag se ejecutó una vez. | Reproducido en jsdom con documento aislado y captura mock; sonda retirada | Fijar cancelación durante el buffer y desmontaje con propiedad de listeners explícita. |
| Q64 | Gesture puntero | Dos pointerdown antes del buffer sustituyen pointerId y enlazan listeners dos veces; move del segundo dispara dos callbacks. Tras up, el siguiente gesto también dispara dos. | Ambas consecuencias reproducidas en jsdom; sondas retiradas | Fijar punteros y limpieza en gestos consecutivos; reproducir multi-touch nativo. |
| Q65 | Gesture sequential | drag y rotate borran activeSnapPoint en pointerdown, anulando la restricción de vecinos. Con velocidad cero, drag salta de 100 a 300 y rotate de 90 a 270 con wrap false. | Reproducido en ambos resolvers con jsdom y reloj fijo; sondas retiradas | Decidir snap de referencia; cubrir continuidad, wrap y proyección. Sin consumidor actual de este modo. |
| Q66 | AxialDrag cancel | Tras down/cancel/down/move 20px, onDrag se ejecuta dos veces. cancel limpia flags y captura, pero no document listeners. | Reproducido en jsdom, documento aislado y captura mock; sonda retirada | Fijar cleanup durante el buffer, drag activo y desmontaje sin perder posición asentada. |
| Q67 | AxialDrag puntero | No se guarda el pointerId del down. Move de ID2 arrastra la sesión de ID1; up de ID2 emite onDragEnd y la cierra. | Ambos casos reproducidos en jsdom; sondas retiradas | Fijar identidad y release/cancel de otros IDs; probar multi-touch nativo antes de corregir. |
| Q68 | AxialDrag value01 | Con referenceSize 400, snaps [0.5,1] y activeSnap 0.5, offsetPx devuelve 200 pero value01 devuelve 0 al leer sólo _offsetPx. | Reproducido en jsdom mediante getters públicos; sonda retirada | Caracterizar snaps controlados y progreso; medir su efecto en Drawer antes de corregir. |
| Q69 | ZoomPan mínimo | Con minScale 2/maxScale 5, scale empieza en 1 y tras zoomTo(3)/reset vuelve a 1. Contradice el mínimo declarado, aunque reset documenta explícitamente 1. | Dos sondas jsdom fallan; 19 tests existentes pasan; sondas retiradas | Adjudicar seed/reset y medir Cropper con mínimos personalizados antes de corregir. |
| Q70 | Cropper zoom ARIA | El wrapper da aria-label Zoom al root de Slider, pero el thumb con role slider carece de nombre accesible. | Reproducido con matcher de nombre accesible en Chromium; sonda retirada | Fijar nombre del thumb y traducciones; contrastar APG Slider. |
| Q71 | Cropper límites | Cambiar maxScale de 5 a 2 tras mount deja aria-valuemax en 5; ZoomPan conserva la configuración capturada por el constructor. | Reproducido con prop reactiva y clic nativo en Chromium; sonda retirada | Adjudicar límites actualizados; medir clamp, controles y estados actuales. |
| Q72 | Cropper disabled | A escala 1.2, activar disabled y llegar al reset por Tab/Enter devuelve escala 1. Los controles no reciben disabled y resetZoom no lo comprueba. | Reproducido con teclado nativo en Chromium; sonda retirada | Fijar bloqueo de reset y Slider; preservar exportación programática. |
| Q73 | Cropper puntero | Down ID1 en Selection y move ID2 de 32px desplazan crop.x de 0.25 a 0.35; la sesión no conserva pointerId. | Chromium montado, eventos sintéticos y captura mock; sonda retirada | Cubrir selección, handle y pan; reproducir multi-touch nativo. |
| Q74 | Cropper metadatos | apg afirma keyboard nudge desde C5, pero Selection/Handle no tienen handler de teclado y README lo difiere. El campo de metadatos se conserva. | Discrepancia confirmada por lectura; efecto en consumidores de metadatos sin reproducir | Adjudicar y alinear la justificación; no implementar teclado por inferencia. |
ImagePicker e ImageAdjustments: Q75–Q78
| ID | Área | Hallazgo | Evidencia | Cierre pendiente |
|---|---|---|---|---|
| Q75 | ImagePicker payload | La selección emite file nuevo con url null; remove emite file null con la URL anterior. El efecto de URL se ejecuta después del callback. | Dos sondas Chromium con PNG y URLs reales fallan. | Fijar correspondencia y timing de callbacks, reemplazo y cleanup. |
| Q76 | ImagePicker onChange | ArrowUp cambia brillo y preview, pero conserva una sola emisión de selección. Cambiar fit externamente a contain tampoco emite. | Dos sondas con teclado/clic nativos fallan. | Adjudicar y cubrir el contrato que promete full value whenever anything changes. |
| Q77 | ImageAdjustments ARIA | Los ocho thumbs tienen nombre accesible vacío; aria-label del root compuesto no nombra el thumb. | Ocho sondas Chromium del panel real reciben vacío; brillo embebido ya estaba reproducido. | Cubrir nombres de todos los thumbs, traducciones y teclado. |
| Q78 | ImagePicker / FileUpload | La transición empty→ready desmonta FileUpload antes de emitir commit-set-add; el runtime informa destino provider ausente y omite señal perceptual. | Sonda captura el diagnóstico del logger real tras upload nativo; selección y preview funcionan. | Conservar el destino semántico y el handler durante selección/desmontaje. |
Las seis sondas fallaron mientras pasaban 21 tests de caracterización en tres archivos. Se montaron ActiveUix, Soma y ActiveEidos reales; el PNG se creó por canvas y se seleccionó mediante la API Playwright de input files. No se automatiza el diálogo de archivos del sistema operativo. Los spies de console observan la ejecución original del logger, sin sustituirlo. Se retiraron las sondas al terminar, sin corregir estos comportamientos.
Q75: tras cargar el PNG, el img tiene blob URL pero la última emisión todavía tiene url null. Después de pulsar Remove, file es null y url mantiene el blob previo, que el efecto revoca al actualizarse. Q76: tras selección hay una llamada onChange; ArrowUp en brillo pone brightness=1 y el filtro brightness(1.01), pero sigue habiendo una llamada. Un botón que cambia el binding fit a contain reproduce la misma ausencia. Q77: el matcher de nombre del thumb de brillo recibe vacío. Es un uso distinto de la misma pauta que Q70, en ImageAdjustments, no un defecto nuevo adjudicado al motor Slider por inferencia. La auditoría propia del panel amplía la reproducción a brightness, contrast, saturation, temperature, hue, blur, grayscale y sepia: ocho sondas fallan mientras pasan 22 tests de caracterización en dos archivos. Se montan servicios UIX reales y las sondas se retiran al terminar. Q77 conserva su ID y sigue abierto. Q78: 100ms después de la selección, console recibe el mensaje del runtime file-upload.commit-set-add found no DOM element for target part provider. El flujo sigue en ready y el handler corre; se pierde la señal, no la carga de imagen. La reproducción no mide sonido físico ni vibración.
Después de sustituir la conexión repetida del wrapper por bindProps, las cuatro sondas de Q75/Q76 vuelven a fallar con los mismos resultados mientras pasan los cuatro canarios Eidos. El helper no modifica esos comportamientos; las sondas de contraste se retiraron al terminar.
Reproducción de Q70–Q73 y L-152 en Cropper
Cinco sondas montaron Cropper Eidos en Chromium con ActiveUix, Soma y ActiveEidos reales, imagen PNG local de 200×100 y viewport 320×160. Pasaron 19 tests existentes mientras fallaron las cinco expectativas. Se retiraron las sondas; no se modificaron estos comportamientos.
Q70: el matcher de nombre accesible del thumb con role slider recibió nombre vacío en vez de Zoom; aria-label sólo aparece en el root compuesto. La referencia de cierre es APG Slider y el contrato thumbLabels de Soma. Q71: un botón cambia maxScale de 5 a 2 después del montaje; aria-valuemax del thumb sigue siendo 5. El constructor de Cropper copió los límites a ZoomPan una vez; el test no adjudica aún el mínimo ni clamps de transición.
Q72: pulsar + lleva la escala a 1.2. Activar disabled, partir de un botón previo al root y usar Tab llega a los controles, incluido reset. Enter en reset lleva aria-valuenow a 1 en vez de conservar 1.2. El puntero bloqueado por CSS no impide la activación mediante teclado; resetZoom omite el guard. Q73: down ID1 (100,100) y move ID2 (132,100) sobre Selection cambian crop.x de 0.25 a 0.35. Se termina con pointercancel ID1. Sólo la captura DOM está mockeada, no servicios UIX. No se acredita multi-touch nativo ni se da por reproducida la identidad de Handle/Viewport por similitud textual.
L-152: la sonda experimental con bind:ref quedó null, pero el gate posterior detectó que ref no es bindable en el wrapper Eidos. Ese enlace se retiró del harness: no es evidencia de fallo usando una API válida. Se conserva el ID existente como limitación de reenvío de bindables, confirmada por tipos, sin crear un duplicado ni cambiar su estado oficial en el ledger.
Q74: la justificación apg del Morfo afirma keyboard nudge; no hay binding ni handler de teclado en Selection o Handle, y el README lo difiere. Es una discrepancia de metadatos por lectura, no otro fallo de interacción reproducido. Se preserva el campo hasta adjudicar su corrección.
Reproducción de Q69
Crear ZoomPan con minScale 2 y maxScale 5 produce scale 1. En una segunda sonda, fijar viewport 200×100, ejecutar zoomTo(3) y reset también produce scale 1. Ambas expectativas de scale >= minScale fallan, mientras pasan 19 tests existentes de Cropper, incluidos cinco de la capa. Las sondas se retiraron y el comportamiento se conserva.
El mínimo declarado y la vuelta explícita a escala 1 en reset tienen contratos contradictorios; decidir semilla y reset es parte del lote posauditoría. No se infiere todavía un fallo visual de Cropper con minScale personalizado ni se cambia el mínimo efectivo de sus controles.
Reproducción de Q66–Q68
Cuatro sondas usaron AxialDrag con ActiveDom real, documento jsdom aislado por caso y captura mock. Q66: down de puntero 1 con buffer 5px, cancel(), otro down y move a 20px ejecutaron onDrag dos veces; el primer juego de listeners sigue enlazado y comparte el estado activo del siguiente gesto. Q67: down de ID1 y move de ID2 a 20px dispararon onDrag una vez; otra sonda inició drag con ID1 y up de ID2 disparó onDragEnd una vez, finalizando la sesión equivocada. El estado sólo guarda el ID capturado tras movimiento, no la identidad de seguimiento del down.
Q68: sin iniciar gesto, referencia 400, snaps [0.5,1] y activeSnap externo 0.5 produjeron offsetPx 200 y value01 0 en vez de 0.5. El primero lee snap externo; el segundo usa _offsetPx local. Drawer consume ambos, pero estas sondas de capa no acreditan su efecto visual en el componente.
Fallaron cuatro sondas y pasaron ocho pruebas existentes de AxialDrag y Drawer. Se retiraron las sondas; los defectos se conservan. Un canario separado verifica arrastre de ratón y captura nativos en Chromium para el camino normal. No reproduce todavía los casos multi-touch de Q67.
Reproducción de Q63–Q65
Cinco sondas ejecutaron Gesture con un documento jsdom aislado por caso, ActiveDom real y captura de puntero mock. Q63: down de puntero 1 con buffer 5px, cancel() y move a 20px ejecutaron onDrag una vez; cancel no cerró la sesión pendiente. Q64: down de 1 y down de 2 antes del buffer, seguido de move de 2 a 20px, ejecutaron onDrag dos veces. Tras up de 2, down de 3 y move a 20px volvieron a ejecutar dos callbacks; quedó un juego de listeners anterior. ActiveDom.dispose no limpia estos listeners por el gesto.
Q65 se midió con performance.now fijo en cero, eliminando velocidad y proyección. Drag right de ancho 400px, snaps [100,200,300] y sequential true asentó 100; el siguiente down/move/up a 300 asentó 300 en lugar del vecino de 200px. Rotate con centro (200,200), snaps [0,90,180,270], sequential true y wrap false asentó 90; el siguiente gesto al punto izquierdo asentó 270 en lugar de 180. Ambos pointerdown borran activeSnapPoint antes del resolver. Los consumidores actuales de Gesture no configuran snaps secuenciales; Drawer con snaps usa AxialDrag y no se adjudica a ese camino el defecto.
Fallaron las cinco sondas y pasaron los 65 tests existentes. Se retiraron las sondas y se conservaron estos comportamientos. La evidencia no valida captura ni multi-touch nativos; las pruebas de cierre deben añadirlos.
Reproducción de Q60–Q62 y L-110
Cuatro sondas temporales montaron Knob Eidos en Chromium. Con min 20, max 100 y value omitido, aria-valuenow fue 0, frente al default min del tipo (Q60). Con value 20 y step 0, ArrowRight publicó aria-valuenow NaN (Q61). Para Q62, el dial de talla sm tenía Label compuesto. Pointerdown cerca del centro superior del dial y pointermove al punto situado dos píxeles antes de su borde derecho, a la altura de su centro, produjeron 75 en lugar de 85 para min 0, max 100, step 5 y sweep -135..135. El pivote de Gesture.rotate se mide sobre el root completo, incluido Label: su centro vertical fue 57,25 px. Los eventos de esta sonda fueron sintéticos, con cajas DOM reales; no se validó captura de puntero. Se inspeccionó la captura del indicador tras el gesto. La cuarta sonda pulsó Label con Playwright y obtuvo document.body como elemento enfocado, en lugar de Control (L-110). Fallaron las cuatro mientras pasaron trece pruebas válidas. Se retiraron las sondas; esos comportamientos se preservan.
Reproducción de Q57–Q59
Tres sondas temporales montaron Splitter Eidos con paneles 25/50/25 y
dos separadores. El primero no emitió aria-controls, pese a que el panel
tenía un ID real (Q57). En layout horizontal, su caja es vertical y
aria-orientation emitió horizontal (Q58); la captura se inspeccionó.
Para Q59, una escritura externa fijó 40/35/25. Enter colapsó a 0/75/25 y
un segundo Enter produjo 25/50/25, en lugar de 40/35/25. Las tres sondas
fallaron mientras las seis pruebas normales pasaron. Se retiraron las
sondas; no se cambió runtime. Son discrepancias frente al patrón APG,
que advierte que la revisión de su ejemplo aún está pendiente; no se
presentan como resultados de una prueba con lector de pantalla.
Reproducción de Q55–Q56
La primera sonda montó ScrollArea Eidos de 200 × 120 px con contenido
600 × 600 px y ambas barras. Tras medir overflow, aplicó
--scroll-area-thumb-min-size:64px y desplazó el viewport a scrollTop=480.
El track vertical midió 112 px; el thumb mantuvo height inline de 22,4 px,
pero su caja pintada midió 64 px y excedió el final de la barra en
41,59375 px. La captura mostró el recorte del thumb en el borde de la raíz.
La segunda sonda pasó las mismas dimensiones como objeto style: la raíz
midió 0 px de alto. Fallaron ambas aserciones y pasaron las otras cinco
pruebas. Las sondas se retiraron; canario permanente y suite del provider
volvieron a pasar 5/5. No se alteró pintura, fusión de estilos ni cálculo.
Reproducción de Q52–Q54
Dos sondas temporales montaron el mismo harness Eidos en Chromium. Tras
la medición inicial, desplazar el viewport RTL a scrollLeft=-800 produjo
0 celdas; la captura confirmó el viewport en blanco. En un montaje nuevo,
scrollToCell(20,10,{rowAlign:'start',columnAlign:'start'}) llevó
scrollTop a 480 px, pero scrollLeft permaneció en 0. La tercera sonda
creó un provider de 2 × 2 con claves únicas por eje y obtuvo
a|b|c, a|b|b|c, a|c, a|b|c; falló la aserción de cuatro claves
únicas. No se montó un consumidor con esas claves: su posible aborto de
render queda por reproducir. Las tres sondas se retiraron, el runtime
permanece intacto y el canario permanente conserva la cobertura válida de
LTR y del anclaje inicial RTL.
Reproducción de Q47 y evidencia de Q48–Q51
El canario temporal montó Table Eidos con selección múltiple, dejó Ada sin
seleccionar y pulsó el botón Open de su celda. La acción se ejecutó y
aria-selected de Ada cambió a true. La aserción fallida se retiró;
la prueba permanente comprueba render, sort, selección, detalle y la acción
por separado. El README Eidos conserva mediciones anteriores para Q48 y Q49,
describe la discrepancia de tipos Q50 y señala la falta de feedback visual
Q51. No se cambió ningún handler, tipo público ni estilo.
Reproducción de Q45 y evidencia de Q46 y L-027
El canario temporal montó GridList Eidos con selección múltiple, marcó
beta y alpha, y pulsó el botón Open dentro de alpha. El contador de
acciones llegó a 1, pero el valor enlazado cambió de beta,alpha a alpha.
La aserción fallida se retiró; el canario permanente verifica la acción y
la selección por fila y checkbox por separado. El README Eidos conserva la
medición anterior de doble hover, y el ledger mantiene L-027 diferido.
No se modificó el handler ni la receta visual.
Reproducción de Q43 y evidencia de Q44
El canario temporal montó TreeGrid Eidos con src expandido e index dentro de
RowChildren. Tras pulsar la fila index, el valor enlazado terminó en src,
no en index: el handler del padre procesa el mismo clic después del hijo.
La aserción fallida se retiró del test permanente, que cubre expansión,
estructura y selección de una fila hermana. El README Eidos conserva las
mediciones anteriores de hover para Q44; esta pasada no repitió la captura de
píxeles. No se cambió ningún handler ni estilo.
Reproducción de Q41 y evidencia de Q42
Un canario temporal montó TreeView Eidos con una rama src abierta y una
hoja index. Después de enfocar BranchControl, ArrowDown dejó
document.activeElement en ese control, en vez de moverlo a la hoja. La
aserción fallida se retiró; la prueba permanente de expansión, selección y
tamaño pasó junto con los cuatro tests Soma (5/5). El mismo DOM coloca
data-archetype="item" en el Branch que envuelve la fila y sus hijos;
el README Eidos conserva la medición visual previa del velo extendido.
No se modificó la navegación ni la receta.
Reproducción de Q40
Una sonda temporal montó NavTree Eidos real con tres nodos cuyos IDs eran
a, a#root/2 y a. El provider avisó del duplicado a, pero la clave
derivada del tercer nodo ya pertenecía al segundo; Svelte lanzó
each_key_duplicate para los índices 1 y 2. Se retiró la sonda y la
prueba permanente de navegación pasó 1/1. No se cambió el algoritmo.
Reproducción de Q39
Una sonda temporal en el test del provider asignó pageSize=0 con 95
elementos. Las aserciones de totalPages=0 y pages=[] pasaron; la de
pageRange={start:0,end:0} falló al recibir {start:1,end:0}. Se retiró
la sonda y la suite normal de Soma y Eidos pasó 4/4. No se ha decidido si
el cero debe rechazarse, normalizarse o producir un rango vacío.
Reproducción de Q38
Una sonda temporal creó el provider y un Link con href='#intro', cambió
la fuente reactiva a '#usage' y dejó que Svelte actualizara. El
targetId y activeId siguieron en intro, aunque el wrapper lee el
href actual al construir las props del <a>. Pasaron la sonda y los
dos tests existentes de IO (3/3); se retiró la sonda. La divergencia
entre atributo y destino observado requiere caracterizar el consumidor
completo antes de elegir si se prohíbe el cambio o se re-registra.
Reproducción de Q37
La prueba permanente de Breadcrumb montó el Ellipsis decorativo real en
Chromium y confirmó role="presentation" junto a aria-label, mientras el
botón interactivo conservó type="button" y aria-haspopup="menu".
Pasaron 4/4 tests de Eidos/Soma. La guía WAI-ARIA sobre ocultar semántica
establece que los navegadores ignoran role="presentation" cuando el
elemento tiene una propiedad ARIA global como aria-label. Queda por medir
el árbol accesible real y decidir cuál de las dos semánticas pretende UIX;
no se cambió el Morfo ni el render.
Reproducción de Q35 y Q36
Dos sondas temporales montaron el SkipLink real en Chromium. Al hacer clic
con un onclick de consumidor, el foco pasó al <main> pero el callback
registró cero llamadas (Q35). Un segundo enlace apuntó a un <main> con
display:none: el foco no llegó a ese nodo y el tabindex="-1" que el
wrapper acababa de añadir siguió presente (Q36). Pasaron ambas sondas y
la prueba normal de foco (3/3); después se retiraron las sondas. La prueba
permanente cubre el camino visible, su geometría enfocada en Chromium y la
retirada del tabindex después del blur. No se cambió el handler.
Reproducción de Q34
Una sonda temporal en el test cliente real de Sticky montó un scroll-host
de 200 px, una sección de 280 px con centinela y box sticky, y contenido
posterior. Con offset=12, al desplazar 100 px el box estaba pegado y
result.stuck era true. Tras desplazar 400 px, el límite inferior de
la sección y el box estaban fuera de la vista (getBoundingClientRect().bottom < 0 para ambos), pero result.stuck seguía en true después de esperar
al observador. Pasaron la sonda y el test existente (2/2); se retiró la
sonda. La referencia de Chrome usa un segundo centinela para detectar la
salida de la sección. No se modificó el runtime ni se infirió la solución
para edge=bottom sin prueba.
Reproducción de Q32 y Q33
La sonda temporal montó Section con size="sm", containerSize="sm",
decor="glow", display="flex" y width="50%" en Chromium, junto a un
Section as="footer". El primero produjo un <section> con Container,
Background.Pattern y Section.Header interiores, padding superior de 32 px,
display: block y --box-width: 100%; el segundo produjo <footer>.
Pasó 1/1 antes y después de corregir sólo documentación, y se retiró.
No se alteró el runtime ni se infirió cómo usan defaultElement sus
consumidores.
Reproducción de Q31
Una sonda temporal cargó eidos/index.css y montó Container en un padre
de 1000 px. Con size="sm", maxWidth={320} y width="50%", la medida
computada permaneció en 480 px; marginLeft={24} y marginX={24} tampoco
desplazaron los márgenes que fijó align. La misma sonda confirmó el root
as="section", el padding por token y su override con paddingX={0},
size="full" sin límite de ancho y container-type: inline-size. Pasó
1/1 y se retiró. La decisión de compatibilidad queda para el lote de
defectos posterior a la auditoría.
Reproducción de Q30
Una sonda temporal cargó eidos/index.css y montó dos Group grow de
200 px con hijos Box de 30 y 50 px. En fila, ambos hijos acabaron con el
mismo ancho; en columna conservaron anchos diferentes. La misma sonda
comprobó el wrap por defecto, attached en ambos ejes e inline-flex;
pasó 2/2 y se retiró. El tipo permite direction="column", y su JSDoc
describe grow como igualación de ancho. La corrección exige decidir si
esa promesa se mantiene para columna o se acota a fila; ButtonGroup
vertical también compone Group y debe cubrirse en el lote posauditoría.
Reproducción de Q29
Una sonda temporal montó <Stack width="200px" align="start" alignContent="end"> con un hijo Box de 20 px. Chromium computó
flex-wrap: nowrap y align-content: end, pero el hijo permaneció en el
inicio del eje transversal; la prueba pasó 1/1 y se retiró. La propiedad
CSS no tiene efecto en contenedores flex de una sola línea, según
MDN.
Esto confirma una prop pública inerte en el uso normal de Stack; no se
ha decidido retirar la prop heredada ni exponer wrap, porque ambos
cambian el contrato.
Reproducción de Q28
Una sonda temporal de Vitest client montó cuatro Box absolutos con width={20}
y left={10} o right={10} dentro de contenedores de 200 px en LTR y RTL,
cargando eidos/index.css. En LTR, ambos quedaron a 10 px del borde físico
solicitado. En RTL, ambos quedaron a 170 px de ese borde. Las dos aserciones
RTL fallaron, y la sonda se retiró sin modificar la receta. Antes de corregir,
hay que fijar si esos nombres garantizan lados físicos o si la API quiere
propiedades lógicas con otros nombres; también probar inset, insetX y
insetY para evitar regresiones.
Reproducción de Q18–Q19
Una sonda temporal de Vitest client montó Highlight sin importar Mark, con el
CSS base de Eidos. <Highlight text="A B" query=" " /> produjo un <mark>.
Otra instancia con query="world" mostró fondo nativo amarillo
rgb(255, 255, 0) y padding-inline-start: 0px. La primera aserción de la
sonda esperaba fondo transparente y falló; se corrigió para fijar la salida
observada, pasó 1/1 y se retiró. No se modificó el runtime.
Reproducción de Q14–Q16
Una sonda temporal de Vitest client montó un Avatar con Avatar.Image
(src explícito) y Avatar.Fallback delayMs={10000}. Durante loading, el
fallback ya estaba en el DOM. Al despachar load en el <img>, el callback
onImageStatusChange del root recibió loaded y el de Avatar.Image no
recibió nada. El root no tenía demora propia: esto aísla la prop de la part.
En el mismo harness, <Image src="/audit-image.png" alt="Audit"><Image.Img /></Image> montó un <img> sin atributo src y con alt="". El provider
conservaba data-status="loading"; la part no había heredado los atributos
nativos que su tipo y README prometen. Un tercer caso usó la ruta abreviada
con fallback="Loading image": tras despachar error, el fallback desapareció
y [data-image-error] quedó sin texto. La sonda pasó 1/1 afirmando esas salidas
observadas y se retiró; no se modificó el runtime. La primera versión de la
sonda esperaba que Image.Img no se montara, hipótesis refutada: el nodo sí
existe, pero carece de src.
Reproducción de Q11
La prueba permanente de paridad geométrica pasó 12/12 casos: cuatro textos a
dos anchos en Chromium, Firefox y WebKit. El harness temporal de carga tardía
usó FontFace con la Lora local, midió primero con fallback y luego añadió la
fuente. En WebKit, un ancho de 124 px dio 4 líneas antes y 5 tras cargarla;
después de invalidar la familia, el motor siguió contando 4 en varias
ejecuciones. Esperar un frame y 150 ms no bastó; otra ejecución con una
medición canvas adicional antes de la carga pasó. El harness no montó SText
ni reprodujo el evento loadingdone, por lo que la causa sigue abierta. Se
retiró la prueba temporal para no dejar el gate rojo y no se cambió el runtime.
La prueba posterior monta <SText> con @font-face CSS, escucha el evento
loadingdone de su familia y lee bind:lineCount. A 124 px, Lora cambió el
DOM de 4 a 6 líneas y el binding acabó en 6 en Chromium, Firefox y WebKit
(3/3). Así, la discrepancia del harness parcial no se reproduce en el flujo
real del componente. La prueba queda como regresión; Q11 no autoriza un cambio
del algoritmo ni del hook sin un fallo reproducible en un consumidor real.
Reproducción de Q01-a y Q01-b
Dos pruebas temporales en Vitest client (Chromium) reprodujeron los riesgos de
ActiveUix. Para Q01-a, announce('old', 'polite', 25) seguido de
announce('new', 'polite', 0) dejó la región vacía al avanzar 25 ms: el timer
del primer anuncio borró el segundo. Para Q01-b, se hizo attach a un mismo
ActiveApp, se destruyó la primera instancia y se hizo otro attach. Al
invocar el canal announce del motor compartido, el spy de la primera
instancia recibió el mensaje y el de la segunda no recibió ninguno.
Las pruebas temporales se retiraron para no dejar la suite roja. No se cambió el runtime: corregir cualquiera de los dos casos altera el comportamiento de anuncios y pertenece a un lote de defectos distinto de las extracciones neutrales autorizadas.
Reproducción de Q01-c y cobertura de L-155 (2026-09-23)
Una prueba temporal de Vitest client (Chromium) adjuntó ActiveUix a un
ActiveApp, llamó a announce('First root', 'polite', 10_000) y comprobó que
app.timers contenía uix:announce:polite. Tras uix.dispose(), la aserción
de que la clave hubiera desaparecido falló: el temporizador seguía pendiente.
La prueba temporal se retiró y no se cambió el runtime. Este resultado fija la
deuda de limpieza de attach; no demuestra que el callback borre un nodo de otra
instancia, ya que conserva la referencia al nodo anterior.
La cobertura permanente de L-155 ahora comprueba attach con anuncio por defecto
en el sink compartido, el opt-out de defineUixServices y el opt-in del motor
Sema desnudo. La suite dirigida pasó de 101/101 a 104/104 pruebas.
Reproducción de Q05
Una prueba temporal de Vitest client (Chromium) creó ActiveUix con
prefs.storage: false, dom: false y una ruta inválida en
events.overrides.runtime. Se sustituyó matchMedia para contar los listeners
del watcher de preferencias. El arranque lanzó como se esperaba, pero había
registrado dos listeners change y no retiró ninguno (1 prueba fallida,
32 omitidas por filtro). Tras retirar la prueba, la suite ActiveUix pasó
32/32. Esto confirma la falta de rollback en ese camino de error.
Otra prueba temporal creó un iframe con <html dir="rtl"> mientras el documento
global tenía dir="ltr"; pasó frame.contentWindow como dom.targetWindow y
desactivó la proyección. La preferencia direction inicial fue ltr en vez de
rtl (1 prueba fallida, 32 omitidas por filtro). La suite ActiveUix volvió a
pasar 32/32 al retirar esta prueba. No se ha comprobado todavía una diferencia
de matchMedia ni de idiomas entre ventanas; la divergencia de dirección sí
demuestra que el bootstrap lee el documento ajeno al destino configurado.
Reproducción de L-126
En este checkout, dos pruebas temporales de Vitest server crearon dos raíces
createActiveEidos con el mismo ActiveDom, document.head y los mismos IDs de
estilo. Después de construir la segunda raíz, first.dispose() eliminó
#uix-eidos-static y dejó data-theme sin valor, aunque second seguía vivo.
Ambas pruebas fallaron por separado. Se retiraron del árbol para conservar la
suite verde: la corrección cambiaría la semántica de ownership del runtime y
requiere un lote de defecto autorizado expresamente. La suite Eidos existente
volvió a ejecutarse después de retirar las pruebas temporales.
Reproducción de L-153
Una prueba temporal pasó al resolver una señal emerge con
channels: ['haptic'] y overrides: { haptic: { intensity: 0.5 } }.
resolveSignature() devolvió la firma parcial { intensity: 0.5 }. Al
entregarla a HapticChannel.handle(), la promesa rechazó con
TypeError: Cannot read properties of undefined (reading 'pattern') en
kindToPattern(), antes de llegar a la defensa de valores numéricos S-31.
El resultado fue 1 test fallido y 30 pasados en resolver.test.ts.
Se retiró la prueba temporal y las dos suites dirigidas del resolver y el
canal háptico volvieron a pasar (43/43). No se ha elegido aún si una firma
incompleta debe rechazarse, silenciarse o completarse; esa decisión cambia
el contrato y queda separada de las extracciones neutrales.
Reproducción de L-140
Un harness temporal montó el Select real con value={['a']}, un item
value="a" label="Alpha" dentro del Content cerrado y un Select.Value
sin children. Antes de abrir el portal, [data-select-value] mostró a en
vez de Alpha (1 prueba fallida en Vitest client, Chromium). Se retiró el
harness y la suite existente del provider pasó 13/13. La variante con
children personalizados en Select.Value no se ha reproducido todavía; no
se ha cambiado el comportamiento de selección ni el registro de etiquetas.
Herramientas y mantenimiento
| ID | Área | Evidencia de código | Disposición propuesta |
|---|---|---|---|
| Q03 | Gate de tipos | check-gate.ts pedía salida humana mientras parseaba marcadores machine |
Corregido: solicita salida machine; check:gate pasó dos veces con el ledger existente |
| Q04 | ActiveUix | Attach distingue motores prestados y fallbacks propios; la cabecera y los tests ya reflejan ambos casos | No extraer una vista común sin ahorro probado: podría volver eager los servicios de ActiveApp |
| L-157–L-159 | Guards de texto | Varias defensas dependen de cómo se parte una línea, se cita una cadena o se declara un tipo | Migrar sólo invariantes que lo requieran a AST, con corpus contado y mutaciones negativas |
| Comentarios largos | ActiveUix/Sema | La historia de decisiones ocupa una parte notable de coordinadores críticos y mezcla invariantes activos con episodios pasados | Mover historia a documentos de proceso cuando se toque una zona; conservar junto al código sólo contrato y razón vigente |
Candidatos que no son defectos
Esta tabla conserva las condiciones de entrada de la auditoría. Los pilotos
de repetidor, dimensiones de pickers y serialización de longitudes ya se
ejecutaron en astra; sus resultados y pruebas figuran en el plan. Las demás
filas siguen pendientes de una comparación específica antes de extraer código.
| Área | Repetición observada | Condición de entrada |
|---|---|---|
| CssField/NumberField | SpinPressRepeater + factory son 65 líneas idénticas por provider |
CssField no importa sus trigger providers; faltan pulsación sostenida, cancelación, salida y disabled |
| Tres pickers Eidos | Resolución visual, dimensiones y composición Popover/PickerShell idénticas | Faltan pruebas directas de wrappers Eidos y de SSR/estilo compuesto |
Longitudes en Content Eidos |
Cinco overlays y cuatro pickers comparten bloques exactos de serializeLength y dimensionVar, con dos políticas de cero |
formatLayoutLength no es equivalente; hace falta una matriz de caracterización antes de una ayuda pura |
| Longitudes de overlays Eidos | Las 30 variables llamaban serializeLength antes de que dimensionVar la volviera a llamar |
Resuelto en astra: se retiró la primera llamada; matriz CSS, contratos Eidos y tipos pasaron |
| ContextMenu/DropdownMenu Morfo | 216 líneas normalizadas coinciden; difieren Trigger, teclado, retorno de foco y dirección | No hay comparación compilada de esas diferencias; un factory puede ocultarlas o romper tipos literales |
| Dialog/AlertDialog Eidos | Parte del content visual se solapa | Focus, role, descripción y acciones siguen siendo contratos separados |
| Calendar/RangeCalendar | Ya comparten CalendarNav y gridWalk |
Límites de vista, título y selección de rango tienen contratos distintos; no procede más extracción |
| ActiveUix standalone/attach | Adquisición y lectura de servicios repetidas | Los modos tienen ownership, preboot y pereza diferentes |
| Blocks compuestos | Sólo coincide el ensamblado de namespace de article-grid y feature-split |
Es superficie de API tipada, no lógica; un constructor genérico ocultaría exports y ahorraría poco |
| VirtualList/VirtualGrid Eidos | Root y CSS de cromo casi idénticos al sustituir identidad y tokens; rangos Soma diferentes | Q52–Q53 bloquean paridad RTL; hooks/forwards nuevos requieren ahorro probado y tests de ambas familias. |
La regla es deliberada: un defecto se corrige en su propio lote con una prueba que lo reproduzca; una duplicación sólo se extrae cuando puede demostrar que conserva el resultado actual. Ninguno de estos apuntes autoriza cambios de comportamiento.
T01 — presupuesto del canario ZoomPan (infraestructura de pruebas)
Fecha: 2026-09-26. El gate termina con 504 archivos/5583 tests aprobados y un archivo/test fallido. El último click en Reset del canario ZoomPan recibe Timeout 107ms exceeded tras los pasos de ancla/pan y dos capturas, dentro de un presupuesto de 30s. No falló una aserción numérica ni se adjudica una regresión del motor por ese diagnóstico.
La recogida de capturas pasa a ser opt-in mediante VITE_UIX_AUDIT_SCREENSHOTS=1. La prueba normal mantiene todos sus clicks nativos y aserciones con 30s; no se usa force ni un timeout mayor. Cierre: dirigido con capturas, inspección de ambas imágenes y gate completo sin capturas de este canario. Validación final: 12/12 tests dirigidos con capturas, ambas inspeccionadas; gate completo 505/505 archivos y 5584/5584 tests. T01 queda cerrado. Es deuda de pruebas separada de la cola funcional; no permite dar por cerrado Q69 ni otro defecto del sistema.
T02 — escala de las capturas de auditoría (infraestructura de pruebas)
Fecha: 2026-09-27. El panel mide 392px en su DOM y body/section tienen zoom=1, pero el iframe de Vitest mide 156.88px frente a sus 414px CSS. Las capturas guardadas tenían 158px de ancho. La sonda que exige proporción 1 falla; no demuestra que la receta reduzca el componente.
Con sólo browser.ui=false el iframe pasa a 332.68px: la sonda sigue fallando mientras pasan 18 canarios funcionales. El contexto Playwright exterior de 1280×1400 mantiene la escala 1: la configuración temporal pasa 19/19 tests en cinco archivos. La configuración mantenida scripts/audit-visual.config.ts repite 19/19, reutilizando plugins, aliases, descubrimiento y browsers normales. Se inspeccionan ocho capturas nuevas de ZoomPan, Cropper, ImagePicker y ImageAdjustments. Se retira la sonda y los artefactos de fallo se conservan en tmp.
El gate previo de ImageAdjustments pasa 506 archivos/5594 tests. El gate con la herramienta mantenida repite 506/506 archivos y 5594/5594 tests: tipos de src/scripts sin errores, 893 documentos sin incidencias y smoke apps/base 27/27. T02 queda cerrado como infraestructura visual, separada de la cola funcional; no cierra Q69–Q78.