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

42 KiB
Raw Blame History

L04.3 — Sublistados, relaciones y selectores

Fecha: 24 de octubre de 2026. Alcance limitado a L04.3; L04.4 y la densidad móvil general L01-01 permanecen pendientes.

1. Resumen ejecutivo y fuentes

Inventario previo a cambios funcionales. Se consultan AGENTS, DESIGN y la matriz de skills; L01 y auditoría visual; L02.1/L02.2/L02.3; L03.1/L03.2/L03.3; L04.1/L04.2; patrones de listados, listados compactos y diálogos; componentes, rutas y procedimiento Playwright. Los documentos históricos conservan sus medidas y limitaciones.

Skills principales: ux-tables y ux-inputs-and-forms. Complementarias: navegación/búsqueda para retorno y proveedor remoto; recuperación/vacíos/microcopy para estados; shadcn para APIs Base UI; composición y React para estado mínimo y responsabilidades. No se ejecutan generadores ni se instalan dependencias. Los auditores ux-*-audit y orchestration-policy ausentes no se presentan como ejecutados. Los patrones propios prevalecen sobre las recomendaciones genéricas de columnas, altura y acciones.

2. Inventario previo: lectura de la matriz

Cada fila identifica un consumidor real. Q = TanStack Query, P = props derivadas del propietario, L = estado local mientras permanece montado, C = cursor del proveedor, T = EntityTable (búsqueda/orden/página locales salvo indicación), K = compacto sin herramientas añadidas. Las tablas T conservan identidad protegida, tamaño y preferencias existentes. Ningún sublistado hereda automáticamente sort/page/q del listado autónomo padre. Las confirmaciones conservan sus operaciones y permisos actuales.

La clasificación inicial es de código; no equivale a una prueba visual. Las verificaciones posteriores identifican qué escenarios se ejecutaron.

3. Sublistados

Consumidor / módulo y ubicación bajo src/web Propietario, datos y ámbito Búsqueda / orden-página / selección Acciones y navegación Duración / responsive / accesibilidad / clasificación previa
CurrentWorkstations · Companies · people/detail/ui Persona; Q inventario/perfiles y P compañía K; sin búsqueda/paginación ni selección Enlaces a puestos y activos L durante ficha; lista adaptable y enlaces reales. Corregir referencia pendiente/error para evitar ausencia engañosa; retorno de ficha pendiente
WorkstationAssets · Companies · workstations/detail/ui Puesto; P inventario/catálogo K con CollectionPreview; orden principal y miembros de dominio; sin selección Enlaces a activos, editar puesto Preview L; composición por contenedor ya verificada en v2/v3. Conservar expansión y foco al navegar; no rediseñar
WorkstationProfiles · Companies · workstations/detail/ui Puesto; P perfiles/personas/cuentas y estados K/CompactTable; archivados y preview L; expansión de configuración Enlaces a persona/perfil/cuenta; alta y disclosure Mantener estados y elegibilidad v2/v3, sin tabla de exploración nueva. Revisar retorno y expansión; identidad adaptable 840/600
AssetRelatedInformation (perfiles) · Companies · assets/detail/ui Activo; Q perfiles y P compañía T local; ninguna selección Enlaces a perfil/persona Estado de referencia debe usar contrato L02.3; retorno no conserva consulta/página. Scroll interno y nombre protegido existentes
SoftwareInstallationsPanel · Companies · software-installations/list/ui Activo obligatorio; Q software/recursos/catálogo T; q/closed/orden/página L Editor/historial modal, enlace al recurso Estados corregidos L04.2. Distinguir ficha (retorno) de modal (interacción local); no heredar q del padre
PersonDetails (asignaciones) · Companies · people/detail/ui Persona; P asignaciones/departamentos T local; sin selección Editar/historial/borrado existente Conservar tabla durante modales; consulta independiente del listado Personas. Retorno desde otra relación de la ficha pierde estado local
DepartmentSection · Companies · departments/list/ui Compañía; P departamentos/asignaciones/personas T local; sin selección Edición modal; avatares enlazan a personas Identidad y API de edición correctas; no nueva ficha de departamento. Revisión de estados del propietario y retorno contextual
SiteSection · Companies · sites/list/ui Compañía; P sedes T, archivadas L, limpieza L03.3 Modal alta/edición, archivo/restauración/borrado elegible Excepción modal legítima; no existen fichas ni tablas de personas/puestos por sede en esta pantalla
CompanyOverview · Companies · companies/detail/ui Compañía; P resumen y relaciones agregadas K, métricas/enlaces; sin selección Destinos reales de sección No convertir métricas en tablas; propietario ya conserva ámbito
EnvironmentContent/EnvironmentSection · Companies · work-environments/detail/ui Perfil/entorno; Q agregado de once fuentes Listas por familia y disclosure; sin paginar localmente las referencias Gestionar configuración y enlaces existentes No crear fichas para configuraciones. Corregir desmontaje tras error con caché y distinguir referencias pendientes; conservar L04.1/L04.2
DashboardDetailsDialog (compañías) · Companies · dashboard/detail/ui Dashboard/modal; Q resumen de compañías T local; sin selección Navegación a compañía Identidad protegida L02.1. Revisar estabilidad de carga/error y modal con tabla
DashboardDetailsDialog (registros/actividad) · mismo Dashboard/modal; Q proveedor por página/actividad Página del servidor; actividad cronológica, sin búsqueda local ficticia Destino de registro Excepción legítima frente a T; no repaginar página remota ni ordenar historial de negocio
ProcessDetail (tareas) · Companies · processes/detail/ui Proceso; P tareas e historial Orden de instrucciones, sin T ni selección tabular Seguimiento modal No imponer orden alfabético al proceso; retorno de listado L04.2 permanece

