# Implementación UI/UX v3: ficha de puesto de trabajo Fecha: 24 de octubre de 2026. Ruta: `/companies/:companyId/workstations/:id`. ## Resultado y alcance M08 conserva las diferencias semánticas entre configuración, pendiente, revisión, ciclo de vida, error y ausencia. Software adopta la misma receta Badge que las configuraciones de perfiles. Las mediciones justifican corregir el contraste de la edición principal, los contadores, los estados técnicos no operativos y el resumen compartido de teletrabajo. M09 aproxima el skeleton a la cabecera, las dos bandas y la columna secundaria existentes, sin modificar las consultas ni imponer alturas al contenido real. La [consolidación M01–M09](cierre-auditoria-uiux-ficha-puesto-trabajo.md) separa implementación, verificaciones pendientes y deuda ajena. Esta entrega no acredita conformidad WCAG integral ni resuelve el problema de concurrencia del backend detectado durante las pruebas. ## Línea base y preparación La línea base funcional es [v2.2](implementacion-uiux-ficha-puesto-v2.2.md), con M01/M02 de [v1](implementacion-uiux-ficha-puesto-v1.md) y M03/M04/M06 de [v2.1](implementacion-uiux-ficha-puesto-v2.1.md). Se contrastaron la [auditoría original](auditoria-uiux-ficha-puesto-trabajo.md), M08/M09 y E05/E07/E08/E12, DESIGN.md, los patrones de listados compactos y diálogos, estructura web, WD04.3, matriz de skills y procedimiento Playwright. Se consultaron sus capturas y mediciones; las evidencias históricas se conservan y se comprueban mediante hashes. Antes de modificar producción se ejecutaron `pwd`, `git status --short`, Node v24.20.0 y PNPM 11.25.0. Registro inicial local: `/tmp/metis-uiux-v3-initial-status.txt`. Había modificaciones previas de las entregas anteriores, listados, búsqueda y Recursos; continuaron apareciendo cambios ajenos durante el trabajo, incluidos locales. No se revierten ni se atribuyen a v3. Se conservaron copias locales del alcance para revisar el delta real. El preparador documentado creó una instalación desechable con `metis_desk_test`; login real con usuario ordinario y sesión privada. Playwright MCP usa Docker/stdio, imagen fijada y Chromium 155.0.8059.12; comprobada conectividad WSL. No se instalaron dependencias, skills ni navegadores. Se usa el origen anunciado por Vite. ## Skills aplicadas | Skill | Aplicación efectiva | | --- | --- | | **shadcn** | Badge `outline`/`secondary`, Button `secondary`, Skeleton y APIs instaladas de Base UI/Vega. Sin regenerar vendor. El CLI instalado `docs badge skeleton` falló por `EAI_AGAIN`; se contrastaron las fuentes locales y sus exports. | | **frontend-design** | Mantener composición e identidad; aproximar estructura de carga a responsabilidades y ancho real, con alturas solo de placeholders. | | **ux-error-recovery** | Distinguir carga, cero, incertidumbre y error; conservar datos durante refetch y reintentos independientes. | | **ux-microcopy** | Conservar textos precisos es/en; pendiente y revisión siguen siendo conceptos distintos, sin nuevas etiquetas de salud. | | ux-dashboard | Mantener la prioridad de pendientes sin convertirlo en notificación; conservar jerarquía de paneles. | | ux-empty-states | Verificar que ausencia y error siguen separados en M07. | | ui-ux-pro-max | Búsqueda local dirigida `text contrast dark mode`, dominio UX: resultados Contrast Readability y Color Contrast; aplicados como apoyo a mediciones efectivas, sin otra paleta. | | vercel-react-best-practices | No sincronizar estado derivado ni bloquear consultas independientes; CSS para adaptación y movimiento reducido. | | vercel-composition-patterns | Prop opcional de variante en el control existente; marcador privado, pequeño y presentacional del skeleton, sin nueva capa genérica. | | ux-design-review | Consolidación de uso, textos, estados, teclado y aplicación del sistema visual. No se ejecutan auditores ausentes. La referencia interna `docs/orchestration-policy.md` de esa skill no está disponible. | | rdx-solid | Solución local, contratos existentes, prueba de los estados documentales y revisión de consumidores. | No están instalados los auditores especializados de heurísticas, microcopy, accesibilidad, estética, IA, dark patterns o responsive. No se simulan ni instalan. El sistema existente conserva tipografía, tokens y composición. ## M08: diagnóstico y matriz semántica [Matriz detallada de representación y contraste](auditorias/ficha-puesto-trabajo/implementacion-v3/comparaciones/estados-y-contraste.md). | Categoría | Código y significado real | Representación y decisión | | --- | --- | --- | | Configurado | `configured`, documentación de configuración; no demuestra acceso efectivo | Badge `outline` en familias y ahora en Software. | | Pendiente | `pending`, configuración pendiente | Badge `secondary`, texto «Pendiente de configurar». Conserva Solo pendientes. | | Retirada pendiente | `removal_pending`, retirada documentada por completar | Badge `secondary` y texto propio; no se fusiona con pendiente de configurar. | | Revisión requerida | `review` derivado de referencias/cobertura; puede coexistir con configurado | Se conserva el aviso «Requiere revisión» en ámbar: contraste suficiente y significado diferente del estado de configuración. | | Total de pendientes | Recuento documental de los estados actuales | Número ámbar cuando positivo, con título y acción existentes; cero confirmado neutral. No es notificación de mensajes. | | Desconocido | No se puede confirmar un total o cobertura | Texto explícito neutral; nunca convertirlo en cero ni en error de negocio. | | Activo/inactivo | Estado de ciclo de vida documentado | EntityStatus conserva etiqueta y punto decorativo. No significa conectado en tiempo real. | | Archivado | Perfil histórico que puede mostrarse con el control existente | Etiqueta y ámbito activo/archivado conservados; no equivale a eliminado. | | Error de consulta | Fallo de una fuente | Alert/error específico, reintento y conservación de datos previos cuando existen. No es un pendiente. | | Sin registros | Consulta completada sin filas | Mensaje específico de colección vacía; no equivale a fuente pendiente o fallida. | Se mantienen las distinciones documentales: cobertura/autorización registrada no acredita permisos SMB efectivos; aplicaciones asignadas a perfiles no equivalen a instalaciones; soporte disponible no comprueba conectividad real. ### Cambios justificados 1. **Software:** EntityStatus binario utilizaba `active=false` para estados como pendiente de configurar o retirada pendiente. Se sustituye por la misma receta Badge de las familias, conservando cada etiqueta, filtro y acción. EntityStatus continúa en ciclo de vida, donde sí encaja su contrato. 2. **Edición principal:** contraste inicial 3,70:1 en oscuro y 3,83:1 en hover claro para texto de 14 px. La ficha solicita `editVariant="secondary"` al WorkstationActions existente: 12,33:1 claro y 15,58:1 oscuro en reposo. Es un control relleno de la paleta existente; conserva etiqueta, prominencia, ámbito y foco. Los demás consumidores mantienen `default`. 3. **Contadores:** el texto atenuado sobre fondo muted de Equipamiento/Perfiles mide 4,396877984572111:1 en claro. Se corrige localmente su texto con `foreground`, conservando fondo, cifras, ámbito y disponibilidad. No cambia DetailPanel ni su receta global. La muestra anterior está en [contraste-contadores-antes.json](auditorias/ficha-puesto-trabajo/implementacion-v3/comparaciones/contraste-contadores-antes.json): se tomó con el contador de M06 aún intacto, durante la primera pasada v3, antes de su corrección específica. 4. **Estados técnicos de Equipamiento:** operativo conserva `outline`. Averiado, mantenimiento y retirado pasaban a `destructive` y daban 1,6490871246180994:1 en oscuro. Adoptan `secondary` localmente: 15,58:1 oscuro y 12,33:1 claro, sin cambios en las etiquetas, la asignación o las restricciones. No se añade una severidad que el modelo no proporciona. 5. **Teletrabajo:** «Autorizada» medía 3,2726754151865913:1 en oscuro por su verde fijo. `TeleworkAuthorizationSummary` usa ahora `foreground` para estado y aviso de revisión, conservando vigencia, fechas y notas. La etiqueta alcanza 18,92:1 claro y 17,11:1 oscuro. Se comprueban los tres consumidores: ficha, entorno de perfil y listado de teletrabajo, en ambos temas y con/sin revisión. 6. **Conservaciones:** pendientes y revisión en ámbar ya alcanzan su umbral. No se uniforman todos los indicadores ni se añaden tokens globales o señales de severidad. ### Método de contraste Se obtienen colores computados en navegador para texto, fondos, opacidad y bordes. Canvas convierte los colores CSS, incluidos OKLCH, a sRGB; se componen fondos transparentes hasta la superficie efectiva y la opacidad de controles. Se calcula luminancia relativa y `(Lclaro + 0,05)/(Loscuro + 0,05)`. Las decisiones usan valores sin redondear; las tablas redondean solo para lectura. Referencias: [WCAG 2.2, contraste de texto](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html) y [contraste no textual](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html). Se aplica 4,5:1 a texto normal y 3:1 a texto grande según tamaño/peso efectivos. Los controles disabled se registran y se distinguen de los umbrales de elementos activos. Los puntos de EntityStatus llevan `aria-hidden` y tienen una etiqueta textual redundante: no se afirma que el verde decorativo por sí solo cumpla 3:1. Tampoco se evalúa un borde decorativo como información esencial. Se inspeccionan reposo, hover y foco de acciones representativas, estados con revisión/retirada pendiente simulados en la frontera HTTP, ausencia, error y desconocido. No es una auditoría exhaustiva de cada nodo descriptivo, borde, anillo y estado de todos los diálogos de la aplicación; las muestras identifican exactamente el texto/control medido. ## M09: diagnóstico, medición y decisión La cuadrícula inicial de seis paneles uniformes no anticipaba ni la cabecera móvil ni las dos bandas 900/1000 px y la pila lateral. En la observación inicial a 390/320 px, el primer marcador de panel empezaba en Y=243 frente a Y=391 del panel real: diferencia estática de 148 px. Se observaron también eventos `layout-shift` durante las respuestas de fuentes; no se atribuyen todos al skeleton. **Decisión:** refinar la estructura del skeleton. Se incorporan marcadores de título, acciones y metadatos; banda Equipamiento/Pendientes desde 900 px de contenedor, pendientes de 256 px alineado al extremo; banda Perfiles/columna apilada desde 1000 px. Se mantienen seis paneles ligeros y alturas orientativas solo durante carga. Ninguna tarjeta real recibe alturas fijas. No se reproducen todos sus datos ni se añaden animaciones de entrada. La ficha desactiva el pulse de sus Skeleton cuando `prefers-reduced-motion: reduce`. Se comprobó el valor computado `animation-name: none` en los 24 marcadores iniciales. La información real sigue apareciendo al resolverse su fuente; no hay temporizadores para prolongar la carga ni una consulta bloqueante nueva. [Mediciones y comparación de carga](auditorias/ficha-puesto-trabajo/implementacion-v3/comparaciones/carga.md). Incluyen inventario, perfiles, software y soporte retenidos por separado a 1440/390/320, geometría inicial/final y eventos PerformanceObserver. ### Condiciones comparables y límites de estabilidad Las primeras medidas `carga-*` fueron exploratorias, sin limitar concurrencia. La API llegó a producir `SequelizeConnectionAcquireTimeoutError` en lecturas anidadas de Recursos; no es una regresión del skeleton y no se corrige desde el frontend. Para obtener muestras reproducibles se limita a dos el número de peticiones API simultáneas del **navegador de pruebas**, sin retardos temporales artificiales y sin modificar queries o servidor. Se repitieron ambos skeletons bajo esa misma condición. Los registros **`control-carga-*`** comparan exclusivamente el skeleton anterior y el nuevo con el resto de M08 constante durante esa muestra, mismas fixtures y mismo origen. Las correcciones finales de color de contadores y teletrabajo se hicieron después y no alteran la geometría de esa serie. Para la medida anterior se sustituyó temporalmente solo el fichero de skeleton propio, con copia, comprobación de cambios concurrentes y restauración en `finally`. Las capturas iniciales completas de v2.2 permanecen separadas. No se mezclan las dos series para calcular mejoras. PerformanceObserver registra valor, momento, `hadRecentInput` y rectángulos de fuentes. Se separan eventos anteriores a liberar la respuesta y eventos posteriores sin entrada reciente. El resumen utiliza ventanas de sesión de hasta cinco segundos, con menos de un segundo entre eventos, conforme a [la definición de CLS](https://web.dev/articles/cls). Son muestras de laboratorio de transiciones controladas, no un CLS de producción, percentil de usuarios ni benchmark repetido. No se promete una reducción de CLS a partir de la geometría o de un único recorrido. La incidencia de concurrencia sin control de red queda abierta como deuda de infraestructura/Recursos ajena. Pasar los recorridos con concurrencia de prueba limitada no demuestra que esa incidencia esté resuelta en condiciones normales. ## Accesibilidad y tema oscuro Se verifican los tokens oscuros efectivos aplicando `.dark` en la sesión de prueba. No se añade un selector de tema al producto. Tarjetas, textos y variantes se inspeccionan en claro/oscuro a 1440 y 390 px. El shell conserva sus superficies propias; no se confunde soporte de tokens CSS con una nueva preferencia de usuario implementada. El atajo de zoom nativo no cambia `innerWidth` ni DPR. Un segundo intento mediante `chrome://settings/appearance` fue rechazado por Playwright: esos ajustes no están disponibles en su contexto aislado. No se modifica la configuración global ni se reemplaza por escalado CSS o emulación de DPR. **Zoom nativo 200/400 % no ejecutado.** Las pruebas responsive y las emulaciones históricas de reflow tienen su propia evidencia y no lo sustituyen. No se encontraron Orca, speech-dispatcher, espeak-ng ni una integración NVDA; tampoco axe/pa11y instalados. **No se ejecutó un lector de pantalla real.** Se inspeccionó el árbol accesible nativo de Chromium mediante CDP, además de nombres, regiones, encabezados, tablas, estados expandido/contraído, teclado y foco. El árbol incluye encabezado de compañía fuera de main y un h1 de puesto dentro de main; la inspección ARIA/CDP no equivale a una prueba con tecnología de asistencia. [Resultados de accesibilidad](auditorias/ficha-puesto-trabajo/implementacion-v3/comparaciones/accesibilidad.md). ## Regresión acumulada y evidencias Las capturas de siete resoluciones cubren 1600×1000, 1440×900, 1280×900, 1024×768, 768×1024, 390×844 y 320×720. Se comprueban además 599/600/601 y 839/840/841 px de Card de Perfiles, y 899/900/901 y 999/1000/1001 px del contenedor de bandas. El ancho medido, no el viewport, determina cada distribución. Fixtures reproducibles: 15 compañías; principal con 59 personas, 137 activos, 73 recursos, 57 puestos y 64 perfiles; puesto denso con 80 miembros y 50 perfiles activos más 10 archivados. Relaciones coherentes, nombres/cuentas/rutas extensas y otras compañías para comprobar aislamiento. Los cambios de formularios se restauran; las revisiones adicionales son historial sintético de la prueba. Los recorridos y sus resultados finales se recogen en `mediciones.json`: edición/cancelación/historial/software; completar Equipamiento y restaurar foco; cero frente a desconocido/error; carga/refetch/reintentos; las seis regresiones v2.1 y cinco de v1. El runner reutiliza métodos con el destino v3 y adapta el selector accesible de Equipamiento en memoria; no escribe en las evidencias históricas. Las tandas finales completan los seis recorridos de v2.1 y los cinco de v1, además de los seis métodos funcionales de v2.2. Las repeticiones aisladas completan los casos de carga a 320 px y recuperación de soporte que agotaron una espera en tandas largas. No se afirma una única ejecución conjunta sin fallos. Los primeros intentos fallidos se distinguen de defectos de producto: simulación de carpetas ajustada al contrato `mappings`, selección de elementos HTML en la instrumentación de contraste para excluir SVG, selección inequívoca del párrafo de autorización frente a la columna con la misma etiqueta, pool agotado y un error de resolución Vite tras cambios concurrentes de búsqueda. Se reiniciaron solo API/Vite propios conservando base y configuración privada en memoria. No se instaló ni modificó el paquete interno de búsqueda. ## Validación técnica y consumidores | Comando/comprobación | Resultado observado | | --- | --- | | Tipos dirigidos de Assets, Companies y Web | Correctos. Incluye consumidores de `WorkstationActions.editVariant`. | | Biome y ESLint dirigidos al delta propio | Correctos; comprobación final registrada al cierre. | | Prueba directa de `workstation-detail.test.tsx` | 26/26, incluidos casos es/en de los tres estados de Software y los cuatro estados técnicos con asignación y principal conservados. | | Pruebas directas de teletrabajo y entorno | 5/5 y 7/7; total de las tres suites dirigidas: 38 casos. | | Assets completo | Correcto; el runner informa 27 archivos. | | `pnpm build` | Correcto, dos tareas; aviso existente de tamaño de chunk. | | `pnpm typecheck` global | Falla en vendor `calendar.tsx:165`, TS2375 por `locale` opcional. Verificado de nuevo. | | `pnpm lint` global | 15 errores, 1 warning y 5 infos en la ejecución global registrada. | | `pnpm check` global | 206 errores, 2 warnings y 7 infos en la última ejecución, tras nuevos cambios concurrentes; el alcance propio se comprueba aparte. | | `pnpm test` global | Falla en Resources, `src/api/application/resource-scope.test.ts`; cinco tareas correctas de seis ejecutadas. No completa Assets/Companies en esa tanda. | | Prueba directa de `companies-page.test.tsx` | 10/12; siguen fallando los casos de líneas 180 y 210, ajenos a la ficha. | No se trasladan los resultados históricos de v2.2 como si fueran actuales. Se separan las comprobaciones dirigidas y los fallos globales observados en este árbol concurrente. No se cambian vendor, contratos HTTP, DTO, migraciones, persistencia ni permisos. Fuentes propias: ocho ficheros de código/pruebas, con `workstation-dashboard-skeleton`, `workstation-assets`, `workstation-software`, `workstation-detail-page`, `WorkstationActions`, `TeleworkAuthorizationSummary` y sus dos suites modificadas. Los consumidores de WorkstationActions en listado e inventario conservan la variante por defecto. `DetailPanel`, Badge, Skeleton y FormDialog conservan implementación y contratos; el ajuste compartido de TeleworkAuthorizationSummary queda limitado a sus colores y se comprueban sus tres consumidores; se documenta el uso local. Comandos ejecutados: `pnpm --filter @metis/assets --filter @metis/companies --filter @metis/web typecheck`, `pnpm --filter @metis/assets test`, `pnpm build`, `pnpm typecheck`, `pnpm lint`, `pnpm test` y `pnpm check`. Biome y ESLint se ejecutaron con los ocho ficheros propios explícitos. Las suites de componentes se ejecutaron directamente con `TSX_TSCONFIG_PATH=../../tsconfig.json node --import tsx --test ` desde Companies; no se presenta el paquete completo de Companies como correcto. Los JSON de evidencias se comprueban con el límite de tamaño explícito `--files-max-size=16777216`; el check global conserva su límite por defecto y avisa del tamaño de mediciones. ## Reproducción y cierre Procedimiento de preparación: `scripts/setup-playwright-wsl.sh`, `scripts/visual-audit.py`, `visual-audit-volume.py` y `workstation-dashboard-fixtures.py`. Mantener el preparador abierto y pasar su sesión privada solo mediante `METIS_PLAYWRIGHT_STORAGE_STATE`. El runner `scripts/workstation-uiux-v3.test.py` guarda exclusivamente en `implementacion-v3`; usar `METIS_UIUX_PHASE=antes` para preparar/capturar antes de modificar y `despues` para la versión final. `METIS_UIUX_LOAD_LABEL=control-carga` distingue la comparación controlada del ensayo exploratorio. Cambiar la variable de fase no cambia por sí solo el código. El preparador propio y los supervisores sustitutos de API/Vite se cerraron por sus PID exactos. Se verificó que los cinco procesos registrados terminaron, que el contenedor propio desapareció y que `session.json`/`database.env` ya no existen. El cierre está registrado en mediciones; las capturas se conservan sin credenciales. No se realizan limpiezas globales ni se detienen procesos por nombres genéricos. Riesgos residuales: zoom nativo y lector real pendientes; otras combinaciones de navegador/dispositivo sin probar; contraste global fuera del alcance sin certificación; fallo de concurrencia de Recursos y checks globales ajenos. No se presenta la ficha como una comprobación operativa o de permisos efectivos. La estabilización visual de M01–M09 se separa del cierre integral de accesibilidad e infraestructura. La transición instrumentada utiliza el puesto principal con dos perfiles y dos activos. Los estados vacíos y de volumen se comprueban funcional y visualmente, sin un barrido de CLS para cada combinación de datos.