metis-desk/docs/adopcion-listados-l04-2.md
2026-10-25 01:19:17 +02:00

39 KiB
Raw Blame History

L04.2 — Adopción de listados en catálogos y configuraciones

Fecha: 24 de octubre de 2026. Entrega limitada a L04.2; L04.3/L04.4 siguen pendientes. Fuentes: DESIGN, matriz de skills, L01, L03.1, L03.2, L03.3, L04.1, columnas, estados, listados, componentes, rutas y Playwright.

1. Resumen ejecutivo y alcance

Ambos bloques están implementados y verificados: 17 métodos MCP nuevos y 30 regresiones seleccionadas correctos. Catálogos navegables y Procesos conservan consulta y retorno; las configuraciones modales mantienen estado local con ámbito y estados de consulta coherentes. Las comprobaciones propias pasan; las limitaciones globales se detallan en §14.

Auditoría dirigida y matrices preparadas antes de modificar producción. Adoptar los contratos existentes según el ciclo real de cada consumidor. No convertir un editor modal en una ficha ni aplicar q/sort/page del padre a un sublistado independiente. El estado remoto continúa en TanStack Query; URL para consulta navegable, History para scroll/foco, preferencias existentes para tamaño/columnas y estado local para modales.

Skill principal: ux-tables (comparación, identidad, estados y manipulación a volumen). Complementarias consultadas: ux-navigation/search (ámbitos/retorno/criterios), ux-empty-states/error-recovery (vacío, coincidencias y errores), microcopy (mensajes), shadcn (API Base UI), composición y React best practices (responsabilidades/estado derivado). Se mantienen DESIGN y patrones propios frente a recomendaciones genéricas. Los auditores ux-*-audit y orchestration-policy no están instalados; no se instalan ni se finge su ejecución.

2. Diagnóstico previo

Los catálogos de Assets/Resources tienen q/tab en URL y key por pestaña; orden/página son locales y se pierden al salir o recargar. Las pestañas ejecutan dos replaces (tab y búsqueda por separado). Tabla con loading/unavailable básico más error externo; no compone refetch/error posterior. Marcas conserva todo local; plantillas de procesos oculta la tabla cuando carga o falla. Sus operaciones son modales/expansiones, sin detalle navegable. Accesos tiene q/kind/environmentId/resourceId en URL; metadatos/columnas dependen de kind; orden/página son locales y la tabla solo se monta con data.

Configuraciones de carpetas/correo/certificados/aplicaciones/impresoras/teletrabajo/remotos mantienen q local, sort/page de EntityTable y editores/historiales modales. Los filtros initialProfileId/initialPersonId limitan el conjunto y no son criterios limpiables. Varias tablas desaparecen ante refetch fallido o esperan solo una parte de sus referencias. Procesos tiene q/closed URL y detalle real, con orden/página locales y sin retorno de lista. Software es un sublistado por ordenador, dentro de fichas/diálogos: q/closed locales; referencias recursos/catálogo indispensables y enlace a recurso real.

3. Matriz A — Catálogos, antes de implementar

Todos usan EntityTable, nombre/identidad protegidos, acciones por fila y tamaño compartido entity-page-size. Ninguno de estos consumidores tenía clave propia de columnas ni contrato controlado sort/page. Nombre asciende por defecto, con comparador común; búsqueda normalizada. Las definiciones de secciones/campos dentro de editores de plantilla son composición ordenada, no catálogos independientes: conservan su orden de dominio y su editor.

