24 KiB
L03.2 — Normalización y coherencia de búsquedas (V07)
Fecha: 24 de octubre de 2026. Referencias: L01, L03.1, L02.2, L02.3, listados y Playwright MCP.
1. Resumen y alcance
Las comparaciones de búsquedas locales comparten un contrato: ignorar caja y acentos vocálicos ordinarios, reconocer Unicode equivalente y recortar espacios exteriores. Conservan ñ, puntuación, texto mostrado, datos almacenados y campos de cada consumidor. No cambia la ordenación con Intl.Collator ni el contexto de L03.1.
Se extrae y generaliza el criterio existente del selector de columnas de L02.2, acotando la transformación de marcas a vocales latinas. No se mantiene una segunda implementación. No se cambia backend, SQL, autenticación, rutas, estilos, vendor o dependencias. La adopción de código no acredita validación visual de todas las configuraciones.
2. Inventario previo de mecanismos
A: filtro explícito del módulo; B: global local de TanStack Table; C: selector local; D: búsqueda delegada; E: buscador de destinos del workspace. Inventario mediante código; las comprobaciones de navegador se documentan por separado.
| Tipo / consumidor | Campos conservados | Normalización anterior | Estado de consulta y vacío |
|---|---|---|---|
| A · AssetList | Nombre, plantilla de la especificación, sede y estado traducido | Minúsculas/includes, trim; sin tildes | q/template URL o búsqueda del picker; vacío de consulta EntityTable. |
| A · Recursos | Nombre y plantilla concatenados | Minúsculas/includes, sin trim ni tildes | q/template URL, selección pathname; vacío de consulta. |
| A · Personas | Nombre exclusivamente | Minúsculas/includes, trim; sin tildes | q/contactsOnly URL o fallback embebido L03.1; vacío de consulta. |
| A · Catálogos assets/resources | Nombre de definición dentro de su pestaña | Minúsculas/includes, sin trim ni tildes | q/tab URL; vacío de consulta. |
| B · Directorio de compañías | Nombre en la tabla inicial; segundo listado recibe datos filtrados | includesString, trim; sin tildes | q/filtros URL; no busca inventarios de compañías. |
| A · Puestos | Nombre, responsable y sede | Minúsculas/includes, trim; sin tildes | Local; no se migra navegación a L03.1. |
| A · Perfiles | Nombre, persona y activo | Minúsculas/includes, trim; sin tildes | q/archived URL y vacío existente. |
| A · Accesos | accessLabel existente según tipo y referencias | Minúsculas/includes, trim; sin tildes | q/tipo/entorno/recurso; restricciones intactas. |
| A · Aplicaciones, impresoras y certificados de perfil | Recurso y etiqueta del perfil, persona y activo | Minúsculas/includes, trim; sin tildes | Local, restricción por perfil y vacío existentes. |
| A · Correo de perfil | Dirección y etiqueta del destino | Minúsculas/includes, trim; sin tildes | Local, restricción por perfil. |
| A · Accesos remotos | Persona, extremos y método/protocolo | Minúsculas/includes, trim; sin tildes | Local, persona/cerradas y vacío intactos. |
| A · Teletrabajo | Persona | Minúsculas/includes, trim; sin tildes | Local, restricción por persona. |
| A · Procesos | Nombre, persona y tipo traducido | Minúsculas/includes, trim; sin tildes | q/closed URL; tareas intactas. |
| A · Carpetas de perfil | Ruta, perfil y nombre de carpeta/necesidad | Minúsculas/includes, trim; sin tildes | Local; conserva barras/UNC y ámbito de perfil. |
| A · Software instalado | Nombre del recurso y versión | Minúsculas por idioma/includes, sin trim ni tildes | Local, activo y cerradas intactos. |
| B · Marcas | Columnas elegibles existentes con value: nombre y origen; elegibilidad nativa de booleanos | includesString, trim; sin tildes | Local y filtro de estado del módulo. |
| B · Sedes | Nombre, estado traducido, dirección y teléfono según value | includesString, trim; sin tildes | Local y filtro de archivadas. |
| B · Departamentos | Nombre, estado traducido y número de personas según value | includesString, trim; sin tildes | Local y vacío existente. |
| B · Infraestructura y sublistados EntityTable | Columnas elegibles ya declaradas con value | includesString, trim; sin tildes | Local; no hereda campos del inventario general. |
| C · AssetPickerList | Hereda los cuatro campos de AssetList | Filtro del módulo | Controlador del diálogo; exclusiones/selección provisional intactas. |
| C · FieldPickerList | Nombre + descripción, tipo y unidad | includesString, trim; sin tildes | Local; seleccionados permanecen aunque el filtro los oculte. |
| C · OptionPickerList | Etiqueta y descripción | includesString, trim; sin tildes | Local; radio provisional independiente del filtro. |
| C · Columnas | Etiqueta y keywords | NFD y eliminación general de marcas protegiendo ñ; trim | Local al diálogo; agrupación/visibilidad L02.2. |
| C · IconPicker y Select compactos | Opciones aportadas al Select de Base UI | Sin filtro textual local propio; navegación de la primitiva | No se reemplaza su typeahead por un buscador de listado. |
| D · DirectoryDomainPicker | Consulta por nombre/DNS del proveedor | Contrato servidor no acreditado | Query keys, search/cursor, AbortSignal, vacío/reintento remotos. |
| D · PublicationPicker/RemoteOptionPicker | Candidatos del proveedor SMB | Contrato servidor | Search/cursor, selección provisional; sin refiltrar página. |
| D · Relaciones/publicaciones/historiales | Contrato de cada proveedor; muchos sin buscador | Sin filtro local que migrar | Cursores y estado remoto intactos. |
| E · WorkspaceSearchContent | Nombres de compañías y etiquetas Inicio/Compañías/Catálogos | Minúsculas/includes, trim; sin tildes | Local al shell/modal, Escape limpia; misma ayuda de ámbito. |
Los filtros explícitos desactivan el global genérico mediante onSearchChange, como antes. Las tablas genéricas conservan la inferencia nativa de elegibilidad de TanStack; acciones, selección y columnas sin value no se convierten en campos buscables. Ocultar una columna no redefine su elegibilidad. Se mantiene el vacío/contador/limpieza ya existente.
3. Contrato de comparación
- Coincidencia parcial sobre representaciones normalizadas, sin fuzzy ni tokenización.
- Trim exterior; minúsculas independientes de la configuración regional del equipo.
- NFD/NFC canónico; no NFKD ni transliteración general.
- Se pliegan grave, agudo, circunflejo, tilde y diéresis sobre a/e/i/o/u.
- Ñ/n, ç/c y letras de otras escrituras permanecen distintas.
- Se conservan espacios interiores, puntos, guiones, dos puntos y barras.
- Consulta vacía no filtra. Null/undefined/objetos no producen texto para consultas no vacías.
- Primitivos string/number/boolean/bigint conservan valores como 0/false.
- El resultado normalizado nunca sustituye datos almacenados ni el texto visible.
4. Utilidad compartida y responsabilidades
text-search.ts contiene normalizeSearchText y
createTextMatcher, exportados por @repo/rdx-ui/lib/text-search. Es un helper puro sin React,
DTO, consultas ni APIs, ejecutable también en Node. Vive junto a los helpers existentes de
la biblioteca donde ya estaba normalizeColumnSearch; todos sus consumidores dependen de ella.
No exige una dependencia nueva de rdx-ui hacia otro paquete.
normalizeColumnSearch conserva su API como alias del contrato común. createTextMatcher prepara la consulta una vez fuera de callbacks por fila; el consumidor aporta los valores. No se añade un hook, efecto, índice permanente o caché del inventario.
5. Campos buscables y reglas de negocio
Activos mantiene nombre/plantilla/sede/estado. No se amplía a notas, IP, MAC, número de serie, características o relaciones. Recursos mantiene nombre/plantilla; Personas, nombre. Las pruebas negativas comprueban correo de persona y etiquetas de campos fuera del contrato. Las configuraciones que ya buscaban rutas/versiones/extremos siguen haciéndolo, sin transferir esa capacidad al inventario. Los filtros funcionales permanecen fuera del helper.
6. Consumidores modificados
useEntityTable y el filtro inicial de Compañías usan el predicado sobre getValue elegible. AssetList, recursos, Personas, ambos catálogos, puestos, perfiles, accesos y las configuraciones A del inventario sustituyen únicamente la comparación. Los pickers y tablas equivalentes lo reciben por composición; el workspace conserva búsqueda de compañías/destinos exclusivamente. Columnas conserva agrupación, keywords, defaults, protecciones y almacenamiento.
7. Excepciones
No cambian el cotejo exacto del alta rápida de accesos, identidad de direcciones de correo, color de avatares, validaciones o UUID: son contratos de identidad/dominio, no búsqueda de listados. Tampoco cambia la búsqueda remota ni su cancelación/cursor/query keys. Collation, índices y resultados poblados del proveedor quedan para otra actuación; no se simula una búsqueda global filtrando solo la página recibida.
8. Unicode y ñ
Tras minúsculas y NFD, solo se retiran las cinco marcas acordadas dentro de clusters con base vocal latina; otras marcas se conservan. NFC recompone el resultado. N + tilde conserva ñ sin sustitución provisional; se prueban marcas combinadas sobre vocales y sobre ñ. Á/A+agudo, Agüero/aguero y graves coinciden. Peña/Pena, año/ano y cañón/canon no coinciden. Griego, cirílico y japonés no se transliteran ni pierden marcas por un borrado global de Unicode.
9. Identificadores técnicos
Las pruebas conservan 192.168.5.201, AA:BB:01:02:03:04, guiones, números, ceros,
\\srv\Área y /srv/Área. Quitar separadores no crea una equivalencia con la cadena completa.
Esto verifica el comparador, no acredita búsqueda por IP/MAC en Activos, cuyo ámbito no cambia.
10. URL y L03.1
PORTATIL sigue siendo el valor del input y de q; solo su comparación equivale a portatil.
URLSearchParams puede codificar espacios como +: se conserva el valor decodificado. No se
modifican History, parámetros, query keys o preferencias. Cambiar consulta reinicia página
por los handlers existentes y conserva sort. Normalizar no añade entradas al historial.
El retorno conserva el texto original y su contexto operativo conforme a L03.1.
11. Rendimiento
text-search.bench.mjs separa 100 muestras de filtrado y 10 de render SSR de EntityTable, con cinco calentamientos por operación. Cada conjunto sintético devuelve la mitad de coincidencias. Ejecución:
TSX_TSCONFIG_PATH=tsconfig.json node --import tsx packages/rdx-ui/src/lib/text-search.bench.mjs
| Registros | Mediana filtro normalizado | Includes anterior con consulta acentuada | Mediana SSR tabla con búsqueda |
|---|---|---|---|
| 30 | 0,028 ms | 0,002 ms | 7,238 ms |
| 300 | 0,372 ms | 0,026 ms | 10,674 ms |
| 1.000 | 1,862 ms | 0,061 ms | 13,499 ms |
Includes anterior sirve como referencia de coste, no como alternativa funcional equivalente: falla con la consulta sin tilde. SSR incluye React/TanStack/HTML; no mide layout, pintura o latencia interactiva. No incluye red ni Playwright y no acredita producción. Muestras/máximos en benchmark.json. No se justifican debounce universal, índices, virtualización o cachés nuevas.
12. Pruebas automatizadas
Utilidad: caja/vocales, NFC/NFD, ñ, diéresis, graves, marcas, espacios, parcial, vacíos, valores sin texto, puntuación, números, repetición y escrituras no latinas. EntityTable incluye una regresión que falla antes del cambio y pasa después con filas y consulta visible verificadas. Mantiene los tests de Collator y estado controlado/no controlado.
Activos/Recursos amplían pruebas por identidad con consultas sin tilde, espacios/NFD/ñ y negativas sobre campos no buscables. Catálogo de activos comprueba nombre y consulta visible. Personas tiene prueba propia es/en con schema real, Solo contactos, Peña/Pena, NFD y correo excluido. Fixtures unitarias pequeñas complementan el volumen; no lo sustituyen.
13. Playwright y evidencia
scripts/search-ui.test.py reutiliza el MCP y helpers existentes e incluye 14 regresiones L03.1 y ocho escenarios nuevos. Bloquea escrituras API y no inicia servicios. La instalación sintética autorizada se preparó con 15 compañías, 50 personas, 51 activos y 66 recursos. Variantes de personas y 50 departamentos son respuestas GET; pickers usan 50 opciones. No se presentan como un proveedor remoto verificado ni como escrituras persistidas.
Se verifica la matriz completa en Chromium headless mediante el MCP Docker fijado por el
proyecto. El retorno conserva la consulta original portatil , Nombre descendente,
página 3, las mismas filas y el enlace de origen:
| Resolución | Scroll X/Y antes y después | Resultado |
|---|---|---|
| 1920×1080 | 0 / 0; el contenido cabe en altura | Conservado |
| 1440×900 | 0 / 150 | Conservado |
| 1366×768 | 0 / 150 | Conservado |
| 1024×768 | 0 / 150 | Conservado |
| 768×1024 | 40 / 150 | Conservado |
| 390×844 | 40 / 150 | Conservado |
| 320×640 | 40 / 150 | Conservado |
En las siete medidas no hay overflow horizontal global. portatil, PORTÁTIL,
porta + agudo combinante + til y rtatil devuelven los mismos 41 portátiles. Recursos
encuentra 62 registros por nombre/plantilla con aplicacion, espacios exteriores y NFD.
Personas devuelve únicamente Pena con Pena, y siete apellidos Peña con ñ precompuesta o
descompuesta; el correo de la fixture no entra en la búsqueda. Catálogos devuelven una
plantilla Portátil/Aplicación; Departamentos confirma 50 administraciones y distingue
25 Pena/25 Peña, PC-001 (uno) y PC001 (cero).
Los pickers de 50 opciones mantienen la selección provisional después de ocultarla por un filtro sin coincidencias, recuperarla y confirmar. Se comprueba foco inicial. Durante un refetch retenido se puede buscar sin tilde: no cambia la instancia de tabla ni se pierde foco/consulta al recibir datos. El vacío ofrece Limpiar filtros. El cambio es/en conserva consulta, resultados, orden y página; recargar conserva q. El idioma vuelve al español inicial por comportamiento previo de la aplicación; no se añade persistencia de idioma.
Capturas, mediciones, consola y logs están en el índice local. Se abren e inspeccionan nueve capturas representativas: Activos a 1920/390/320, Personas con ñ, Recursos, picker de opciones, inglés, vacío y catálogo de activos. Las restantes imágenes son evidencia capturada, sin afirmar inspección visual individual de todas ellas.
Para repetir, mantener vivo el preparador y ampliar el volumen según Playwright MCP:
METIS_PLAYWRIGHT_STORAGE_STATE=.artifacts/playwright/authenticated-ID/session.json \
python3 scripts/search-ui.test.py
La suite permite ejecutar los 22 métodos juntos. Esta entrega los ejecuta en lotes y repeticiones identificados; no se declara una única ejecución 22/22.
14. Comprobaciones y regresiones
Línea base actual: calendar.tsx:165 TS2375 vendor; lint 15 errores/1 warning/4 infos; check 167 errores/1 warning/4 infos. Compañías conserva el archivo SSR fallido documentado. Los resultados finales se registran con códigos de salida, sin presentar suites fallidas como correctas ni modificar vendor para ocultar deuda.
15. Skills y limitaciones
Principal leída: ux-search, para consulta/ámbito/recuperación. Complementarias: ux-tables (resultado y paginación), ux-microcopy (no prometer campos nuevos), vercel-composition-patterns (predicado sin entidades), vercel-react-best-practices (estado derivado y medición), shadcn (API Base UI y foco). Se leen referencias de estado derivado, separación de implementación y Base/Radix. No surge una duda adicional que requiera ui-ux-pro-max. Los auditores *-audit y su política no están disponibles y no se instalan. Prevalecen AGENTS/DESIGN y APIs reales.
No se acredita WCAG completo, lectores de pantalla, otros motores o producción. El contrato no pretende equivalencias lingüísticas universales. Las búsquedas remotas no se declaran corregidas. La adopción del helper en configuraciones no equivale a recorrerlas todas pobladas.
16. Estado y pendientes
V07 resuelto en los consumidores locales y escenarios comprobados, con la comparación compartida implantada en los restantes filtros locales inventariados. No se declara resolución universal: la validación se limita a las suites y escenarios ejecutados. L04 debe completar cobertura poblada de configuraciones, marcas/sublistados no recorridos y el contrato propio de proveedores remotos. No se implementa L03.3. V05/V08/V12 conservan sus alcances históricos.
17. Resultados técnicos y cierre
| Comando | Resultado |
|---|---|
| Typecheck dirigido rdx-ui/core/assets/resources/companies | Los cinco correctos. |
| pnpm --filter @repo/rdx-ui test | 13/13 archivos correctos. |
| pnpm --filter @metis/core test | 3/3 archivos correctos. |
| pnpm --filter @metis/assets test | 27/27 archivos correctos tras ampliar casos de búsqueda. |
| pnpm --filter @metis/resources test | 11/11 archivos correctos tras ampliar casos de búsqueda. |
| pnpm --filter @metis/companies test | 45/46 archivos correctos; conserva companies-page.test.tsx fallido. |
| Prueba dirigida people-search.test.tsx | Correcta; consultas concretas y filtros en es/en. |
| Biome/ESLint dirigidos | Correctos tras corregir espaciado de las pruebas. |
| pnpm typecheck | Falla TS2375 en calendar.tsx:165, igual a la línea base. |
| pnpm lint | 15 errores, un warning y cuatro infos, igual a la línea base. |
| pnpm check | 167 errores, un warning y cuatro infos, igual a la línea base. |
| pnpm build | 2/2 tareas correctas; permanece el aviso de chunks >500 kB. |
| pnpm test | 7/8 tareas correctas; fallo conocido de Compañías. Ejecutado con MariaDB metis_desk_test separada de la instalación visual y retirada al finalizar. |
| Infraestructura de auditoría | 10/10 pruebas Python correctas, incluido fallo anterior a credenciales con captura/consola y sin sesión ni rellenado. |
| Playwright búsquedas L03.2 | Ocho métodos distintos comprobados: primer lote 7 correctos y un error de limpieza del test; el método 22 repetido pasa (15,164 s). |
| Playwright contexto L03.1 | 14/14 correctos (358,176 s). |
| Playwright columnas L02.2 | 8/8 correctos (166,555 s). |
| Playwright pickers L02.1 | 8/8 correctos (189,768 s), incluida regresión de presentación remota. |
| Playwright estados L02.3 | 8/8 correctos (243,010 s). |
| Playwright paneles/contraste/foco/shell | Cinco métodos distintos comprobados: primer lote 4 correctos y un timeout por fixture fuera de página; navegación móvil repetida pasa (31,233 s). |
Son 51 métodos distintos de navegador verificados, sin sumar repeticiones. Los errores de red 503/403 de escenarios negativos se identifican como provocados. Las consolas finales de búsquedas, contexto, columnas, pickers y navegación no registran errores ni warnings; la de estados registra cuatro errores de red 503 deliberados, sin warnings.
No se cuentan como resultados correctos los intentos intermedios. Las primeras expectativas nuevas sobre href confundían %20 con la codificación + de URLSearchParams; se corrige la fixture manteniendo el texto decodificado y se repiten Activos/Recursos correctamente. El primer comando dirigido de Personas con el CLI de tsx no pudo abrir su pipe IPC en sandbox; la ejecución mediante node --import tsx sí pasa sin necesitar esa infraestructura.
Incidencia del entorno de navegador
La instalación autorizada inicia sesión real como usuario ordinario y el preparador de volumen confirma los recuentos anteriores. Antes del primer escenario L03.2, su preparador termina con KeyboardInterrupt, confirma retirada del contenedor y elimina session.json. Los ocho métodos nuevos fallan por conexión rechazada, sin verificar sus escenarios. No se atribuye este fallo a la comparación de búsqueda ni se reutiliza la aplicación real.
La revisión automática inicialmente rechaza repetir el preparador y crear la base aislada de integración. El usuario autoriza expresamente ambas acciones. El test global se ejecuta contra su propia MariaDB y la retira; la repetición visual se documenta con sus resultados reales. El primer intento fallido se conserva. No se tocan el contenedor huérfano previo ni las bases de datos reales.
18. Archivos principales
- Utilidad, pruebas y medición: text-search.ts, text-search.test.ts y text-search.bench.mjs.
- Tabla genérica: use-entity-table.ts, entity-column-configuration.ts y entity-list.test.tsx; scripts de test de rdx-ui.
- Inventarios: AssetList, useResourcesPageController y sus pruebas existentes.
- Compañías: PeopleSection, controlador de directorio, WorkspaceSearchContent, controladores locales enumerados en el inventario y people-search.test.tsx.
- Catálogos: controladores de assets/resources y prueba de catálogo de activos; marcas, sedes y departamentos reciben el contrato a través de EntityTable.
- search-ui.test.py: escenarios nuevos y regresiones L03.1.
- visual-audit-ui.test.py: consulta sin tilde en el shell y localización explícita del activo sintético, evitando suponer que está en la primera página con 51 registros.
- visual-audit.py: diagnóstico de captura/consola únicamente antes de rellenar credenciales si falla el arranque del acceso; diez pruebas de infraestructura correctas, con un caso específico de diagnóstico previo a credenciales. El diagnóstico no omite autenticación ni guarda sesiones.
- DESIGN, patrón de listados, componentes y seguimientos de ambas auditorías: contrato, alcance y límites. Los cambios previos del usuario se conservan. La relación local de archivos propios excluye modificaciones concurrentes ajenas en traducciones, exports de assets y ficha de puesto.
Cierre de la validación
El primer arranque se interrumpe y el siguiente agota el tiempo de acceso; ambos se limpian. Tras la autorización adicional de hasta tres reintentos, el primero funciona y permite completar las comprobaciones. No se necesitan más reintentos ni se utiliza la aplicación real. El preparador final termina con código 0, confirma retirada del entorno y se verifica que su session.json ya no existe. Tampoco quedan contenedores de integración propios.
Se conservan los intentos intermedios. El método de idioma suponía incorrectamente inglés persistido después de recargar; se corrige solo su limpieza. La regresión del shell suponía AUDIT-PORT-01 en la primera página; se usa la búsqueda real y se comprueba además auditoria sin tilde. No se modifican idioma, paginación o código de negocio para satisfacer los tests.
Relación completa de archivos propios: inventario local.
Seguimiento L04.1
L04.1 adopta URL de orden/página, preferencias explícitas de columnas y retorno de scroll/foco en Puestos, Perfiles y directorio de Compañías. Conserva la búsqueda normalizada y los campos de cada entidad, los filtros de archivados/activas y el ámbito. La limpieza controlada agrupa criterios y página en un único replace. Las medidas y limitaciones anteriores se conservan; los resultados nuevos se registran en el informe L04.1. Restan L04.2–L04.4 y no se declara V05 ni L04 resueltos universalmente.