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

28 KiB
Raw Blame History

L04.1 — Adopción de listados en Puestos, Perfiles y Compañías

Fecha: 24 de octubre de 2026. Fuentes: DESIGN, L01, L03.1, L03.2, L03.3, columnas, estados, selectores, listados y Playwright.

1. Resumen y alcance

Adopción de los contratos existentes de URL, preferencias y retorno; no es otra arquitectura de navegación. TanStack Query conserva datos y referencias. Las rutas de Puestos abren su ficha; las de Perfiles abren entorno y configuraciones; Compañías abre su workspace. No se añaden rutas de negocio, filtros ni campos buscables.

Skills consultadas: ux-navigation como principal (rutas, scopes, History y foco); ux-tables/ux-search para tabla y criterios; shadcn para APIs/foco; vercel-composition-patterns para la extensión opcional y vercel-react-best-practices para separar URL, datos y estado derivado. ux-microcopy se aplica a mensajes es/en y ux-error-recovery al registro desaparecido y recuperación. No se necesita otra consulta a ui-ux-pro-max ni se instala ningún auditor/skill. No se declara una auditoría WCAG completa.

2. Auditoría y matriz previa, antes de modificar producción

Estado observado en código al iniciar L04.1. La evidencia de navegador se registra separadamente. Local significa vida del componente; URL sobrevive enlace/recarga.

Estado Puestos antes Perfiles antes Compañías antes Contrato esperado / mecanismo existente
Búsqueda y filtros search local; nombre/sede/responsable; sin selectores adicionales q/archived URL; nombre/persona/ordenador q/activeOnly/companyId URL; solo nombre buscable URL para consulta; mantener defaults/campos y ámbito L03.3
Ordenación EntityTable local; se pierde al desmontar EntityTable local; entorno sustituye la tabla EntityTable local; workspace desmonta directorio useListLocation y EntityTable.navigation validan columnas reales
Página Local, se pierde con ficha Local, se pierde con entorno/configuración Local, se pierde al entrar en compañía page en URL; esperar referencias antes de normalizar
Tamaño entity-page-size compartido en localStorage Igual Igual Conservar clave, valores y setters existentes
Columnas Local, sin clave persistente Local, sin clave persistente Local, sin clave persistente Habilitar clave propia mediante API existente; no guardar query en preferencias
Scroll Sin captura/retorno de listado Sin captura/retorno de listado Sin captura/retorno de directorio useListReturn sobre raíz propia y contenedor real de workspace
Foco BODY/título tras reconstrucción; enlaces de activos/personas conservados Nombre abre entorno sin query; botones de gestión navegan sin estado de lista Nombre y acción abren compañía; Atrás sin contrato de foco de fila History guarda origen; restaurar enlace verificado o buscar como alternativa
Selección Ficha en pathname, historial/edición locales Perfil/configuración en pathname; fallback local embebido Workspace en pathname; fallback local cuando no hay callback Preservar rutas/selección y semántica de cada entidad
Datos remotos useListQuery inventario; tabla solo con data; error/refetch externos Perfiles+inventario+accesos; tabla solo cuando hay referencias useListQuery compañías; tabla solo con data EntityListState y tabla estable; no duplicar DTO para restaurar
Diálogos/provisional Editor, historial y ciclo de vida locales Editor, historial y ciclo de vida locales Alta/editor locales No llevar a URL; no competir con finalFocus ni restaurar por cerrar modal

Puestos vive actualmente en modules/assets/src/web/workstations/list; su ficha está en Companies. Perfiles y Compañías viven en Companies. CompanyInventory alterna ficha y listado de Puestos, desmontando este último; WorkProfilesPage sustituye su listado por ProfileConfigurations. El directorio se desmonta al cambiar el área del workspace.