Consumidor / módulo / controlador Ruta, datos y ámbito Existente y diferencia legítima Cambio pertinente / clasificación No necesario / pruebas
AssetCatalogPage · Assets · useAssetCatalogPageController /catalogs/assets y /companies/:id/catalogs/assets; catalogApi.get(scope) q/tab, plantillas/campos/relaciones; nombre buscable; heredado/builtin y effectiveActive; acciones copia/estado/edición/detalle modal/borrado elegible Adopción directa de navegación de consulta y estados; adaptación por pestaña/scope Sin rutas de editor ni filtros nuevos. Recarga, cambio de pestaña, inválidos, herencia/retirada y cancelar
ResourceCatalogPage · Resources · useResourceCatalogPageController /catalogs/resources y /companies/:id/catalogs/resources; catalogApi.get(scope) q/tab, plantillas/campos; nombre buscable; procedencia y estado efectivo; permisos de gestión global actuales Igual, conservando el ámbito y las restricciones reales del backend Sin nuevos permisos/acciones ni cambios al modelo de recursos. Catálogo global/compañía y cancelación
BrandCatalogPage · Assets · useBrandCatalogPageController /catalogs/brands; brandApi.list; global Búsqueda de EntityTable por sus columnas comparables; status local; editor/borrado modal; builtin restringe borrar Corrección de estados inicial/refetch/error, manteniendo consulta/orden/página locales URL y History nuevos no necesarios: no existe ficha. Volumen, filtro, cancelar, carga/error y foco modal
ProcessTemplatesPage · Companies · useProcessTemplatesPageController /catalogs/process-templates; listProcessTemplates (API /processes/templates); global Búsqueda de tabla, orden/página locales; tipo/estado/instrucciones/historial inline; edición/copia modal Adopción directa de estados estables Sin URL de editor ni modificación de instrucciones. Volumen, historial expandido, cancelar y errores
AccessWorkspacePage · Companies · useAccessWorkspacePageController /catalogs/access; getAccess(global) q/kind; sistemas/tipos/permisos según accessKinds; nombre por accessLabel; campos dinámicos; edición/historial/ayuda modal Adopción con validación de columnas según kind y limpieza atómica al cambiar colección No heredar orden incompatible ni crear catálogo universal. Pestañas, inválidos, recarga y vacío
AccessWorkspacePage de compañía /companies/:id/access; getAccess(id), people Además cuentas/entornos/grupos/recursos/necesidades/asignaciones; environmentId/resourceId son ámbito explícitamente quitables con sus acciones propias Adaptación por compañía/kind; conservar restricciones al limpiar búsqueda No convertir ámbitos en filtros descartables. Permisos, identidad local, enlaces y retorno

4. Matriz B — Configuraciones, antes de implementar

Ruta autónoma de compañía y, en las cinco primeras familias, subruta de perfil real /companies/:id/work-profiles/:profileId/. Los DTO y sus estados/periodos/relaciones no se homogeneizan. Los editores tienen su propia selección provisional y validación.

Consumidor / controlador Fuentes imprescindibles y campos buscables actuales Ámbito / acciones / navegación Cambio pertinente / clasificación Diferencia preservada / pruebas
FolderMappingsPage / useFolderMappingsPageController folderApi, access, profiles; path, perfil, nombre de carpeta Compañía o perfil; edición/historial/borrado modal; configuración distinta de necesidad SMB Estado agregado; consulta/orden/página locales, excepción modal justificada initialProfileId no se limpia; sin nuevas relaciones. Volumen, vacío, error de referencia, editor/historial
MailConfigurationsPage / useMailConfigurationsPageController mailApi, inventory, profiles, mailboxes; dirección y destinatario Compañía/perfil y legacy; configuraciones y buzones distintos; edición/historial/borrado modal Estado agregado; esperar las cuatro fuentes, conservar consulta local Conservar legacy/revisión/estados. Página 3, perfil obligatorio, cancelar y refetch
CertificateConfigurationsPage / useCertificateConfigurationsPageController certificateApi, profiles, inventory, resources; recurso y etiqueta del perfil Compañía/perfil; canCreate depende de perfil activo; editor/historial/borrado modal Igual Perfil, certificado/recurso y vigencia no cambian. Datos poblados y carga/error
ApplicationConfigurationsPage / useApplicationConfigurationsPageController applicationApi, profiles, inventory, resources; recurso y etiqueta Compañía/perfil; canCreate y ciclo de vida existentes Igual No confundir instalación del equipo con configuración del perfil. Editor e historial
PrinterConfigurationsPage / usePrinterConfigurationsPageController printerApi, profiles, inventory; impresora y etiqueta Compañía/perfil; impresora es activo; editor/historial/borrado Igual Perfil obligatorio y activo elegible. Búsqueda, páginas, cierre y referencias
RemoteConnectionsPage / useRemoteConnectionsPageController remoteApi, assets, resources; persona/origen/destino/método Compañía/persona; closed local, vigencia/estados; editor/historial/borrado Estado agregado y consulta local; closed sigue siendo voluntario initialPersonId no se limpia. Sin copiar filtros del perfil. Refetch/finalizados/foco
TeleworkAuthorizationsPage / useTeleworkAuthorizationsPageController teleworkApi y company.people; persona Compañía/persona; edición/historial/borrado, periodos Estado estable de una fuente; consulta local No reinterpretar autorización como acceso remoto. Carga/error, ámbito y cancelación
ProcessesPage / useProcessesPageController getProcesses y company.people; nombre/persona/tipo traducido Compañía; q/closed URL; ficha real; alta/edición/cierre/borrado existentes Adopción de URL completa, retorno y tabla estable No alterar pasos/cierre/permisos. Detalle/Atrás/retorno explícito, retirada GET, refetch y filtros
SoftwareInstallationsPanel softwareApi, resources, catálogo; nombre del recurso/versión Ordenador obligatorio en ficha/diálogo; q/closed local; editor/historial/borrado y enlace al recurso Corrección de estados agregados; excepción funcional legítima para URL local No absorber q/page del padre ni perder assetId al limpiar. Editor, vacío/refetch/error y enlace