4. Relaciones

Consumidor / ubicación Propietario y datos / ámbito Operaciones y navegación Estado, capacidad y decisión previa
AssetRelationships · Assets · asset-relationships/list Activo; Q inventario, relaciones activas Asociar/finalizar/borrar existentes; enlace a otro activo Lista L; falsa ausencia inicial en código. Estados y marcador de origen para retorno, sin alterar reglas
AssetRelationships, finalizadas · mismo Activo; mismo Q, endedAt Historial separado en details; no confundir con vigente Conservar orden y disclosure, identidad de relación y extremos; sin paginación artificial
DirectoryRelationships/DirectoryRelationshipTable · Assets · directory-memberships/shared Activo o dominio-recurso; Q página y summaries Enlace al otro extremo; rol/estado declarados por proveedor C local independiente por instancia; corregir pérdida de filas en refetch fallido, sin inferir totales ni roles
PublicationList activa · Assets · network-share-publications/shared Activo o SMB; Q página/summaries/publications Traslado/finalización modal; enlace recurso/publicador C; conservar página y tabla ante error posterior, identidad record y permisos actuales
PublicationList histórica · mismo Mismo ancla, consulta includeEnded separada Histórico con periodo/actor; sin acciones de relación activa C separado del activo; no orden local ni totales inventados
AssetLocalIdentities · Companies · local-identity-environments/detail Activo; Q identidades/accesos Crear/asociar/retirar existentes; enlace al entorno C; acceso indispensable para etiquetas. Evitar falso vacío/referencias incompletas y conservar datos en actualización
MailboxRelations · Companies · mailboxes/shared/ui Buzón-recurso; Q usos y P personas Asociación/cierre modal; fechas y persona Lista, sin T; estados incompletos y ausencia sin mensaje; conservar identidad y vigencia
AssetPrinterUsage · Companies · infrastructure/shared/ui Impresora; Q configuraciones/perfiles y P compañía Enlaces a usuarios/equipos según consumidor Lista documental, no puertos de red. Revisar referencias/estado sin cambiar modelo
CompanyResourceRelatedContent · Companies · resources/detail/ui Recurso; P capacidades de dominio/SMB/buzón Composición anterior y enlaces cuentas/grupos/permisos con resourceId/environmentId No inventar propietario universal: publicador SMB, entorno de dominio y usos de buzón son relaciones diferentes
Catálogo/plantillas: FieldSections/TemplateSectionsEditor y diálogos de definición Definición; P secciones/campos Reordenación/edición/selección de composición Excepción: orden de dominio, no tabla administrativa nueva. Probar selector anidado sin modificar composición
AssetSupport y bloques de soporte del puesto Activo/puesto; Q y P contratos de soporte existentes Gestión en diálogo y datos documentales Mantener composición v2/v3; no convertir tarjetas en T. Regresión de apertura/cancelación
AssetDirectoryMembership · Assets · directory-memberships/detail Activo; Q pertenencia vigente + elegibilidad Asociar, rol, trasladar/finalizar con comandos existentes; dominio enlazado Agrega ambas fuentes, distingue vacío/fallo, conserva historial de lectura; el picker aplica al editor, no al servidor

No existe relación directa universal Persona→Activo: se deriva de puestos/perfiles y conserva ambas semánticas. Tampoco existe un ResourcePickerList de producción: los recursos se eligen mediante SelectWithAction o proveedores remotos específicos. No se crean componentes con esos nombres para rellenar el inventario.

5. Selectores y contenedores

