267 lines
19 KiB
Markdown
267 lines
19 KiB
Markdown
|
|
# L02.3 — Estabilidad de listados y estados de consulta (V12)
|
|||
|
|
|
|||
|
|
Fecha: 22 de octubre de 2026. Implementación en Activos y adopción equivalente en Recursos.
|
|||
|
|
Este documento complementa [L01](auditoria-listados-l01.md), [L02.1](selectores-accesibilidad-l02-1.md),
|
|||
|
|
[L02.2](configuracion-columnas-l02-2.md) y el [patrón de listados](patron-de-listados-de-entidades.md).
|
|||
|
|
|
|||
|
|
## 1. Resumen de la implementación
|
|||
|
|
|
|||
|
|
El inventario mantiene su instancia de `AssetList`/`EntityTable` desde la primera petición.
|
|||
|
|
Búsqueda, cabeceras conocidas, configuración y espacio de paginación permanecen reconocibles.
|
|||
|
|
La consulta principal, el catálogo y los datos de red tienen estados y reintentos independientes.
|
|||
|
|
Las actualizaciones conservan la caché de TanStack Query y comunican cuándo fallan.
|
|||
|
|
No se modifican backend, rutas, autenticación, permisos, dependencias ni vendor.
|
|||
|
|
|
|||
|
|
Archivos afectados, agrupados por responsabilidad:
|
|||
|
|
|
|||
|
|
| Área | Archivos principales |
|
|||
|
|
| --- | --- |
|
|||
|
|
| rdx-ui, componentes | `entity-list.tsx`, `entity-list-controls.tsx`, `entity-table-configuration.tsx`, `entity-table-content.tsx`; nuevos `entity-list-status.tsx` y `entity-table-skeleton.tsx`, en `packages/rdx-ui/src/components/`. |
|
|||
|
|
| rdx-ui, contrato/pruebas/textos | Nuevo `src/lib/entity-list-state.ts`, `src/entity-list.test.tsx` y `src/locales/{es,en}.json`. |
|
|||
|
|
| Activos | `modules/assets/src/web/assets/list/controllers/use-inventory-page-controller.ts`, nuevo `list/helpers/asset-list-query-state.ts`, `list/ui/inventory-page.tsx`, `list/ui/asset-workstation-action.tsx`, `shared/ui/asset-list.tsx` y `modules/assets/src/common/locales/{es,en}.json`. |
|
|||
|
|
| Recursos | `modules/resources/src/web/resources/list/controllers/use-resources-page-controller.ts`, nuevo `list/helpers/resource-list-query-state.ts`, `list/ui/resources-page.tsx` y `modules/resources/src/common/locales/{es,en}.json`. |
|
|||
|
|
| Pruebas MCP | Nuevo `scripts/list-states-ui.test.py`; actualización de `scripts/picker-ui.test.py` y `scripts/visual-audit-ui.test.py` para contratos vigentes y datos abundantes. |
|
|||
|
|
| Documentación | Este informe, `DESIGN.md`, `docs/patron-de-listados-de-entidades.md`, `docs/componentes-de-interfaz.md` y los seguimientos de `docs/auditoria-listados-l01.md` / `docs/auditoria-ui-ux-visual.md`. |
|
|||
|
|
|
|||
|
|
## 2. Diagnóstico de consultas
|
|||
|
|
|
|||
|
|
| Consulta / clave real | Datos y necesidad | Disponibilidad, actualización y error |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| `inventoryKeys.company(companyId)` → `["inventory", companyId]` | GET `/api/assets/:companyId`: activos, instantáneas, puestos y relaciones. Imprescindible para filas y selección. | Inicialmente `data` indefinido; refetch conserva datos. Error inicial impide operar sobre filas; error posterior permite consultar la copia anterior. |
|
|||
|
|
| `catalogKeys.scope(companyId)` → `["asset-catalog", companyId]` | GET `/api/asset-catalog/:companyId`: plantillas y campos vigentes. Necesario para configurar el catálogo completo y editar/crear. | Independiente del inventario. Las instantáneas permiten consultar filas mientras llega; sin catálogo se explica la limitación y se deshabilitan configuración y alta. Si falla refetch se conservan las definiciones anteriores y se indica su antigüedad. |
|
|||
|
|
| `infrastructureKeys.company(companyId)` → `["asset-infrastructure", companyId]` | GET `/api/asset-infrastructure/:companyId`: roles, interfaces, IP y MAC. Accesorio para el inventario. | Pendiente/error no bloquea filas; aviso localizado y reintento propio. Refetch fallido mantiene los últimos datos de red. |
|
|||
|
|
| `inventoryKeys.company(companyId)` de Resources → `["resource-inventory", companyId]` | GET `/api/resources/:companyId`: recursos y referencias. | Misma separación entre carga, disponibilidad, actualización y error; conserva contratos de selección URL y diálogo explícito. |
|
|||
|
|
| `catalogKeys.scope(companyId)` de Resources → `["resource-catalog", companyId]` | GET `/api/resource-catalog/:companyId`: plantillas de recursos. | No bloquea lectura de instantáneas. Configuración y alta requieren referencias disponibles; el error tiene recuperación propia. |
|
|||
|
|
|
|||
|
|
Estas consultas no dependen unas de otras y se habilitan al montar la página con `companyId`.
|
|||
|
|
Sedes/personas llegan mediante `lookups` desde la consulta de compañía del padre; no se añaden
|
|||
|
|
consultas ni se cambia ese requisito de montaje. Los campos dinámicos se derivan del catálogo
|
|||
|
|
y de las instantáneas reales, sin consulta adicional.
|
|||
|
|
|
|||
|
|
`useListQuery` mantiene su intervalo de 60 s en primer plano, refetch al recuperar foco/conexión
|
|||
|
|
y deduplicación por claves. El cliente real configura `retry: false`: los reintentos añadidos
|
|||
|
|
son explícitos y dirigidos a la consulta correspondiente. No cambia la política global.
|
|||
|
|
|
|||
|
|
Antes, `AssetInventoryPage` condicionaba `AssetList` a `query.data` y agrupaba el pending del
|
|||
|
|
inventario, catálogo e infraestructura. El mensaje genérico «Cargando catálogo…» no identificaba
|
|||
|
|
la consulta retenida. En Recursos, el pending/error combinado podía ocultar datos utilizables.
|
|||
|
|
|
|||
|
|
## 3. Modelo de estados adoptado
|
|||
|
|
|
|||
|
|
`EntityListState` es una unión discriminada presentacional: `loading`, `ready`, `refreshing`,
|
|||
|
|
`unavailable` y `stale`. `entityListState` combina disponibilidad, actividad y fallo; no conoce
|
|||
|
|
TanStack Query. Los adaptadores de módulo leen `data`, `isFetching`, `isError` y `error`.
|
|||
|
|
|
|||
|
|
| Datos disponibles | Consulta | Presentación |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| No | Pendiente | `loading`, mensaje específico y skeleton |
|
|||
|
|
| Sí, incluidos cero registros | Correcta | `ready`; vacío solo si la respuesta válida está vacía |
|
|||
|
|
| Sí | En curso | `refreshing`, filas anteriores y aviso discreto |
|
|||
|
|
| No | Fallida | `unavailable`, error y reintento recuperable |
|
|||
|
|
| Sí | Fallida | `stale`, copia anterior, aviso explícito y reintento |
|
|||
|
|
|
|||
|
|
Los errores conservan `retrying` para deshabilitar el reintento duplicado e indicar actividad.
|
|||
|
|
No se guardan DTO, marcas temporales ni estados de consulta duplicados en React. Se opta por
|
|||
|
|
explicar «últimos datos disponibles» sin introducir una hora ni duplicar `dataUpdatedAt`.
|
|||
|
|
|
|||
|
|
## 4. Cambios de composición
|
|||
|
|
|
|||
|
|
Activos monta siempre `AssetList`, sin keys dependientes de la consulta. Su controlador deriva
|
|||
|
|
el conjunto legible de la caché; Resources aplica la misma regla. `EntityTable` conserva el hook
|
|||
|
|
de tabla y acepta `state`, `onRetry` y `columnsDisabled` opcionales. Los consumidores legacy,
|
|||
|
|
incluidos PickerList y selectores remotos, mantienen sus contratos existentes.
|
|||
|
|
|
|||
|
|
Las páginas deciden permisos, dependencias y operaciones; rdx-ui solo recibe textos y callbacks.
|
|||
|
|
`useContextualDetail`, presupuestos de contenedor, navegación y `EntityNotFound` se conservan.
|
|||
|
|
Un error transitorio no confirma que haya desaparecido una selección. Una respuesta correcta
|
|||
|
|
que la retire sigue utilizando el contrato de desaparición existente.
|
|||
|
|
|
|||
|
|
## 5. Carga inicial
|
|||
|
|
|
|||
|
|
La búsqueda y ordenación de columnas conocidas funcionan durante la espera; sus valores se
|
|||
|
|
mantienen cuando llegan los datos. Diez placeholders como máximo reservan una página plausible,
|
|||
|
|
con las clases de las columnas reales. Son `aria-hidden`, sin nombres de entidades, selección,
|
|||
|
|
links ni botones de acción. No se anuncian diez registros ni se muestra un total cero inventado.
|
|||
|
|
|
|||
|
|
Paginación/tamaño de página permanecen visibles pero deshabilitados hasta disponer de datos.
|
|||
|
|
El catálogo pendiente tiene un marcador decorativo y un mensaje contextual cuando hay filas.
|
|||
|
|
Las pestañas y columnas solo utilizan definiciones/instantáneas realmente conocidas. La alta
|
|||
|
|
espera a inventario y catálogo válidos; los datos de red pendientes no bloquean el inventario.
|
|||
|
|
|
|||
|
|
## 6. Refetch y datos anteriores
|
|||
|
|
|
|||
|
|
«Actualizando activos…»/«Updating assets…» sustituye el resumen en su banda habitual, sin spinner
|
|||
|
|
modal, skeleton completo ni toast por cada intervalo. Las filas y herramientas no se desmontan.
|
|||
|
|
Se conservan búsqueda, plantilla, orden, página válida, preferencias, selección, scroll y foco
|
|||
|
|
durante la petición. El refetch normal del catálogo/red no añade bandas que muevan el listado.
|
|||
|
|
|
|||
|
|
## 7. Error y recuperación
|
|||
|
|
|
|||
|
|
El error inicial y el posterior aparecen en la banda de estado, fuera del ancho desplazable de
|
|||
|
|
las columnas. Así, el mensaje y Reintentar no requieren scroll horizontal en móvil. La tabla
|
|||
|
|
conserva cabeceras y espacio corporal, sin simular registros.
|
|||
|
|
|
|||
|
|
Un 503 posterior comunica que se muestran datos anteriores; permite búsqueda y consulta.
|
|||
|
|
Alta/edición y operaciones sensibles se restringen cuando su consulta necesaria no es válida;
|
|||
|
|
el borrador ya abierto se conserva ante un error transitorio. Los reintentos de catálogo/red
|
|||
|
|
no invalidan indiscriminadamente otras consultas.
|
|||
|
|
|
|||
|
|
Una denegación `InventoryApiError` con `FORBIDDEN` oculta los datos en caché del inventario y
|
|||
|
|
muestra falta de permiso sin prometer recuperación mediante Reintentar. Se conserva la
|
|||
|
|
navegación a otros destinos. No se altera la autorización del servidor.
|
|||
|
|
|
|||
|
|
## 8. Estados vacíos
|
|||
|
|
|
|||
|
|
La respuesta válida sin activos conserva «Esta compañía todavía no tiene activos.» y su alta
|
|||
|
|
de cabecera, cuando las referencias están listas. Cero coincidencias conserva la búsqueda y
|
|||
|
|
«Limpiar filtros». Un error no utiliza ninguno de esos mensajes. `—` sigue reservado para
|
|||
|
|
valores ausentes/controles sin valor conocido; no sustituye los estados de consulta.
|
|||
|
|
|
|||
|
|
## 9. Componentes compartidos
|
|||
|
|
|
|||
|
|
- `lib/entity-list-state.ts`: unión y derivación pura, incluida compatibilidad legacy.
|
|||
|
|
- `EntityListStatus`: estado, mensaje y recuperación con Alert/Button existentes; destino de
|
|||
|
|
foco opcional `retryFocus`, sin DTO, query keys ni permisos.
|
|||
|
|
- `EntityTableSkeleton`: placeholders decorativos con geometría de columnas conocidas.
|
|||
|
|
- `EntityTable`: instancia estable y estado explícito; `EntityTableConfiguration` permite
|
|||
|
|
deshabilitar la configuración dependiente; `EntityListPagination` distingue total desconocido.
|
|||
|
|
|
|||
|
|
Adopción nueva limitada a los inventarios de Activos/Recursos con layout `content`. No se
|
|||
|
|
convierte ningún selector remoto en tabla local ni se generalizan estados de consultas ajenas.
|
|||
|
|
|
|||
|
|
## 10. Accesibilidad
|
|||
|
|
|
|||
|
|
La carga inicial tiene un único `role=status`; los skeletons no participan en el foco.
|
|||
|
|
La tabla señala `aria-busy` durante carga/refetch normal. El refetch periódico no genera
|
|||
|
|
anuncios live repetidos. Los errores utilizan el Alert existente y texto explícito, además
|
|||
|
|
del color. Los controles pendientes tienen explicación contextual en es/en.
|
|||
|
|
|
|||
|
|
Reintentar funciona con Enter y enfoca la búsqueda persistente antes de iniciar la recuperación;
|
|||
|
|
así su desaparición no deja el foco en `body`. El destino se aporta desde el consumidor.
|
|||
|
|
Las animaciones nuevas respetan `prefers-reduced-motion`. Estas comprobaciones no acreditan
|
|||
|
|
cumplimiento WCAG completo ni sustituyen pruebas con lector de pantalla.
|
|||
|
|
|
|||
|
|
## 11. Resultados responsive
|
|||
|
|
|
|||
|
|
La matriz de carga inicial comprende 1920×1080, 1440×900, 1366×768, 1024×768, 768×1024,
|
|||
|
|
390×844 y 320×640. Se comprueba estructura, búsqueda habilitada, paginación pendiente,
|
|||
|
|
placeholders sin controles y ausencia de overflow horizontal global. La tabla conserva
|
|||
|
|
su scroll horizontal local. Paneles siguen los mínimos V01.3 (1144 px) y V01.4 (984 px).
|
|||
|
|
|
|||
|
|
La línea base retenida antes del cambio tenía **cero tablas y cero controles de búsqueda y
|
|||
|
|
configuración**, tanto a 1440×900 como a 320×640. La corrección conserva una tabla y sus
|
|||
|
|
herramientas. Las medidas completas, incluidas posiciones, se guardan junto a las capturas.
|
|||
|
|
|
|||
|
|
En la prueba de refetch a 1920×1080 se usan página 2, orden descendente, selección contextual,
|
|||
|
|
columnas opcionales y scroll real: horizontal 120 px y vertical 150 px. Durante la espera se
|
|||
|
|
conservan ambos scrolls, foco e identidad DOM; la cabecera de tabla permanece en y=230 px.
|
|||
|
|
El aviso de fallo posterior ocupa espacio adicional (26 px en ese escenario), sin desmontar
|
|||
|
|
filas ni reiniciar scroll/selección. No se promete layout idéntico ante mensajes de error.
|
|||
|
|
|
|||
|
|
## 12. Pruebas
|
|||
|
|
|
|||
|
|
| Comprobación ejecutada | Resultado real |
|
|||
|
|
| --- | --- |
|
|||
|
|
| `pnpm --filter @repo/rdx-ui typecheck`, `@metis/assets typecheck`, `@metis/resources typecheck` | Correctas las tres comprobaciones dirigidas. |
|
|||
|
|
| `pnpm --filter @repo/rdx-ui test` | 11/11 ficheros; el fichero de listado ejecutado directamente obtiene 27/27 casos. |
|
|||
|
|
| `pnpm --filter @metis/assets test` / `@metis/resources test` | 27/27 y 11/11 ficheros. |
|
|||
|
|
| `pnpm exec biome check <archivos TS/TSX/JSON afectados>` / `pnpm exec eslint <TS/TSX afectados>` | Correctos, sin diagnósticos nuevos. |
|
|||
|
|
| `pnpm typecheck` | Falla en `packages/shadcn-ui/src/components/calendar.tsx:165`, TS2375 de `locale` con `exactOptionalPropertyTypes`; mismo fallo vendor previo. La interrupción global no sustituye los typechecks dirigidos. |
|
|||
|
|
| `pnpm lint` | Falla: 15 errores, un warning y cuatro infos preexistentes. |
|
|||
|
|
| `pnpm check` | Falla: 168 errores, un warning y cuatro infos preexistentes. |
|
|||
|
|
| `pnpm test` | Falla: 7/8 tareas correctas; dos expectativas SSR antiguas de Compañías (`Personas (1)` y el mensaje de acceso de persona). Ejecutada contra otra MariaDB temporal `metis_desk_test`, sin utilizar la BD del navegador. |
|
|||
|
|
| `pnpm build` | Correcto, 2/2 tareas; persiste el aviso de chunk mayor de 500 kB. |
|
|||
|
|
| MCP, L02.3 | 7/7 métodos principales + 1/1 adicional de plantilla/contraste/reintento móvil, **ocho escenarios automatizados distintos correctos**. |
|
|||
|
|
| MCP, regresiones seleccionadas | 9/9: navegación móvil/teclado/rutas, capacidad del shell y Activos, contraste, asistentes, foco, capacidad de Recursos y edición anidada. |
|
|||
|
|
| MCP, L02.2 | 8/8 métodos correctos. |
|
|||
|
|
| MCP, L02.1 | 8/8 métodos correctos tras actualizar las expectativas del configurador L02.2. |
|
|||
|
|
|
|||
|
|
Se ejecutan **33 métodos MCP distintos**; las repeticiones de diagnóstico no incrementan ese
|
|||
|
|
total. Las pruebas unitarias nuevas cubren ocho combinaciones de consulta,
|
|||
|
|
compatibilidad legacy, estructura inicial, ausencia de registros ficticios, datos anteriores
|
|||
|
|
y distinción entre error, vacío válido y filtros en es/en.
|
|||
|
|
|
|||
|
|
`scripts/list-states-ui.test.py` intercepta exclusivamente GET del entorno sintético: retención
|
|||
|
|
y liberación inicial/refetch, 503 inicial/posterior, reintento real, catálogo/red independientes,
|
|||
|
|
403, respuesta vacía válida, filtros, edición conservada, movimiento reducido y traducción.
|
|||
|
|
No cambia opciones internas de QueryClient para simular los estados; la reconexión controlada
|
|||
|
|
dispara el mecanismo normal del consumidor.
|
|||
|
|
|
|||
|
|
Ejecutar con la sesión privada activa del preparador, sin escribir su contenido ni guardarla
|
|||
|
|
en Git. El procedimiento de [Playwright MCP](playwright-mcp.md) explica cómo obtenerla:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
METIS_PLAYWRIGHT_STORAGE_STATE=.artifacts/playwright/authenticated-ID/session.json \
|
|||
|
|
python3 scripts/list-states-ui.test.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
La suite contiene ya los ocho métodos. La ejecución documentada separó el octavo, incorporado
|
|||
|
|
al final, de los siete primeros. Para las regresiones se seleccionaron los nueve métodos
|
|||
|
|
indicados, no los 28 del fichero entero. La consola final de estas regresiones y la de columnas
|
|||
|
|
no registra errores/warnings. En las simulaciones L02.3 aparecen los 503 deliberados del GET
|
|||
|
|
interceptado; no se clasifican como fallos espontáneos.
|
|||
|
|
|
|||
|
|
## 13. Evidencias
|
|||
|
|
|
|||
|
|
Directorio local ignorado: `.artifacts/playwright/l02-3/`. Contiene baseline `before/`, capturas,
|
|||
|
|
snapshots, geometría, foco, consola y escrituras bloqueadas en `after/`, y logs de validación.
|
|||
|
|
Los errores HTTP 503/403 se provocan deliberadamente y no representan incidencias espontáneas.
|
|||
|
|
El índice distingue ejecuciones intermedias y finales. Las imágenes no se versionan ni se
|
|||
|
|
incluyen sesiones privadas; su entrega fuera de esta instalación requiere compartir esos
|
|||
|
|
PNG/mediciones de forma explícita.
|
|||
|
|
|
|||
|
|
Índice local: `.artifacts/playwright/l02-3/indice-evidencias.md`. Capturas representativas
|
|||
|
|
abiertas: baseline retenido 1440, carga nueva 1440, error inicial 320, error posterior 1920,
|
|||
|
|
catálogo fallido 1440 y reintento visible 320. El contraste real del texto obtiene 4,83:1 en
|
|||
|
|
carga y 10,01:1 en error sobre sus fondos computados; son dos muestras concretas, no una
|
|||
|
|
auditoría integral de contraste.
|
|||
|
|
|
|||
|
|
Se reutiliza `scripts/visual-audit.py`, login real y usuario ordinario: una única instalación
|
|||
|
|
propia desechable, exclusivamente `metis_desk_test`, con **15 compañías**, y una principal con
|
|||
|
|
**50 personas, 51 activos y 66 recursos** mediante el preparador de volumen existente.
|
|||
|
|
La sesión anterior encontrada devolvía 401 y no se reutilizó ni se eliminaron servicios ajenos.
|
|||
|
|
Al terminar se cierra el preparador propio: salida correcta, servicios temporales retirados y
|
|||
|
|
comprobación explícita de que su `session.json` ya no existe. Las capturas se conservan sin sesión.
|
|||
|
|
|
|||
|
|
## 14. Regresiones
|
|||
|
|
|
|||
|
|
Las suites de columnas L02.2, selectores L02.1 y los casos seleccionados de
|
|||
|
|
`visual-audit-ui.test.py` comprueban navegación móvil/portátil, presupuestos de inventario,
|
|||
|
|
detalle de Recursos, contraste de selección, asistentes y retorno de foco. Se preservan
|
|||
|
|
visibilidad persistente, IDs de campos y acciones ancladas. Los tests anteriores deben esperar
|
|||
|
|
datos disponibles explícitamente: la existencia de la tabla ya no implica que acabó el GET.
|
|||
|
|
|
|||
|
|
Las primeras ejecuciones detectaron supuestos obsoletos en pruebas: un único botón Editar,
|
|||
|
|
etiquetas DOM sin la marca Obligatoria, `selection` configurable y todos los destinos visibles
|
|||
|
|
sin scroll con quince compañías. Se actualizan las expectativas al contrato L02.2 y al volumen
|
|||
|
|
real, usando nombre accesible para la identidad protegida y comprobando que el foco hace visible
|
|||
|
|
Inicio en el menú desplazable. No se cambia el shell para hacer pasar esas expectativas.
|
|||
|
|
|
|||
|
|
Los instrumentos nuevos también se corrigieron antes de la ejecución final: esperar promesas
|
|||
|
|
de Locator, limitar Reintentar a su listado (hay otros observadores de la misma consulta) y
|
|||
|
|
esperar las compuertas en el contexto Node del MCP. Se conservan sus logs fallidos intermedios.
|
|||
|
|
|
|||
|
|
## 15. Limitaciones
|
|||
|
|
|
|||
|
|
No se acredita rendimiento de producción, otros motores, lectores de pantalla ni acceso a
|
|||
|
|
datos reales. La sesión y el navegador son efímeros. Las interceptaciones no prueban una caída
|
|||
|
|
real del backend. Compañía/lookups conserva su carga exterior; otros listados legacy no adoptan
|
|||
|
|
automáticamente el nuevo estado. Siguen vigentes los fallos globales preexistentes de calendario
|
|||
|
|
vendor, lint/check y dos expectativas SSR de Compañías; no se corrigen fuera de alcance.
|
|||
|
|
|
|||
|
|
Skills leídas: `ux-tables` principal; `ux-empty-states`, `ux-error-recovery`, `ux-microcopy`,
|
|||
|
|
`shadcn`, `vercel-composition-patterns` y `vercel-react-best-practices` complementan estados,
|
|||
|
|
mensajes, primitivas reales, composición y derivación sin efectos. Prevalecen DESIGN y contratos
|
|||
|
|
de Metis. Los auditores `*-audit` y `docs/orchestration-policy.md` referidos por algunas skills
|
|||
|
|
no están instalados/disponibles; no se instalan ni se afirma haberlos ejecutado.
|
|||
|
|
|
|||
|
|
## 16. Pendientes de L03 y L04
|
|||
|
|
|
|||
|
|
V05 (restauración entre rutas) y V07 (normalización general de búsqueda) permanecen pendientes.
|
|||
|
|
V08 sigue resuelto en los escenarios L02.2, sin reordenación ni densidades nuevas.
|
|||
|
|
L03 conserva su alcance futuro; L04 podrá valorar adopciones de estado en otros consumidores,
|
|||
|
|
sin refactor masivo de consultas ni paginación/virtualización nuevas en esta entrega.
|
|||
|
|
|
|||
|
|
**V12 queda resuelto en los escenarios descritos y ejecutados.** No se cambia el estado de
|
|||
|
|
otros hallazgos ni se declara que todos los listados del monorepo adopten este contrato.
|