5. Diagnóstico HTTP 401/404, previo a cambios

Preflight MCP con sesión ordinaria sintética existente, sin escrituras: tres rutas retiradas /api/tickets, /api/interventions y /api/intervention-templates/global devuelven 404 con y sin sesión. /api/dashboard/work devuelve 401 anónimo y 404 autenticado. Evidencia local: .artifacts/playwright/l04-2/preflight.json.

identity.test.ts:82 recorre esas cuatro rutas con fetch sin cookie, antes de preparar su usuario/sesión. createApp instala primero sesión y módulos, y al final el fallback 404. registerDashboardRoutes monta authenticate en /api/dashboard antes de resolver /work; requireAuthenticated responde 401 sin sesión y no llama next. Con sesión válida se llega al router sin /work y después al fallback 404. No es un recurso inexistente resuelto antes de autenticación ni un fallo de credenciales del navegador de auditoría.

Se confirma el origen de la discrepancia entre expectativa del test y orden de middleware, y su presencia antes de L04.2. L04.1 ya conservó el fallo en test.log y no modificó servidor. No se dispone aquí de una ejecución histórica anterior a L04.1 que permita fechar su introducción: no se afirma preexistencia histórica universal. No se modifican seguridad, endpoint, expectativa ni fixture para hacerlo pasar.

Precisión de la matriz B tras revisar las celdas

Las siete familias de configuración no contienen enlaces de navegación en sus filas: los nombres abren historial y las acciones abren editores/confirmaciones. La vista de perfil vuelve al entorno mediante el botón del contenedor. Por ello, conservan consulta, orden y página locales durante los diálogos; no necesitan nuevos parámetros URL. Se verificará que limpiar no elimina initialProfileId/initialPersonId y que cambiar de perfil no reutiliza la instancia local del anterior. Procesos sí tiene ficha y enlace navegable: adopta URL/History. Software tiene un enlace a recurso dentro de una ficha/modal; volver no convierte la apertura efímera del modal en una ruta nueva.

6. Bloque A — Implementación y resultados parciales

Catálogos de activos/recursos y Accesos adoptan useListLocation, useListReturn y estado agregado de consulta. Cambio de pestaña/kind limpia q/orden/página en una sola operación, conservando el comportamiento previo de reiniciar búsqueda y evitando aplicar un orden a columnas incompatibles. Limpiar búsqueda conserva scope, tab/kind, environmentId y resourceId; esos ámbitos mantienen sus acciones explícitas independientes.

Columnas: claves asset-catalog-columns:<scope>:<kind>, resource-catalog-columns:<scope>:<kind> y access-columns:<scope>:<kind>; evitan perder la selección al navegar/recargar y no mezclan pestañas ni compañías. No se añaden grupos artificiales. Marcas y plantillas de procesos mantienen consulta, orden y página locales; sus tablas dejan de desaparecer al cargar/refrescar/fallar y conservan recuperación.

Se reutiliza companyListQueryState mediante un hook de presentación con mensajes i18n, sin DTO, consultas nuevas ni otra máquina de estados. Estados de catálogo se adaptan a sus propias clases de error; 403/401 no dejan filas de caché accesibles en la tabla. Las acciones de mutación y su feedback permanecen específicos de cada catálogo.

Incompatibilidad de composición detectada y resuelta

El caso de recarga guardaba Y=150, restauraba el foco con preventScroll y terminaba en Y=78. Las mediciones completas muestran que la altura del catálogo y las fuentes ya estaban estables: el mensaje de carga externo del directorio desaparecía y reducía 72 px el contenedor, provocando anclaje de scroll. Se descarta la hipótesis inicial de fuentes y se retira el cambio exploratorio al hook. Core/History queda sin modificaciones.

La composición suministra layoutReady, derivado del estado real de las consultas propietarias del contenedor, a los tres catálogos navegables; solo condiciona restauración, no bloquea sus filas ni cambia el shell. Default true conserva los consumidores embebidos. No hay temporizadores, estado remoto duplicado ni comprobaciones de DOM basadas en textos. Se añade un caso con la consulta del contenedor retenida, además del de fuente retenida.

Las dos suites SSR de catálogo fallan antes de implementar orden/página y pasan después. Pruebas dirigidas de Assets catálogo/Marcas, Resources catálogo y Companies Accesos/procesos: 5/5 archivos correctos. Tipos y formato se comprueban por paquetes afectados. Las pruebas MCP y resultados restantes se incorporan al cerrar cada bloque.