Consumidor / ubicación Datos, ámbito y selección Búsqueda/orden/página Confirmación/cancelación y decisión previa
AssetPickerDialog/List · Assets · assets/select Q inventario/catálogo + infraestructura accesoria; compañía y options elegibles; única/múltiple T local fill, filtro por plantilla; borrador no se pierde al buscar Remonta al abrir; confirmar cambia formulario padre, no servidor. Revisar carga/error estable, actualización de elegibilidad y recuperación de selección inválida
FieldPickerDialog/List · rdx-ui y adaptadores Assets/Resources catalog-fields/select P campos/canAdd; múltiple T local, identidad/selection protegidas Confirm booleano: false conserva borrador/error; alta rápida anidada separada. Contrato existente correcto; verificar a volumen y tamaños estrechos
OptionPickerDialog/List / OptionSelectionField · rdx-ui P opciones; única T local fill; sin preferencias nuevas available deriva opciones actuales. Cancelar no aplica; remonta al reabrir; confirmar evita disabled. Correcto en código
WorkProfileSelectionField · Companies · work-profiles/shared P candidatos de puesto/persona/cuenta; compañía/perfil Adaptador OptionSelectionField Respeta elegibilidad y texto de restricción; no crear selectores independientes por cada entidad
PublicationPicker (asset/share) · Assets · network-share-publications/select Q proveedor con AbortSignal; compañía, excludedId; única provisional Búsqueda remota y cursor; no orden/página local RemoteOptionPicker conserva copia de opción: revalidar si reaparece modificada/deshabilitada. Conservar borrador legítimo fuera de la página
DirectoryDomainPicker · Assets · directory-memberships/select Q dominios; compañía, excludedId; única inmediata Proveedor remoto por cursor y búsqueda Botón aplica elección al editor padre, sin confirmar entidad en servidor; no añadir segundo paso. Verificar respuesta obsoleta y error
SelectWithAction de persona/compañía/sede/cuenta/recurso y RemoteEndpointFields/RemoteTargetField P opciones acotadas; única Combobox/Select simple; sin tabla/cursor inventados Conservar API y alta relacionada; no convertir enums ni referencias acotadas en PickerList
LocalIdentityEditor · Companies · local-identity-environments/manage Editor con campos de entorno/sistema; Q/P Select simple y referencias Operación modal de dominio, no selector remoto universal; abrir/cancelar conserva dueño
IconPicker · rdx-ui Catálogo local de iconos Búsqueda propia, no entidades Fuera de selección de entidades; mantener contrato

El inventario de selectores acotados se concreta en: CompanySelect (Companies, companies/shared/ui, props de compañías, Select Base UI y alta opcional); WorkProfileSelectionField en sus tres usos workstation/person/account (Companies, work-profiles/shared/ui, OptionSelectionField local); RemoteEndpointFields (Companies, remote-connections/shared/ui, origen y destino dependientes del tipo); RemoteTargetField (misma ubicación, AssetSelect para activo y SelectWithAction para sede/recurso). Se conservan sus ámbitos, campos bloqueados y acciones de alta. Los adaptadores CatalogFieldPickerDialog/List de Assets y Resources consumen FieldPicker, cada uno con su catálogo; no son un proveedor universal nuevo.

Durante la ejecución aparece SoftwareApplicationPicker (Resources, application-references/select/ui): TanStack Query, búsqueda remota diferida, cursor, selección única y restricciones de asociación global. Se inventaría por código como trabajo concurrente, sin modificarlo ni certificar su proveedor. Su callback requiere un candidato presente en la página actual; debe revisarse específicamente la confirmación de una selección conservada fuera de esa página. Los resultados del selector de publicaciones no demuestran ese caso.

Contenedores reales: FormDialog/FormBody/FormActions, Sheet de navegación, Popover de ayuda/columnas, paneles contextuales V01.3/V01.4, Tabs y Collapsible. No se localiza un Drawer propio de estos consumidores. No sustituir primitivas Base UI ni añadir traps de foco.

6. Matriz de duración y cambios previstos

Estado Duración adecuada Decisión antes de implementar
Listado autónomo URL + History de retorno + preferencias existentes Mantener L02–L04.2; solo regresión
Consulta/orden/página de tabla de ficha con navegación real Entrada de la ficha propietaria, sin contaminar parámetros del listado padre Adaptación mínima al History existente si se confirma pérdida; validar datos de UI, nunca DTO. Consumidores reales: perfiles/software de activo y asignaciones de persona
Expansión de preview/disclosure de ficha Interacción y retorno de esa ficha Conservar cuando el enlace originario desaparecería del preview; sin persistencia global
Coordenadas/foco de ficha Contrato useListReturn existente Reutilizarlo; no otra arquitectura. Esperar fuentes de composición; recursos conserva su contrato contextual de inventario
Borrador de selección Solo apertura del diálogo L; nunca History/URL/localStorage
Cursor y búsqueda de proveedor Consulta del proveedor, ligada al ancla Mantener C y AbortSignal; no normalizar remotamente por suposición
Columnas y tamaño Preferencias ya habilitadas No cambiar claves ni introducirlas para listas triviales
Datos/remotos y errores TanStack Query Derivar disponibilidad de todas las referencias; denegación no expone caché

7. Verificación inicial y límites

Sesión ordinaria real reutilizada, sin preparar otra instalación: localhost:55317. Preflight MCP: 15 compañías, 50 personas, 51 activos y 66 recursos. Lectura; archivo privado de sesión fuera de Git. Las ampliaciones posteriores se harán por GET sintéticos validados. El workspace estaba ampliamente modificado: copias previas de 2090 archivos e inventario de Git en .artifacts/playwright/l04-3/. No se atribuye todo su diff a L04.3.

Se implementa la conservación del estado de lectura de fichas sobre History nativo, separada de la selección transaccional y de la caché remota. Se comprueban pérdidas de contexto y la elegibilidad de una selección modificada. Los bloques de relaciones adoptan los estados de consulta compartidos. La validación no equivale a conformidad universal de todos los consumidores inventariados.

