30 KiB
R2.0 — Resumen para aprobación
Ratificación posterior — 24 de octubre de 2026: D01–D10 y D04-R ratificadas en los términos recomendados de R2.0; variante A, Resource único con
scopeexplícito. Solo se autoriza implementar R2.1a. El registro vigente de alcance y evidencias está en 11 — Lectores compatibles. Los estados «propuesto», «recomendado» y «pendiente» del cuerpo se conservan como evidencia de la versión documental inicial y quedan actualizados por este registro; ratificación conceptual no equivale a ejecución de R2.1b–R2.6.
Estado: contrato completo propuesto, pendiente de ratificación. No aprobado automáticamente. R2.0 termina con diez documentos; no implementa ni autoriza R2.1–R2.6. Los principios expresos del usuario se marcan aprobados como restricciones, no como aprobación del diseño técnico completo.
1. Decisiones recomendadas
| Decisión | Recomendación para ratificar | Consecuencia principal |
|---|---|---|
| D01 | Resource único con scope explícito global/company y owner NULL/UUID, CHECK, propiedad/plantilla inmutables | Cambia raíz/persistencia y nuevos DTO; legacy local queda intacto |
| D02 | Solo serie Aplicación stockKey template:application, campos globales, sin integración | Regla inicial ya establecida por el usuario; otras plantillas excluidas |
| D03 | Capacidad conceptual resources.global.manage solo para administrador inicial, comprobada desde Identity en cada operación | Restricción nueva para producto e igualmente para mutaciones globales de plantillas/campos Resources; sin grants delegables |
| D04 | Mantener explícitamente el modelo de soporte compartido actual, sin simular ACL operador–compañía | Contexto de operación A nunca acepta local B, aunque el operador pueda abrir B por separado |
| D04-R | Mantener list/CRUD locales y añadir lecturas por propósito para catálogo/candidatos/referencias | Separación ya requerida; firmas y proyecciones concretas recomendadas |
| D05 | Producto mínimo para soporte, notes/especificación completa/historia de actores solo para manager | No exponer compañías usuarias, instalaciones, perfiles, licencias o datos operativos ajenos |
| D06 | Solo active existente; inactivo resoluble, fuera de nuevas asociaciones; plantilla inactiva solo bloquea alta Resource | needsReview derivado en instalación/perfil abiertos, sin campo universal ni DML masivo |
| D07 | UUID como identidad, homónimos permitidos global/local, avisos de coincidencia sin equivalencia; replay por creationId UUIDv7 | No unique global por nombre; reglas locales legacy intactas; sin tabla extra de idempotencia |
| D09 | Routers/DTO nuevos del mismo módulo; legacy exacto; proyección mínima/lotes; negociación explícita de cliente y keys por contexto | Paths, schemas, header y límites detallados en 04 son propuestas, no funcionalidades existentes |
| D10 | Lectores duales antes de DDL, expansión ensayada y gates por catálogo/software/perfil | No primer global con backend incompatible ni downgrade tras uso |
Convivencia/no fusión automática, licencias locales, UUID estable, validación en servidor, no compañía ficticia y preservación de referencias históricas son decisiones de partida aprobadas por el usuario. Los detalles técnicos de esta tabla siguen pendientes de ratificación salvo los alcances expresamente marcados. No se pregunta a mitad del trabajo por estas opciones: el contrato revisable permite decidirlas después.
2. Decisiones bloqueadas y condiciones de bloqueo
No se ha encontrado una incompatibilidad que impida proponer Resources global sobre el modelo actual. Quedan bloqueadas las siguientes ejecuciones, sin ocultarlas como «detalle de implementación»:
- Inicio R2.1: falta ratificación explícita de D01 y autorización del trabajo de implementación; antes de R2.1b además falta ensayo del esquema efectivo/version patch de MariaDB 11.8, FKs y CHECK. La preferencia por scope explícito no es aprobación.
- Activación global: no existe hoy permiso manage ni está aprobada su asignación. D03/D04/D05 deben ratificarse e implementarse/probarse antes de G3b.
- Variante con administradores delegables: BLOQUEADA si se exige desde primera versión, porque Identity no dispone de contrato de grant/revoke ni persistencia de permisos. La propuesta admin-inicial-only evita añadir ese alcance; no lo simula.
- Variante de ACL estricta operador–compañía: BLOQUEADA para activación si ese es el requisito de negocio. La aplicación documenta soporte compartido, no esa ACL; debe diseñarse por separado antes de afirmar aislamiento de operador.
- Consolidación que modifique vínculos: BLOQUEADA hasta ADR de sucesión y auditoría/reversión. El destino operativo fijo impide usar update actual para sustituir resourceId.
La política admin inicial, el modelo compartido y la privacidad son decisiones humanas de negocio. Las condiciones de SQL y pruebas son evidencias técnicas futuras que no se sustituyen por aprobación documental.
3. Decisiones diferidas
D08 consolidación con mutación; grants/revokes delegables; ocultación de un producto global por compañía; otras plantillas globales; campos de categoría/familia/identificador externo; historial público de producto; borrado físico global; vista transversal de uso de compañías. Se puede completar primera versión y R2.6 de coexistencia sin estas extensiones. No son funcionalidades prometidas ni migraciones ocultas de R2.1.
4. Riesgos críticos
- Ensanchar indiscriminadamente IResourceInventoryService.list permitiría destinos globales en remoto y afectaría consumidores operativos que no deben compartirlos. La matriz 06 fija cada propósito, incluido los que siguen solo locales.
- Crítico condicionado: confundir autenticación del espacio compartido con ACL por compañía. Si el despliegue requiere operadores aislados, el contrato de soporte compartido no satisface ese requisito.
- Autorizar al administrador global como bypass de pertenencia rompería integridad: incluso manager no puede vincular local B a instalación/perfil de A.
5. Riesgos altos
Mutaciones globales de plantillas hoy no restringidas; DTO/mapper no nullable y strict legacy; FKs compuestas/DDL con commit implícito; propagación que presupone companyId; actividad validada en otra transacción; exposición de notas/actores; clientes/caché desactualizados; vuelta a lectores que no entienden globales. Se exige serialización común conservadora, proyecciones distintas y activación controlada; no se atribuye probabilidad numérica ni se afirma vulnerabilidad explotada.
6. Dependencias y orden
R2.1a prepara lectores sin DDL → R2.1b expande esquema/backfill → R2.2 aporta seguridad/contratos/resolución en transacción → R2.3 catálogo → R2.4 software y R2.5 perfiles con lectores secundarios → R2.6 coexistencia/avisos. Activación de software y perfil puede separarse; compartir composición/contratos no fusiona agregados. El registro de relaciones tipadas y consumidores SMB/directorio/Access no adquiere ámbito global.
7. Condiciones para comenzar R2.1
Ratificar D01 y constatar D02 restringida, aceptar subetapas de lectores/DDL y alcance excluido, autorizar expresamente la implementación posterior y preparar baseline/test aislado. R2.1a puede prepararse sin cerrar grants ni UI; R2.1b necesita preflight SQL documentado y recuperación ensayada. No se necesita poblar producción ni tener catálogo global abierto.
8. Condiciones para habilitar globales
Todos los lectores/propagaciones/backend compatibles; esquema completo con CHECK/FKs ON y backfill íntegro; autorización global y política operador/contexto aprobadas; proyecciones/paths y privacidad aceptadas; pruebas de seguridad, serialización, idempotencia y recuperación pasadas; catálogo y UI con estados/teclado comprobados. Para asociaciones, además lectores operativos/históricos y clientes compatibles y flags específicos. El primer global ya impide downgrade trivial; las referencias globales obligan a mantener resolución aunque se apaguen flags.
9. Fuera del alcance de R2.0
Cualquier código funcional, schema/DTO existente modificado, migración/DDL, permiso concedido, componente/hook/i18n/dependencia/configuración de despliegue alterada, pruebas HTTP/BD, siembra, catálogo implementado, transferencia de recursos, licencias globales o consolidación ejecutada. Tampoco se ejecuta el plan de pruebas futuro ni se valida una UI inexistente en Playwright.
10. Ratificación humana necesaria
Ratificar los detalles de D01, D03, D04, D05, D06, D07, D09 y D10 según registro 02; D02 inicial y vetos de integridad ya están establecidos. D08 no requiere aprobar mutaciones para lanzar coexistencia: permanece diferida. Una aprobación posterior debe identificar versión del contrato, decisiones aceptadas y variantes rechazadas. No se registra aprobación por silencio, por tiempo transcurrido ni porque el asistente recomiende una opción.
Índice de los diez entregables
- Contrato arquitectónico e invariantes.
- Decisiones D01–D10 y correspondencia D04.
- Seguridad, privacidad y escenarios S01–S12.
- API, DTO, errores, búsqueda y UX.
- Persistencia, MariaDB y unidad de consistencia.
- Matrices completas de consumidores.
- Despliegue, compatibilidad y rollback.
- Pruebas e invariantes/riesgos trazados.
- Implementación R2.1–R2.6, alcance y aceptación.
- Este resumen para revisar/ratificar.
Evidencia y comprobación R2.0
Se leyeron íntegramente los doce documentos de auditoría y se contrastaron las decisiones con código actual. HEAD fa9d95fa9e227a66a45e278d98e2895d8a9995ad; Node v24.20.0 y PNPM 11.25.0 coinciden con package.json. Las 99 huellas de fuentes citadas por auditoría 12 coincidían al inicio; durante el trabajo se detectaron cambios concurrentes, con 97 iguales y dos fuentes web modificadas en la revisión de cierre. Estas dos modificaciones afectan búsqueda local (createTextMatcher), no ámbito/permisos/backend. Se releyeron y las anclas se recalcularon sobre el contenido actual; discrepancia C09 y contrato de búsqueda revisado en 01/04. No se atribuyen esos cambios a R2.0 ni se modifican. Se ampliaron lecturas de Identity/User/module, ambos builders/mappers, SQL/constraints, proyecciones y componentes/patrones compactos. Los conflictos documentales y diferencias temporales C01–C09 están resueltos expresamente en 01; no se sobrescribió la auditoría histórica.
Esta tarea solo escribe diez Markdown nuevos bajo esta carpeta y conserva íntegros los doce de auditoría. Otros cambios de código/documentación aparecidos en el árbol compartido son concurrentes y ajenos a esta entrega; se inspeccionan cuando afectan evidencia, sin editarlos ni revertirlos. Scripts de comprobación temporales en /tmp. No se ejecutaron pnpm typecheck/lint/test/check/build ni suites funcionales: no hay código cambiado y los resultados anteriores no se reutilizan como validación actual. No se conectó BD ni se ejecutaron migraciones, datos sintéticos o Playwright. Diseño/UI se apoya en normas y skills ya consultadas, sin auditores especializados ni certificación visual.
La comprobación documental debe validar enlaces/archivo/ancla de fuente, D01–D10, INV-01–INV-26 y T01–T26, escenarios y propósitos de matrices, operaciones de API, gates y alcance permitido de cada fase. Se conservan evidencias de símbolos en el apéndice siguiente para repetir la comprobación contra el árbol actual. Las referencias futuras de tipos/paths propuestas no se confunden con símbolos/rutas ya existentes.
Evidencias de código contrastadas
Todas las entradas son código existente; los nombres propuestos en 04 no se añaden a esta lista.
Fuentes documentales completas de la auditoría
| Fuente | SHA-256 al formalizar |
|---|---|
| 01-modelo-resource.md | d8dda2ac4e22351eb3be203da7331c9e1ade5f0975bd51ea94bc10b983b6f78b |
| 02-plantillas-aplicacion.md | 4be8cb2dba0fa8e54fdda7bff0ac83027b98f6d29aef5eadf27208eeb54d4e1c |
| 03-sequelize-mariadb.md | 2805772bc224be908cf82df775d93c907926573ca7d1d7cbd67b82cc70fb15f9 |
| 04-aislamiento-autorizacion.md | 562771079ce0fa35e798a93e43e7f6189381e12cd10b03ccbfd889a8f68f6053 |
| 05-consumidores-resource.md | 9deba084c334c2cbb79584a3f083bce313284641a9a737c6b42a952ebf3531be |
| 06-software-configuraciones.md | a900e206f30827829731973b427770019ad411e26afa19013386b39d76b3efe3 |
| 07-contratos-api.md | 5148d7494bee890ed519c07947d28533778e098a1cf65679c65a95537707df5d |
| 08-propuesta-ui-ux.md | d4162d5c2ceef6183658a901a31018e4070ea712df650de60ad05ef83f9ec5a9 |
| 09-alternativas-arquitectonicas.md | cf29fc96d801d658b31189b6379bca22afbaff610d528e09aaec7ec9ff09c11c |
| 10-plan-implementacion.md | 532387597f375c5daec91ffec4e4badb6b57c78b2e2eb4ae74327d390734a93d |
| 11-resumen-ejecutivo.md | 7df1095dd62e65ce654f685a924796cca0baaa4ef786e34ec0d34b27291f0bdc |
| 12-matriz-trazabilidad.md | 6030853b658bc9cf404e59f4e3e3471eb8bd6ffbd5678814b11e8a3597efae70 |
Resultado de comprobación documental
Correctos: 10 entregables, 224 enlaces locales (181 con línea), 69 anclas de símbolos, D01–D10 y los 26 invariantes con sus T01–T26. Los doce documentos de auditoría conservan sus huellas. Se ejecutaron comprobadores Python de existencia/anclas/cobertura y whitespace individual con git diff --no-index --check; git diff --check no reporta errores. La comparación con el baseline detectó cambios concurrentes en 27 archivos ya existentes y otros nuevos ajenos a esta tarea, conservados sin editarlos ni revertirlos. Esa comparación no se presenta como ausencia de cambios del resto del repositorio.
El siguiente comprobador es reproducible desde la raíz, solo lectura; no sustituye la revisión semántica de matrices/decisiones ni ejecuta tests futuros:
python3 - <<'PY'
from pathlib import Path
import hashlib
import re
import subprocess
base = Path('docs/architecture/resources-global-scope')
files = sorted(base.glob('*.md'))
assert len(files) == 10
links = 0
for file in files:
body = file.read_text()
assert chr(123) * 2 not in body and chr(125) * 2 not in body
assert body.count(chr(96) * 3) % 2 == 0
for target in re.findall(r'\]\(([^)]+)\)', body):
if target.startswith(('https://', 'http://')):
continue
name, _, anchor = target.partition('#')
source = (file.parent / name).resolve()
assert source.is_file(), target
if anchor.startswith('L'):
assert 1 <= int(anchor[1:]) <= len(source.read_text().splitlines())
links += 1
result = subprocess.run(['git', 'diff', '--no-index', '--check', '/dev/null', str(file)], capture_output=True, text=True)
assert result.returncode in (0, 1) and not result.stdout and not result.stderr
contract = (base / '01-contrato-arquitectonico.md').read_text()
tests = (base / '08-plan-pruebas.md').read_text()
decisions = (base / '02-decisiones-d01-d10.md').read_text()
for number in range(1, 27):
assert f'| INV-{number:02} |' in contract
assert f'| T{number:02} / INV-{number:02} |' in tests
for number in range(1, 11):
assert f'| D{number:02} |' in decisions
summary = (base / '10-resumen-para-aprobacion.md').read_text()
anchors = re.findall(r'^\| E-([^| ]+) \| \[([^]]+)\]\([^#]+#L(\d+)\) \| `([^`]+)` \|$', summary, re.M)
for key, name, line, token in anchors:
assert token.replace(' / ', '|') in Path(name).read_text().splitlines()[int(line)-1], key
sources = re.findall(r'^\| \[([^]]+\.md)\]\(../../auditorias/resources-global-scope/[^)]+\) \| `([a-f0-9]{64})` \|$', summary, re.M)
assert len(sources) == 12
for name, digest in sources:
assert hashlib.sha256((Path('docs/auditorias/resources-global-scope') / name).read_bytes()).hexdigest() == digest
print(f'OK: {len(files)} documentos, {links} enlaces, {len(anchors)} símbolos, 26 invariantes con pruebas y 12 fuentes intactas.')
PY