7. Bloque B — Implementación y diferencias preservadas

Las siete familias de configuración conservan montada EntityTable desde la carga inicial. El estado agregado incorpora todas las fuentes imprescindibles de la matriz B; no basta con que llegue la colección principal. Un fallo posterior conserva filas, consulta y herramientas; una denegación oculta las filas y no ofrece un reintento engañoso. Reintentar espera las consultas reales y delega su resultado en TanStack Query, sin promesas rechazadas sin gestionar ni cerrar editores. No se alteran mutaciones, query keys ni invalidaciones.

Las configuraciones mantienen búsqueda/orden/página locales porque sus filas abren edición o historial modal. La identidad de la instancia depende de compañía y perfil/persona en CompanySection, de perfil/persona en ProfileConfigurations y del ordenador en el modal de software. Cambiar de ámbito no arrastra criterios de otra colección. Limpiar modifica solo los criterios voluntarios; el perfil/persona/ordenador sigue restringiendo los datos.

Procesos incorpora useListLocation, enlaces con la consulta completa y useListReturn. La referencia de retorno pertenece exclusivamente al bloque del listado: se desconecta en la ficha aunque el controlador siga montado. Conserva q/closed, instrucciones, seguimiento y acciones existentes. La ausencia confirmada ofrece retorno mediante BrowserLink; una entrada directa sin History válido usa el fallback existente.

Software conserva su ámbito obligatorio y estado local. Se comprueban el editor anidado, cancelación y enlace real al recurso contextual V01.4. Atrás vuelve a la ficha de origen; no reabre automáticamente la ventana efímera de gestión de software. Esta diferencia está deliberadamente fuera del contrato de una lista con ficha propia.

Columnas, filtros y selección por familia

Se conservan los IDs y renderizadores existentes. Nombre/identidad y acciones siguen protegidos; no se añade selección de filas ni grupos artificiales a tablas pequeñas.

Familia Columnas (IDs, además de actions) Filtros voluntarios / identidad
Activos y recursos: catálogos name, origin, details, state q y tab; name obligatorio; details cambia de significado según pestaña
Marcas logo, name, status, origin Búsqueda de tabla y status local; name obligatorio
Plantillas de procesos name, kind, state, steps, history Búsqueda de tabla; name obligatorio; instrucciones e historial son composición inline
Accesos name, campos de accessFields[kind], localOwner cuando corresponde, state, review q/kind; resourceId/environmentId con eliminación explícita; name obligatorio
Carpetas name, profile, path, drive, permissions, accessAccount, accountCoverage, state, review q local; name obligatorio
Correo name, profile, method, state q local; name obligatorio
Certificados name, profile, state, location, expiry, review q local; name obligatorio
Aplicaciones name, profile, state, delivery, version, review q local; name obligatorio
Impresoras name, profile, state, connection, default, review q local; name obligatorio
Remotos person, method, details, state q y closed locales; person obligatorio
Teletrabajo person, state, start, end, details q local; person obligatorio
Procesos name, person, kind, state, progress q/closed navegables; name obligatorio
Software name, type, version, license, state q/closed locales; name obligatorio

8. Contratos de URL y preferencias

Consumidor Consulta navegable Preferencias / estado efímero
Catálogos Assets/Resources q, tab (ausente = templates; fields/relations según catálogo), sort, direction, page Columnas por scope y kind interno; tamaño compartido existente; editor/detalle local
Accesos global/compañía q, kind, resourceId, environmentId, sort, direction, page Columnas por scope/kind; editores/historial/ayuda locales
Procesos q, closed=true, sort, direction, page, también en enlace de ficha processes-columns:; alta/seguimiento locales
Marcas / plantillas de procesos No se añaden parámetros Búsqueda/estado/orden/página locales; tamaño existente
Siete configuraciones / software No se añaden parámetros de consulta Consulta/orden/página locales, closed donde existía; perfil/persona/ordenador obligatorios

Solo se controlan orden/página cuando la ruta coincide con el consumidor. Se reutiliza la validación de columnas ordenables y páginas de L03.1: parámetros inválidos se corrigen al disponer de datos, sin certificar una página con datos parciales. Búsqueda y filtros reinician página; Limpiar conserva orden/columnas/tamaño. Cambiar tab/kind descarta q/sort/direction/page incompatibles en un único replace, sin crear una entrada por pulsación. Los filtros de ámbito conservan sus reglas anteriores, incluida la salida explícita de environmentId al cambiar a colecciones que no admiten ese contexto.

No se guardan DTO, cookies ni datos remotos en URL/History/localStorage. Las claves nuevas de columnas usan IDs, no nombres traducidos. No cambia entity-page-size ni el contrato no controlado de EntityTable; Core y rdx-ui no reciben cambios funcionales de L04.2.