Compañías no tiene una acción Volver en su workspace embebido: el retorno existente al directorio es Atrás del navegador. Volver desde una sección interna recorre esas entradas de History; el acceso global «Compañías» sigue siendo navegación al directorio por defecto. No se rediseña el shell V01 para convertir ese acceso en otra acción.

3. Contratos implantados y matriz después

Consumidor Estado navegable Preferencias Retorno Datos y modales
Puestos q, sort, direction, page en su listado y enlace a ficha Tamaño compartido; columnas por compañía Atrás y enlace de breadcrumb/móvil; origen verificado o búsqueda Inventario y referencias de compañía; editor/historial/ciclo de vida siguen locales
Perfiles q, archived, sort, direction, page; entorno conserva la consulta Tamaño compartido; columnas por compañía Entorno → listado; configuración → entorno por History; no se inventa ficha Perfiles, inventario, accesos y estado de compañía; historial/edición siguen modales
Compañías q, activeOnly, companyId, sort, direction, page Tamaño compartido; columnas del directorio global History al directorio; entrada anterior propia, sin foco sobre otra compañía Query global; selección del workspace y editor conservan su contrato

Los tres controladores reutilizan useListLocation y useListReturn; EntityTable mantiene los modelos de TanStack Table. No se modifica Core/History ni se introduce otro almacén. El fallback local de Puestos fuera de su ruta permanece. La apertura de configuración de Perfiles sigue sus rutas reales: la página/controlador padre permanece montada y sus queries pueden seguir disponibles mientras la tabla está sustituida por el entorno.

Las filas mantienen identidad por UUID. Se conservan los enlaces de Puestos a responsables y activos, las acciones principales/secundarias, archivado y reglas de ciclo de vida. El listado no adquiere filtros independientes de sede/responsable: siguen siendo campos de búsqueda. No se modifican relaciones de negocio ni permisos.

4. URL y validación

Ruta Parámetros del listado Otros parámetros conservados
/companies/:id/workstations q, sort, direction, page companyId cuando ya existe y es compatible con pathname
/companies/:id/work-profiles q, archived, sort, direction, page Ámbito y parámetros permitidos por el parser existente
/companies q, activeOnly, sort, direction, page companyId como ámbito global

Se reutilizan nombres, parser y límites existentes. useEntityTable valida columnas ordenables reales, asc/desc y página positiva segura; rechaza ordenar por acciones, reconduce dirección/página inválidas y limita páginas al resultado. Nombre comienza ascendente. Los booleanos mantienen su semántica existente: true activa el criterio; no se inventa un filtro por aceptar un valor desconocido. El parser del workspace sigue validando UUID, ámbito, pestañas y claves; esta validación no sustituye al servidor.

Búsqueda/filtros eliminan page cuando cambian el conjunto. Ajustes usan replace; enlaces usan push. La canonicalización espera consultas y referencias verificadas; durante carga, refetch o error no convierte una página válida en 1 por un conjunto provisional vacío. La consulta original, incluidos espacios exteriores, permanece en q.

El enlace de Puestos a su ficha y los retornos móvil/breadcrumb conservan la consulta. El entorno de Perfil también la conserva. Las configuraciones poseen su propia búsqueda: no heredan q/sort/page de otra colección. History recupera la URL del entorno; el retorno explícito del entorno usa returnToList con fallback al listado si el enlace fue directo. Una configuración abierta directamente conserva su fallback histórico al entorno. No se añade persistencia artificial para reconstruir un listado que nunca se visitó.

5. Preferencias y estado temporal

  • Tamaño: clave compartida existente entity-page-size; valores/defaults sin cambios.
  • Puestos: workstations-columns:<companyId>.
  • Perfiles: work-profiles-columns:<companyId>.
  • Compañías: company-directory-columns.

La API existente valida visibilidad, protege identidad/acciones y recupera defaults ante almacenamiento inválido/no disponible. No cambian IDs de columnas ni claves de inventarios. Limpiar criterios conserva orden válido, columnas, tamaño y ámbito. Los diálogos, selección provisional, aperturas y edición no se llevan a URL ni se copian a almacenamiento.