La sesión reutilizada caducó durante la ejecución (cookie de ocho horas). No se recuperaron credenciales ni se alteró su seguridad. Se preparó después una instalación propia: el primer intento autenticó pero agotó la espera del listado y limpió automáticamente; el segundo bloqueó HMR solo en el navegador de diagnóstico y completó el recorrido real. Origen propio: localhost:55867. visual-audit-volume.py comprobó 15 compañías, 50 personas, 51 activos y 66 recursos persistidos únicamente en metis_desk_test. Las extensiones de lectura producen 66 activos, 116 recursos, 50 puestos, 50 perfiles (46 en el principal y 4 en otro ordenador para evitar duplicados activos persona/host), 50 asignaciones y 50 registros por familia de configuración, además de 50 publicaciones, 25 periodos finalizados y 50 pertenencias. Se añade una comprobación de unicidad de perfiles activos por persona/ordenador, además de los schemas. Los campos, referencias y pertenencia de compañía se validan con los schemas reales y comprobaciones del grafo. No se presentan como escrituras de esas relaciones.

La preparación ordinaria usa HTTP real; las pruebas de interfaz posteriores bloquean escrituras. Las retiradas, errores, latencias y respuestas obsoletas son interceptaciones GET. La API de referencias de software añadida concurrentemente usa POST de solo lectura; se intercepta explícitamente con el schema instalado, sin enviar esa petición al servidor ni permitir mutaciones. No se prueba una publicación efectiva en SMB, Active Directory ni equipos reales.

8. Problemas demostrados y cambios por consumidor

Hallazgo Evidencia y corrección Límite
Confirmación de opción remota que acaba de quedar deshabilitada El ensayo inicial 81 falló: el radio estaba deshabilitado pero el pie permitía confirmar. RemoteOptionPicker deriva la opción actual por UUID y bloquea confirmación durante carga/error o inhabilitación Una opción legítimamente fuera de página sigue seleccionada. Su vigencia fuera de la respuesta visible se vuelve a validar en el comando propietario
Consulta/página/orden de sublistado perdidos al volver Ensayo inicial 82 falló. Perfiles/software del activo y asignaciones de persona utilizan contextos independientes de ficha No copia q/sort/page del listado padre; no serializa DTO
Foco y desplazamiento de otra tabla useListReturn identifica la tabla del origen; se prueba el segundo sublistado con desplazamiento horizontal y activación Enter Medir antes del clic sobre un enlace parcialmente oculto era un error del ensayo: Playwright lo desplazaba para hacerlo visible. Se usa activación de teclado para comprobar X sin ese efecto
Layout compuesto todavía incompleto al volver CompanyEntityContext espera consultas activas de composición y su estado ya renderizado en el DOM. useListReturn vuelve a medir mediante ResizeObserver antes de aplicar el contexto Las medidas iniciales con marcadores pendientes se separan del origen estable; no se rebajan las comparaciones de coordenadas
Preview y configuración expandida desaparecen durante el viaje CollectionPreview admite control opcional; puesto conserva preview, archivados y expansión de perfil. PrinterUsage conserva su historial desplegado No se guarda selección provisional ni se reejecuta una solicitud imperativa antigua de foco
Relación con referencias pendientes mostrada como ausencia CurrentWorkstations, identidades locales y perfiles agregan sus fuentes necesarias antes de declarar vacío No se deducen relaciones ni se crean asignaciones
Un refetch fallido eliminaba la información disponible Publicaciones, directorios, vínculos de activos, uso de impresoras, buzones y entorno de perfil adaptan EntityListStatus/entityListState Error recuperable conserva caché con aviso; denegación oculta filas y acciones de lectura/mutación pertinentes
Reintento de publicaciones reiniciaba cursor El reintento refetch de la página actual conserva el cursor; Primera página sigue siendo una acción separada No calcula offsets ni totales
Modal de recurso fuera del root del inventario Retorno de detalle separado del retorno de listado; desplazamiento en FormBody cuando corresponde El foco inicial del panel continúa a cargo de V01/Base UI; el bloque relacionado solo restaura un retorno guardado

La matriz previa es un inventario, no una declaración de que todos los elementos necesitan cambios. SiteSection, DepartmentSection, procesos, controles SelectWithAction y editores de secciones conservan sus estructuras y reglas. DashboardDetailsDialog mantiene su implementación; su rama de actividad/registro pertenece al proveedor y su revisión específica de estados con caché permanece sin validación en esta entrega. No se corrige el dashboard completo por proximidad.