9. Ámbitos, permisos y dependencias

Global, compañía, heredado y retirado conservan su semántica. Los elementos de serie y heredados mantienen las restricciones de edición/copia/borrado existentes; la retirada no elimina instantáneas ni se interpreta como ausencia. La revisión documental y los estados pendientes/configurados/finalizados se representan con sus etiquetas anteriores.

La matriz B identifica las referencias imprescindibles. Datos de compañía/personas proceden del contenedor real; las consultas de inventario, perfiles, buzones, recursos y accesos siguen en sus módulos. Las configuraciones no se transforman en recursos, activos ni permisos. No se añaden relaciones ni nuevos privilegios. Una respuesta 401/403 de cualquier fuente obligatoria impide presentar sus filas almacenadas como accesibles.

10. Retorno, foco y estabilidad del contenedor

History registra scroll vertical, scroll horizontal y foco de fila, con el scope y la consulta del listado. Se restaura después de que la colección y su contenedor estén disponibles. layoutReady?: boolean (default true) es una señal de composición de los catálogos y Procesos: CompaniesWorkspace y CompanyDetail la derivan de sus consultas. No es un segundo estado remoto ni un cambio a los breakpoints o estructura del shell.

Se reproduce y corrige el desplazamiento de 72 px descrito en §6, sin cambiar Core ni relajar las aserciones de coordenadas. Si desaparece un proceso, el foco vuelve a búsqueda; si hay refetch al regresar, no se declara válida prematuramente la fila de caché. Con URL directa, orden/página se validan y el retorno usa el fallback seguro.

En modales se conserva la tabla y Base UI devuelve el foco al control originario. El editor de software es un diálogo anidado: el padre permanece montado aunque Base UI lo excluya temporalmente del árbol accesible. No se crean entradas History para editar, cancelar ni consultar historial local. No se persiste la apertura del modal al seguir un enlace a otro recurso.

11. Carga, actualización, error y vacío

Se reutilizan entityListState y companyListQueryState; el nuevo useCompanyListState solo aporta textos traducidos para las consultas que recibe. No carga datos ni sustituye TanStack Query. Las tablas muestran estructura inicial, marcadores y herramientas; conservan datos durante actualización y ante error posterior. Error inicial, denegación, ausencia de registros y ausencia de coincidencias siguen siendo estados diferentes. Las acciones de alta respetan disponibilidad de referencias y permisos.

Los reintentos usan refetch sin throwOnError; un error permanece en su contexto de consulta. No se capturan fallos para hacerlos desaparecer. El feedback de mutación y los errores de validación de cada editor no se mezclan con los errores de lectura de la tabla.

12. Accesibilidad e inspección visual

Se verifican aria-sort, controles con nombre, columna de identidad protegida, búsqueda, limpieza por teclado, foco inicial/retorno y diálogos anidados. La tabla conserva scroll horizontal propio y acciones ancladas; no se cambia a tarjetas ni se modifica vendor. Las capturas representativas abiertas incluyen catálogo a 1440/320, Procesos a 320, Software a 1440, Correo a 320 y Correo en inglés a 390. Se inspeccionan texto de estados, identidad, procedencia/retirada y foco visible; no se introducen tokens o colores nuevos.

La captura en inglés a 390 muestra que el rango del toolbar puede quedar excesivamente estrecho junto al selector largo de orden, partiéndose en muchas líneas. El layout común de herramientas no se ha modificado aquí; se registra para la revisión de densidad y responsive restante. No se afirma que toda la interfaz esté libre de problemas visuales, ni conformidad WCAG general, compatibilidad con lectores de pantalla o todos los temas.

13. Playwright MCP: cobertura y evidencias

Runner reproducible: scripts/catalog-configuration-ui.test.py. Reutiliza los clientes MCP Docker y helpers existentes; no añade framework ni navegador en WSL. Recibe METIS_PLAYWRIGHT_STORAGE_STATE del preparador, conserva los archivos privados ignorados y bloquea escrituras desde el navegador. Las fixtures GET se validan con los schemas reales antes de ejecutar escenarios; no son una prueba de persistencia del servidor.

Para repetir con una instalación sintética mantenida y volumen preparado:

La compañía debe disponer de al menos 50 personas/activos/recursos, 50 aplicaciones, un certificado activo y una impresora operativa. El runner comprueba estas referencias reales y falla explícitamente si faltan; visual-audit-volume.py prepara el volumen base, pero por sí solo no garantiza todos los escenarios especializados. Completar esas referencias únicamente en la instalación desechable antes de ejecutar el bloque B.

