**Estado actual:** [WD04.3 — Consolidación de Responsable y contexto](#wd043--consolidación-de-responsable-y-contexto), 24 de octubre de 2026. Los apartados anteriores conservan la evolución de las entregas previas.
La ficha presenta ordenador principal, configuraciones pendientes, personas y perfiles, responsable y contexto, equipamiento, software, configuraciones por perfil, soporte/acceso remoto y último cambio. El historial completo, edición, renombrado, alta de perfil y ciclo de vida siguen usando las operaciones existentes.
La implementación utiliza consultas reales. El JSON de la auditoría solo se importa en pruebas; no alimenta la aplicación ni se inserta en una BD. No hay endpoints, modelos, esquemas, migraciones ni dependencias nuevos.
Se han conservado los ocho entregables de [la auditoría](auditorias/workplace-dashboard/08-resumen-ejecutivo.md) como descripción del estado anterior y base funcional. No existe una imagen aprobada accesible en esta conversación o adjunta a la tarea: la comparación se realiza con la especificación textual del usuario. No se afirma fidelidad de píxel respecto a una imagen no disponible.
## Composición y diferencias justificadas
- El shell, sus sidebars, búsqueda superior y navegación conservan su implementación.
- Cabecera con breadcrumb, nombre editable, estado, compañía, sede y responsable. Editar, historial y menú de ciclo de vida permanecen accesibles.
- La primera banda reserva al ordenador la columna izquierda y sitúa pendientes al extremo derecho, sin ocupar el hueco con estadísticas. No se han creado las cuatro tarjetas eliminadas.
- El grid inferior utiliza `minmax(0,1.6fr)` y `minmax(0,1fr)` desde 1000 px de contenedor: aproximadamente 62/38. La primera banda cambia desde 900 px. Por debajo se conserva una columna y el orden lógico pedido.
- Paneles compactos con borde, radio y espaciado del sistema existente; sin sombras decorativas ni gráficos.
- Se utiliza el catálogo propio de iconos Tabler. La especificación menciona Lucide, pero prioriza el design system instalado para componentes/tokens. No se ha introducido otra biblioteca ni cambiado vendor.
- El azul de la ficha utiliza los tokens existentes `secondary` y `secondary-foreground`, asignados localmente a los roles primarios dentro de su contenedor. El tema global y los portales de diálogos conservan su configuración. No se añade otra paleta.
- Las plantillas, nombres y fechas visibles proceden del servidor; no se fuerza «Portátil corporativo» ni la fecha de la ilustración cuando el catálogo o las revisiones reales dicen otra cosa.
- Las celdas sin valor usan «—». Responsable ausente en cabecera se expresa como «Sin responsable», un estado semántico fuera de una celda de listado.
## Componentes reutilizados y componentes nuevos
| Unidad | Reutilización / motivo |
| --- | --- |
| `DetailPanel`, `DetailField` | Estructura común. `DetailPanel` incorpora `density="compact"`; el valor por defecto conserva sus recetas anteriores |
| `EntityTable`, `EntityStatus`, `entityListState` | Tablas con búsqueda, orden, paginación, columnas configurables y estados inicial/actualización/error/datos anteriores |
| `WorkstationNameEditor`, `WorkstationActions`, `WorkstationEditorDialog`, `WorkProfileEditorDialog` | Operaciones reales conservadas. `WorkstationActions.children` permite intercalar la acción de historial sin duplicar el menú |
| `WorkstationHistoryDialog`, `WorkstationHistory`, `TimeLine` | Historial completo real. Se exporta el diálogo desde la API pública de Assets; añade altura estable y destino de foco de retorno |
| `SoftwareInstallationsPanel` | Gestión completa de instalaciones dentro de `WorkstationSoftwareDialog`; conserva alta, edición, borrado, cerradas e historial |
| `AssetSupport`, `RemoteSummary`, `TeleworkAuthorizationSummary` | Consulta y gestión de soporte/contexto con semántica existente |
| `buildEnvironment` | Reutiliza el cálculo de configuraciones y sus detalles, sin copiar políticas de autorización |
| `WorkstationComputer`, `WorkstationResponsible`, `WorkstationLatestChange` | Presentación específica de responsabilidades distintas de la ficha |
| `WorkstationPendingConfigurations`, `WorkstationProfileConfigurations`, `WorkstationConfigurationFamily` | Conteo verificable, selección explícita y grupos con estado independiente |
| `WorkstationSoftware`, `WorkstationSupport` | Integración de fuentes/operaciones existentes con contexto del equipo y la persona seleccionados |
| `WorkstationQueryFeedback`, `WorkstationDashboardSkeleton` | Feedback repetido por fuente y geometría de carga inicial de esta pantalla |
`WorkstationAssets` y `WorkstationProfiles` se adaptan en sus ubicaciones existentes. El antiguo `WorkstationPeople` se retira tras buscar sus referencias: solo lo utilizaban la composición anterior y sus pruebas. La distinción entre responsable y personas usuarias se presenta ahora en los bloques de perfiles y contexto. Sus referencias en la auditoría son históricas, no importaciones activas.
Los componentes nuevos viven en `modules/companies/src/web/workstations/detail/`; no se ha creado un framework de widgets ni trasladado lógica específica a la biblioteca visual genérica.
## Consultas, relaciones y selección
El controller conserva inventario, puesto y operaciones locales. `useWorkstationConfigurationQueries` consulta recursos, Access, carpetas, correo, aplicaciones, impresoras, certificados, remoto y teletrabajo con claves centralizadas. Software utiliza su clave por compañía y soporte su clave por activo. No se crea una consulta por perfil o tarjeta de equipamiento.
Las consultas del detalle de perfiles/configuraciones/software/soporte no se habilitan sin un ordenador principal confirmado dentro de `assetIds`. El shell puede conservar sus consultas propias por compañía. Se ha retirado del controller la consulta de catálogo que ya no necesitaba esta composición; las especificaciones de activos proporcionan su plantilla legible.
Las relaciones se resuelven por ID y compañía. Los perfiles pertenecen al ordenador principal; el responsable procede de `personId`. Los activos actuales proceden exclusivamente de `assetIds`. Las impresoras configuradas por perfil y los activos históricos no se incorporan a ese equipamiento.
Perfiles activos y archivados se distinguen explícitamente; el acceso a archivados amplía la tabla existente. La ausencia de cuenta no invalida un perfil. El selector de configuraciones utiliza perfiles activos, conserva el ID seleccionado durante refetch y, si deja de ser válido, muestra el primer activo con una explicación. No se sincroniza estado remoto mediante efectos.
Cada configuración conserva su familia, perfil y procedencia. Aplicación del perfil e instalación de equipo son registros distintos. Las carpetas muestran estado y cobertura documental por separado, incluida cobertura desconocida. Cuando faltan metadatos de recursos/Access, se informa de esa dependencia y no se presenta una lista vacía como si fuese un resultado completo.
El soporte corresponde al ordenador. El contexto remoto identifica a la persona del perfil seleccionado y limita conexiones a las que usan ese activo como origen o destino. La autorización de teletrabajo es de esa persona. No se inicia conexión ni se deduce presencia, VPN activa o permiso efectivo sobre SMB.
## Indicadores y revisiones
La única tarjeta estadística es «Configuraciones pendientes». Cuenta IDs distintos por familia de carpetas, correo, aplicaciones, impresoras y certificados en estado `pending`, con `profileId` de un perfil activo del principal y la misma compañía. Excluye legacy sin perfil, archivados, otras compañías, `removal_pending`, revisión y software instalado.
El total solo se presenta si perfiles y las cinco consultas necesarias tienen datos sin fallo. Ante fallo deja de ser definitivo, aunque se conserven datos anteriores. Sin ordenador la población de perfiles del principal es vacía y el total es cero. El botón de pendientes selecciona un perfil con pendientes, activa el filtro y lleva el foco a la sección.
Estado técnico y asignación de uso se distinguen: `values.status` describe el estado técnico; `assigned` indica reserva en un puesto activo. Un equipo averiado puede conservar su asignación y no debe aparecer como disponible. No se usa un semáforo global de salud.
Último cambio compara las dos últimas revisiones por fecha, sin mutar arrays: nombre, estado, sede, responsable, principal y miembros añadidos/retirados. Solo describe diferencias verificadas. No se mezclan eventos de otras entidades; las etiquetas relacionadas se resuelven con sus nombres disponibles actualmente.
## Carga, errores y accesibilidad
La carga inicial conserva una geometría próxima al dashboard. Cada consulta secundaria presenta skeleton, actualización o error con reintento propio; no derriba la cabecera ni las otras tarjetas. Las tablas conservan datos y controles si falla una actualización con caché. No se desmonta el selector durante refetch ni se oculta la diferencia entre cero y total desconocido.
Se reutilizan enlaces reales, regiones nombradas, un `h1`, paneles `h2` y subgrupos `h3/h4`. No hay contenedores con clic que sustituyan a enlaces. Los estados tienen texto, los iconos decorativos están ocultos y las tablas mantienen cabeceras. Las rutas largas se pueden leer completas mediante ajuste de línea; el overflow de tablas queda dentro de su zona.
El historial devuelve el foco al disparador concreto; el acceso a pendientes mueve el foco a una sección identificada. Las primitivas existentes gestionan teclado, menús, selectores y diálogos. La verificación interactiva y sus límites se registran abajo; no se declara cumplimiento WCAG global.
## Entorno de pruebas y reproducción
Se utilizó el preparador aislado `scripts/visual-audit.py`, sin conectar a la BD habitual. Su MariaDB desechable utiliza exclusivamente `metis_desk_test`, API/Vite en puertos libres y sesión real de usuario ordinario. El origen anunciado de esta ejecución fue `http://localhost:49383`.
Preparación y pruebas reproducibles, desde WSL:
```bash
bash scripts/setup-playwright-wsl.sh
python3 scripts/visual-audit.py
# En otra terminal, con la ruta privada anunciada por el preparador:
Los nuevos preparadores rechazan sesiones fuera de la ubicación privada y escenarios de otra instalación. Crean datos mediante HTTP real y CSRF. Las comprobaciones que sustituyen el principal o modifican la cuenta de carpeta restauran sus valores en `finally`. No se guardan credenciales en el informe ni se instala Chromium en WSL.
Volumen inicial de la auditoría interactiva: **15 compañías, 59 personas, 135 activos y 73 recursos** en la compañía principal. La variante S04 tiene **80 miembros y 60 perfiles** (50 activos y 10 archivados). S10 añade un activo sintético de sustitución, elevando después el inventario a 136; queda dentro del mismo entorno desechable.
## Verificaciones y límites
Verificaciones ejecutadas sobre esta implementación:
| Comprobación | Resultado |
| --- | --- |
| Tipos de Companies, Assets, RDX UI y Web | Correctos con comandos dirigidos |
| Pruebas dirigidas de dashboard, relaciones y ficha | 20 pruebas correctas, usando `--test-isolation=none` para exponer cada caso |
| Biome sobre archivos del cambio | Correcto, sin supresiones |
| ESLint de espaciado sobre archivos del cambio | Correcto |
| `pnpm build` | Correcto; Vite conserva advertencia de bundle mayor de 500 kB |
| Playwright MCP | 11 métodos interactivos verificados mediante pasadas completas y dirigidas; cubren S01–S11, teclado, contraste, paginación y guardados reales |
| `pnpm typecheck` global | Se detiene en `packages/shadcn-ui/src/components/calendar.tsx:165`, por opcionalidad exacta de `locale`; vendor no modificado |
| `pnpm lint` global | 15 errores fuera del cambio, principalmente bloques sin llaves en código de fotos; también diagnósticos de ejemplos de skills |
| `pnpm check` global | 167 errores fuera del cambio, incluyendo formato de ejemplos/fixtures y código de fotos |
| `pnpm test` global | La última pasada completa deja 41 de 42 archivos de Companies correctos; falla únicamente `companies-page.test.tsx`, con las dos aserciones ajenas descritas abajo. El test del dashboard detectado inicialmente se corrigió y pasa |
Las dos aserciones ajenas esperan los literales `Personas (1)` y `Esta persona no tiene acceso a Metis Desk`; los archivos de compañías/personas afectados no se han modificado en esta tarea. No se amplía el alcance para corregirlas. Los fallos globales impiden declarar todo el monorepo en verde; las comprobaciones dirigidas distinguen el dashboard de esa deuda.
La primera pasada interactiva detectó etiquetas de prueba antiguas, una espera de refetch que no provocaba un evento de reconexión real y una comprobación de texto que incluía una etiqueta oculta al lector. Se corrigieron los recorridos sin ocultar fallos ni introducir esperas arbitrarias. También se corrigieron una etiqueta de compañía sin traducir y las cabeceras extensas de perfiles observadas en las capturas.
Quedan fuera de lo acreditado: comparación con la imagen original ausente, lector de pantalla real, zoom 200/400 %, modo oscuro y auditoría WCAG completa. No se implementa autorización granular por compañía: se conservan autenticación y comprobaciones de pertenencia existentes, con el límite documentado en la auditoría.
## Evidencias visuales
Las capturas e informes sintéticos se guardan en `.artifacts/playwright/workstation-dashboard-implementation/`, fuera de Git. Se abrieron capturas de escritorio, móvil y fallos parciales para revisar la composición; la inspección final se detalla al cerrar la pasada.
Se generan S01 en 1600, 1440, 1280, 1024, 768 y 390 px; vistas de configuraciones; S02, S03, S04 de alta densidad, S05, S06, S07 con datos anteriores, S08 sin coincidencias, S10 y S11. `measurements.json` registra geometría, hashes y comprobaciones; no contiene cookies. Se han inspeccionado también S01 de 1600 px, configuraciones en 390 px, cobertura desconocida y desmantelado. Las mediciones no detectaron desbordamiento horizontal global en los seis anchos. El muestreo de 38 textos/acciones/enlaces dio contraste mínimo **5,03:1**. No hubo excepciones JavaScript de página; los HTTP 503 simulados son parte de los escenarios de error. La ubicación local no garantiza conservación portable: al compartir el trabajo hay que adjuntar los PNG elegidos, nunca `session.json`.
## Archivos del cambio
Los siguientes archivos contienen la implementación, sus pruebas o su documentación. Los ocho entregables originales de auditoría permanecen fuera de estos cambios.
-`modules/companies/src/web/workstations/detail/ui/workstation-profile-configurations.tsx` (componente histórico sustituido en WD04.2 por [workstation-profile-configuration-details.tsx](../modules/companies/src/web/workstations/detail/ui/workstation-profile-configuration-details.tsx))
-`modules/companies/src/web/workstations/detail/ui/workstation-responsible.tsx` (componente histórico retirado en WD04.3; su información contextual pasa a [workstation-responsible-context.tsx](../modules/companies/src/web/workstations/detail/ui/workstation-responsible-context.tsx))
## Refinamiento visual y adopción del listado compacto
Segunda iteración, 22 de octubre de 2026. Se mantiene el dashboard real y sus contratos.
El refinamiento sustituye la infraestructura de exploración dentro de las tarjetas por
el [patrón compacto](patron-de-listados-compactos.md#11-primera-implementación-compartida).
La captura anterior `S01-1600.png` se conserva y se ha inspeccionado. No se dispone del
mockup original aprobado: se aplica la especificación textual, sin afirmar fidelidad
exacta de píxeles. Los ocho documentos históricos de `auditorias/workplace-dashboard/`
permanecen intactos.
### Componentes y operaciones
| Cambio | Resultado |
| --- | --- |
| Nuevos `CompactTable`, `CompactList`, `CompactListItem` en rdx-ui | Primitivas compartidas sobre Table/listas nativas, con identidad estable, nombres accesibles y textos aportados por el consumidor. Sin DTO, consultas ni dependencia de Workstation. |
| Nuevo `CollectionPreview` en rdx-ui | Resumen inicial de cinco elementos en perfiles, equipamiento y software; Mostrar todos/Mostrar menos permite acceder al conjunto cargado completo, sin paginación ni recorte silencioso. |
| `collection-cell-content.ts` | Extrae sin cambiar su lógica el criterio de ausencia de EntityTableContent; ambas tablas conservan `—`, cero, controles y contenido compuesto. |
| `WorkstationProfiles` | Compact Table con Perfil, Persona, Cuenta, Estado y Configuraciones; sin búsqueda, barras, Columnas, ordenación visible, rangos o pie de paginación. Orden estable por nombre e idioma. |
| Archivados | Acción compacta en la cabecera, con flecha decorativa y estado pulsado. Desaparece la línea adicional de nombres archivados. Se mantiene su consulta; el resumen inicial sigue mostrando perfiles activos. |
| Categorías | Etiquetas es/en breves según las familias reales: Correo, Carpeta, Aplicación, Impresora y Certificado. Se mantiene el enlace al perfil completo y sus avisos de revisión. |
| `WorkstationAssets` | Compact Item List con enlace, icono, plantilla, Principal y badges de estado técnico y uso. Miembros deduplicados por identidad; no se añaden impresoras de configuración ni miembros históricos. |
| `WorkstationSoftware` | Lista compartida con versión, licencia, estado y revisión. Conserva Gestionar software y su diálogo con alta, edición, borrado e historial. Sigue siendo software del principal, distinto de aplicaciones por perfil. |
| `WorkstationComputer` | Identidad/icono, estados técnicos/de uso como badges y botón secundario real para abrir el activo. Composición horizontal adaptable sin imágenes externas. |
| `DetailField density="compact"` | Variante opcional sin separadores, padding vertical de 4 px y columnas etiqueta/valor 0,7/1,3; solo Responsable y contexto la adopta. Default anterior intacto. |
| `WorkstationConfigurationFamily` | Adopta CompactList/CompactListItem y Badge. Mantiene nombres, rutas UNC, detalles, estados, revisión y destinos de gestión; reduce el espaciado y conserva metadatos a 12 px. |
| Cabecera y cuadrícula | Separación principal de 16 a 12 px; metadatos flexibles y cabecera con menor separación. Primera banda conserva exclusivamente ordenador y pendientes, con espacio libre intencional. |
| Tokens | Se retira el alias local de primary a secondary de la primera implementación. Acciones y enlaces usan los tokens reales de Metis, sin paleta propia ni cambios globales. |
| Soporte y último cambio | Se conservan sus componentes, subbloques, gestión y algoritmos. Se inspecciona su presentación completa; el soporte sigue siendo registro documental y el remoto se limita a la persona del perfil seleccionado. |
Se reutilizan DetailPanel, EntityListState/EntityListStatus, Badge, Button, Table,
BrowserLink, PersonAvatar, Skeleton y las primitivas Base UI instaladas. `EntityTable`
no cambia su composición ni comportamiento por defecto; solo comparte el helper de
contenido ausente. No se añaden dependencias, APIs, modelos, migraciones ni consultas.
### Navegación contextual
La barra global la compone `WorkspaceSidebar` y la contextual `CompanyFixedNavigation`,
coordinadas por `WorkspaceMobileNavigationProvider` y los presupuestos de capacidad
vigentes. La global persiste `metis-desk:sidebar-collapsed`; `companyHidden` es estado de
sesión del provider. Ambas se usan en las rutas del workspace/compañía, no son un
componente exclusivo de la ficha del puesto.
Existe un mecanismo oficial: Ocultar secciones libera la columna contextual; la franja
con compañía/sección mantiene el contexto y abre la navegación completa en Sheet.
Fijar secciones permite volver a la columna cuando hay capacidad. Se comprueban ambos,
Escape, teclado y retorno de foco. A 1600 px, el ancho de `main` pasa de 1288 a 1528 px
al ocultarla manualmente y vuelve a 1288 al fijarla.
No se cambia el shell, ni se fuerza colapso por ruta, ni se añade otra preferencia. La
captura comparable conserva la navegación fija anterior. El modo oculto es una elección
explícita ya existente, evitando cambios inesperados de ancho al abrir la ficha.
### Medidas antes y después
Misma instalación desechable, mismos datos S01 y ancho de 1600 px; coordenadas respecto
al viewport con la página al inicio. Capturas a 1600×1000. Son mediciones de estos datos,
no alturas CSS fijas ni garantías para todo contenido.
| Medida | Antes | Después |
| --- | --- | --- |
| Alto Ordenador principal | 177 px | 113 px |
| Alto Personas y perfiles | 510,5 px | 221,5 px (−57 %) |
| 390 | 390/390 px | 739,5/294,5 px | Tabla con ancho comparativo mínimo de 36 rem y desplazamiento propio; listas apiladas y texto completo consultable. |
El objetivo orientativo de 160–220 px queda próximo en escritorio con dos perfiles; a
1440 px el encabezado/filas requieren más espacio. Se conserva altura natural, sin
recortar nombres, botones o estados para cumplir una cifra. Los rangos 0/1/2/10/60 se
cubren en pruebas de componente; S04 comprueba 50 activos y diez archivados, 60 perfiles
en total, y 80 miembros alcanzables desde la ampliación.
### Evidencias y pruebas
Las capturas están en `.artifacts/playwright/workstation-dashboard-refinement/`, con
subdirectorios `before` y `after`, excluidos de Git. Se copian solo PNG y mediciones
sanitizadas, nunca la sesión. Los enlaces requieren conservar esa carpeta para compartir
el informe con sus imágenes.
- S01: [antes a 1600](../.artifacts/playwright/workstation-dashboard-refinement/before/S01-1600.png), [después a 1600](../.artifacts/playwright/workstation-dashboard-refinement/after/S01-1600.png), [1440](../.artifacts/playwright/workstation-dashboard-refinement/after/S01-1440.png), [1280](../.artifacts/playwright/workstation-dashboard-refinement/after/S01-1280.png), [1024](../.artifacts/playwright/workstation-dashboard-refinement/after/S01-1024.png), [768](../.artifacts/playwright/workstation-dashboard-refinement/after/S01-768.png), [390](../.artifacts/playwright/workstation-dashboard-refinement/after/S01-390.png).
principal sustituido, autenticación, teclado, foco y contraste. Las pruebas de búsqueda
paginada del resumen se sustituyen por ausencia de esas herramientas y ampliación con
acceso a todos los elementos; los listados completos conservan sus pruebas propias.
Las primeras ampliaciones del script necesitaron corregir selectores de regiones
anidadas y la etiqueta accesible «Secciones de [compañía]». El perfil creado se retira
siguiendo su ciclo de vida (desactivar antes de eliminar). Fueron ajustes del recorrido,
sin nuevos defectos demostrados del producto. Las modificaciones sintéticas de los
escenarios de escritura se restauran en finally.
### Skills, diferencias y límites
Se consultaron las seis skills instaladas solicitadas: frontend-design (composición y
jerarquía), ux-dashboard (relevancia y densidad), ux-tables (comparación/lista y lectura),
shadcn (primitivas, tokens y Base UI), vercel-composition-patterns (composiciones distintas
sin flags de EntityTable) y vercel-react-best-practices (sin duplicar estado remoto ni
consultas por fila). Se revisó su matriz y referencias aplicables. El CLI shadcn no está
expuesto como ejecutable local; se contrastaron las APIs reales instaladas, sin instalar
ni regenerar componentes. No se invocaron auditores especializados ausentes.
Tabler, Inter, el primario rojo, las primitivas Badge existentes y la navegación del
producto prevalecen sobre cualquier detalle no verificable del mockup. No se han
inventado estados, salud del equipo, conexiones en tiempo real o permisos efectivos.
No se cambia la cobertura documental, el conteo de pendientes, la selección durante
refetch, el algoritmo de diferencias ni los contratos de acceso.
Continúan fuera de la verificación práctica completa lector de pantalla, zoom 200/400 %,
modo oscuro, rendimiento bajo cientos de filas y cumplimiento WCAG global. Las nuevas
colecciones no implementan búsqueda, ordenación interactiva o paginación remota; esas
capacidades no se afirman por estar contempladas como opcionales en el estándar.
Cierre de la entrega: 20 archivos de código/JSON pasan Biome y los TS/TSX afectados
pasan ESLint de espaciado; `git diff --check` correcto. Se comprueban 231 enlaces locales
y doce anclas de la documentación afectada, incluidos los destinos de capturas.
Las evidencias conservan 14 PNG anteriores y 28 posteriores, además de mediciones.
El preparador se cerró mediante SIGINT: retiró sus servicios, contenedor y sesión privada;
se comprobó que `session.json` ya no existe. Las capturas sanitizadas permanecen disponibles.
## WD04.1 — Equipamiento unificado
Fecha: 23 de octubre de 2026. Alcance limitado a la unificación de la representación de
los miembros del puesto. Se conservan los cambios locales de las entregas anteriores.
Los ocho documentos históricos de auditoría no se modifican.
### Composición y componentes
Antes se mostraban una tarjeta de Ordenador principal y otra de Equipamiento que volvía
a incluirlo. Ahora existe una sola tarjeta **Equipamiento**, inmediatamente después de
la cabecera, junto a Configuraciones pendientes. El principal es su primer miembro
válido, con icono de plantilla, nombre enlazado, tipo y badge Principal en la misma
línea de metadatos. Conserva los badges técnico y de uso sin un tamaño especial ni
una tarjeta anidada. Los secundarios mantienen el orden declarado en `assetIds`.
Después se conservan Personas y perfiles y Responsable y contexto; Configuraciones
por perfil queda a la izquierda de Software y Soporte. Último cambio se sitúa después
de la cuadrícula, a ancho completo. Solo cambia la colocación de esos componentes,
no su presentación interna, sus acciones ni sus cálculos. El shell y la cabecera no
se rediseñan.
| Archivo / componente | Cambio WD04.1 |
| --- | --- |
| `workstation-detail-content.tsx` | Una única instancia de WorkstationAssets en la primera banda; elimina su ubicación anterior y el render de WorkstationComputer. Recoloca Software y Último cambio según la composición objetivo. |
| `workstation-assets.tsx` | Reutiliza CompactList, CompactListItem, CollectionPreview, DetailPanel, Badge y EmptyState. Añade avisos de consistencia y feedback de inventario. |
| `workstation-equipment.ts` y su test | Selector presentacional de referencias actuales, con resolución por ID/compañía, deduplicación, principal válido primero y diagnóstico de referencias. No sustituye el modelo funcional del dashboard. |
| `workstation-computer.tsx` | Retirado. Búsqueda en el monorepo: solo tenía un consumidor de código, WorkstationDetailContent; los demás resultados eran referencias documentales. WorkstationComputerField del editor es otro componente y se conserva. |
| `use-workstation-detail-controller.ts` | Conserva íntegros computer, perfiles, fuentes y conteo. Reutiliza la consulta de catálogo de activos por compañía para resolver iconos reales. |
| `modules/assets/src/web/index.ts` | Expone el AssetTemplateIcon existente para el consumidor real de Companies; no se duplica la correspondencia entre claves e iconos. |
| `workstation-detail-page.tsx` | En fallo inicial sin datos muestra Equipamiento con error/reintento. Con inventario conocido, el feedback vive en la tarjeta, no en una lista vacía. |
| `workstation-dashboard-skeleton.tsx` | Retira el placeholder de ordenador independiente y conserva un único espacio de equipamiento. |
| Locales es/en de Assets | Dos avisos de principal inconsistente/no disponible; retira la etiqueta openAsset sin consumidores después de eliminar la tarjeta independiente. |
| Tests de detalle, nuevo test de equipamiento y script MCP | Añaden cobertura de unicidad, posición, errores, consistencia, navegación y estados; conservan los recorridos de gestión anteriores. El script de tests de Companies incluye el nuevo fichero. |
La consulta de catálogo utiliza `catalogKeys.scope(company.id)` y `catalogApi.get`,
compartida y deduplicada por TanStack Query. Se habilita cuando el puesto tiene
miembros; no es una consulta por activo ni depende de que exista principal. Usa el
icono de la plantilla por ID; si los metadatos todavía no están disponibles, utiliza
la caja genérica y conserva el tipo legible de la especificación. No infiere el
principal por nombre, icono, tipo o posición del inventario. No hay endpoints,
contratos HTTP, dependencias, modelos, migraciones o políticas de acceso nuevos.
### Datos, acciones y estados
La composición procede exclusivamente de `values.assetIds` actuales, deduplicados.
`computerAssetId` identifica al principal solo cuando esa referencia pertenece a la
composición y resuelve un activo de la compañía. No se incorporan activos históricos
ni impresoras asociadas únicamente a configuraciones de perfil. El selector no modifica
los arrays recibidos; los secundarios conservan un orden determinista independiente
del orden de llegada del inventario.
Se conserva Editar puesto en la cabecera de Equipamiento como acción contextual de
composición. Abre el mismo editor y utiliza el mismo callback que la acción global;
no crea otro diálogo ni otra operación. En vacío se ofrece una única acción dentro
del estado vacío, sin repetirla también en la cabecera de esa tarjeta. En fallo inicial
sin puesto conocido no se inventa una acción de edición.
El nombre de cada activo sigue siendo un BrowserLink a su ficha real. Esa navegación
conserva la capacidad anterior de Abrir ficha del activo; no queda un botón redundante
para el principal ni se usan contenedores clicables en lugar de enlaces.
| Caso | Presentación |
| --- | --- |
| Principal válido | Primera fila, una única vez, badge Principal y estados del activo real. |
| Miembros sin principal | Muestra los miembros, indica discretamente que no hay ordenador principal y conserva edición. No elige el primer portátil como sustituto. |
| Sin activos | EmptyState dentro de Equipamiento con descripción y edición de composición. |
| Inactivo/desmantelado | Solo composición actual; el historial sigue disponible por la operación existente. No recupera miembros de revisiones. |
| Principal fuera de assetIds | Aviso explícito para revisar el puesto, sin incorporarlo ni marcar otro miembro como principal. |
| Referencia ausente o de otra compañía | Aviso de principal no disponible y fila de referencia no resuelta, sin inventar nombre, tipo o estados; no se muestra el badge Principal. |
| Fallo de inventario sin caché | Equipamiento con error recuperable; no muestra vacío, contador cero ni detalles de un puesto desconocido. El resto requiere recuperar los datos del puesto. |
| Refetch / error con datos previos | Mantiene la composición y la ampliación existentes y muestra el feedback de consulta. |
Estado técnico sigue siendo `asset.values.status`; uso sigue siendo `asset.assigned`.
Un activo averiado puede continuar asignado. No se deriva disponibilidad del estado
técnico ni se modifica la condición de asignación de puestos inactivos.
`workstationDashboard.computer` y la resolución del controller permanecen. Software,
soporte, perfiles y configuraciones siguen dependiendo del principal confirmado dentro
de assetIds. La nueva función de presentación conserva también referencias no resueltas
para explicarlas; no cambia los miembros resueltos que usa el modelo funcional. La
selección de perfil, el algoritmo de diferencias, cobertura documental y políticas de
Access permanecen intactos. Los nombres del equipo que aparecen como contexto de una
conexión remota no son otra tarjeta ni otro listado de miembros.
### Responsive y comparación visual
Se conservaron capturas del estado anterior en esta misma instalación, antes de modificar
las tarjetas. Las posteriores se inspeccionaron visualmente: S01 de escritorio y móvil,
S03, S06, S04 denso, casos sin principal, inconsistencias y fallo/recuperación. Se mantiene
la cuadrícula por contenedor, el espacio libre antes del indicador de pendientes y la
proporción 1,6:1 en escritorio. En móvil Equipamiento ocupa el ancho y Pendientes aparece
después. No hay alturas fijas de filas ni recortes de activos.
Medidas S01 a 1600×1000, al inicio de la página:
| Medida | Antes | WD04.1 |
| --- | --- | --- |
| Paneles del dashboard | 9 | 8 |
| Representaciones del principal como miembro/resumen | 2 | 1 |
- [Miembros sin principal](../.artifacts/playwright/workstation-dashboard-wd041/after/S12-members-without-principal.png), [principal fuera de composición](../.artifacts/playwright/workstation-dashboard-wd041/after/S13-principal-outside.png), [referencia no resuelta](../.artifacts/playwright/workstation-dashboard-wd041/after/S13-principal-unresolved.png), [referencia de otra compañía](../.artifacts/playwright/workstation-dashboard-wd041/after/S13-principal-foreign.png), [inventario fallido](../.artifacts/playwright/workstation-dashboard-wd041/after/S14-equipment-unavailable.png), [inventario recuperado](../.artifacts/playwright/workstation-dashboard-wd041/after/S14-equipment-recovered.png).
Las capturas completas utilizan el procedimiento temporal ya documentado, restaurando
los estilos después. Las medidas normales se registran en measurements.json de cada
fase. Para compartir las imágenes hay que conservar la carpeta de evidencias; no se
copia la sesión privada.
### Validación WD04.1
Entorno: Node 24.20.0 y PNPM 11.25.0. Se reutilizan los preparadores existentes de auditoría
con MariaDB independiente exclusivamente `metis_desk_test`, API/Vite en puertos libres
y usuario ordinario autenticado por el formulario real. Volumen: 15 compañías, principal
con 59 personas, 135 activos y 73 recursos; S04 con 80 miembros y 60 perfiles. El escenario
de sustitución de principal añade un activo temporal más.
- **29 pruebas dirigidas correctas**, incluidas seis nuevas del selector y tres nuevas de
presentación. Cubren orden principal/secundarios, deduplicación, ámbito, vacío,
desmantelado, falta de principal, inconsistencias, estado técnico/uso, unicidad de la
sección y navegación; se conservan las pruebas previas de relaciones y funcionalidades.
- **20 métodos MCP comprobados.** El pase inicial de 15 tuvo una interrupción de
browser_navigate y un timeout al fijar la navegación contextual; ambos recorridos
pasaron al repetirse sin modificar navegación o Access. El pase complementario de
esos dos y los cinco escenarios nuevos fue correcto (7/7). La captura/medición de los
seis anchos se repitió correctamente con la presentación final.
- Edición real de responsable/composición, renombrado, alta/retirada de perfil,
archivados, selector y refetch, gestión de software, soporte registrado visible,
pendientes y su foco/filtrado, historial, principal sustituido y cobertura desconocida
siguen verificados. Las escrituras sintéticas restauran valores en finally.
- Los casos incoherentes o referencias ajenas se simulan interceptando respuestas GET
de la instalación desechable; no se saltan invariantes para persistirlos. El caso sin
principal se prepara con el update real y se restaura después. El error 503 se retira
y se comprueba recuperación con Reintentar.
- Tipos dirigidos de Assets, Companies y Web correctos. Biome y ESLint dirigidos,
paridad es/en y comprobaciones documentales se ejecutan sobre los archivos afectados.
-`pnpm build` correcto. Permanecen el aviso previo de chunks grandes y los fallos globales
ya existentes: typecheck en calendar.tsx:165 de vendor; lint/check con 15/167 errores
ajenos; test en companies-page.test.tsx. En Companies pasan 42/43 ficheros, incluidos
todos los del dashboard; los otros siete paquetes de tests completan correctamente.
No se afirma un pase global limpio ni una validación WCAG completa. La muestra de
contraste contiene 36 elementos, mínimo 4,53:1; no hubo excepciones JavaScript de página.
Lector de pantalla, zoom 200/400 %, modo oscuro y rendimiento con más volumen permanecen
fuera de las comprobaciones prácticas de esta entrega.
Skills aplicadas: ux-dashboard como principal para agrupar la composición sin duplicar
información; frontend-design y ux-tables para jerarquía y densidad; shadcn para reutilizar
las APIs/tokens instalados; composición y React para mantener un único consumidor de
Equipamiento y estado remoto en TanStack Query. Se consultaron la matriz y los criterios
instalados pertinentes, sin instalar skills ni dependencias ni modificar vendor.
No se integra Configuraciones en Perfiles, no se retira Responsable y contexto, no se
reestructura Soporte y no se modifica la cabecera ni la navegación lateral. Esas tareas
quedan para entregas posteriores.
Cierre WD04.1: 12 archivos TS/TSX/JSON pasan Biome y los TS/TSX afectados pasan ESLint.
`git diff --check` correcto; 73 enlaces locales y dos anclas del informe comprobados,
paridad es/en y sintaxis Python correctas. Se conservan 14 PNG anteriores y 34 posteriores.
El preparador retiró sus servicios y contenedor al recibir SIGINT; se comprobó la retirada
de session.json. Las capturas y mediciones sanitizadas permanecen disponibles.
## WD04.2 — Personas, perfiles y configuraciones unificados
Fecha: 23 de octubre de 2026. Implementación sobre la composición WD04.1.
### Arquitectura e interacción
Antes, Personas y perfiles y Configuraciones por perfil eran dos tarjetas. La segunda
mostraba automáticamente el primer perfil y añadía un selector independiente. Ahora
una única tarjeta combina `WorkstationProfiles` (CompactTable) y
`WorkstationProfileConfigurationDetails` (contenido contextual). Desaparecen la tarjeta
y el selector anteriores. El antiguo componente solo tenía un consumidor; se retira
tras buscar sus referencias. Los ocho entregables históricos de auditoría se conservan.
La primera banda mantiene Equipamiento y Pendientes. El segundo grid conserva los
umbrales y proporción 1,6:1; la izquierda contiene Personas y perfiles y la derecha
apila Responsable y contexto, Software, Soporte y Último cambio. Las alturas son
independientes. Equipamiento, cabecera, navegación y operaciones de software mantienen
sus componentes existentes; no se implementa WD04.3.
La tabla conserva Perfil, Persona, Cuenta, Estado y Configuraciones, con sus enlaces
independientes, alta y acceso a archivados. El resumen muestra categorías reales o el
estado confirmado sin configuraciones; una fuente incompleta muestra «—». Cada perfil activo
tiene un botón explícito Ver/Ocultar con nombre accesible que incluye el perfil,
`aria-expanded`, `aria-controls` e indicador de dirección. La fila conserva semántica
HTML de tabla y no se convierte en un control interactivo.
La expansión empieza cerrada, es única, permite contraer y sustituye el detalle al
abrir otro perfil. Se reutiliza `Collapsible` de Base UI mediante el wrapper vendor,
controlado por la selección; los activadores explícitos están en las celdas y el
panel único aparece debajo de la tabla, dentro de DetailPanel y fuera de su scroll
horizontal. El panel controlado permanece como destino de `aria-controls`; el contenido
de configuración solo se monta para el perfil abierto. No se modifica CompactTable
ni se crea infraestructura genérica de acordeones.
teclado y aislamiento de sesión conservaron sus recorridos de regresión. Las mutaciones
sintéticas añaden revisiones aunque se restauren los valores actuales.
Se midieron las seis anchuras (1600, 1440, 1280, 1024, 768 y 390), contraído y expandido,
sin overflow horizontal global. A 390, la tabla final mide **326 px tanto de contenido
como de viewport**, con scrollLeft 0: persona, estado y expansión visibles. Tab recorre
perfil → persona → cuenta → expansión; Espacio abre el detalle. Enter, Espacio, foco
visible y retorno desde diálogos se verificaron en los recorridos de teclado. Se
midieron 30 muestras de texto/acciones: contraste mínimo observado **4,53:1** en tema
claro, no una certificación global de accesibilidad. No hubo errores JavaScript no
capturados en página; los 503 de los escenarios de fallo fueron deliberados.
Las primeras iteraciones de pruebas necesitaron adaptar selectores al nuevo detalle,
esperar el render tras refetch, usar el contrato real de certificado al restaurar y
liberar la petición retenida mediante su Route. El retorno contextual del perfil vuelve
al dashboard; para editar se utiliza el enlace al listado completo y su búsqueda. La
prueba móvil detectó 2 px de overflow interno, corregidos ampliando la columna de acciones
y permitiendo ajustar el nombre. Esos casos se repitieron hasta obtener los resultados
indicados; no se silencian sus fallos anteriores como si hubieran pasado a la primera.
### Comparación visual y capturas WD04.2
Se conservan **14 PNG anteriores y 49 posteriores**, incluidas iteraciones y escenarios
funcionales, con `measurements.json` y huellas SHA-256 en los directorios ignorados de
Playwright. Las capturas se abrieron y revisaron: escritorio, móvil, detalle integrado,
vacío compacto y carga parcial. No se guardan sesiones en estos directorios estables.
| Aspecto | Antes | WD04.2 |
| --- | --- | --- |
| Tarjetas del dashboard | 8 | 7 |
| Selector independiente de perfil | 1 | 0 |
| Relación visual de configuraciones | Tarjeta separada | Detalle contextual dentro de Personas y perfiles |
| Detalles de configuración montados | Primer perfil seleccionado por defecto | Ninguno inicialmente; uno al expandir |
| Vacío de perfil | Cinco mensajes por familia | Una explicación y cinco accesos de gestión |
| Móvil | Control fuera del ancho inicial de la tabla | Identidad agrupada y expansión visible |
| Columnas inferiores | Filas del grid compartidas | Dos pilas de altura independiente |
En las capturas iniciales de 390, el borde inferior del último bloque pasa de 3642 a
2818 px; a 1280, de 2638 a 1930 px. Son muestras de la presentación inicial contraída,
no una promesa de reducción fija: el detalle expandido crece con sus datos y las pruebas
de guardado modifican el historial mostrado en Último cambio. No se igualan alturas ni
se recorta contenido para obtener esas diferencias.
- [Antes a 1600](../.artifacts/playwright/workstation-dashboard-wd042/before/S01-1600.png), [después a 1600](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-1600.png) y [página completa](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-full-page.png).
- [Detalle integrado](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-integrated-expanded.png), [perfil vacío](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-profile-without-configurations.png) y [pendientes](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-configurations.png).
- [Móvil final](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-mobile-profile-controls.png), [móvil expandido](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-mobile-expanded-final.png), [1440](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-1440.png), [1280](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-1280.png), [1024](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-1024.png) y [768](../.artifacts/playwright/workstation-dashboard-wd042/after/S01-768.png).
- [Carga del detalle](../.artifacts/playwright/workstation-dashboard-wd042/after/WD042-detail-loading.png), [Recursos no disponibles](../.artifacts/playwright/workstation-dashboard-wd042/after/WD042-resources-unavailable.png), [archivo durante refetch](../.artifacts/playwright/workstation-dashboard-wd042/after/WD042-profile-archived-while-open.png), [certificado guardado](../.artifacts/playwright/workstation-dashboard-wd042/after/WD042-certificate-saved.png) y [pendiente fuera del resumen S04](../.artifacts/playwright/workstation-dashboard-wd042/after/S04-pending-outside-preview.png).
### Limitaciones y cierre WD04.2
No se certifica WCAG, uso con lector de pantalla, zoom, tema oscuro ni dispositivos
físicos: las evidencias corresponden a Chromium/MCP y los tamaños indicados. Las lecturas
agregadas siguen siendo independientes y no forman una fotografía transaccional. La
selección local se restablece al abandonar la ficha; no se introduce persistencia de
expansión entre rutas.
No se modificaron vendor, los ocho documentos históricos, Equipamiento WD04.1,
Responsable y contexto, Soporte, Software, cabecera ni navegación global. Los cambios de
composición solo recolocan sus consumidores. Se conservan los cambios previos del árbol
sin crear commits ni revertir trabajo ajeno. Las incidencias globales anteriores quedan
fuera de WD04.2 y se declaran arriba.
El preparador recibió SIGINT y retiró exclusivamente sus servicios y MariaDB desechable.
Se comprobó que `session.json` ya no existe. Las capturas y mediciones sanitizadas
permanecen en los directorios estables indicados.
## WD04.3 — Consolidación de Responsable y contexto
Fecha: 24 de octubre de 2026. Cambios limitados a la presentación y resolución de su
contexto, sobre Equipamiento WD04.1 y Perfiles/configuraciones WD04.2 efectivamente
implementados. Se conservan los cambios previos del árbol de trabajo.
### Presentación y componentes
Se retira la tarjeta Responsable y contexto. La cabecera conserva breadcrumb, nombre
editable, estado, compañía, sede, responsable y sus acciones originales. Compañía,
sede y persona mantienen enlaces reales independientes; no se anidan botones dentro
de enlaces ni se hace clicable la banda completa. El nombre del responsable permanece
visible y permite ajuste de línea, incluido el caso largo. Sin responsable se muestra
«Sin responsable», sin inferirlo de los usuarios de perfiles.
`WorkstationResponsibleContext` añade junto al nombre un activador de información con
nombre accesible traducido y Tooltip. Popover, Tooltip y Button se componen mediante
`render` según Base UI instalado, con un único botón nativo. El Popover presenta nombre,
rol Responsable del puesto, departamento y cargo vigentes, y Abrir ficha de persona.
No añade una segunda fila fija con información organizativa secundaria.
`workstation-detail-content.tsx` elimina el render/import del panel anterior; Software,
Soporte y Último cambio ocupan la pila derecha desde el inicio del segundo grid. No se
estiran tarjetas ni se reserva un hueco. La proporción y los umbrales responsive existentes
se conservan. La carga inicial pasa a seis placeholders. Tras buscar referencias en el
monorepo, se retiran `WorkstationResponsible` y el resolver anterior, que solo utilizaban
ese panel y sus pruebas.
### Relaciones organizativas y asignaciones múltiples
El responsable procede exclusivamente de Workstation.personId y de la compañía de la
ficha. Sede procede de siteId del puesto; no se obtiene del activo ni de la persona.
La persona responsable sigue separada de los perfiles y del contexto remoto de Soporte.
No se modifican DTOs, relaciones, asignaciones, validaciones de dominio ni persistencia.
`workstationOrganizationalAssignments` deriva las relaciones desde CompanyDTO:
misma compañía/persona y periodo semiabierto `startDate <= hoy < endDate`, o sin fecha
de fin. Conserva el criterio de fecha UTC del resolver anterior. No filtra relaciones
vigentes arbitrariamente por el estado actual de departamento/persona: una relación
existente puede conservarse conforme al contrato del dominio.
Se muestran **todas las asignaciones vigentes**, con las principales primero y una
etiqueta Principal; fecha de inicio e ID estabilizan el orden restante. De ese modo no
se descartan las secundarias ni se elige la primera de varias sin principal. Si hay más
de una, se anuncia su cantidad. Tampoco se oculta una segunda principal: el modelo puede
admitir periodos finitos solapados en departamentos diferentes. La presentación no
introduce otra política de elección ni modifica esas relaciones.
Sin asignación vigente, departamento y cargo muestran «—». El cargo procede de la
asignación presentada. El campo general Person.position continúa en la ficha de persona;
no se usa para atribuir un cargo a una relación organizativa inexistente. Esta decisión
sustituye el fallback del panel anterior y evita presentar información genérica como si
perteneciera a una asignación vigente.
### Fuente, carga, fallo y actualización
Personas, departamentos y asignaciones llegan **juntos en CompanyDTO**, mediante la
query centralizada `companyKeys.detail(company.id)`. No existe endpoint independiente
de asignaciones ni estado de carga separado. El contexto observa esa misma query con
`enabled: false`: no inicia otra lectura al montarse o abrirse; su reintento usa la API
existente y actualiza la caché compartida. Los campos se derivan de las props actuales,
sin copiarlos a estado local.
Durante refetch se conservan los datos anteriores y se indica Actualizando dentro del
Popover. Si falla, cabecera y responsable siguen visibles y el contexto muestra aviso
y Reintentar. Tras recuperar la fuente, desaparece el aviso y el foco pasa al título
contextual después del commit, mediante un efecto exclusivo de sincronización de foco.
Si el reintento vuelve a fallar, el foco retorna a Reintentar. Cambiar responsable/compañía/puesto restablece el Popover por identidad;
actualizar datos de la misma persona conserva su contexto.
**Límite del contrato actual:** CompanyDetail monta esta ficha cuando dispone de compañía.
Por ello los casos de compañía inicialmente ausente o asignaciones inicialmente cargando
por separado no se pueden reproducir como fuentes independientes. Se conserva ese contrato
y su feedback global; no se fabrica una compañía parcial ni se reestructura el shell para
simularlos. Sí se verifican refetch, fallo y recuperación de la fuente organizativa real
con datos previos. Sin responsable no se monta el contexto ni se resuelven sus asignaciones.
### Accesibilidad, responsive y skills
Se reutilizan las primitivas instaladas, sin cambiar vendor. La información contextual
se abre explícitamente con ratón, Enter o Espacio; Escape cierra y devuelve el foco al
activador. Título/descripción nombran el contenido y el botón mantiene relación ARIA con
el Popover. Tooltip explica el icono también al foco. El enlace a persona es independiente
y el detalle tiene un segundo acceso explícito a su ficha.
La misma cabecera se adapta por flex-wrap. El Popover conserva el posicionamiento y las
colisiones de Base UI, anchura limitada al viewport y altura/desplazamiento limitados al
espacio disponible. Nombres y valores largos pueden partirse sin truncamiento irreversible.
Los vacíos son «—» y los estados son textuales. Todo texto nuevo mantiene es/en.
Skills consultadas: ux-dashboard para jerarquía/detalle progresivo; ux-navigation para
metadatos, enlaces y teclado; frontend-design para continuidad visual y densidad; shadcn
para APIs reales de Popover/Tooltip y render; vercel-composition-patterns para encapsular
la interacción; vercel-react-best-practices para derivación y caché compartida;
ui-ux-pro-max, mediante búsqueda local «popover keyboard focus», para indicadores de foco
visibles y no ocultos. Se revisaron
la matriz, skills-lock y sus APIs/referencias aplicables. No existe auditor especializado
de accesibilidad instalado; se utilizan las verificaciones disponibles de navegador, sin
instalar skills, dependencias, ni aplicar cambios globales de navegación, color o tipografía.
### Validaciones y comparación WD04.3
Se ejecutaron las comprobaciones desde WSL/bash con Node 24.20.0 y PNPM 11.25.0.
La instalación autenticada desechable utiliza exclusivamente `metis_desk_test`, con
usuario ordinario y volumen reproducible: 15 compañías, 59 personas, 135 activos y 73
recursos; S04 incluye 80 miembros y 60 perfiles (50 activos y 10 archivados). Los casos
organizativos múltiples/largos/históricos se simulan sobre respuestas GET de esa compañía
en el navegador, sin poblar bases reales ni alterar sus relaciones persistidas.
| Validación ejecutada | Resultado |
| --- | --- |
| Pruebas dirigidas de dashboard, organización, relaciones, equipamiento, expansión y renderizado es/en | 42 pruebas correctas |
| Typechecks de Companies, Assets y Web | Correctos |
| Biome de los 12 TS/TSX/JSON afectados y ESLint de sus TS/TSX | Correctos |
| `pnpm build` | Correcto; permanece aviso de tamaño de chunks |
| `pnpm typecheck` global | Persiste el error previo del vendor `calendar.tsx:165` sobre locale y exactOptionalPropertyTypes |