9. APIs compartidas y responsabilidades

  • Core: useEntryState valida mediante Zod únicamente estado de lectura por ruta propietaria y clave. Usa metisEntryState de la entrada History actual. Conserva metadatos ajenos. Sin scope coincidente se comporta como estado local. El consumidor remonta al cambiar de propietario. Los límites de serialización no impiden seguir interactuando: el valor inválido no se escribe en History.
  • useDetailTableContext de Companies adapta esa lectura a EntityTableNavigation; cada tabla tiene búsqueda, orden y página propios. El consumidor mantiene su filtro semántico y proporciona los datos. Página uno se canoniza a null. No se añade una URL alternativa ni se duplica TanStack Query.
  • useListReturn conserva su comportamiento por defecto. kind: detail utiliza un registro de retorno separado para la ficha, compatible con el registro existente de listado. Captura el contenedor de scroll más cercano (FormBody o workspace), la tabla accesible y el UUID/href de origen. canRestore comprueba caché y tablas todavía ocupadas en el DOM. ResizeObserver y MutationObserver esperan geometría y commits reales de los indicadores de consulta hasta restaurar una vez y se desconectan; no sondea ni añade temporizadores. El modal propietario permite restaurar dentro de sí, pero un modal anidado sigue impidiéndolo; initialFocus: false evita orientar de nuevo un panel que V01 acaba de abrir, conservando restauración cuando existe un contexto guardado.
  • CompanyEntityContext compone esas capacidades para fichas. En Recursos se limita al contenido relacionado, con clave por recurso; el inventario mantiene su contrato de retorno. No duplica queries ni almacena filas.
  • CollectionPreview.expanded/onExpandedChange es opcional; los consumidores sin control conservan el estado interno. CompactListItem.entityId aporta identidad de origen sin conocer entidades ni rutas.
  • FormDialog.initialFocus="title" es una opción explícita para la ficha modal de recurso: enfoca su título antes de restaurar un retorno, evitando confundir el primer enlace autoenfocado por Base UI con una acción del usuario. Los pickers conservan su búsqueda por defecto.
  • RemoteOptionPicker.finalFocus y los adaptadores de publicación/directorio reutilizan la propiedad instalada de FormDialog/Base UI. Los editores aportan el ref del disparador. Reintentar orienta hacia un control persistente, evitando perder foco al desaparecer el botón.
  • useAssetCollectionState aporta textos de Assets al contrato entityListState. Companies reutiliza useCompanyListState y reconoce también las APIs existentes que expresan denegación mediante Error.message. Ninguno consulta endpoints.

No se modifica EntityTable, TanStack Table, vendor, tokens, CSS global, Base UI ni los proveedores del servidor para esta entrega. Los cambios concurrentes ajenos visibles en el workspace no se atribuyen a L04.3.

10. Navegación y duración del estado

Los contextos de perfiles, software y asignaciones se escriben en claves diferentes de la ficha. La navegación real conserva la entrada propietaria y la restauración valida ruta y metadatos. El registro de retorno incluye tabla cuando existe; si desaparece el origen, se utiliza la búsqueda de esa tabla antes de recurrir al root. El listado padre sigue validando sus propios parámetros y preferencias.

Los cursores de relaciones se conservan por ancla e instancia activa/histórica. Se almacenan los tokens recibidos, sin interpretar su contenido ni convertirlos en números de página. Se validan los límites del contrato; identidades locales valida UUID. La pila conservada está acotada a 100 entradas; no constituye un límite de navegación del proveedor, pero una pila mayor deja de serializarse para retorno. No se afirma continuidad ilimitada de miles de páginas.

Se conserva la separación de ámbitos por compañía, persona, perfil, activo y recurso. Un ámbito distinto descarta el estado anterior. Los mensajes de referencia desconocida muestran — cuando corresponden a una celda; los estados de consulta y ausencia siguen siendo mensajes propios.

11. Selección provisional y confirmación

AssetPicker, FieldPicker, OptionPicker y PublicationPicker mantienen el borrador solo mientras está abierto el diálogo. Buscar o paginar no aplica cambios al formulario; Cancelar/Escape no invoca persistencia y reabrir inicia una interacción nueva. Confirmar una selección puede actualizar el formulario padre, sin significar guardado en servidor.

AssetPicker valida candidatos actuales, límites y disponibilidad de inventario/catálogo. En selección múltiple se permite retirar una opción ya seleccionada que haya dejado de ser elegible; no puede confirmarse una selección inválida. RemoteOptionPicker usa la opción actual si reaparece en la página, impide confirmar disabled/carga/error y conserva una elección fuera de página. DirectoryDomainPicker aplica la referencia inmediatamente al editor, como antes; el guardado de pertenencia sigue siendo otra operación. No se añade un segundo paso de confirmación artificial.

Los ensayos confirman aplicación al editor de publicación y cancelación posterior. No se ha guardado esa publicación ni trasladado una pertenencia real. Las validaciones de comandos, conflictos y autorización del servidor conservan su semántica y sus pruebas existentes.

12. Local y remoto

Colección Operaciones Contrato conservado
Tabla local completa / picker local Filtrado normalizado, orden y paginación locales; selección por identidad Utilidades L03.2, UUID y callbacks existentes. No se filtra por índice ni se confunde ñ/n
Publicaciones / pertenencias Página y cursor del proveedor; resumen únicamente de la página Sin ordenación local de la página, totales o roles inferidos
PublicationPicker search + cursor remotos y AbortSignal Cambiar consulta reinicia cursor. Claves separadas descartan respuesta obsoleta. El fixture remoto solo busca como se declara, sin acreditar normalización del servidor
DirectoryDomainPicker Búsqueda/cursor remoto y elección inmediata UUID excluido deshabilitado. Se verifica el dominio real excluido y cero coincidencias; no se acredita una colección real de 50 dominios
SelectWithAction / enums Selector acotado y alta contextual instalada Se mantienen; no se convierte cada referencia en tabla