METIS_PLAYWRIGHT_STORAGE_STATE=.artifacts/playwright/authenticated-<ejecución>/session.json \
  python3 scripts/catalog-configuration-ui.test.py

Por defecto, load_tests selecciona los 17 métodos nuevos (61–69 y 71–78), aunque reutiliza la preparación de L04.1. También permite indicar nombres completos de métodos para ejecuciones dirigidas; los resultados de esta entrega se obtuvieron por bloques. Las rutas reales y respuestas de sesión se obtienen del informe privado del preparador. No incorporar session.json al informe ni a Git.

Bloque A: nueve métodos 61–69 correctos

Métodos Verificación ejecutada
61 Diez combinaciones global/compañía y plantillas/campos/relaciones; URL, orden descendente, página 3 y recarga con scroll/foco exactos
62 Cambio de pestaña atómico, ADMINISTRACION/Pena, cancelar edición y teclado; sin pérdida de consulta
63 Accesos global/compañía: kind, orden/página, ámbito environmentId y limpieza
64 50 marcas y 50 plantillas de proceso: sort/página 3 y modal sin crecimiento de History
65 Catálogo de compañía en las siete resoluciones; definiciones propias/heredadas/retiradas
66 Cinco catálogos: refetch 503 conserva tabla y 403 oculta caché, sin pageerror
67–69 Fuente y consulta externa retenidas, restauración sin salto prematuro; preferencias por pestaña y parámetros inválidos

Resultados verdes repartidos entre browser-a-layout-ready.log (61/62) y browser-a-tail.log (63–69). Los intentos fallidos anteriores no se borran: hay errores de selector/etiqueta del test, además del fallo real de scroll corregido en §6.

Bloque B: ocho métodos 71–78 correctos

Métodos Verificación ejecutada
71 Las siete familias con 50 registros: orden/página 3, edición/cancelación, historial, sin resultados y limpieza con foco
72 Restricciones por perfil/persona, cambio a ámbito compañía y retorno al entorno; no se borra la restricción obligatoria
73 Las siete familias: dependencia pendiente, 503 con datos y reintento, 403 sin filas/reintento ni pageerror
74 Errores iniciales y recuperación, vacío real y sin coincidencias en tres familias representativas
75 Procesos: listado/ficha/Atrás o retorno explícito, siete resoluciones con URL/filas/página/sort/scroll/foco exactos
76 Procesos: recarga, retirada GET simulada, regreso durante refetch, limpieza, inválidos, editor cancelado y URL directa ausente
77 Software: 50 instalaciones, página 3, editor anidado/cancelación y enlace al recurso; Atrás vuelve al puesto
78 Correo en siete resoluciones y limpieza por teclado en inglés a 390, conservando perfil y foco

Logs: browser-b-first.log (71–74), browser-b-navigation.log (75/76), browser-b-final-tail.log (72 ampliado) y browser-b-software-capacity.log (77/78). Los reintentos de 77 corrigieron instrumentación: contar diálogos con includeHidden para el padre inerte y esperar la ficha contextual de recurso, en vez de una página que el producto no tiene. No se añadió una ficha nueva ni se cambió el producto para el test.

Datos y límites de transporte

Primera instalación reutilizada: 15 compañías, 59 personas, 137 activos y 73 recursos reales sintéticos. Grafos GET adicionales: 50 sedes, 50 puestos, 50 perfiles, 50 definiciones por colección y 50 registros por familia de configuración/software/procesos. Hay nombres largos/tildes/ñ, distintos estados y referencias coherentes a DTO reales. Enriquecer GET no modifica esa base ni crea datos en otra compañía.

Login/sesión reales; HTML, JavaScript, CSS y componentes reales. Para aislar trabajo concurrente se desactiva HMR en el cliente, se capturan secuencialmente referencias GET reales y se reproducen en lectura. Las respuestas de volumen y fallos son interceptaciones GET declaradas. Esto no certifica el comportamiento concurrente de todas las APIs ni sus mutaciones. Los fallos esperados de red generan mensajes de consola; se distinguen de pageerror y de errores de transporte del entorno.

La primera instalación se cerró externamente durante las regresiones posteriores. Se conservan ECONNREFUSED y session.json ausente como pruebas interrumpidas, no como regresiones del producto. Se comprobó y reutilizó otra instalación existente, ordinaria, con 15 compañías, 50 personas, 51 activos y 66 recursos; no se inició otro entorno visual.

Las capturas/mediciones y logs están en .artifacts/playwright/l04-2/, ignorados por Git. El índice local identifica resultados verdes, diagnósticos y repeticiones; estas imágenes no son evidencia portable por el mero enlace Markdown al repositorio.

14. Pruebas dirigidas, regresiones y comprobaciones técnicas