6. Retorno, scroll y foco

useListReturn guarda únicamente coordenadas e identidad en history.state, por entrada y scope: ruta del listado y compañía, o directorio global. Captura el contenedor real de workspace y el horizontal de tabla. Espera composición/fuentes y limita cada coordenada al rango disponible, sin setTimeout ni segunda copia de DTO. Una pantalla sin scroll restaura 0; no se exige una coordenada imposible.

El foco vuelve al enlace original si el dato y el enlace siguen verificados. Si se retira la entidad o no puede verificarse, vuelve a búsqueda. Nunca se escoge otra fila ni se considera una respuesta fallida como confirmación de un registro conservado en caché. Un refetch durante el retorno espera las fuentes; no impone el foco sobre una interacción posterior. Cerrar historial/editor conserva la misma tabla y respeta finalFocus de Base UI.

Compañías no añade una acción Volver al shell. Atrás desde workspace vuelve al directorio; si se visitó una sección interna, se recorren sus entradas. El acceso global Compañías sigue siendo navegación nueva al directorio por defecto. Cambiar compañía no importa q, página, scroll ni foco del listado de otra compañía.

Mediciones representativas verificadas: Puestos conserva página 3, orden descendente y foco de fila; en 1440 el scroll es X=0/Y=150, en 1024 X=16/Y=150 (límite real), en 390 y 320 X=40/Y=150. En 1920 no hay recorrido vertical y se conserva 0. Perfiles conserva página 3 y X=40/Y=150 en móvil. Directorio conserva página 2; en 390 restaura X=40/Y=117, limitado al máximo vertical disponible. Los JSON registran antes/después, UUID, href, filas, geometría, consulta, filtros y aria-sort; no se valida únicamente la URL.

7. Búsqueda, filtros y extensión mínima compartida

Se conserva createTextMatcher: caja, tildes vocálicas, Unicode canónico y espacios exteriores equivalentes; ñ distinta de n y puntuación técnica preservada. Puestos busca nombre/sede/responsable; Perfiles nombre/persona/ordenador; Compañías solo nombre. No se amplían campos ni se modifica normalización, proveedor remoto o política de ordenación.

archived y activeOnly participan en limpiar; companyId permanece como ámbito. Se verifican consultas con espacios/tildes, Peña/Pena distintos, cero coincidencias, reajuste de página y español/inglés. No se añade una banda de chips.

Incompatibilidad detectada: al combinar búsqueda, archived y página externa, la limpieza previa generaba dos cambios efectivos de URL. Se conserva la prueba roja. EntityTableNavigation añade únicamente onClearFilters?: el consumidor agrupa criterios y page en un replace; EntityTable conserva el foco de búsqueda. Sin callback, continúa el flujo anterior de búsqueda/callback/page. Los tres nuevos consumidores lo proporcionan; los pilotos y consumidores no controlados mantienen sus contratos. La medición verde registra un único cambio efectivo de URL; las escrituras internas de metadatos de History no se confunden con navegación. No se altera History ni la API obligatoria del componente.

8. Carga, error y permisos

Las tres tablas permanecen montadas en el listado durante carga/error; reutilizan EntityListState, skeleton, actualización con datos anteriores y recuperación existentes. El helper de Companies companyListQueryState compone fuentes de directorio y Perfiles; no conoce endpoints ni duplica datos. Puestos reutiliza el adaptador de permisos de Assets. La señal de compañía se propaga desde su propietario para no verificar responsables/sedes con referencias pendientes o fallidas.

Se verifican carga inicial con page conservada, refetch con filas anteriores, 503 inicial sin filas, recuperación conservando la misma tabla, 503 posterior y 403 que oculta caché sin ofrecer un reintento improcedente. El contenedor de compañía conserva además su recuperación existente para sus propios datos. No se alteran permisos ni autenticación.