13. Responsive y geometría

Matriz de tamaños: 1920×1080, 1440×900, 1366×768, 1024×768, 768×1024, 390×844 y 320×640. El selector real de publicaciones se comprueba en los siete tamaños: diálogo contenido en viewport, sin overflow horizontal global, columnas accesibles y borrador independiente del resultado visible. Los cursores y acciones pertenecen al diálogo, y la altura sigue el patrón picker existente.

Los sublistados de perfiles/software conservan scroll horizontal propio. En 320 px la tabla de miembros del dominio requiere scroll interno y no ensancha el documento. Las fichas de persona/puesto y el publicador móvil conservan la composición instalada. Las regresiones de selectores aportan zoom efectivo de texto del 200 %, nombres largos, ayuda, primera columna compacta y pie visible.

No se rediseña la densidad móvil de todos los listados. L01-01, jerarquía global de fichas, V04 y L04.4 no se consideran resueltos por estas medidas.

14. Accesibilidad

Se ejercitan foco inicial de búsqueda, radios/checkboxes por teclado, Escape/Cancelar, retorno al disparador de un selector anidado, Enter en enlaces y retorno al registro de origen. Si el registro desaparece, la búsqueda de la tabla queda disponible como alternativa. El reintento se orienta a un elemento persistente. Los controles usan etiquetas y estados reales de Base UI; no se añade un focus trap manual.

La tabla de selección conserva selection al principio y la identidad protegida. Las filas de relaciones/historial tienen identidad estable. No se afirma conformidad WCAG completa: faltan auditoría con lector de pantalla, otros navegadores y verificación global de contrastes de todas las superficies.

15. Pruebas automatizadas y regresiones

La nueva suite scripts/embedded-relations-ui.test.py amplía los helpers MCP y las fixtures anteriores; embedded-relations-fixture.js se limita a datos sintéticos de lectura. software-reference-read.fixture.js simula únicamente el resolve de referencias de software del contrato concurrente instalado; no autoriza otros POST. El grafo se valida antes de la interacción. No introduce framework, rutas productivas de prueba ni dependencias.

Core verifica metadatos inválidos, aislamiento de 15 propietarios y coexistencia de retorno de listado/detalle. rdx-ui prueba preview controlado/no controlado e identidad. Assets añade pruebas observables de carga con cabeceras, error recuperable con datos y denegación sin filas. Companies conserva su prueba de carga/perfil ausente y adapta el caso de fallo parcial con caché a la nueva presentación; el helper de disponibilidad cubre errores con code y message.

Los ensayos conservan también la corrección del grafo de perfiles (los repetidos activos se distribuyen entre hosts) y el desfase de 32 px asociado al layout todavía en actualización. Se repiten los escenarios afectados con cardinalidades válidas y espera de layout real. Los reintentos de instrumentación se conservan en evidencias: fixture characteristics es un record, selectores que confundían el modal padre con el último hijo y mediciones anteriores al scroll automático de un clic. No se presentan como fallos del producto ni se cambian las expectativas de negocio para obtener verde.

Resultados finales y comandos: véase la tabla de validación al final de este documento.

Correspondencia con los 22 escenarios mínimos

Escenario Ensayo y alcance
1. Persona con varios puestos/activos 88: cinco puestos responsables y uso derivado de perfiles; no se inventa Persona–Activo directo
2. Puesto con activos 41/89 y regresión de puesto: enlaces de composición y perfiles, preview y configuración expandida
3. Activo con relaciones 85/90: publicaciones vigentes/históricas; vínculos genéricos vacíos conservan su mensaje
4. Recurso con propietario/vínculos 86/91: dominio con miembros y SMB con publicador; retorno desde modal de recurso
5. Configuración vinculada a perfil 42/71: entorno → configuración, editores/historial y cancelación, sin guardar
6. Búsqueda + orden + página 82/87: criterios independientes de tablas y del padre
7. Relacionado y regreso 82/85/86/88/89/93: UUID, scroll y foco
8. Selector local: buscar/seleccionar/cancelar Regresión L03.2 caso 20 y pickers 03/07
9. Seleccionar/cambiar búsqueda/confirmar Pickers 03 y búsqueda 20: aplicación al formulario/fixture, sin persistencia
10. No elegibles 81/91/92: opción actual disabled, publicador y dominio excluidos
11. Consulta + cursor remotos 83, página siguiente y nueva consulta; 86, página dos de miembros
12. Respuesta obsoleta 84: consulta antigua retenida y liberada después de la nueva
13. Error y reintento 84: 503, confirmación bloqueada, búsqueda/foco y recuperación
14–15. Selector 320/390 px 83, más matriz de pickers locales
16. Scroll horizontal interno 87 y 86: segundo sublistado y miembros en modal, sin overflow global
17. Escape y foco 83/92 y regresión pickers: solo cierra la interacción superior
18. Vacío y sin coincidencias 84/92 y estados de lista anteriores, diferenciados de fallo
19. Refetch 85/90: datos previos, busy real y reintento sobre el cursor actual
20. Activos/Recursos/Personas Regresiones de contexto, estados, búsqueda y filtros
21. Puestos/Perfiles/Compañías Regresiones 41–43, matriz original y recorridos 88/89
22. Catálogos/configuraciones Regresiones 61/71/73/75/77, sin alterar el ámbito obligatorio