Las suites existentes de catálogo de Assets/Resources incorporan URL de q/tab/sort/page con datos parseados y búsqueda sin tildes; la prueba falla antes de la implementación y pasa después. Procesos incorpora 30 procesos válidos para URL directa, orden/página y enlaces con consulta. Correo verifica que una referencia obligatoria pendiente conserva la estructura y no se interpreta como vacío. Las fixtures no reemplazan la validación de los schemas reales.

Regresiones MCP: 30 métodos seleccionados correctos

Entrega Métodos / log válido Resultado
L04.1 41, 42, 43, 45, 46 · regression-adoption.log 5/5; Puestos/Perfiles/Compañías, retornos, filtros, columnas y modales
L03.1 01, 04, 05 · regression-context.log; 06, 08, 13 · regression-context-active.log 6/6; Activos/Recursos/Personas, retirada GET, refetch y aislamiento
L03.2 17, 18, 19 · regression-search.log 3/3; Unicode/ñ, catálogos y puntuación técnica
L03.3 25, 26, 27, 31 · regression-filters-active.log 4/4; limpieza, ámbito y parámetros inválidos
L02.3 02, 03, 04 · regression-states-active.log 3/3; dependencias, caché, error/vacío/denegación y recuperación
L02.2 03, 06, 07 · regression-columns-active.log 3/3; preferencias, consumidores simples, campos compartidos y foco
L02.1 01, 03, 07 · regression-pickers-active.log 3/3; capacidad, teclado, selección provisional, activos/perfil/dominio
V01 resource_routes_and_explicit_detail · regression-responsive.log; responsive_resize_focus_and_modality e inventory_resize_focus_and_actions · regression-responsive-volume.log 3/3; resize, foco, panel/diálogo, edición cancelada y ficha

No se repiten todas las suites visuales históricas. V02/V03/V06/V09 mantienen sus componentes; la muestra comprueba foco, modales anidados, i18n, cabeceras y estados, sin certificar contraste general ni todos los asistentes. La selección se limita al alcance de composición afectado y a las regresiones exigidas.

Los primeros tres fallos de filtros proceden de totales fijados en los tests. El runner ahora obtiene people/assets/resources de las respuestas reales, conserva la exigencia de volumen mínimo y compara totales exactos. Los 50 registros creados solo por GET para sedes/perfiles/software siguen teniendo expectativas específicas. Una repetición quedó interrumpida por la retirada externa del entorno, antes de ejecutarse sus comprobaciones. En dos casos V01 el activo conocido dejó de estar en la primera página a causa del volumen: el adaptador lo hace visible con q=AUDIT-PORT-01, conservando las aserciones originales de foco/resize/panel. No se modifica el producto ni se rebajan esas aserciones.

Comprobaciones técnicas

Comando / alcance Resultado ejecutado
pnpm exec tsc --build, proyectos Companies/Assets/Resources/Core/rdx-ui Correcto; scoped-types.exit=0
pnpm exec biome check, 51 archivos TS/TSX/JSON propios Correcto, sin supresiones ni cambios adicionales; scoped-check-final.exit=0
pnpm exec eslint, TS/TSX propios Correcto; dos separaciones entre funciones de Procesos corregidas; scoped-spacing-final.exit=0
Suites de Assets, Core y rdx-ui 27/27, 3/3 y 13/13 archivos-suite correctos
Suites de Companies 47/48 archivos-suite; fallan las dos aserciones de companies-page.test.tsx:180/210 descritas abajo
Suites de Resources Catálogo/recursos y restantes contratos correctos; el primer HTTP falla por listen EPERM del sandbox; repetido con permiso localhost: 2/2 subtests HTTP correctos
pnpm typecheck global Falla en vendor calendar.tsx:165 (locale opcional / exactOptionalPropertyTypes); mismo diagnóstico que baseline-typecheck.log
pnpm lint / pnpm check Fallan; línea base 37/213 errores, ejecución posterior 15/171. Ningún diagnóstico en los 51 archivos propios; detalle completo en lint/check-complete.log
pnpm build Correcto, 2/2 tareas recuperadas de caché Turbo; no se presenta como recompilación forzada
pnpm test --continue=always, MariaDB temporal separada 8/10 tareas correctas; únicamente fallan Companies (243/245) y servidor (8/8 iniciales, 18/19 de integración)
Sintaxis Python Correcta en los tres scripts propios/adaptados, sin instalar herramientas

Los recuentos de Node bajo --test corresponden a archivos-suite; no se convierten en un número inventado de aserciones. La ejecución agregada inicial con pnpm --filter se detuvo tras el fallo de Resources y no ejecutó todos sus dependientes; se ejecutaron después los cinco scripts de paquete individualmente. Resource HTTP se diagnosticó con ejecución directa: listen EPERM 127.0.0.1, y pasó con el mismo código al permitir el socket local.

