28 KiB
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.