16. Evidencias Playwright

Raíz local ignorada en Git: .artifacts/playwright/l04-3/. after/ contiene capturas, snapshots, mediciones por PID, validaciones de grafo, consola y bloqueo de escrituras. regressions/ separa las suites anteriores; los logs de cada ejecución indican su resultado. Los PNG representativos se abren e inspeccionan, además de medirlos.

El índice de evidencias y el archivo de entrega seleccionan imágenes/mediciones sin sesiones ni credenciales. No se distribuye session.json, ficheros de entorno ni el perfil del navegador. Las capturas muestran exclusivamente datos sintéticos. Un PNG aislado no sustituye un resultado funcional.

17. Diagnóstico de fallos globales

Antes de los cambios se ejecutaron typecheck/lint/check y se conservaron logs, status y copia de 2090 fuentes. Se compara cada fallo con L04.1/L04.2 y con esas copias; no se clasifica automáticamente todo rojo como anterior.

  • Vendor: packages/shadcn-ui/src/components/calendar.tsx:165, TS2375 por locale opcional frente a exactOptionalPropertyTypes. Presente en baseline y en L04.2; no se modifica vendor.
  • Companies: las aserciones antiguas de companies-page.test.tsx:180 (Personas (1)) y :210 (texto de acceso) están documentadas en L04.2 y reaparecen. No se alteran sus expectativas para ocultarlas.
  • HTTP/identity: la prueba de apps/server/src/identity.test.ts:82 pide 404 anónimo en /api/dashboard/work y recibe 401 del middleware previo. L04.2 verificó 401 anónimo/404 autenticado. No se cambia autenticación, autorización ni expectativa como parte de una adopción de UI.
  • Durante el trabajo apareció TS2339 en sequelize-software-installation.repository.ts:56, sobre resourceId de SoftwareRevisionRow. La copia previa no contiene ese código: es un cambio concurrente de persistencia, ajeno a esta entrega. Desaparece en la comprobación dirigida final, sin modificar persistencia en L04.3. No se declara preexistente sin más.
  • Los primeros ensayos de Resources en sandbox fallaron al abrir loopback (listen EPERM 127.0.0.1); el diagnóstico con aislamiento desactivado lo mostró y la repetición con permiso de red pasó. No se clasifica ese intento como fallo de la implementación.
  • Los fallos propios iniciales de mensajes/expectativas en SMB y entorno se corrigieron y repitieron. La prueba anterior ocultaba caché ante error recuperable; las nuevas aserciones exigen conservarla con aviso y ocultarla ante denegación.

Lint/check ya fallaban en la línea base y también incorporan diagnósticos concurrentes en APIs y software global ajenos a L04.3. lint-comparison.json y check-comparison.json comparan archivo/regla con la línea base; no aparece ningún diagnóstico final en los ficheros de esta entrega. No se atribuye toda la deuda al pasado ni se corrigen otros trabajos por proximidad.

La tabla final distingue el resultado global de las comprobaciones dirigidas. El workspace recibe cambios concurrentes: las validaciones describen la revisión registrada por cada log, no garantizan que otros trabajos posteriores permanezcan invariables.

18. Excepciones y límites

  • No se crea una relación universal Persona–Activo ni un ResourcePickerList inexistente; se conservan los caminos reales por puestos/perfiles y los selectores específicos.
  • No se crean fichas de configuraciones ni tablas de personas/puestos de sede que no existen. Historial y orden de tareas/secciones siguen su semántica de dominio.
  • Identidades locales y buzones se adaptan por código y tienen pruebas nativas; no se acredita un recorrido MCP completo con 50 periodos locales ni 50 usos de buzón en una ficha de recurso.
  • El contrato de confirmación rechazada de FieldPicker (callback false) conserva su implementación; no se acredita aquí un ensayo MCP específico de ese rechazo.
  • SoftwareApplicationPicker, añadido concurrentemente en Resources, reutiliza RemoteOptionPicker con otro contrato y selección inicial. No se certifica ese proveedor ni sus reglas globales mediante los ensayos de publicaciones.
  • DashboardDetailsDialog queda inventariado; falta ensayo específico de error/refetch de sus tres ramas. No se afirma adopción universal de todas las superficies inventariadas.
  • No se acredita desasociación persistida ni foco posterior a un guardado destructivo. Se usan desaparición GET, cancelaciones y pruebas nativas de comandos; no se borra para simular.
  • No hay prueba de rendimiento de producción ni acceso a compañías reales. No se toca la instalación habitual.

19. Documentación y decisiones mantenidas