Las dos aserciones SSR de Companies esperan «Personas (1)» y «Esta persona no tiene acceso a Metis Desk». Se reproducen mediante Node directo en company-failure-direct.log y ya figuran en las evidencias de L04.1; no se modifican expectativas ni UI ajenas a L04.2. Los diagnósticos completos de lint/check incluyen skills, código de fotos/procesos y barrels/formatos fuera del alcance. La línea base está truncada; no se afirma correspondencia uno a uno para diagnósticos que entonces no se imprimieron. La reducción de recuentos durante trabajo concurrente tampoco se atribuye íntegramente a esta entrega.

La suite global se ejecutó realmente con una MariaDB propia, exclusivamente metis_desk_test, retirada automáticamente. La repetición final confirma Assets 146/146, Resources 95/95, Core 11/11, rdx-ui 78/78 y los fallos de Companies y servidor indicados. El único fallo de servidor en esa repetición es identity.test.ts:82, HTTP 401 frente a 404, exactamente el escenario diagnosticado antes de implementar (§5). No se alteran autenticación, endpoints ni fixtures.

La primera ejecución global también falló al importar resource-application.response.dto.ts:15, ResourceSpecificationSchema no definido, en typed-relationships/windows-domains-ui. Ese DTO estaba siendo modificado fuera de L04.2; su importación se corrigió externamente antes de la repetición. Ambos logs se conservan (test.log y test-repeat.log); estos dos fallos no se presentan como deuda histórica confirmada ni se ocultan bajo el 401/404. Tipos dirigidos comprobados nuevamente tras ese cambio: scoped-types-final.exit=0. Las dos MariaDB propias se retiraron con código 0.

Archivos y revisión documental

Inventario propio: 62 archivos (51 TS/TSX/JSON: Assets 8, Resources 6, Companies 37; 3 scripts y 8 documentos). Controladores/vistas adaptados, hook de presentación, composición de layout/ámbitos, traducciones y cuatro suites existentes son los cambios principales. scripts/adoption-ui.test.py solo admite un directorio de evidencias opcional, con su default anterior; scripts/filter-ui.test.py elimina totales fijos de la base real.

Lista completa local: archivos modificados y índice de evidencias. El workspace ya tenía cambios extensos de otras entregas; el inventario no atribuye a L04.2 todo el diff de esos archivos. Hay copia previa de 42 archivos de código propios; otros ocho archivos de composición y el nuevo hook se identifican separadamente en baseline-not-copied.txt.

Se conservan las observaciones históricas y se añaden seguimientos en DESIGN, L01, L03.1, L04.1, patrón, componentes y rutas. Los enlaces nuevos resuelven. El único enlace roto del barrido es el histórico de L01 a workstation-people.tsx, ya presente en la copia inicial; no se modifica una referencia histórica ajena para aparentar un barrido sin incidencias.

git diff --check es correcto. No quedan clientes MCP propios activos ni bases de integración propias; se confirma la retirada por sus dos nombres exactos. La instalación visual reutilizada y su sesión quedan a cargo de su propietario: no se detienen ni borran.

15. Limitaciones y frontera de la entrega

No se guardan formularios ni se ejecutan bajas/retiradas reales de negocio. Se comprueba apertura/cancelación y lectura de historiales, no la persistencia positiva de cada editor. No se reauditan la seguridad de producción, todas las combinaciones administrativas ni todos los enlaces posibles. Denegaciones del servidor se simulan mediante GET para verificar la UI, sin sustituir pruebas de autorización del backend.

El diagnóstico 401/404 está en §5; no se cambia para obtener checks verdes. La deuda de vendor y los cambios simultáneos ajenos se mantienen identificados por sus logs. No se modifican dependencias, migraciones, HTTP, modelos ni paquetes vendor por L04.2.

16. Pendientes para L04.3 y cierre de fase

L04.3/L04.4 conservan su alcance pendiente: sublistados/consumidores restantes y cierre transversal documental, según L01. No se declara L04 ni V05 resueltos universalmente. La revisión de densidad del toolbar largo, auditoría de accesibilidad ampliada y guardados positivos requieren escenarios propios; no se presentan como comprobados aquí.

Seguimiento L04.3

L04.3 distingue software en modal (consulta local) de software en ficha navegable (estado de lectura de esa entrada). Conserva las restricciones de perfil/persona y los contratos de catálogos/configuraciones. La nueva composición de relaciones reutiliza el contrato de estados y retorno; los resultados y fallos globales históricos aquí documentados permanecen como evidencia anterior.