La revisión acumulada de consola encontró un rechazo no gestionado en los callbacks nuevos de Reintentar al usar throwOnError: true. Se corrige en los tres consumidores utilizando refetch() como los pilotos: TanStack Query publica el error y mantiene la recuperación. La prueba de errores comprueba expresamente que reintentar no produzca pageerror.

9. Pruebas automatizadas y técnicas

Pruebas añadidas a las suites existentes:

  • Assets inventory.test.tsx: Puestos con 30 DTO válidos, búsqueda URL, orden descendente, página 3 efectiva, filas y enlaces con consulta.
  • Companies profile.test.tsx: 30 perfiles válidos, q/archived/sort/page y entorno.
  • Companies company-filters.test.tsx: directorio de 30 compañías, ámbito/limpieza y página 3.
  • company-list-query-state.test.ts: dependencias, actualización, error inicial/posterior, denegación y caché. Se registra en el script test del paquete existente.

Para repetir la comprobación, mantener abierto python3 scripts/visual-audit.py, usar la ruta privada de sesión que indique y preparar volumen con el procedimiento existente:

export METIS_PLAYWRIGHT_STORAGE_STATE=".artifacts/playwright/<instancia>/session.json"
python3 scripts/visual-audit-volume.py
python3 scripts/adoption-ui.test.py

No copiar el contenido del archivo de sesión ni conectarlo a otra base. Al terminar, cerrar el preparador para retirar sus servicios y la sesión, según Playwright. El script de adopción exige ese volumen y no crea datos por sí mismo.

Los runners de Node contabilizan archivos en las ejecuciones aisladas; no se presentan esos totales como número de casos unitarios. Las pruebas SSR no acreditan interacción, scroll ni foco; esas comprobaciones se realizan con MCP.

Comprobación Resultado real
Typecheck dirigido Assets, Companies y rdx-ui Correcto (tsc --build de los tres proyectos)
Biome de los 23 archivos TS/TSX/JSON afectados y ESLint dirigido Correctos
Native de los cuatro archivos de adopción/estado 4/4 archivos correctos
pnpm --filter @metis/assets test 27/27 archivos correctos
pnpm --filter @metis/core test 3/3 archivos correctos, incluye History
pnpm --filter @repo/rdx-ui test 13/13 archivos correctos, incluye tabla controlada y no controlada
pnpm --filter @metis/companies test 47/48 archivos correctos; los dos casos fallidos están en companies-page.test.tsx
pnpm typecheck Falla en vendor calendar.tsx:165, TS2375 por locale opcional; igual que línea base
pnpm lint Falla: 15 errores, 1 warning, 4 infos; informe visible idéntico a línea base salvo tiempo/recuento de archivos
pnpm check Falla: 169 errores, 1 warning, 4 infos; mismo total e informe visible de línea base
pnpm build Correcto; conserva aviso de chunk de frontend >500 kB
pnpm test con MariaDB temporal separada Falla: 8/10 tareas correctas; Companies y servidor. Servidor: 8/8 pruebas iniciales y 18/19 de integración; identity.test.ts:82 obtiene 401 y espera 404 (--continue=always para ejecutar todas las tareas)
Compilación Python del script de adopción Correcta

Biome limita por defecto los diagnósticos visibles; la comparación no pretende verificar individualmente los 169 que no muestra. Sí se verifican los archivos afectados sin errores. Las comprobaciones finales de tipos/formato se repiten tras la corrección de Reintentar.

Los fallos globales se contrastan con la línea base tomada antes de modificar código y con L03.2/L03.3. El diagnóstico directo de Companies identifica las mismas aserciones companies-page.test.tsx:180 (Personas (1)) y :210 (microcopy de acceso). No se modifican esos tests ni la implementación ajena para conseguir un resultado global verde.

