metis-desk/docs/architecture/resources-global-scope/16-r2-5-configuraciones-globales.md
2026-10-25 01:19:17 +02:00

249 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# R2.5 — Aplicaciones globales en configuraciones de perfil
Fecha: 24 de octubre de 2026. Implementación integrada en el árbol de trabajo, con **flags cerrados por defecto**. La validación dirigida se distingue de la aceptación global: R2.4 conserva G6 pendiente y esta fase no declara el monorepo completamente aceptado.
## 1. Objetivo y alcance
`ApplicationConfiguration` puede referenciar una aplicación global por su UUID real sin copiarla. La configuración continúa perteneciendo a su compañía y perfil, con entrega, versión, estado, notas e historial propios. No existe una configuración global paralela ni relación automática con `SoftwareInstallation`.
## 2. Estado de R2.4
Se conserva la implementación de [R2.4](15-r2-4-software-global.md), incluido su límite de aceptación G6. Su suite SQL/HTTP se vuelve a ejecutar: **13/13**, con ambos órdenes de desactivación/instalación y compañías instalando en paralelo. Los cambios compartidos son extracción de dependencias/metadata, capacidades del cliente y selección por propósito; no cambian las policies de software ni sus licencias. El cursor mixto de software conserva el contexto `mixed-r24`. También se repite su recorrido MCP tras la extracción: selector mixto, versión, licencia particular, inactividad, gates cerrados, 52 instalaciones y seis anchos correctos.
## 3. Prerrequisitos comprobados
HEAD al inicio: `34b8f915381de02f9e13334634455074a5dc55ee`; árbol previamente modificado y con trabajo concurrente. Se registra instantánea de 2729 ficheros de texto y se conserva el estado anterior para atribuir el diff de esta fase. Node 24.20.0, PNPM 11.25.0, bash/WSL, Sequelize v6 y MariaDB 11.8.x fijada por digest en los procedimientos de prueba.
Se reutilizan las lecturas completas de [01](01-contrato-arquitectonico.md)–[10](10-resumen-para-aprobacion.md), los informes [11](11-r2-1a-lectores-compatibles.md)–[15](15-r2-4-software-global.md) y las auditorías de consumidores/configuraciones realizadas en esta misma sesión; se contrastan sus contratos con el código vigente. Sus huellas permanecen intactas. Se consultan también las guías de aplicaciones/perfiles, dashboard, listados compactos, diálogos, estructura web, componentes y DESIGN. No se convierten propuestas antiguas ni mejoras pendientes en funcionalidades implementadas.
Discrepancias resueltas: el documento funcional anterior describía únicamente aplicaciones particulares y el repositorio consultaba inventarios fuera de su transacción. Se actualiza la guía funcional y se conectan lectores ligados a la transacción. La precisión de locks compartidos documentada en R2.4 sigue vigente; no se reescriben decisiones ni auditorías históricas.
## 4. Archivos modificados
| Área | Archivos principales |
| --- | --- |
| Configuración/composición | `apps/server/src/config/database.ts`, `infrastructure/http/identity-runtime.ts`, módulos de Resources y Companies. |
| Resolver/capabilities | `resource-global-gates.ts`, `resource-reference-reader.ts`, opciones HTTP globales y DTO de capabilities. |
| Aplicación | Policy, mapper, puerto y casos de uso `application-configuration.*`; capacidad interna del cliente compartida. |
| Persistencia | `sequelize-application-configuration.repository.ts`; `resource-configuration-dependencies.ts` y `configuration-resource-references.ts`, compartidos con software. |
| HTTP | `application-configuration.routes.ts`; DTO común y endpoints operativos conservados. |
| Selector/referencias | `modules/resources/src/web/application-references/`: componentes por propósito, API, keys y hook común; wrapper de software preservado. |
| Perfil | Listado/controlador, formulario/controlador/editor, API e historial de configuraciones; locales es/en. |
| Entorno y puesto | Modelo de filas de entorno, ficha del perfil, sección expandida del puesto y componentes presentacionales de filas. |
| Caché | Invalidación global selectiva de consultas de configuraciones que usan el UUID. |
| Pruebas/procedimientos | Suite `global-profile-applications.integration.test.ts`, barreras compartidas de concurrencia, tests dirigidos y regresiones R2.2–R2.4; runners SQL/MCP y nuevo recorrido visual. |
| Documentación | Guía de aplicaciones del perfil, biblioteca de componentes y este informe. |
El inventario de archivos de esta fase y las huellas se conservan en los artefactos de validación. El diff contra HEAD contiene además trabajo anterior/concurrente. No se modifican vendor, archive, los doce documentos de auditoría ni los informes históricos de Resources v2.
## 5. Contratos utilizados
Se mantienen los invariantes R2.0 de propiedad local, UUID compartido, referencia mínima, privacidad, propósito decidido por el servidor, recuperación histórica y despliegue por gates. Las capas siguen la normativa del proyecto: Domain/Application sin Sequelize; Infrastructure y composición proporcionan `Transaction` a los servicios públicos de Resources/Assets.
`globalResourceIds` y la compatibilidad del cliente son datos internos del repositorio, no campos nuevos de `ApplicationConfigurationDTO`. No se acepta `scope` ni una copia del producto para justificar una asociación.
## 6. Elegibilidad
| Referencia | Nueva asociación / reconfiguración dependiente | Existente |
| --- | --- | --- |
| Global activa, plantilla stock real `template:application` y campos compatibles | Con catálogo y gate de perfil efectivos | Se resuelve incluso con gates cerrados |
| Global inactiva | Excluida/rechazada | Conservada; notas y retirada según estado |
| Aplicación particular propia de serie o plantilla propia `usage: application` | Compatible con las reglas anteriores | Conservada |
| Aplicación particular ajena | 404 sin datos del recurso ajeno | No habilita acceso cruzado |
| SO local/global, licencia, SMB, certificado o tipo incompatible como aplicación | Rechazado | No se reclasifica un registro histórico |
| UUID inexistente o perfil ajeno | 404 | Sin nombre inventado ni sustitución |
Software mantiene su regla distinta de SO local. El perfil no recibe ese permiso al compartir selector. Toda alta exige disponibilidad; cambiar estado/versión/entrega hacia `pending` o `configured` también. Una edición solo de notas, no-op o avance de retirada no crea esa dependencia de actividad.
## 7. Resolver por propósito
Se usa la sesión pública R2.2 con `purpose: application-configuration`, tanto para resolver como para `validateNewAssociation`. Companies no introduce otro resolver ni abre indiscriminadamente el inventario particular. La función compartida `loadGlobalConfigurationReferences` solo convierte referencias ya validadas por Resources a la proyección interna; no decide elegibilidad ni abre transacciones.
Se resuelven lotes de hasta 100 UUID únicos. La UI separa compañía y propósito en sus claves y solicita únicamente las aplicaciones ausentes del inventario particular que utiliza el perfil mostrado.
## 8. Integración transaccional
El repositorio comienza la transacción y obtiene primero la sesión de Resources: raíz de catálogo con `LOCK IN SHARE MODE`, compañía con `FOR UPDATE`, recursos solicitados con current reads protegidas y raíces operativas. Perfiles, sus revisiones, personas, activos, inventario particular, configuraciones y revisiones se cargan en esa unidad. Tras las policies del agregado, la asociación nueva/dependiente se revalida mediante Resources antes de escribir.
Se reutilizan los locks y el orden R2.4. Las mutaciones de catálogo/producto conservan su lock exclusivo. No se crea una tabla de locks ni un lock exclusivo que serialice todas las asociaciones entre compañías. Las lecturas usan sesiones sin locks de escritura. El borrado conserva negociación y orden de locks.
Ensayos reales con barreras `afterQuery`, sin esperas arbitrarias:
1. Configuración alcanza el INSERT y se detiene antes de commit; la desactivación queda observada en `INNODB_LOCK_WAITS`; al liberar, la configuración termina 201 y la desactivación 200. La lectura posterior deriva revisión.
2. Desactivación se detiene antes de commit; la configuración espera; al liberar, relee inactivo y devuelve 409. No existen raíz ni revisiones de esa asociación.
3. Dos altas simultáneas de la misma pareja perfil/producto terminan 201 y 409, con una sola raíz abierta.
La observación administrativa de locks ocurre exclusivamente dentro del contenedor propiedad del runner; no se cambian privilegios de la aplicación. Los timeouts son límites de fallo, no evidencia de orden. El ensayo R2.4 añade la prueba de dos compañías que alcanzan ambos INSERT antes de permitir los commits.
## 9. Modelo de configuración
Se conserva `profileId + resourceId` como destino inmutable. `companyId`, identidad de raíz/revisión, `delivery`, versión, estado y notas conservan sus Value Objects y reglas. `delivery` sigue siendo `installed` o `web`; web no admite versión y el formulario la limpia explícitamente al cambiar la entrega.
Perfil, persona y activo siguen siendo particulares y coherentes con la compañía. La configuración puede existir sin cuenta o licencia. Compartir ordenador o producto no comparte configuración, notas, entrega, versión o historial. No se infiere una instalación ni se actualiza otra configuración al cambiar un producto global.
## 10. Persistencia y FKs
No se añaden migraciones, columnas, tablas ni JSON. Se verifican las FKs reales de `application_configurations` y `application_configuration_revisions` en MariaDB 11.8.x con R2.1b aplicado. `resourceId` continúa siendo una FK simple por UUID; perfil, compañía, actor y snapshots mantienen sus relaciones. No se elimina ninguna restricción.
El dueño NULL pertenece exclusivamente al Resource global. La configuración mantiene compañía/perfil concretos; versión/notas opcionales conservan NULL. Una FK simple no garantiza pertenencia: la comprobación transaccional protege perfil, activo y recursos particulares. Se prueba un producto con tres configuraciones en dos compañías y una sola fila Resource.
Evidencia: [FKs](../../../.artifacts/resources-global-scope/r2-5/profile-foreign-keys.json). Se conserva la clave única nullable de pareja abierta y la persistencia de solo revisiones nuevas.
## 11. HTTP y DTO
Se mantienen GET/POST `/api/application-configurations/:companyId`, actualización y borrado existentes. DTO de entrada/salida sin campos de ámbito adicionales. Sesión, autenticación, origen, CSRF y actor de sesión conservados. El administrador global tampoco puede asociar perfil o producto particular ajenos.
Se aplica la misma negociación R2.0/R2.4: `X-Metis-Resources-Contract: 2` y `Vary`. Sin cabecera, el CRUD particular sigue funcionando. Si una respuesta contiene configuraciones globales o una mutación necesita ese soporte, se devuelve 409 `RESOURCE_CLIENT_UPGRADE_REQUIRED`; no se omiten registros para degradar silenciosamente. Cabecera desconocida o entrada inválida: 400. Perfil/recurso inexistente, incompatible o ajeno: 404 sin detalles privados; actividad/gate/conflicto: 409; sesión ausente: 401; CSRF: 403.
La capability mínima existente incorpora `profileSelection` y `profileAssociation`; no expone permisos administrativos. El servidor elige el propósito al guardar. Se comprueba UUID en mayúsculas sin bypass de negociación.
## 12. Selector mixto
`ResourceApplicationSelect` comparte la infraestructura R2.4 por propósito. Para perfil muestra «Seleccionar aplicación», con UUID, nombre, procedencia y proveedor. Resources filtra antes de paginar: aplicación global activa y aplicación particular propia elegible, sin OS/licencias. Página de 20, búsqueda remota y cursor opaco; no se descarga todo el catálogo global para filtrar en React.
Se conservan selección provisional y UUID al cambiar búsqueda/página; la reapertura resuelve el producto aunque no esté en la primera página. Producto/perfil siguen deshabilitados en edición. El picker mantiene estados de consulta pendiente, vacío, error y reintento; las llamadas tienen cancelación/timeout. Con gate cerrado se conserva el selector particular. Las altas rápidas siguen siendo particulares y la ayuda lo explica expresamente.
## 13. WorkProfile
Se conserva el perfil seleccionado, persona, cuenta, activo y compañía. El listado filtrado y el entorno resuelven en lotes solo sus productos. Se muestran nombre, procedencia, versión, entrega, estado y revisión; el historial añade el enlace correcto del producto. Los errores de metadata se presentan aparte y no eliminan las configuraciones particulares válidas ni cambian el perfil elegido.
La prueba SSR es/en comprueba un producto global sin `ResourceDTO` particular y excluye la versión de otro perfil. La prueba de navegador comprueba otro perfil del mismo ordenador con entrega web y versión vacía.
## 14. Workstation
La expansión de Personas y perfiles conserva su selección y filtro. Las referencias globales solo se incorporan a las filas de aplicaciones del perfil expandido; no se amplían carpetas, certificados, correo, Access o soporte. Se muestran nombre/enlace global, badge, entrega, versión y estado.
El cálculo de pendientes no se modifica: usa configuraciones por perfil y su estado, excluyendo perfiles/estados que ya excluía. La prueba MCP comprueba un único pendiente, su navegación a la expansión correcta y ausencia de notas de otro perfil del mismo ordenador. Tras desactivación permanece pendiente, con señal de revisión separada. Software del ordenador continúa vacío cuando solo se han creado configuraciones de perfil.
## 15. Lectura histórica
El resolver de lectura acepta referencias globales existentes inactivas, incluso con gates cerrados. Renombrar/desactivar no crea revisiones operativas ni cambia UUID, perfil, estado, versión, entrega o notas. Se comparan snapshots anteriores y el historial de la otra compañía. El nombre se resuelve actualmente por UUID; no se expone el historial administrativo global.
Una edición semánticamente idéntica conserva el número de revisiones. Las operaciones de retirada y borrado mantienen sus contratos previos; no se usan para simular una migración de producto.
## 16. Desactivación
El producto inactivo deja de ser candidato y no admite nuevas asociaciones ni reconfiguración dependiente. Una configuración existente sigue visible con su UUID, versión y entrega. Notas y retirada continúan según las transiciones existentes; no se cierra automáticamente ni se traslada a otro Resource.
`needsReview` sigue derivado por el builder existente: no se persiste ni se escribe masivamente en perfiles. No equivale a estado pendiente ni aumenta por sí mismo el contador de pendientes del puesto.
## 17. Caché e invalidaciones
Se distinguen catálogo público/privado, capabilities y candidatos por compañía/propósito, referencias por conjunto ordenado de UUID, configuraciones por compañía y los inventarios particulares. No se inventa una compañía NULL ni se utiliza el DTO administrativo en selectores.
Guardar invalida configuraciones de su compañía —la misma familia consumida por perfil, entorno y resumen del puesto— y sus candidatos/referencias de perfil. Borrar invalida configuraciones; no modifica elegibilidad del producto. Renombrar/estado global invalidan las configuraciones ya cacheadas que usan ese UUID y sus lotes de referencias; no se invalidan indiscriminadamente compañías ajenas ni inventarios particulares. Los candidatos se invalidan porque pueden ganar/perder elegibilidad. Se añaden pruebas del alcance selectivo para ambos consumidores.
Cambios externos se observan al refrescar, recuperar foco/reconectar o mediante el refresco periódico de los lectores existentes. No hay push ni promesa de instantaneidad entre navegadores.
## 18. Flags
| Capacidad | Condición efectiva | Default |
| --- | --- | --- |
| Catálogo | `RESOURCE_GLOBAL_CATALOG_ENABLED` y preflight compatible | false |
| Administración | Policy inicial R2.3 y catálogo; no se delega | Sin cambios |
| Candidatos software | catálogo AND `RESOURCE_GLOBAL_SOFTWARE_CANDIDATES_ENABLED` | false |
| Asociación software | catálogo AND `RESOURCE_GLOBAL_SOFTWARE_ENABLED` | false |
| Selección/asociación de perfil | catálogo AND `RESOURCE_GLOBAL_PROFILE_ENABLED` | false |
R2.5 no depende de los flags de software. Se prueban perfil abierto/software cerrado, software abierto/perfil cerrado y catálogo cerrado con flags subordinados true —efectivamente ambos cerrados—. Se mantienen lectores globales existentes al apagar. Abrir catálogo conserva el preflight scoped de CHECK/FKs; no se habilita en una base habitual ni se modifica ningún `.env`.
## 19. Pruebas unitarias y de representación
Suite dirigida de ApplicationConfiguration, SoftwareInstallation, entorno y expansión: **28/28**. Incluye disponibilidad global, recuperación histórica, entrega/versión, inmutabilidad, idempotencia, representación es/en y separación de perfiles. Resources: **102/102**, incluidos gates independientes y caché selectiva. Identity dirigido: **11/11**.
Se usan `--test-isolation=none` para obtener resultados explícitos de los subtests; no se consideran suficientes los resultados agregados por fichero del runner. La suite completa de Companies registra **254 pruebas: 252 pasan y dos fallan**, ajenas al flujo; detalle en §24.
## 20. MariaDB
`python3 scripts/resource-scope-test.py --profiles --regressions`: **11/11** en R2.5 (incluye el test padre) y **50/50** regresiones. El ensayo se repite dentro del recorrido amplio aislado y mantiene la integración correcta. Dos órdenes de commits observados en InnoDB y una carrera de pareja abierta; tipos, recursos/perfiles/activos ajenos, estados, NULL, FKs e historial probados.
Volumen: 15 compañías; principal con 50 personas, activos, perfiles y puestos, más de 50 recursos particulares y al menos 50 configuraciones. Se recorre una búsqueda mixta de 72 UUID únicos con páginas de siete, sin duplicados ni datos privados. Las configuraciones de compañías/perfiles distintos conservan entrega, versión, estado e historial propios.
[Resultados](../../../.artifacts/resources-global-scope/r2-5/profile-results.json), [integración](../../../.artifacts/resources-global-scope/r2-5/integration.log), [regresiones](../../../.artifacts/resources-global-scope/r2-5/regressions.log). Únicamente `metis_desk_test` desechable; contenedores retirados al terminar.
## 21. HTTP real
Runtime de producción con bootstrap y usuario ordinario, cookies/CSRF reales. Se cubren altas particulares/globales, plantilla propia application, negociación, cabecera desconocida, campos extra, recurso/perfil fijo, recursos ajenos/incompatibles/inactivos, perfil/activo ajeno, historial, gate cerrado, lectura y retirada tras apagado y ausencia de instalaciones automáticas.
Las barreras intercalan peticiones HTTP reales con transacciones MariaDB; no se sustituye la garantía por mocks de repositorio ni por validación TypeScript.
## 22. Playwright MCP
`python3 scripts/visual-audit.py --global-profiles --check`: instalación temporal, MCP Docker/stdio fijado, Vite build y login ordinario por el formulario real. S01–S13 cubren búsqueda/procedencia, selección retenida tras búsqueda sin resultados, alta/reapertura, versiones y entregas diferentes en otra compañía y otro perfil, desactivación, gate cerrado, expansión/pendientes, error parcial/reintento y volumen. La única simulación de transporte es un GET de candidatos 500; las escrituras son reales sobre la base sintética.
Se verifican seis anchos —1600, 1440, 1280, 1024, 768 y 390—, picker móvil, Escape/retorno de foco y ausencia de desbordamiento de página en el recorrido principal. Se revisan las imágenes. La tabla mantiene el scroll horizontal del patrón existente para sus columnas; esto no certifica WCAG ni sustituye pruebas con lector de pantalla.
Volumen visual: 15 compañías; principal con 50 personas, 51 activos, 51 perfiles, 50 puestos, al menos 50 recursos particulares y **52 configuraciones en el perfil principal**; 50 aplicaciones globales. El segundo perfil del mismo ordenador y la compañía B tienen configuraciones independientes adicionales. El procedimiento elimina sesión, credenciales y servicios temporales.
Skills consultadas: `rdx-solid` (capas, unidades de consistencia y pruebas), `ux-search` (selector remoto, recuperación y selección), `ux-inputs-and-forms` (contexto, entrega y guardado) y `shadcn` (primitivas/APIs y composición existentes). Se reutilizan las lecturas aplicables de React/composición de esta sesión para la extracción por propósito. No se instalan dependencias ni skills. No están instalados auditores especializados de Sequelize/seguridad/accesibilidad; se realizan las comprobaciones disponibles con alcance declarado.
## 23. Capturas
**32 comprobaciones y 16 capturas** sintéticas, con SHA-256, conservadas fuera de Git: [manifiesto](../../../.artifacts/playwright/r2-5/final/r25-report.json). No contienen cookies, passwords ni `storageState`. Las capturas de página son una vista del viewport, no la totalidad de sus filas; no se retocan para ocultar recortes.
| Evidencia | Capturas |
| --- | --- |
| Selector y recuperación | [Mixto](../../../.artifacts/playwright/r2-5/final/r25-01-mixed-selector.png), [vacío con selección retenida](../../../.artifacts/playwright/r2-5/final/r25-02-empty-selection-retained.png), [error](../../../.artifacts/playwright/r2-5/final/r25-05-partial-error.png) |
| Formulario | [Entrega y versión](../../../.artifacts/playwright/r2-5/final/r25-03-form-delivery-version.png), [gate cerrado](../../../.artifacts/playwright/r2-5/final/r25-06-gate-closed-local-form.png) |
| Independencia | [Compañía B](../../../.artifacts/playwright/r2-5/final/r25-company-b-independent.png), [segundo perfil web](../../../.artifacts/playwright/r2-5/final/r25-second-profile-web.png) |
| Puesto y pendientes | [Expansión](../../../.artifacts/playwright/r2-5/final/r25-04-workstation-expanded-pending.png), [390](../../../.artifacts/playwright/r2-5/final/r25-workstation-390.png) |
| Responsive | [1600](../../../.artifacts/playwright/r2-5/final/r25-profile-1600.png), [1440](../../../.artifacts/playwright/r2-5/final/r25-profile-1440.png), [1280](../../../.artifacts/playwright/r2-5/final/r25-profile-1280.png), [1024](../../../.artifacts/playwright/r2-5/final/r25-profile-1024.png), [768](../../../.artifacts/playwright/r2-5/final/r25-profile-768.png), [390](../../../.artifacts/playwright/r2-5/final/r25-profile-390.png), [picker móvil](../../../.artifacts/playwright/r2-5/final/r25-mobile-picker.png) |
## 24. Regresiones y validación global
| Comando / comprobación | Resultado |
| --- | --- |
| `python3 scripts/resource-scope-test.py --profiles --regressions` | 11/11 + 50/50 |
| `python3 scripts/resource-scope-test.py --software` | R2.4 13/13 |
| `python3 scripts/resource-scope-test.py --catalog` | R2.3 11/11 |
| `python3 scripts/resource-scope-test.py --security` | R2.2 11/11 |
| Suites dirigidas con `node --import tsx --test --test-isolation=none` | 28/28 en aplicaciones/software/entorno/expansión; Identity 11/11 |
| `pnpm --filter @metis/resources test` | 102/102 |
| `pnpm --filter '!@repo/shadcn-ui' -r typecheck` | Correcto en paquetes propios, incluidos Companies, Resources, Assets, Server y Web |
| Biome/ESLint sobre la lista explícita de código de esta fase | Correctos; no se normaliza todo el árbol |
| Compilación Python dirigida y revisión de diff | Procedimientos y cambios propios comprobados |
| `pnpm build` | Correcto; conserva aviso de tamaño del bundle web |
| `python3 scripts/visual-audit.py --global-profiles --check` | Recorrido real y capturas descritos arriba |
| `python3 scripts/visual-audit.py --global-software --check` | Regresión visual R2.4 correcta tras compartir el selector |
| `python3 scripts/resource-scope-test.py --profiles --monorepo` | Integración R2.5 correcta; integración legacy y Companies conservan fallos ajenos |
| `pnpm typecheck`, `pnpm lint`, `pnpm check` | Ejecutados; el árbol global no queda verde |
Las regresiones incluyen Resources particular/global, WorkProfile, ApplicationConfiguration particular, instalaciones y licencias, Assets, puestos, SMB, Access, remoto e historial. El ensayo amplio registra Assets **147/147**, Identity **11/11**, Resources **102/102** y Companies **252/254**. El recorrido de paquetes equivalente a `pnpm test` se ejecuta dentro del entorno SQL desechable; no se lanza contra configuración habitual.
Fallos globales actuales con evidencia:
- Companies: dos expectativas de `companies-page.test.tsx`, ficha/contactos y formulario de persona, iguales a las documentadas en R2.4. Las suites dirigidas de esta integración pasan.
- Integración legacy Identity: `identity.test.ts:82`, 404 esperado frente a 401 actual en ruta archivada. Persiste; no se cambia la regla de autenticación para hacer verde el test.
- Typecheck global: `packages/shadcn-ui/src/components/calendar.tsx:165`, TS2375 sobre `locale`, vendor intacto.
- Lint/check globales: diagnósticos del árbol previo/concurrente; el código propio de esta fase se verifica aparte. No se atribuye sin evidencia cada diagnóstico a HEAD ni se modifica código ajeno para ocultarlo.
Los fallos de preparación/importación/cierre del fixture y el locator de densidad encontrados durante la implementación se corrigieron antes de obtener los resultados dirigidos anteriores. No se mantienen como supuestos éxitos ni como defectos de dominio.
## 25. Riesgos residuales
La coordinación compartida puede hacer esperar mutaciones del catálogo; las operaciones de una compañía siguen serializadas. Se prueban los órdenes descritos, no throughput de producción ni ausencia universal de deadlocks. No hay push entre operadores ni cálculo de licencias/compatibilidad instalada–configurada.
Se mantiene la estrategia de metadata/paginación R2.2; no se afirma coste O(pageSize) ni benchmark nuevo. El inventario particular continúa cargándose para los flujos existentes; el catálogo global no se precarga entero en React. La resolución por lotes evita una petición por fila, aunque más de 100 UUID necesita varios lotes.
Las tablas densas móviles conservan su desplazamiento horizontal y los límites del patrón compartido. Ante un fallo de metadata se muestra feedback con reintento y se conserva el registro; no se inventa un nombre. No se certifican accesibilidad integral ni lector de pantalla. Las capturas locales ignoradas deben conservarse aparte para revisión en otra máquina.
## 26. Gates de aceptación
| Gate | Evidencia / estado |
| --- | --- |
| G1 — Dominio | Configuración particular, UUID compartido, entrega/versión/estado/historial independientes, sin copia ni instalación automática: pasa en pruebas dirigidas. |
| G2 — Seguridad | Recursos/perfiles/activos ajenos e incompatibles rechazados, inactivos protegidos, sesión/CSRF y proyecciones mínimas: pasa en SQL/HTTP. |
| G3 — Consistencia | Sesión ligada a transacción, ambos órdenes de commits observados y pareja única/FKs: pasa en MariaDB. |
| G4 — Contratos | DTO estable, negociación, propósito, selección por UUID, caché y procedencia: pasa en pruebas dirigidas/MCP. |
| G5 — UI/UX | Alta, edición, perfiles, expansión, pendientes, recuperación y seis anchos probados; límites de accesibilidad indicados en §22. |
| G6 — Activación | Flags independientes, default false, preflight y consumidores ajenos particulares: pasa como implementación; no se activa base habitual. |
| G7 — Validación | Pruebas dirigidas, SQL/HTTP, regresiones, tipos propios, build y MCP correctos; **aceptación global pendiente** por los fallos de §24. |
No se declara R2.5 completamente aceptada ni se da por superado G6 de R2.4. Se entrega la implementación verificable con los flags habituales cerrados.
## 27. Prerrequisitos de R2.6
Resolver o aceptar expresamente la deuda de validación global y aprobar el alcance futuro. Consolidar requiere un contrato de equivalencia y sucesión que preserve historiales; no se deduce de coincidencias de nombre. Revisar conflictos de parejas abiertas, referencias actuales/históricas e idempotencia antes de cualquier operación de migración.
R2.5 no implementa consolidación, cambio de `resourceId`, transferencia de compañía, licencias/SO globales, nuevas plantillas globales, delegación, ACL nueva, fabricantes, importación ni migración automática.