Se documentan contratos de ficha y fronteras local/remoto en patrón, componentes y contexto. DESIGN solo enlaza el alcance verificado, sin cambiar tokens, tipografía ni layout. Las auditorías y L04.1/L04.2 conservan sus observaciones históricas y reciben seguimiento. No se altera AGENTS, el lock de skills ni vendor para esta entrega.

20. Frontera de L04.3 y pendientes para L04.4

L04.3 implementa y verifica los consumidores y recorridos descritos; sus excepciones impiden declararla una certificación universal. L04.4 requiere otra instrucción. Debe partir del inventario, revisar dashboard y consumidores no verificados, contrastar las regresiones restantes y resolver los fallos globales en sus tareas responsables. No debe reiniciar los patrones L02/L03 ni atribuirse densidad móvil general o WCAG a partir de estos ensayos.

Validación final registrada

Comando / bloque Resultado registrado
pnpm typecheck Falla en calendar.tsx vendor (TS2375), ya presente en baseline
pnpm --filter @metis/core --filter @repo/rdx-ui --filter @metis/assets --filter @metis/companies --filter @metis/resources --no-bail typecheck Correcto en los cinco paquetes; repetición final Core/Companies también correcta
Biome check dirigido a los 59 archivos de código y dos fixtures JS Correcto, sin diagnósticos propios en el control final
ESLint dirigido a TS/TSX/JS Correcto; se conserva el espaciado normativo
pnpm lint --max-diagnostics=1000 / pnpm check --max-diagnostics=1000 Fallan globalmente: deuda de línea base y cambios concurrentes. Comparación por archivo/regla conservada; ninguno de sus diagnósticos finales apunta a los ficheros L04.3
pnpm test --continue=always con MariaDB temporal propia 8/10 tareas correctas; tres aserciones anteriores: dos Companies y una identity HTTP 401/404
Core / rdx-ui / Assets / Resources en la suite global 14/14, 79/79, 147/147 y 99/99 respectivamente
Companies en la suite global 245/247; los dos fallos son los citados de companies-page.test.tsx, no se alteran
Server 8/8 HTTP de unidad; 18/19 de integración, con el 401/404 documentado
pnpm build y repetición tras ajuste de layout Correcto, dos tareas. Se conserva el aviso de tamaño de bundle
python3 scripts/embedded-relations-ui.test.py con la sesión propia 13/13 con schemas, referencias y unicidad de perfiles activas comprobadas; 41 mediciones en la ejecución final
Repetición del caso 82 después del último ajuste de commit Tres regresos consecutivos correctos, sin tolerancias sobre X/Y ni foco
Regresiones anteriores 38 métodos distintos correctos tras resolver el helper read-only: 8 pickers, 7 contexto, 4 estados, 4 filtros, 2 columnas, 3 V01, 2 búsqueda y 8 L04.1/L04.2. No se suman las repeticiones como cobertura nueva
Regresión final de comportamiento por defecto de useListReturn Activos en siete resoluciones y recorrido Recursos correctos después del ajuste de layout
Sintaxis Python / enlaces nuevos / diff / vendor Verificados en la revisión documental final; sin cambios en packages/shadcn-ui

Los ocho métodos de L04.1/L04.2 se ejecutaron antes de introducir la comprobación adicional de cardinalidad del grafo de relaciones; los cinco recorridos afectados por la redistribución de perfiles se repitieron y la suite específica final completa pasó con el grafo corregido. No se presenta una nueva ejecución íntegra de todas las suites históricas después de cada ajuste menor: se documentan las repeticiones dirigidas. La rama de un proveedor aparecido concurrentemente no se certifica por esos resultados.

Consola de la suite final: 12 respuestas 503 y cuatro 403 generadas por los escenarios de error/denegación; no se registran errores JavaScript ni warnings en esa ejecución. El bloqueador final registra cero intentos de mutación. Los abortos de lectura POST en intentos anteriores quedan separados como diagnóstico de infraestructura de pruebas.

La evidencia de la suite final está identificada por el PID 1066106 en el índice. Los PNG se abrieron: selector SMB a 320/1920 px, retorno de perfiles en escritorio, sublistado de software desplazado a 390 px, histórico de impresora a 390 px y dominio en modal a 320 px. El espacio vacío del picker respeta su altura estable; la tabla del dominio necesita desplazamiento interno, con cabecera/acciones visibles. No equivale a corregir densidad móvil general.

Entrega local sin secretos: índice de evidencias y archivo de capturas/mediciones. Ambos se excluyen de Git: para trasladar las imágenes a otra instalación se comparte expresamente el ZIP, sin sesiones, credenciales ni fixtures de base de datos.

El preparador propio terminó tras SIGTERM con salida 130 esperada y ejecutó su finally de limpieza. Se verificaron proceso detenido, sesión borrada y mensaje de contenedor retirado. La retirada se registra en cleanup.json; los tres contenedores temporales de integración terminaron con cleanup 0. No se retira ninguna instalación ajena. Las búsquedas observadas constan en snapshots/mediciones; no se conserva un HAR completo de todas las solicitudes remotas.