El fallo global adicional de apps/server/src/identity.test.ts:82 ocurre al comprobar 404 en rutas retiradas sin sesión; obtiene 401. No hay cambios de L04.1 en app.ts, identity.test.ts ni en autenticación/servidor. Los informes anteriores no permiten acreditar que este caso ya fallara antes; se registra como fallo global observado, sin clasificación de preexistencia demostrada, y no se altera la seguridad para satisfacerlo. El extenso recorrido de ese método se interrumpe en esa aserción: las verificaciones posteriores no se consideran ejecutadas.

10. Playwright MCP: cobertura, datos y evidencias

Se utiliza la imagen oficial fijada en .codex/config.toml, Docker/Chromium headless y sesión ordinaria creada por el flujo real de acceso. Se reutiliza primero una sesión sintética existente sin retirar su preparador; sus GET sufren timeouts. Se prepara una instalación propia desechable en metis_desk_test, se retira y se repite una vez con el mismo procedimiento. Solo se mantiene una instalación visual propia activa; no se tocan instalaciones ni sesiones ajenas.

Volumen persistido del entorno final: 15 compañías, 50 personas, 51 activos y 66 recursos. La fixture GET añade 50 sedes, 50 puestos (40 activos/10 inactivos), 50 perfiles (40 activos/ 10 archivados) y completa 50 ordenadores principales; inventario mostrado: 66 activos. Los puestos inactivos no conservan asignaciones actuales y sus perfiles activos se vinculan solo a puestos operativos. Se usan nombres largos/con tildes y relaciones coherentes con personas y activos; los cuatro payloads principales pasan los schemas reales de Node. No se afirman 50 puestos/perfiles persistidos: son fixtures HTTP de lectura autorizadas.

La autenticación sigue comprobándose contra el servidor. Para evitar lecturas concurrentes inestables en este entorno, se capturan secuencialmente 13 GET reales relacionados y se reproducen sus payloads. La prueba no valida esos endpoints de extremo a extremo bajo concurrencia. Las retiradas, demoras, 503 y 403 son interceptaciones explícitas GET; las escrituras de navegador están bloqueadas y su registro debe ser vacío.

El entorno produce ERR_NETWORK_CHANGED, conexiones reseteadas y documentos vacíos al cargar módulos. Se conservan los intentos fallidos. El comprobador bloquea únicamente el WebSocket HMR y entrega respuestas GET obtenidas por el cliente HTTP de Playwright sin alterar HTML/JS/CSS. Las conexiones GET reseteadas admiten hasta dos reintentos; goto solo repite una vez ante ERR_NETWORK_CHANGED y lo registra. No se modifica Vite, la aplicación, la imagen MCP ni la configuración global. La causa del transporte no queda determinada.

Flujo Resoluciones ejecutadas Comprobación
Puestos → ficha → Atrás/retorno explícito 1920×1080, 1440×900, 1366×768, 1024×768, 768×1024, 390×844, 320×640 Página 3, consulta, descendente, filas, X/Y y enlace original
Perfiles → entorno → aplicaciones → entorno → listado Las siete anteriores archived, consulta, página 3, orden, X/Y y foco; q no filtra configuraciones
Directorio → compañía → Sedes → Atrás → directorio Las siete anteriores Página 2, consulta, orden, X/Y y compañía original
Recarga/parámetros inválidos 1440×900 Filas/página/orden, canonicalización y companyId compatible
Limpiar/preferencias/cancelación 1440×900 Página 1, orden/columnas/tamaño conservados, un replace y foco lógico
Retirada/directo y cambio de compañía 390×844 y 1440×900 Fallback búsqueda, URL directa y aislamiento
Historial, teclado e idioma 390×844 Misma tabla al cerrar modal; Enter, Escape y limpieza es/en
Carga/503/403/recuperación 320×640 Skeleton, estado anterior, caché oculta, tabla estable y foco de recuperación

