metis-desk/docs/architecture/preflight-activacion-catalogo-global-sistemas-operativos.md
David c863cc6d96 feat: add unpublished share component and publication operation summary
- Introduced `UnpublishedShare` component for displaying empty state with actions for assigning and viewing history.
- Added `PublicationOperationSummary` component to summarize publication context and actions based on the current state.
- Implemented `CompanyNetworkShareDetail` to manage and display network share details for companies.
- Created `NetworkShareResourceTitle` for collapsible display of resource names with accessibility features.
- Developed `ResourceDetailActions` for managing resource actions like edit, activate/deactivate, and delete.
- Added `ResourceRevisionHistory` to display the history of resource revisions with detailed information.
- Implemented a comprehensive audit script for network share detail UI, including accessibility checks and error handling.
2026-10-26 18:45:30 +01:00

461 lines
62 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.

# Preflight de activación — Catálogo global de sistemas operativos
Fecha: **26 de octubre de 2026**, Europe/Madrid. Inspección iniciada el día 25. Ámbito: repositorio local, diagnósticos y corrección con MariaDB desechable en el apartado 17. **No se ha conectado a producción, leído `.env`, ejecutado migraciones productivas, modificado datos reales, cambiado gates ni desplegado.**
**Dictamen vigente: apartado 17, corrección local sobre `a72d6a2ec8985e1d51f74db68a1b3aabb3693030`: B-01 RESUELTO, B-02 RESUELTO EN ENTORNO REPRESENTATIVO; snapshot global NO PREPARADO.** Los apartados 1–16 conservan los diagnósticos históricos anteriores a esta corrección. El apartado 17 añade las pruebas con persistencia exclusivamente desechable y distingue los cambios concurrentes.
## 1. Resumen y dictamen
**NO PREPARADO para desplegar el artefacto de producción evaluado.** Se conserva la correspondencia de fuentes con el GO técnico, pero el preflight descubre dos bloqueos de ejecución/configuración que ese GO no había ensayado:
1. **B-01, demostrado:** `apps/server/dist/index.js` no supera `node --check`: `SyntaxError: Identifier 'createRequire' has already been declared`. El banner de `apps/server/tsup.config.ts` declara `createRequire`; el bundle vuelve a importarlo al incluir sharp 0.35.5. Dos builds forzados terminan con éxito y generan los mismos bytes, pero el servidor compilado es sintácticamente inválido. No puede desplegarse ese bundle aunque tsup devuelva cero.
2. **B-02, demostrado para la topología TLS → HTTP:** el entrypoint escucha HTTP en loopback; en producción la sesión exige cookie Secure, pero `createApp` no configura `trust proxy` y express-session no configura `proxy`. En un diagnóstico local con `X-Forwarded-Proto: https`, `request.secure=false` y no se emite cookie de sesión. No se ha comprobado la topología real del destino; no se presupone que exista una solución externa no versionada.
El GO previo sigue siendo evidencia de los escenarios de fuentes/HTTP/MariaDB/UI ensayados, **no certifica el arranque de este artefacto de producción ni el entorno desconocido**. B-01 impide el despliegue con independencia de que el origen del defecto esté fuera del catálogo SO. No se corrigen estos bloqueos aquí: la misión prohíbe cambios funcionales salvo diagnósticos no invasivos.
Se deja preparado el expediente y el runbook para una autorización futura. No procede solicitar autorización de activación mientras B-01 y la solución aplicable a B-02 sigan abiertos. Después harán falta verificaciones del destino.
## 2. Fuentes y método
Consultados: [cierre técnico y resolución del GO](cierre-tecnico-catalogo-global-sistemas-operativos.md#19-resolución-dirigida-del-bloqueo-del-panel), [auditoría](auditoria-catalogo-global-sistemas-operativos.md), [decisión SO](decision-catalogo-global-sistemas-operativos.md), [implementación](implementacion-catalogo-global-sistemas-operativos.md), documentación R2.0–R2.6 —en particular [despliegue](resources-global-scope/07-plan-despliegue.md), [persistencia R2.1b](resources-global-scope/12-r2-1b-persistencia.md), [software](resources-global-scope/15-r2-4-software-global.md), [perfiles](resources-global-scope/16-r2-5-configuraciones-globales.md), [coexistencia](resources-global-scope/17-r2-6-coexistencia-duplicados.md)—, [estado D08.2](resources-global-scope/19-d08-2-resolucion-ratificacion.md), [composición modular](../arquitectura/composicion-de-modulos.md), [puesta en marcha](../puesta-en-marcha.md) y [acceso](../usuarios-y-acceso.md).
Se aplicó `rdx-solid`, incluida su referencia backend: contrato del artefacto, composición, seguridad y diferencias verificables. No se aplicaron criterios nuevos de diseño UI ni se instalaron dependencias. Las fuentes documentales históricas se contrastaron con los gates y endpoints actuales; sus flags propuestos no sustituyen los ya implementados.
Estados: **VERIFICADO** = evidencia directa con el alcance indicado; **PENDIENTE DE VERIFICACIÓN** = falta evidencia del destino; **NO CUMPLE** = fallo observado; **NO APLICA** = capacidad ajena o deliberadamente inexistente.
## 3. Snapshot y reproducción exacta — hito A
| Requisito | Estado | Evidencia |
| --- | --- | --- |
| Base Git | VERIFICADO | `main`, `d2bf856c973419277f0b30f6437242cd82f7d720` |
| HEAD representa por sí solo el GO | NO CUMPLE | El GO incluye cambios sin commit, incluidos ficheros nuevos |
| Identificación del estado completo del GO | VERIFICADO | Coinciden los hashes de **1884 fuentes** y **40 archivos de trabajo** con sus manifiestos |
| Reconstrucción | VERIFICADO | Base Git más overlay de esos 40 archivos restaurados en `/tmp`; se verifican todas las huellas y el lockfile; directorio retirado |
| Cambios posteriores funcionales en el snapshot registrado | VERIFICADO: ninguno | Comparación de hashes, no solo `git diff HEAD` |
| Node / PNPM | VERIFICADO | 24.20.0 / 11.25.0; `engines >=24 <25`, `packageManager=pnpm@11.25.0` |
| Lockfile | VERIFICADO | `pnpm-lock.yaml` sin diferencias frente a HEAD; SHA-256 `bcd468ab1f127fffeb7f37ef3bdb5f2c5e85d40c192f3bc4a7cae5b2209b7c17` |
| Dependencias del candidato | VERIFICADO en manifests/lock | Express 4.22.1, Sequelize 6.37.8, MariaDB driver 3.5.4, sharp 0.35.5, React 19.2.5, Vite 8.3.0 |
| Instalación limpia de dependencias para el destino | PENDIENTE DE VERIFICACIÓN | No se ejecuta install ni se cambia `node_modules`; los builds usan la instalación local existente |
| Builds | VERIFICADO como compilación | Dos ejecuciones `pnpm exec turbo run build --force`, sin caché; **12 artefactos idénticos byte a byte** |
| Correspondencia del frontend con MCP | VERIFICADO | `apps/web/dist` coincide byte a byte con `web-build` conservado de `authenticated-6u28upls` |
| Ejecución sintáctica del servidor compilado | NO CUMPLE | B-01, `node --check` devuelve 1 |
Evidencias en [preflight](../../.artifacts/resources-global-operating-systems-preflight/): `traceability.json`, `go-source-overlay.tar`, `build-first.json`, `build-second.json` y `nondeployable-build.tar`. El último conserva exclusivamente los archivos dist diagnosticados: **no es un paquete desplegable**, no incorpora dependencias runtime ni una configuración aprobada del destino. Los sourcemaps requieren política de publicación; no deben exponerse sin decisión del operador.
Para reproducir las fuentes: checkout separado de la base indicada, aplicar `go-source-overlay.tar` en su raíz y comprobar los hashes de `source-snapshot.json` y `workingSources` del [manifiesto del GO](../../.artifacts/resources-global-operating-systems-unblock/manifest.json). El overlay tiene solo rutas relativas y fuentes aprobadas, sin secretos. El ensayo de reconstrucción restaura los archivos requeridos desde los objetos Git y aplica el overlay; **no equivale a un build en un checkout limpio con dependencias recién instaladas**.
Además del snapshot hay evidencias regeneradas `.artifacts/` y un `.pyc` del trabajo concurrente, sin efecto funcional. Este preflight añade el informe, SQL no ejecutado y evidencia local. No modifica las 1884 fuentes/40 archivos del GO. No se sobrescribe trabajo concurrente.
## 4. Inventario del entorno de destino
**No se ha identificado un destino de producción mediante manifests operativos autorizados.** `compose.yaml` y la guía de puesta en marcha describen desarrollo WSL y una BD local; no prueban infraestructura desplegada.
| Componente | Confirmado en repositorio | Estado del destino |
| --- | --- | --- |
| Backend | ESM Node 24, `apps/server/dist/index.js`, dependencias runtime externas; HTTP `127.0.0.1:PORT` | PENDIENTE DE VERIFICACIÓN de host/supervisor/instancias; B-01 NO CUMPLE |
| Frontend | Estáticos `apps/web/dist`; API compilada no los sirve | PENDIENTE DE VERIFICACIÓN de hosting, caché y fallback SPA |
| MariaDB | Compose declara `mariadb:11.8`, volumen persistente y puerto de loopback; tests usaron 11.8.9 | PENDIENTE DE VERIFICACIÓN de motor/patch/esquema/capacidad; no consultar compose efectivo |
| Reverse proxy/TLS | No se localizó manifest de proxy, TLS o despliegue productivo | PENDIENTE DE VERIFICACIÓN; B-02 para terminación TLS y HTTP al backend |
| Sesiones | express-session, `SequelizeSessionStore`; cookie `metis.sid`, HttpOnly, SameSite Strict, 8 horas, Secure en producción | PENDIENTE DE VERIFICACIÓN de acceso real, rotación de secreto y comportamiento entre instancias |
| Autenticación/administración | Identity y guard `requireGlobalResourceManager`; administrador inicial, sin RBAC ficticio de compañía | PENDIENTE DE VERIFICACIÓN de responsables y cuentas autorizadas; no extraer datos personales |
| Auxiliares | Procesamiento de imágenes con sharp, persistencia de sesión, limpieza de recursos al apagar | PENDIENTE DE VERIFICACIÓN de binarios/arquitectura/permisos runtime |
| Despliegue/backup/restore | Procedimientos R2 conceptuales; la guía declara despliegue, HTTPS y backups pendientes | PENDIENTE DE VERIFICACIÓN de procedimiento, ventana, recuperación y prueba de restauración |
`pnpm --filter @metis/server start` carga `.env`; no se ejecutó. `pnpm db:up` prepara entorno y arranca BD; tampoco se ejecutó. Arrancar el backend **no es una inspección de solo lectura**: compone módulos, ejecuta migraciones existentes y seed. No usarlo como prueba inocua contra el destino.
## 5. Configuración real y gates
Fuente: `apps/server/src/config/database.ts`, `config/env-schema.ts`, `identity-runtime.ts`, `modules/resources/src/api/module.ts` y `resource-global-gates.ts`. Todos los valores efectivos del destino son **PENDIENTE DE VERIFICACIÓN**; no se deducen de defaults ni de pruebas aisladas.
| Gate | Default en código | Propósito y dependencias | Propuesta / riesgo |
| --- | --- | --- | --- |
| `RESOURCE_GLOBAL_OS_CATALOG_ENABLED` | false | Alta/edición/reactivación SO administrativas; scoped, integridad y autorización | Etapa 0 false; etapa 1 true. Abre publicación, no solo borradores |
| `RESOURCE_GLOBAL_OS_SOFTWARE_ENABLED` | false | Selección **y** nueva asociación SO, requiere OS_CATALOG | False hasta operación autorizada; true abre ambas capacidades juntas |
| `RESOURCE_GLOBAL_CATALOG_ENABLED` | false | Administración application; requisito de gates application | Conservar valor previamente aprobado; no es dependencia de SO |
| `RESOURCE_GLOBAL_SOFTWARE_ENABLED` | false | Nueva asociación application, requiere CATALOG | Conservar autorización independiente |
| `RESOURCE_GLOBAL_SOFTWARE_CANDIDATES_ENABLED` | false | Candidatos application, requiere CATALOG | No concede asociación por sí solo; no controla candidatos SO |
| `RESOURCE_GLOBAL_PROFILE_ENABLED` | false | Application en perfiles, requiere CATALOG | Conservar autorización; jamás abre SO en perfil |
| `administration` interno | true | Capacidad adicional sometida al guard de Identity | NO APLICA como variable de entorno; no sustituye permisos |
Otros parámetros reales: `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `SESSION_SECRET` (mínimo 32 caracteres), `APP_ORIGIN`, `NODE_ENV` y `PORT` (default 3001, rango 1–65535). Registrar únicamente presencia, validación y coherencia; no valores secretos ni cadena de conexión. `APP_ORIGIN` debe corresponder al origen externo permitido; `NODE_ENV=production` exige Secure, sujeto a B-02. `API_PROXY_TARGET` pertenece al proxy **de desarrollo Vite** y no configura un proxy de producción.
No hay variable de disponibilidad que sustituya el estado real de Resources ni flag que aplique scope. El arranque inspecciona legacy/scoped/parcial; con catálogo global habilitado exige scoped completo y CHECK/FK activos a nivel sesión/global. No inventar variables `TRUST_PROXY`, versiones contractuales o gates por compañía: no están implementadas en este snapshot.
## 6. Precondiciones MariaDB — hito C
| Requisito | Esperado por código/migración | Estado real del destino |
| --- | --- | --- |
| Motor y versión | MariaDB; referencia ensayada 11.8.9; InnoDB y driver Sequelize v6 | PENDIENTE DE VERIFICACIÓN |
| `resources.scope` | VARCHAR(7), ascii/ascii_bin, NOT NULL, DEFAULT company | PENDIENTE DE VERIFICACIÓN |
| `resources.companyId` | CHAR(36), utf8mb4_bin, nullable exclusivamente con scope global coherente | PENDIENTE DE VERIFICACIÓN |
| CHECK | `resource_scope_owner` y `resource_global_no_integration`, cláusulas exactas del inspector; sesión/global activos | PENDIENTE DE VERIFICACIÓN |
| FKs e índices | PK/owners/plantillas/especificaciones/revisiones; FKs operativas preservadas y activas | PENDIENTE DE VERIFICACIÓN |
| Especificaciones y EAV | `resource_characteristics`, `resource_specification_fields`, `resource_specification_field_choices`, secciones, revisiones y especificaciones históricas relacionadas | PENDIENTE DE VERIFICACIÓN |
| Instalaciones | `software_installations`, FKs a compañía/activo/producto/licencia, `currentKey` único; propietario no nullable | PENDIENTE DE VERIFICACIÓN |
| Historial | `software_installation_revisions`, FK a instalación, único `(configurationId, position)`; Resource único `(resourceId, position)` | PENDIENTE DE VERIFICACIÓN |
| Scope aplicado | R2.1b explícita: `scope`, `ownerCheck`, `integrationCheck`, `nullableOwner`; no confiar en un fichero como prueba de aplicación | PENDIENTE DE VERIFICACIÓN |
| Datos preexistentes | Cero owners/referencias inválidas; particulares incompletos permitidos; inactivos utilizados conservados | PENDIENTE DE VERIFICACIÓN |
| Integridad aislada previa | 29/29 + 50/50 y cero revisiones huérfanas en el GO | VERIFICADO como antecedente aislado, no como esquema del destino |
El inspector `resource-scope-schema.ts` compara tipos, nulabilidad, default, charset y texto normalizado de los CHECK. Legacy sin scope puede leerse con gates cerrados; no habilitar globales. Un esquema parcial debe detener el servicio y reanudarse mediante el procedimiento R2.1b autorizado. No ejecutar el CLI como diagnóstico: exige `--apply --writes-paused` y realiza DDL. Ninguna migración se ejecutó en este preflight.
Se preparó [diagnostico-mariadb.sql](preflight-so/diagnostico-mariadb.sql), **solo SELECT y no ejecutado**. Fase 1 consulta versión/metadatos; el operador debe confirmar tablas y scoped antes de la fase 2. Fase 2 devuelve recuentos de plantilla/bindings, identidad incompleta, SO global/particular, instalaciones/revisiones por scope/estado, inactivos usados y referencias inválidas. Las instalaciones por compañía se expresan como histograma de volúmenes, sin UUID/nombres. No extraer valores comerciales, inventarios o datos personales al informe.
Ejecutar únicamente tras autorización específica de lectura, con credencial de mínimo privilegio, límites de tiempo/carga y procedimiento aprobado del operador. No se incluye una contraseña en comandos ni se presume un nombre de base destino. Las consultas se contrastaron estáticamente con el DDL guardado del GO, no con MariaDB real en esta intervención. Recuentos de identidad son diagnósticos orientativos: no sustituyen toda la policy semántica ni la revisión de duplicados.
## 7. Plantilla SO y posibles instalaciones legacy
La stock `template:os` conserva UUID y campos existentes. El seed comprueba ausencia de `field:os_edition_state` para decidir la evolución; añade bindings opcionales de `os_family`, `os_product_version` y `os_edition_state` y conserva los originales/personalizaciones. `provider` y `software_edition` ya existían. Estados: `known`, `not_applicable`, `unknown`; publicación requiere identidad válida. No rellenar particulares antiguos con valores ficticios.
El marcador de campo existente **no demuestra por sí solo** que todos los bindings del destino sean correctos: una edición manual o evolución incompleta necesita diagnóstico, no borrado del marcador. El arranque siembra catálogo aun con gates SO cerrados; estos gates no son un interruptor del seed o de todas las migraciones. Evolución doble y conservación fueron probadas en aislamiento, no sobre el destino. Copias de plantillas SO no adquieren elegibilidad global. No hay DDL específico nuevo de SO ni autorización para D08.2.
## 8. Contratos y lectores — hito D
Cabecera real: **`x-metis-resources-contract`**, valores soportados explícitos `2` y `3`. No existe flag de entorno para negociar la versión. El navegador actual solicita contrato 3 en los consumidores mixtos.
| Contexto | Cliente sin versión | v2 | v3 |
| --- | --- | --- | --- |
| Respuesta compatible exclusivamente particular | Compatibilidad local ensayada | Compatible | Compatible |
| Contexto que exige referencias application global | 409 de actualización cuando corresponde | Compatible por propósito | Compatible por propósito |
| Colección/referencia de software que requiere SO global | 409 `RESOURCE_CLIENT_UPGRADE_REQUIRED`, sin recortar filas | Igual 409 | DTO SO válido |
| SO global como `ApplicationConfiguration` | Rechazado por propósito | Rechazado | Rechazado |
| Versión explícita no soportada, como 4 | NO APLICA | NO APLICA | HTTP 400 para petición con esa versión |
SO público: `kind=os`, `scope=global`, `companyId=null`, identidad y enlace SO; application conserva su DTO/tipo, listado y enlaces. Los particulares conservan pertenencia. Capabilities v2 conserva cuatro claves anteriores; v3 incorpora capacidad SO. Autorización/CSRF/compañía se verifican en servidor, no por esa cabecera.
Los clientes realmente desplegados son **PENDIENTE DE VERIFICACIÓN**: inventariar navegadores con JS cacheado, API consumers, tareas y todas las instancias backend. Actualización coordinada y recarga/control de caché antes de nuevas asociaciones SO. No mezclar backend incapaz de leer SO global con referencias ya persistidas.
Cerrar gates de nuevas dependencias conserva lectura de catálogo, UUID, instalaciones/historial y navegación a inactivos; permite notas/retirada legítima según estado y contrato. El gate cerrado no abre edición administrativa del producto. Desactivación administrativa de seguridad y replay idempotente tienen sus reglas propias; no se afirma que todos los POST queden bloqueados. Esta garantía procede de las pruebas previas; debe verificarse también en el destino autorizado.
## 9. Secuencia progresiva propuesta
**Bloqueada por B-01/B-02 y verificaciones del destino. No se ejecuta.** Todos los cambios de configuración requieren autorización explícita futura.
| Etapa | Configuración SO | Operación propuesta y previos | Smoke / avance | Abortar y reversión |
| --- | --- | --- | --- | --- |
| 0 preparación | OS_CATALOG=false, OS_SOFTWARE=false | Corregir/validar artefacto y TLS/sesiones; fijar release, dependencias, backup/restore, scope; desplegar lectores v3 y frontend coordinados solo tras autorización | Salud, login persistente, lectura local/global existente, tipos/UUID/historial; cero inconsistencias | No abrir flags; detener rollout si falla arranque, sesión o integridad; mantener lectores compatibles |
| 1 administración | OS_CATALOG=true, OS_SOFTWARE=false | Administrador autorizado puede crear/editar/revisar/publicar productos aprobados; revisar evolución y elegibilidad antes | Alta/revisión autorizadas; lectura ordinaria; nuevos candidatos/asociaciones SO aún cerrados | Cerrar OS_CATALOG; conservar productos/historial; desactivar producto incorrecto con permisos |
| 2 selección y 3 operación | OS_CATALOG=true, OS_SOFTWARE=true | Habilitación conjunta de candidatos y asociación; mismos checks que etapa 1 más clientes v3 y activo/compañía autorizados | Canario autorizado: selección, instalación, versión, activo/puesto, historia y negativos de licencia/perfil | Cerrar OS_SOFTWARE y después OS_CATALOG; comprobar lectura/retirada; no borrar filas |
**No hay separación técnica entre selección SO y asociación SO.** No usar SOFTWARE_CANDIDATES de aplicaciones para fingirla. Tampoco hay gate por compañía: un canario limitado a una compañía es un procedimiento operativo, no aislamiento por flag. Acordar quién puede escribir durante esa ventana y cómo se limita el alcance; si no puede limitarse, no anunciar un piloto restringido.
Orden obligatorio: persistencia preparada → backend con lectores v3 → frontend/consumidores compatibles → administración → nuevas asociaciones → verificación. La evolución se ejecuta durante el arranque y puede escribir con flags cerrados, por lo que ese arranque requiere ventana/autorización, no solo permiso de lectura. Mantener los otros cuatro gates según su autorización propia; no modificarlos como efecto secundario de SO.
## 10. Smoke tests operativos preparados
**No ejecutados sobre destino.** Usar sesión real sin copiar cookies/tokens a logs, y registrar código HTTP/requestId/resultados, sin contenido sensible. GET puede tocar la sesión; «lectura» significa sin cambio de negocio, no promesa de cero escrituras técnicas en el servidor.
| Tipo | Comprobación y ruta real | Resultado esperado |
| --- | --- | --- |
| Lectura | Login y persistencia con cuenta autorizada a través del origen HTTPS | Cookie Secure/HttpOnly y sesión mantenida; B-02 resuelto |
| Lectura | `GET /api/resource-global-operating-systems` y `/api/resource-global-applications` | 200 autenticado, tipos separados, sin datos administrativos expuestos |
| Lectura | `GET /api/resource-global-operating-systems/:id` | UUID/SO activo o inactivo legible, destino correcto |
| Lectura | `GET /api/resource-application-candidates/:companyId/capabilities`, contrato 3 | Capabilities acordes con etapa; no equivale a permiso administrativo |
| Lectura | `GET /api/resource-application-candidates/:companyId?purpose=software-installation`, contrato 3 | Solo candidatos activos/elegibles; SO global aparece únicamente en etapa operativa |
| Lectura, aunque use POST | `POST /api/resource-application-references/:companyId/resolve`, cuerpo `{ "purpose": "software-installation", "ids": ["UUID aprobado"] }`, contrato 3 | Referencia SO resuelta por propósito; petición de resolución sin mutación de negocio |
| Lectura | `GET /api/software-installations/:companyId`, contrato 3; ficha activo/puesto e historial desde UI | Instalaciones/versiones/estado/historia existentes completos; rutas global/particular correctas |
| Lectura | Repetir contexto con SO global usando v2/sin cabecera | 409 explícito; no respuesta truncada |
| Escritura, autorización separada | Instalar producto aprobado en **activo de pruebas ya existente y autorizado**, desde diálogo normal | Instalación propia; versión en activo/puesto; historial correcto |
| Escritura negativa, autorización separada | Intentar SO en perfil de aplicaciones | Rechazo, sin configuración persistida |
| Escritura negativa, autorización separada | Intentar licencia de otra compañía en instalación | Rechazo, asociación previa intacta; permiso de prueba no supone acceso libre a esa compañía |
| Escritura, autorización separada | Cambio de versión y retirada válida de instalación usada/inactiva | Misma identidad de producto; nuevas revisiones; lectura preservada |
No crear activos ficticios ni productos de prueba en producción durante el preflight. Las pruebas negativas también requieren permiso y verificación de ausencia de efectos. Si no hay un activo y datos autorizados, el operador debe proponer canario en staging; no inventarlos en la base real.
## 11. Runbook de rollback y recuperación — hito F
Regla común: detener nuevas dependencias cerrando **OS_SOFTWARE=false**, luego nuevas altas/ediciones/reactivaciones con **OS_CATALOG=false**, mantener lectores Resources 3 y los cuatro gates application según autorización independiente. Aplicar configuración a todas las instancias y reiniciar mediante su supervisor aprobado. Configuración operativa/supervisor no están verificados. No ejecutar este plan ahora.
| Incidencia | Detección / respuesta propuesta | Límite y recuperación |
| --- | --- | --- |
| Catálogo SO | Errores de alta/revisión/listado correlacionados; cerrar ambos flags | Conservar lectura e historial; reparar causa y validar antes de reabrir |
| Selector | Candidatos/tipos/etiquetas incorrectos; cerrar OS_SOFTWARE | No hay gate SO solo de selección; comparar capacidades y referencias reales |
| Frontend incompatible | Enlaces/estado o JS antiguo; suspender nuevas asociaciones y distribuir frontend compatible | Mantener backend v3; no servir UI que oculte instalaciones existentes |
| Contrato Resources | 409 de actualización o payload incompatible; detener consumidores antiguos y coordinar versión | No borrar referencias ni rebajar backend; reabrir tras probar clientes v3 |
| Evolución de plantilla | Error de arranque/plantilla/bindings; detener rollout y escritores | Cerrar flags no evita seed al arrancar; no prometer recuperación solo reiniciando. Investigar y autorizar reparación/restore integral consistente |
| Asociación | Rechazos/filas inconsistentes; cerrar OS_SOFTWARE y verificar constraints/referencias | No editar SQL a mano ni reasignar licencia; corregir mediante operación autorizada con historial |
| Producto comercial incorrecto | Desactivar producto para impedir nuevas asociaciones; conservar UUID y uso previo | Identidad publicada fija; otro producto necesita otro UUID. No convertir/reasignar instalaciones ni fusionar particulares |
| Producto inactivo usado | Leer referencia/historia y `needsReview`; decidir continuidad/retirada | Inactivo no significa ausente; retirada legítima sigue permitida. Reactivación solo tras revisión/autorización |
| B-01/B-02 | No publicar el bundle fallido ni abrir flags; resolver en intervención específica | Repetir parse/arranque aislado del compilado y login HTTPS end-to-end antes de replantear preparación |
Conservar Resource, SoftwareInstallation, UUID, licencias, especificaciones e historial. Prohibidos borrado como rollback, fusión de particulares, D08.2 automático o backend incapaz de leer SO global ya referenciados. Un restore de BD requiere autorización, backup/restauración ensayados, corte consistente y análisis de cambios posteriores; no se propone downgrade destructivo del esquema.
Después de una incidencia: metadatos y diagnósticos agregados de la fase C; cero referencias inválidas/huérfanas; comparar con línea base del operador; leer casos existentes activos/inactivos/históricos; probar retirada si hay autorización; verificar sesiones/contratos en todas las instancias. Reabrir solo tras causa corregida, evidencias actuales y nueva autorización.
**Probado previamente en aislado:** cierre de seis flags conserva lectura/historia/retirada y bloquea nuevas altas; carreras/rollback transaccional ensayados. **No probado operativamente:** supervisor, proxy, restauración del destino ni ninguno de los ocho escenarios como simulacro productivo completo. Este runbook es verificable, no un rollback productivo ya ensayado.
## 12. Deuda global y aceptación
| Hallazgo / propietario funcional | Estado comprobado y efecto | Clasificación |
| --- | --- | --- |
| Bundle inválido B-01 / mantenedor de build servidor | Dos compilaciones y `node --check` fallido; colisión banner/sharp | **Bloqueante real**, no ejecutable |
| Sesión Secure B-02 / backend y operación/proxy | HTTP local sin cookie bajo HTTPS reenviado; destino desconocido | **Bloqueante** para topología TLS→HTTP sin solución validada |
| Calendar vendor / mantenedor de dependencia | `pnpm typecheck` vuelve a fallar en `calendar.tsx:165` por `locale` opcional; vendor intacto | No causa B-01; deuda de tipos. Bloquea pipeline si exige verde; no aceptar exención implícita |
| Dos assertions Companies / mantenedor de Companies | Antecedente del GO: ayuda compañía/persona, 305/307; fuentes sin diferencias | No comprometieron catálogo/contratos en escenarios previos; no se reejecuta suite extensa sin cambios. Aceptación CI pendiente |
| Lint / propietarios de fuentes indicadas en log | Nueva ejecución: **15 errores, 1 warning, 5 infos** | Deuda fuera del cambio; clasificar/aceptar explícitamente para release, nunca tratar como CI verde |
| Formato/imports / mantenedores y autores de evidencias | Nueva ejecución: **173 errores, 1 warning, 5 infos** | Incluye copias JSON de evidencias SQL del desbloqueo, posteriores al check previo de 170; no son código runtime. No reformatear evidencia sellada sin actualizar huellas |
| Chunk web >500 kB / frontend | Advertencia en ambos builds, sin fallo de compilación | Riesgo de rendimiento, no prueba de fallo funcional; presupuesto del destino pendiente |
| Runtime/artefacto completo / operación | Dependencias nativas/externalizadas, hosting y lanzamiento no ensayados como release | PENDIENTE DE VERIFICACIÓN; necesario después de B-01 |
Se distinguen fallos antiguos de diagnósticos nuevos. La antigüedad no excusa un artefacto que no arranca: B-01 es bloqueante aunque no se determine aquí cuándo apareció. No se modifican bundler, sharp, vendor, tests de Companies ni áreas ajenas para conseguir verde.
## 13. Evidencias y comprobaciones de esta intervención
Conservadas bajo [evidencias de preflight](../../.artifacts/resources-global-operating-systems-preflight/), con [manifiesto](../../.artifacts/resources-global-operating-systems-preflight/manifest.json): hashes de fuentes/overlay/artefactos, logs de build, parse, sesión proxy y calidad general. El diagnóstico de sesión usa el `createApp` real y express-session instalado, secreto aleatorio efímero y store en memoria para **ese experimento local**, sin BD ni cuentas reales. No certifica el store SQL ni login completo: aísla el mecanismo de emisión de cookie.
Comandos ejecutados: `pwd`, `git status --short`, `git rev-parse HEAD`, `git branch --show-current`, versiones Node/PNPM, comparación de hashes, reconstrucción en directorio temporal, `pnpm build`, dos `pnpm exec turbo run build --force`, `node --check apps/server/dist/index.js`, diagnóstico local proxy, `pnpm typecheck`, `pnpm lint`, `pnpm check` y detalle Biome. Los builds devuelven 0; el parse devuelve 1; tipos/lint/check devuelven error. No se ejecutan el servidor compilado ni scripts `start` contra base configurada.
Reproducción no invasiva desde la raíz, sin cargar `.env` ni abrir BD:
```bash
pnpm exec turbo run build --force
node --check apps/server/dist/index.js
node --import tsx .artifacts/resources-global-operating-systems-preflight/proxy-session-diagnostic.mjs
```
El segundo comando debe reproducir B-01 y devolver 1 en este snapshot. El tercero abre y cierra un HTTP efímero de loopback; el resultado esperado del defecto es `trustProxy=false`, `secure=false`, `sessionCookieIssued=false`, `databaseUsed=false`. El diagnóstico conservado se formateó y volvió a ejecutar con salida cero; esa salida cero significa diagnóstico completado, **no sesión productiva correcta**.
No se repiten MariaDB, unitarias extensas ni Playwright: cero diferencias funcionales frente al GO; se verifican sus hashes/manifiestos y se reutilizan como antecedentes. Los 29/29 + 50/50 y las 35 comprobaciones/69 capturas pertenecen al desbloqueo anterior. Los dos builds nuevos se justifican por la identificación/reproducibilidad de artefactos, y el parse/cookie por riesgos de ejecución productiva no cubiertos antes.
## 14. Riesgos residuales y condiciones de autorización
Además de B-01/B-02: desconocimiento del destino, despliegue mixto de lectores, clientes antiguos, gates globales sin canario por compañía, evolución que escribe al arrancar, backup/restore no ensayado del destino, dependencia de policies/locks para identidad EAV, particulares equivalentes persistentes y falta de medición de rendimiento productivo. No hay unicidad SQL comercial multicampo ni D08.2 implementado.
| Hito | Estado final |
| --- | --- |
| A trazabilidad del candidato | **VERIFICADO** con base + overlay + hashes; fijar release aún es tarea de integración |
| B entorno operativo | **PENDIENTE DE VERIFICACIÓN**; no se dispone de manifest de destino autorizado |
| C persistencia | Requisitos **VERIFICADOS** en código; aplicación/datos destino **PENDIENTE DE VERIFICACIÓN** |
| D contratos/orden | **VERIFICADO** en snapshot y antecedentes; clientes destino **PENDIENTE DE VERIFICACIÓN** |
| E etapas | **VERIFICADO** como propuesta ajustada a gates; selección/asociación SO inseparables |
| F rollback | **VERIFICADO** como runbook preparado; simulacro del destino **PENDIENTE DE VERIFICACIÓN** |
| Artefacto servidor | **NO CUMPLE**, B-01 |
| Sesión de producción TLS→HTTP | **NO CUMPLE** en diagnóstico, B-02; topología destino pendiente |
| Adopción/D08.2 o globalidad de licencias | **NO APLICA**, fuera de alcance |
Responsables requeridos: mantenedor del build para B-01; backend y operación para TLS/sesiones; integración para commit/release inmutable y dependencias; DBA/operación para autorización de lecturas, esquema, backup/restauración y ventana; producto/propietario autorizado para productos, canario y gates; mantenedores de CI para deuda/excepciones expresas.
Condiciones antes de autorizar: artefacto compilado válido y arranque aislado comprobado; sesiones Secure a través de la topología aprobada; identidad de release congelada; destino identificado; inventario de clientes; metadata/datos verificados con autorización; backup/restauración aprobados; smoke y responsables acordados; tratamiento explícito de CI no verde. No cambiar flags como sustituto de cumplir estas condiciones.
**Dictamen final: NO PREPARADO**, referido al snapshot reproducido y al artefacto productivo generado localmente. El entorno real sigue pendiente. El informe prepara las decisiones y acciones necesarias; no solicita, concede ni ejecuta autorización de despliegue o activación.
## 15. Reevaluación del candidato confirmado en Git
Fecha: 26 de octubre de 2026. Solicitud reiterada de preflight; no autoriza corregir funcionalidad, migrar, desplegar ni activar. Se utilizó `rdx-solid` para limitar las comprobaciones a diferencias reales y a los bloqueos productivos ya detectados.
### 15.1. Identificación y diferencias respecto al GO
| Requisito | Estado actual | Evidencia |
| --- | --- | --- |
| Candidato actual | VERIFICADO | `main`, `6992a4ac745acf6b474a0f22d1a859b861119452`; `git status --short` vacío antes de intervenir |
| Trazabilidad del código candidato | VERIFICADO | Ahora está confirmado en Git; reproducible mediante checkout del commit y dependencias fijadas. No necesita el overlay anterior para identificar sus fuentes |
| Igualdad completa con el GO | NO CUMPLE | De 1884 fuentes registradas: **1875 iguales y 9 modificadas**; hay **6 fuentes adicionales** en los mismos ámbitos |
| Archivos de trabajo del GO | VERIFICADO con diferencia documental | De los 40 registrados, 39 coinciden; cambió `docs/componentes-de-interfaz.md` |
| Node/PNPM y dependencias | VERIFICADO en instalación/manifests | 24.20.0 / 11.25.0; lockfile conserva SHA-256 `bcd468ab1f127fffeb7f37ef3bdb5f2c5e85d40c192f3bc4a7cae5b2209b7c17` |
| Instalación limpia de dependencias del destino | PENDIENTE DE VERIFICACIÓN | No se ejecuta install ni se cambia configuración privada |
Los commits `07082001` y `6992a4ac` incorporan el trabajo previamente sin commit y cambios adicionales. Se compararon contenidos con los manifiestos del GO; no se atribuye todo `git diff d2bf856c..HEAD` a una diferencia funcional posterior, porque también contiene aquel trabajo ya validado.
Durante la reevaluación aparecieron cambios concurrentes sin commit en `modules/assets/src/web/index.ts`, `infrastructure-page.tsx`, `use-company-detail-controller.ts`, el nuevo helper `infrastructure-items.ts` y pruebas `infrastructure.test.tsx` / `companies-page.test.tsx`. Se preservaron. **El candidato de esta tabla es el commit, no el árbol concurrente final**: sus diferencias se verificaron leyendo los objetos de `git archive HEAD`. Los hashes del trabajo concurrente se registran aparte como no validados en la fecha de captura; las ejecuciones de esta intervención no certifican esas modificaciones posteriores. Una release que las incorpore necesita nueva identificación y análisis de impacto.
| Diferencia | Clasificación | Impacto y validación |
| --- | --- | --- |
| Columnas adicionales de características/recursos y sus pruebas | Frontend | Cambia el contenido configurable del inventario; Resources reejecutado |
| Preferencias por compañía/plantilla, precedencia de URL y persistencia de orden | Frontend | Afecta navegación y contexto de listados; pruebas nuevas incluidas en Resources |
| `CursorEntityTable` y prueba de visibilidad | Frontend compartido | Puede afectar también listados globales; reejecutada la suite específica de columnas/tablas. Validación visual actual pendiente |
| Traducciones es/en de Resources | Frontend/textos | Fuentes distintas del GO; no certificar con capturas anteriores |
| Guía de listados y componentes | Documentación | Revisada como patrón vigente; no cambia esquema/contrato |
| Script de test en `modules/resources/package.json` | Configuración de validación | Añade nuevas pruebas; no cambia dependencias runtime ni lockfile |
| DTO HTTP, lógica backend, persistencia, seguridad, gates y configuración de build | Sin diferencia funcional identificada respecto al GO | Las diferencias de `common` son locales es/en; los nuevos archivos server son las fixtures/tests del cierre ya registrados en el GO |
Las nueve fuentes modificadas y seis nuevas, con hashes, están enumeradas en [traceability.json](../../.artifacts/resources-global-operating-systems-preflight-6992a4ac/traceability.json). No hay bloqueo de identificación del candidato. **No se traslada el GO íntegro al frontend cambiado**: corresponde validar visualmente los nuevos listados/componente compartido antes de una futura aprobación de release.
### 15.2. Artefactos y bloqueos reproducidos
Se ejecutó `pnpm exec turbo run build --force`: servidor y web compilan, dos tareas correctas. Se calcularon hashes de los 12 archivos dist. **El dist del servidor coincide byte a byte con el del preflight anterior; el dist web es distinto**. Por tanto, la correspondencia del frontend antiguo con MCP descrita en el apartado 3 no se aplica al candidato actual.
- **B-01 sigue NO CUMPLE:** nuevo `node --check apps/server/dist/index.js` devuelve 1, `Identifier 'createRequire' has already been declared`. `tsup.config.ts` conserva el banner y el bundle incluye el segundo import procedente de sharp. La compilación correcta no acredita ejecución; no se arrancó ese servidor ni se abrió BD.
- **B-02 sigue NO CUMPLE para TLS→HTTP:** el diagnóstico conservado se ejecutó con el `createApp` actual. Resultado nuevo: `trustProxy=false`, `http=200`, `secure=false`, `sessionCookieIssued=false`, `databaseUsed=false`. Salida cero del diagnóstico significa que terminó el experimento, no que la sesión de producción funcione.
No se ha configurado confianza en proxy, relajado Secure, cambiado `NODE_ENV`, editado el bundle ni modificado sharp para eludir los bloqueos. La solución de TLS/proxy debe ser aprobada y acotada al proxy real, sin confiar indiscriminadamente en cabeceras reenviadas.
### 15.3. Validaciones dirigidas nuevas y deuda actual
| Comando / ámbito | Resultado nuevo |
| --- | --- |
| `pnpm --filter @metis/resources test`, con loopback permitido | **124/124**, incluido caché, contratos y pruebas nuevas de columnas/preferencias |
| `node --import tsx --test --test-isolation=none src/entity-column-visibility.test.tsx`, desde rdx-ui con TSX_TSCONFIG_PATH del paquete | **9/9** |
| Typecheck directo Resources, Web y rdx-ui | Los tres correctos |
| Biome y ESLint sobre las 15 fuentes modificadas/nuevas | Ambos correctos |
| Build forzado | Dos tareas correctas; advertencia de tamaño de chunk web |
| Parse del servidor compilado | **Fallo bloqueante B-01**, salida 1 |
| Diagnóstico de sesión local | Experimento completado; demuestra **B-02** |
| `pnpm typecheck` raíz | Falla en calendario vendor por `locale` opcional, salida 2 |
| `pnpm lint` raíz | 15 errores, 1 warning, 5 infos; salida 1 |
| `pnpm check` raíz | 173 errores, 1 warning, 5 infos; salida 1 |
No se han corregido incidencias ajenas. Los propietarios y clasificación de deuda del apartado 12 siguen aplicándose: el parse inválido es bloqueante, no una excepción aceptable por antigüedad; los fallos generales requieren tratamiento explícito de CI. Los dos fallos previos de ayuda de Companies son antecedentes, no una ejecución nueva. No se repitió la suite completa; posteriormente se modificó concurrentemente `companies-page.test.tsx`, por lo que su estado en ese trabajo posterior queda pendiente, sin afirmar que sus dos fallos persistan o estén resueltos allí.
No se repitieron MariaDB/HTTP-SQL con fixtures ni Playwright con preparación persistente: no cambió el backend/contrato/persistencia y este preflight no autoriza escrituras de negocio o migraciones. Las 29/29 + 50/50 y las 35 comprobaciones/69 capturas siguen siendo antecedentes con su alcance anterior. Para el nuevo frontend se requiere validación visual dirigida de columnas, preferencias, contexto y listados globales, en entorno aislado autorizado para preparar datos; las pruebas de componente no sustituyen esa comprobación.
### 15.4. Entorno, gates, rollback y autorización
No hay nueva evidencia autorizada del destino. Motor/versión/esquema aplicado, plantilla real, FKs/CHECK/índices, clientes desplegados, proxy, sesiones, supervisor, backup/restore y valores efectivos de gates continúan **PENDIENTES DE VERIFICACIÓN**. No se infieren de defaults ni del compose de desarrollo. El SQL del apartado 6 sigue preparado y **no ejecutado**; sus tablas/migraciones no cambiaron.
Se verificó que los seis nombres de flags y sus dependencias siguen iguales. El plan de los apartados 8–11 sigue vigente como propuesta: persistencia compatible → lectores v3 → frontend coordinado → OS_CATALOG administrativo → OS_SOFTWARE, que abre **selección y asociación juntas**. No hay gate por compañía ni se añaden flags para simularlo. Mantener los cuatro flags application según su autorización independiente.
El rollback propuesto conserva lectores v3, UUID, productos, instalaciones e historiales; cierra nuevas dependencias y altas, permite las retiradas legítimas ensayadas y no activa D08.2. No es un procedimiento productivo ya ejecutado. Los smoke tests de lectura y escritura siguen separados; ninguna escritura, conexión al destino o activación se ejecutó en esta reevaluación.
### 15.5. Evidencias y dictamen vigente
Ejecuciones nuevas, diferencias y hashes: [manifiesto 6992a4ac](../../.artifacts/resources-global-operating-systems-preflight-6992a4ac/manifest.json). El preflight anterior y sus evidencias se conservan sin sobrescribirlos. Esta intervención modifica únicamente este informe y añade evidencias diagnósticas; los cambios concurrentes ajenos permanecen sin certificar.
**NO PREPARADO**, para `6992a4ac745acf6b474a0f22d1a859b861119452` y sus artefactos generados localmente. Primero deben resolverse B-01 y la configuración aplicable de B-02, verificarse el artefacto ejecutable y revalidarse el frontend cambiado. Después faltan las comprobaciones y autorizaciones del destino enumeradas arriba. El código está identificado, pero eso no acredita una release operativa ni autoriza publicarla.
## 16. Reevaluación de a72d6a2e
Fecha: 26 de octubre de 2026. **Candidato: `a72d6a2ec8985e1d51f74db68a1b3aabb3693030`, rama `main`; árbol limpio al comenzar.** Node 24.20.0 y PNPM 11.25.0. Se aplica `rdx-solid` para contrastar diferencias y ejecutar comprobaciones proporcionadas; no se rediseña Resources ni se modifica código funcional.
### Trazabilidad y alcance de las diferencias
El candidato está confirmado en Git y puede recuperarse mediante checkout de ese SHA; no depende del overlay histórico para identificar su código. Los objetos de `git archive` se compararon con las 1884 fuentes del GO: **1854 coinciden, 30 cambiaron y hay 9 fuentes añadidas** en los ámbitos registrados. El lockfile conserva SHA-256 `bcd468ab1f127fffeb7f37ef3bdb5f2c5e85d40c192f3bc4a7cae5b2209b7c17`. No se ejecutó instalación limpia de dependencias; sigue siendo una comprobación pendiente para el empaquetado final.
Desde `6992a4ac`, los commits `0a5fb282` y `a72d6a2e` incorporan las modificaciones concurrentes anteriormente pendientes y nuevas integraciones visuales. La relación completa figura en [traceability.json](../../.artifacts/resources-global-operating-systems-preflight-a72d6a2e/traceability.json).
| Diferencia desde la reevaluación anterior | Clasificación | Tratamiento |
| --- | --- | --- |
| Obtención de infraestructura desde el inventario y exportación del helper | Frontend Assets | Pruebas de infraestructura y tipos reejecutados |
| Navegación de compañía/personas, contexto de listas y rutas | Frontend Companies | Pruebas de compañía/personas/rutas y tipos reejecutados; dos aserciones de presentación siguen fallando |
| Creación de carpeta SMB y enlace posterior a publicación | Frontend Assets/Companies/Resources | Cambia composición de formularios y feedback; se revalidan Resources y publicaciones, sin guardar datos reales |
| Callback `onSaved(id, resource)` y props de lista/editor | Contrato frontend entre consumidores | Tipado de los cuatro módulos/aplicación revalidado; no cambia DTO HTTP ni contrato Resources 2/3 |
| Traducciones, documentación, scripts de auditoría y evidencias | Textos/documentación/validación | No confundir sus resultados históricos con ejecuciones de este preflight |
| Backend, persistencia, seguridad, flags, tsup y lockfile | Sin cambios desde `6992a4ac` | Reutilizables los antecedentes técnicos de esas fronteras; se reproducen B-01/B-02 y se conserva pendiente el destino |
**El GO completo no se transfiere automáticamente al nuevo frontend.** La documentación SMB incorporada registra comprobaciones de su intervención; no se presentan como pruebas nuevas de este preflight ni como certificación de los 35 recorridos SO sobre este candidato. Antes de aprobar una release sigue pendiente la validación visual dirigida de los consumidores modificados y compartidos, con evidencias correspondientes al código que se publique.
### Resultados nuevos
| Comprobación | Resultado |
| --- | --- |
| `pnpm exec turbo run build --force` | Servidor/web compilan, 2 tareas correctas; advertencia de chunk web >500 kB |
| Hashes de dist | 12 artefactos identificados; servidor idéntico al de `6992a4ac`, web diferente |
| `node --check apps/server/dist/index.js` | **NO CUMPLE, B-01**: salida 1 por `createRequire` duplicado, línea 23345 del bundle generado |
| Diagnóstico proxy local sin BD | **NO CUMPLE, B-02 en TLS→HTTP**: `trustProxy=false`, `secure=false`, `sessionCookieIssued=false`; experimento completado con salida 0 |
| Resources completo | **124/124**, HTTP de prueba en loopback y sin BD |
| Assets: infraestructura/publicaciones SMB | **9/9** |
| Companies: compañía/personas/rutas | **29/31**; fallan «Personas (1)» y «Esta persona no tiene acceso a Metis Desk» |
| Typechecks directos Resources, Companies, Assets y Web | Los cuatro correctos |
| Biome/ESLint sobre 25 archivos cambiados TS/TSX/JSON | Ambos correctos |
| `pnpm typecheck` raíz | Salida 2; continúa TS2375 en calendario vendor, `locale` opcional |
| `pnpm lint` raíz | Salida 1; 15 errores, 1 warning y 5 infos |
| `pnpm check` raíz | Salida 1; 173 errores, 1 warning y 5 infos |
Los dos fallos de Companies se han vuelto a ejecutar; ya no se describen aquí como estado desconocido del trabajo concurrente. Coinciden en sus expectativas con fallos previos, pero quedan pendientes de conciliar con la presentación actual; no se asume que su antigüedad justifique ignorarlos. Su responsable es Companies. No impiden compilar; sí impiden declarar satisfactoria esa validación y requieren resolución o decisión explícita de aceptación para una release. No se debilitaron asserts ni se modificaron los tests.
B-01 sigue siendo un bloqueo absoluto del artefacto, responsabilidad de build/servidor: éxito de tsup no garantiza que Node pueda interpretarlo. B-02 corresponde a backend/operación y a la topología TLS aprobada. No se modificaron banner, sharp, Secure ni confianza en proxy. La deuda de calendario, lint/formato y ejemplos permanece fuera de las correcciones de este encargo; su efecto sobre la política CI debe aceptarse o resolverse expresamente.
### Persistencia, destino y plan operativo
No cambian los requisitos de MariaDB, plantilla SO, FKs/CHECK/índices o migración R2.1b descritos en los apartados 6–7. **PENDIENTE DE VERIFICACIÓN** en el destino: versión/motor, esquema efectivamente aplicado, bindings y datos existentes, controles activos, clientes desplegados, proxy, sesiones, backup/restauración, supervisor y valores efectivos de configuración. No se ha obtenido acceso autorizado de lectura al destino ni se han ejecutado las consultas SQL preparadas.
Contratos v2/v3, propósitos, guard administrativo y seis nombres/dependencias de gates siguen sin cambios. Mantener el orden documentado: persistencia preparada → lectores v3 → frontend compatible → catálogo administrativo SO → selección/asociación SO conjuntas. No hay etapa de selección SO independiente ni gate por compañía; no se añaden para forzar un piloto. Los cuatro flags application conservan su autorización propia y los valores efectivos no se infieren de defaults.
El plan de smoke de lectura/escritura y los ocho escenarios de rollback siguen preparados en los apartados 10–11. Cerrar nuevas dependencias/altas no borra ni reescribe referencias: deben mantenerse backend/lectores v3, UUID, licencias, instalaciones e historial, incluyendo inactivos y retirada legítima. No es un rollback productivo probado. No se restaura un backend incapaz de leer SO global ni se implementa D08.2.
No se repitieron suites MariaDB ni preparación Playwright con persistencia: no cambió el backend y este preflight no autoriza migraciones ni escrituras de negocio. Los resultados anteriores 29/29 + 50/50 se conservan como evidencia de integración de las fronteras sin cambios. La validación visual pendiente debe realizarse sobre una release identificada y un entorno aislado autorizado para preparar datos.
### Dictamen y evidencias
**NO PREPARADO**, para `a72d6a2ec8985e1d51f74db68a1b3aabb3693030` y sus artefactos generados localmente. Se confirma trazabilidad, pero B-01 impide ejecutar el servidor y B-02 sigue abierto para TLS→HTTP; también faltan aceptación de las pruebas fallidas, validación visual actual y comprobaciones reales del entorno. No procede elevar este candidato a «preparado para solicitar autorización» por el mero hecho de tener GO de un snapshot anterior.
Evidencias nuevas y comandos: [manifiesto a72d6a2e](../../.artifacts/resources-global-operating-systems-preflight-a72d6a2e/manifest.json). Se preservan los informes anteriores. Los logs corresponden a esta ejecución; ninguna evidencia de producción ni activación se declara realizada. Esta intervención solo actualiza el informe y conserva diagnósticos; no cambia funcionalidad, configuración privada, datos reales, flags o despliegues.
## 17. Resolución correctiva B-01/B-02
### Snapshot y alcance
Intervención autorizada el 26-10-2026, sobre `main`, HEAD `a72d6a2ec8985e1d51f74db68a1b3aabb3693030` **más el diff local correctivo**, sin commit nuevo. El antecedente solicitado `6992a4ac` y la reevaluación de `a72d6a2e` se conservan en los apartados 15–16. Los diagnósticos anteriores describen esos snapshots sin la corrección; no son el dictamen del diff actual.
El árbol contiene además cambios concurrentes de interfaz SMB, documentación y auditorías, identificados en el manifiesto. Se han conservado. Esta intervención modifica build/configuración/HTTP del servidor, el borrado de cookie en Identity, scripts de prueba y documentación. No cambia el dominio de Resources, Assets o Companies, contratos v2/v3, gates, esquema, migraciones ni D08.2. No se ha accedido a producción ni cargado `.env`.
Skill consultada: `rdx-solid`, aplicada a la reproducción antes de corregir, responsabilidad de cada capa y pruebas de comportamiento. No se ha realizado trabajo visual ni una auditoría Playwright nueva; los cambios concurrentes de frontend siguen requiriendo validación propia.
### B-01: procedencia y corrección
La compilación anterior con tsup 8.5.1 terminaba, pero Node 24.20.0 rechazaba `apps/server/dist/index.js` con `SyntaxError: Identifier 'createRequire' has already been declared`, línea 23345. El servidor tiene un único entrypoint, formato ESM, target Node 24. El banner introducía `import { createRequire } from "node:module"` en la primera línea. El código empaquetado de `sharp/dist/sharp.mjs` aportaba otra importación de `createRequire` desde `module` en el mismo ámbito. El banner es texto externo al análisis léxico de esbuild y no participa en su renombrado de símbolos. No se ha demostrado un defecto de sharp.
Se externaliza `sharp`, que necesita resolver sus binarios nativos desde su paquete, y se declara como dependencia runtime directa de `@metis/server` en la versión **0.35.5 ya existente**. Antes de añadirla, la resolución desde el paquete servidor fallaba con `MODULE_NOT_FOUND`; confiar solo en la dependencia transitiva de Companies no basta con PNPM. El lockfile únicamente incorpora ese enlace en el importer del servidor, sin cambiar versiones. El banner conserva el puente `require` para las dependencias CommonJS, importando `createRequire as createServerRequire`.
Eliminar todo el banner podía romper dependencias CommonJS. Cambiar únicamente el alias solucionaba la colisión sintáctica pero conservaba el empaquetado de la dependencia nativa. Externalización más dependencia directa y alias evita ambos problemas con la configuración existente. No se cambia ESM/CJS ni se reescribe el bundle mediante expresiones regulares.
El comando oficial `build` termina ahora con `check:build` (`node --check dist/index.js`), que también falla si falta el artefacto. Se incorporó primero el guard y se observó el fallo antes de corregir. Dos builds limpios sucesivos produjeron JS y sourcemap **idénticos byte a byte**; los hashes figuran en las evidencias. El build raíz también pasa, con la advertencia ya conocida del tamaño del chunk web.
La prueba permanente `pnpm test:server-runtime` ejecuta el proceso **compilado**, sin tsx ni importación sustitutiva del código fuente: arranque anunciado, salud `/api/__health`, sesiones SQL, procesamiento y recuperación de logos y fotos PNG/JPEG/WebP, conversión a WebP de anchura 128 y rechazo de imagen corrupta. El proceso termina por SIGTERM con salida 0; existe un límite de cierre que haría fallar el test si necesitara SIGKILL. No es una comprobación limitada a `node --check`.
### B-02: causa, política y configuración
Un control negativo nuevo con certificado TLS validado y la política original sin proxies reproduce `secure=false`, protocolo HTTP y ausencia de cookie (véase `b02-negative-control.json` en las evidencias). No se presenta como código antiguo recompilado: conserva explícitamente su política original de confianza. En el diagnóstico anterior, Express mantenía `trust proxy=false`. Aunque el cliente usaba HTTPS hasta el proxy, Node recibía HTTP y `req.secure=false`. Identity ya configuraba `cookie.secure=true` en producción: `express-session` evitaba emitir la cookie, en lugar de emitirla sin Secure. Faltaba un contrato de confianza configurable del servidor. La corrección pertenece al servidor y al borde HTTP de Identity; no cambia autorización por compañía.
Se añade `TRUSTED_PROXY_CIDRS`, validada al arrancar y aplicada a Express antes de las sesiones. Solo admite IPs/CIDRs explícitas, máximo 32, sin hosts, alias, número de saltos ni confianza universal. Producción exige una lista no vacía; desarrollo conserva confianza cerrada por defecto. Se rechazan encabezados `X-Forwarded-Proto` duplicados, listas o valores no canónicos antes de sesión. Una conexión no confiable no eleva `req.secure` aunque anuncie `https`.
El logout tenía además un desajuste de atributos: borraba la cookie sin copiar Secure. Ahora conserva el valor de seguridad de la cookie de sesión antes de destruirla. Se mantienen HttpOnly, SameSite Strict, Path, ámbito sin Domain, duración de ocho horas y política de renovación existente. Login posterior genera otra sesión; la anterior queda inválida en SQL.
La topología representativa verificada es **HTTPS → un terminador TLS local → HTTP Node**. El certificado local se valida explícitamente; no se desactiva la verificación TLS. Las IPs loopback `.2`/`.3` son datos sintéticos para distinguir proxies confiables y no confiables, no recomendaciones de producción. El proxy de prueba sobrescribe protocolo, cadena de cliente y host y retira `Forwarded`. La infraestructura real, sus IPs, origen, reglas de cabeceras y accesos siguen pendientes del administrador. La confianza por IP no distingue procesos que comparten origen/NAT: restringir el acceso al backend es obligatorio.
Configuración por entorno y procedimiento: [Proxy TLS y sesiones](../proxy-tls-y-sesiones.md). No se ha introducido un proxy productivo nuevo ni elegido direcciones reales. No se certifica una cadena de varios terminadores; TLS-08 comprueba la sobrescritura de una cadena inyectada en la topología de un solo proxy.
### Matriz ejecutada
| ID | Resultado nuevo |
| --- | --- |
| TLS-01 | HTTPS real mediante proxy confiable: `req.secure=true`, cookie Secure |
| TLS-02 | HTTP directo en producción: sin emisión de cookie de sesión insegura |
| TLS-03 | HTTP directo con protocolo falsificado: no eleva confianza |
| TLS-04 | Bootstrap/login y consulta posterior reales con sesión SQL válida |
| TLS-05 | Proxy TLS de dirección no confiable: sin elevación ni cookie |
| TLS-06 | Proxy confiable informa HTTP: `req.secure=false`, sin cookie productiva |
| TLS-07 | Protocolo duplicado, contradictorio, lista o inválido: 400 sin cookie |
| TLS-08 | Cadena cliente inyectada sobrescrita; IP observada correcta. Varios proxies reales: no aprobados/no verificados |
| TLS-09 | Logout real invalida SQL; borrado con Secure/HttpOnly/Strict/Path y expiración pasada |
| TLS-10 | Servidor compilado en `NODE_ENV=development`: HTTP, HttpOnly/Strict, sin Secure y sin confianza implícita |
| TLS-11 | Servidor compilado en producción sin proxies: arranque rechazado antes de anunciar disponibilidad |
| TLS-12 | Emisión posterior y relogin conservan Secure; cambia el identificador de sesión |
Las pruebas comprueban también ausencia de Domain y expiración de ocho horas. Se conservan en evidencias únicamente `metis.sid` y sus atributos, nunca valores de cookie, claves privadas, contraseñas ni entorno privado. MemoryStore se usa solo en la matriz HTTP de política; el recorrido compilado utiliza el almacén SQL real. Origen incorrecto y CSRF inválido mantienen 403.
### Validaciones y evidencias nuevas
| Comprobación | Resultado |
| --- | --- |
| Build servidor + guard de sintaxis, repetidos | Correctos; artefactos reproducibles en este entorno |
| `pnpm build` | Correcto, servidor y web; advertencia de chunk web >500 kB |
| `pnpm --filter @metis/server test:http` | **19/19** |
| `pnpm test:server-runtime` | **8/8**, MariaDB desechable retirada |
| Sharp: `company-logo-processor.test.ts` | **4/4**, formatos, inválidos, límites y animación |
| Cierre SO con regresiones, comando oficial | **29/29 + 52/52**; dos regresiones nuevas de configuración explican el aumento desde 50 |
| Typechecks Server e Identity | Ambos correctos |
| Biome y ESLint del diff correctivo TS/configuración | Correctos |
| `pnpm typecheck` raíz | Falla por TS2375 preexistente en calendario vendor (`locale` opcional) |
| `pnpm lint` / `pnpm check` raíz | Fallan: lint 15 errores, check 173 errores; ambos con 1 warning y 5 infos. Detalles en el manifiesto |
| Tests de paquetes sin servidor | 7 tareas correctas; Companies falla en las mismas dos aserciones de presentación del apartado 16 |
La prueba de runtime usa una compañía y una persona sintéticas: comprueba fronteras de autenticación e imágenes, no listados ni carga. El cierre SO utiliza sus fixtures amplias de 15 compañías y 50 personas/activos/puestos/perfiles y al menos 53 recursos en la principal. No se declara una auditoría visual con ese volumen en esta intervención. Toda persistencia se ejecutó exclusivamente sobre `metis_desk_test` en contenedores desechables.
No se ejecutó el `pnpm test` raíz completo porque la rama histórica de integración del servidor carga `.env`. Se ejecutaron por separado HTTP sin `.env`, runtime compilado aislado, cierre SO con regresiones y tests de los demás paquetes. Una primera ejecución de integración detectó un import no exportado en la nueva prueba; se corrigió su import sin cambiar la API de Companies y se repitió correctamente. No se modificaron asserts ajenos para ocultar fallos.
Comandos reproducibles y logs, hash de fuentes/artefactos, estado del árbol y resultados se recogen en [manifest.json](../../.artifacts/server-runtime-security/manifest.json). [runtime-results.json](../../.artifacts/server-runtime-security/runtime-results.json) acredita los atributos de cookie y el recorrido compilado; [integration.log](../../.artifacts/server-runtime-security/integration.log) contiene los resultados. Los builds idénticos no certifican otras plataformas nativas ni un entorno de dependencias distinto.
### Dictamen correctivo y condiciones restantes
| Ámbito | Dictamen |
| --- | --- |
| B-01 | **RESUELTO**: build, sintaxis, arranque compilado, imágenes y cierre verificados |
| B-02 | **RESUELTO EN ENTORNO REPRESENTATIVO**: TLS real, confianza restringida, sesiones SQL y falsificación comprobados |
| Validación de producción | **PENDIENTE** |
| Catálogo global SO | **GO previo preservado**, con cierre y regresiones reejecutados para las fronteras afectadas |
| Snapshot global | **NO PREPARADO** |
Antes de una release siguen pendientes: topología/IPs/origen y seguridad del proxy real, plataforma y dependencias nativas de destino, esquema/motor MariaDB, gates efectivos, supervisor y comprobación de cookies en el origen público autorizado. Además, validar visualmente el frontend actual y certificar el trabajo concurrente, y resolver o aceptar explícitamente los fallos globales y las dos aserciones de Companies. El dominio SO no pierde su cierre técnico, pero este no acredita automáticamente todo el snapshot.
No se desplegó, no se ejecutaron migraciones reales, no se cambiaron gates ni datos reales. La corrección de B-01/B-02 no autoriza activación productiva.