La ejecución browser-final-fixed.log finaliza 11/11 métodos correctos en 701 segundos. Sus medidas son after/measurements-679675.json; los tres recorridos principales cubren las siete resoluciones. La consola acumulada de esa ejecución contiene 40 errores de recurso de las respuestas 503/403 provocadas, cero pageerror, y el registro de escrituras es []. La comprobación adicional de edición desde la ficha se registra separadamente: el primer selector coincidía con los dos botones válidos de editar (cabecera/estado vacío); se precisa el de cabecera y browser-detail-cancel-repeat.log pasa, verificando cancelación, foco al botón y retorno completo al listado. No se modifica la aplicación para resolver esa ambigüedad del instrumento. No se presenta un lote anterior interrumpido como correcto por haber pasado algunos métodos.

scripts/adoption-ui.test.py reutiliza visual-audit.py y list-context-ui.test.py; no crea servicios ni otro framework. Métodos 41–51: retorno de Puestos, entorno/configuración, workspace/sección interna, recarga/parámetros inválidos, limpieza/preferencias, cancelación/ búsqueda, desaparición/URL directa, refetch/aislamiento, historial/teclado/idioma, estados de consulta y compañía desaparecida/inaccesible.

La retirada de Perfiles requiere un GET real de refetch: su controlador permanece montado al entrar en el entorno. Se corrige el instrumento para disparar offline/online y comprobar la respuesta antes del retorno; no se atribuye a la aplicación un mock nunca consumido. Los fallos iniciales de scripts y red se mantienen junto a los resultados posteriores.

Capturas abiertas e inspeccionadas: stations-return-1440.png, profiles-return-320.png, directory-return-390.png, work-profiles-loading-320.png y stations-return-320.png. Se observa scroll horizontal conservado y skeleton estable. La densidad móvil y el contador partido del directorio siguen siendo limitaciones visuales previas, fuera de esta adopción. No hay rediseño CSS.

Índice local ignorado: evidencias. Conserva PNG, snapshots, medidas antes/después, fixtures validadas, consola acumulada, registros de escrituras, intentos rojos/verdes y logs técnicos. Las capturas pueden sobrescribirse al repetir el mismo escenario; los JSON y logs distinguen cada proceso/intento.

11. Regresiones

Suite existente Resultado acumulado de métodos distintos Intentos conservados
L03.1 contexto (Activos/Recursos/Personas) 14/14 Lote inicial 13/14; un error de transporte y otra conexión reseteada; caso 03 correcto en context-last-repeat.log
L03.3 filtros 11/11 Lote inicial 10/11; caso 22 correcto al repetir con transporte GET
L03.2 búsqueda 8/8 Lote completo correcto
L02.3 estados 8/8 Lote inicial 7/8; caso 04 correcto en repetición
L02.2 columnas 8/8 Lote inicial 7/8; caso 06 correcto en repetición
L02.1 pickers 8/8 Lote completo correcto

Total: 57 métodos distintos de regresión verificados, además de los 11 de adopción. No significa 57 pruebas verdes en una única ejecución: los fallos de transporte y las repeticiones se detallan en los logs. La adaptación local regressions.py reutiliza los runners existentes, baseline real sintético de 51 activos y GET relacionados capturados; conserva las fixtures específicas de cada suite. No modifica sus archivos versionados.

Se comprueban también tabla no controlada, búsqueda/limpieza, preferencias y tamaño, selectores con teclado/foco/zoom, flujos responsive del workspace y retorno de los pilotos. Los casos de errores mantienen interceptaciones propias. La conectividad de proveedores externos y todos los datos de configuraciones posibles no quedan certificados.

No se infiere cobertura universal de V01/V06 por usar componentes compartidos: se verifican los recorridos responsive, teclado, foco, diálogos y selectores de las suites ejecutadas. Las dependencias remotas reales y configuraciones no pobladas mantienen sus límites.

12. Archivos, revisión y limitaciones

  • Controladores, props y páginas de Puestos, Perfiles y Compañías.
  • Composición CompanySection/CompanyInventory: disponibilidad de referencias.
  • Ficha de Puestos: query del enlace/retorno y fallback tras borrado (sin ejecutar borrado).
  • Helper de estado de Companies, traducciones es/en y pruebas descritas.
  • EntityTableNavigation/EntityTable: callback de limpieza externa opcional.
  • Script MCP de adopción, este informe, DESIGN, patrón/componentes/rutas y seguimientos L01/L03.1/L03.2/L03.3.

Se conserva el workspace previo y el trabajo concurrente, incluida la ficha de Puestos. Los cambios de foco del editor de esa ficha y otras funcionalidades simultáneas no se atribuyen a L04.1. No se modifica vendor, autenticación, contratos HTTP, ORM, migraciones, query keys. No se añaden paquetes de UI ni dependencias. No se certifica WCAG completa ni todas las posibilidades de configuraciones/permisos o servicios externos. No se prueba borrado real. El fallback posterior a eliminación se revisa en código y el registro retirado se simula mediante GET. La revisión de enlaces/diff se recoge con los resultados ejecutados. El barrido incluye una referencia histórica de L01 a workstation-people.tsx cuyo destino ya no existe; el mismo enlace está en la copia previa a esta entrega. Se conserva como evidencia histórica y no se atribuye a L04.1. Los enlaces documentales nuevos deben resolver.

El cierre del preparador propio termina con código 143: desaparece su sesión, pero queda su MariaDB temporal. Se confirma el contenedor mediante una lectura de la compañía sintética propia en metis_desk_test y se retira explícitamente. La comprobación final confirma ausencia de ambos contenedores propios (visual/integración), puerto visual cerrado y session.json eliminado. El runner global confirma su limpieza con código 0. No se cierran preparadores ni contenedores ajenos. Los logs conservan este cierre incompleto inicial y su resolución; no se presenta como una salida normal del preparador. Cookies que Playwright incluyó en diagnósticos locales de transporte se redactan; los archivos de sesión y datos privados permanecen ignorados y no se incorporan a Git.

git diff --check, la revisión de APIs/componentes y el barrido documental se registran en las evidencias. packages/shadcn-ui, pnpm-lock y skills-lock permanecen sin cambios por esta entrega. El inventario completo propio está en archivos modificados.

Estado: L04.1 implementada y verificada en sus tres consumidores y escenarios. Los fallos globales y límites de transporte/backend descritos permanecen abiertos; no se declara una validación técnica global completamente verde.

13. Consumidores pendientes

Catálogos, procesos, configuraciones, sublistados y los restantes consumidores se abordarán en sus entregas. L04.1 no universaliza la adopción ni rediseña navegación global, selectores, estilos o densidad. L04.2–L04.4 no se implementan y L04 no se marca completa.

Seguimiento posterior — L04.2

L04.2 implementa la adopción pertinente en catálogos, Procesos y configuraciones, preservando las excepciones locales de editor/historial. El diagnóstico 401/404 se reproduce con sesión y sin ella: /api/dashboard/work devuelve 401 anónimo y 404 autenticado por el orden del middleware. El test de servidor no aporta cookie. Se confirma su presencia antes de L04.2, sin fechar su introducción anterior a L04.1 ni cambiar seguridad/expectativa. Las mediciones y limitaciones históricas de este documento se conservan; resultados posteriores y regresiones figuran en L04.2. L04.3/L04.4 siguen pendientes y L04 no se marca completa.

Seguimiento L04.3

Los sublistados de fichas utilizan el estado de lectura por propietario descrito en L04.3, sin heredar q/sort/page de estos listados autónomos. Las expansiones del puesto y el contexto de asignaciones/perfiles mantienen una duración propia. Los resultados históricos de esta entrega no cambian; la regresión ejecutada se registra en L04.3.