519 lines
40 KiB
Markdown
519 lines
40 KiB
Markdown
# Decisiones técnicas
|
||
|
||
## ADR-001 — Base reproducible (2026-10-26)
|
||
|
||
Estado: verificada para T01 con compilación JDK 21 y smoke de salud contra server02; ver ADR-004 y evidencia E09 en PROGRESS. Pruebas de persistencia e integración completas corresponden a tareas posteriores.
|
||
|
||
| Componente | Selección | Motivo |
|
||
|---|---|---|
|
||
| Java | 21, `release=21`, Enforcer `[21,22)` | Versión requerida por la especificación |
|
||
| Spring Boot / BOM | 4.1.2 / spring-boot-dependencies 4.1.2 | Release estable verificada en documentación oficial y Maven Central; compatible con Java 21 |
|
||
| Maven | 3.9.12 | Wrapper oficial con distribución fija |
|
||
| Maven Wrapper | 3.3.4, only-script | Scripts oficiales, sin JAR de wrapper en el repositorio |
|
||
| PostgreSQL | 17.11-bookworm | Major 17 requerido y parche fijo; imagen pendiente de pull/verificación con Docker |
|
||
| JUnit | 5.13.4 | Mantener JUnit 5 requerido; sobrescribir junit-jupiter.version del BOM |
|
||
| Surefire / Failsafe | 3.5.4 | Separar pruebas unitarias de integración; verify ejecuta ambas |
|
||
| Maven Enforcer | 3.6.2 | Fallar explícitamente si el JDK no es 21 |
|
||
|
||
MVC, Security, Hibernate, Flyway, JDBC PostgreSQL y demás dependencias se resuelven desde el BOM fijado. No declarar versiones dinámicas ni snapshots de dependencias. `0.1.0-SNAPSHOT` es la versión de desarrollo de este proyecto, no una dependencia externa.
|
||
|
||
Spring Boot 4 usa starters modulares: `webmvc`, `security-oauth2-resource-server` y `flyway`. No se añade `springdoc` hasta validar compatibilidad en T02. OpenAPI será contractual. Testcontainers y servidor de mocks se fijarán y verificarán al incorporarse en T03/T11. No adoptar automáticamente dependencias de test de Boot que cambien JUnit 5; comprobar integración con Spring Test al introducirla.
|
||
|
||
Fuentes consultadas el 2026-10-26:
|
||
|
||
- [Requisitos oficiales de Spring Boot](https://docs.spring.io/spring-boot/system-requirements.html).
|
||
- [Dependencias gestionadas](https://docs.spring.io/spring-boot/appendix/dependency-versions/coordinates.html).
|
||
- [POM publicado de Boot 4.1.2](https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/4.1.2/spring-boot-starter-parent-4.1.2.pom).
|
||
- [PostgreSQL: descargas y release 17.11](https://www.postgresql.org/download/).
|
||
|
||
Alternativa: Boot 3.5, compatible con Java 21, pero se prefiere la línea estable actual para un proyecto nuevo. No cambia la semántica del motor. La compatibilidad de bibliotecas futuras se verificará antes de incorporarlas.
|
||
|
||
## ADR-002 — Alcance de esta entrega
|
||
|
||
El pedido actual comprende arquetipo, plan y seguimiento. Se prepara T01 y se documenta T02–T17; no se implementan anticipadamente el dominio, contratos incompletos ni endpoints con respuestas simuladas. Las tareas se cierran con sus verificaciones, no por existencia de carpetas.
|
||
|
||
La configuración local conserva JWT y exige parámetros externos. No se incluye issuer falso ni contraseña predeterminada. El Compose actual es exclusivamente de desarrollo; no es un despliegue productivo.
|
||
|
||
## ADR-003 — Docker del servicio con PostgreSQL externo (2026-10-26)
|
||
|
||
Por instrucción expresa del usuario se adelanta el empaquetado del arquetipo: Compose contiene sólo orquestador y sustituye el anterior servicio PostgreSQL. No administra base ni volúmenes externos. T17 no se considera terminado: la demo integral sigue pendiente de sus dependencias.
|
||
|
||
Dockerfile multietapa con Temurin 21.0.12.1_1 (JDK para construir, JRE para ejecutar), tags verificados en el [catálogo oficial](https://github.com/docker-library/official-images/blob/master/library/eclipse-temurin). Runtime no root y healthcheck de readiness. Maven Wrapper construye con package y ejecuta pruebas unitarias; verify con integración permanece en CI. El contexto permite sólo fuentes, POM y Wrapper; excluye .env, target y archivos del IDE.
|
||
|
||
Compose exige DB_URL/usuario/contraseña y parámetros JWT, conserva el puerto interno 8080 y publica localhost:8080 por defecto. Se incluye host-gateway para PostgreSQL en el anfitrión. La construcción y conexión real están pendientes de un entorno Docker y valores externos. Referencias: [build multietapa](https://docs.docker.com/build/building/multi-stage/) e [interpolación de Compose](https://docs.docker.com/compose/how-tos/environment-variables/variable-interpolation/).
|
||
|
||
## ADR-004 — Cierre verificable de T01 con despliegue en la red local (2026-10-26)
|
||
|
||
El servicio ya está desplegado por el usuario en server02:8787 con PostgreSQL externo. Se interpreta el health local de T01 como comprobación del entorno de desarrollo en esa red, sin requerir duplicar el despliegue en el equipo del agente. La compilación se realiza localmente con Temurin JDK 21 oficial, descargado a .tools y validado por SHA256 del proveedor; no se modifica el Java del sistema.
|
||
|
||
El perfil explícito deployment-smoke ejecuta cinco pruebas Failsafe de sólo lectura contra una URL obligatoria: health, readiness, liveness, rechazo sin token y rechazo con token malformado. No se omiten errores de conectividad ni pruebas fallidas. Se preservan los patrones normales de integración *IT, IT* y *ITCase al activar el perfil.
|
||
|
||
El build de T01 y la salud del despliegue se verifican por separado: no se afirma que el JAR recién generado haya sido desplegado ni se acredita el runtime remoto por una respuesta health. No se redepliega el servidor ni se accede directamente a sus credenciales o base. Testcontainers, migraciones, JWT válido/roles y A01–A20 siguen pendientes; este smoke no los sustituye. CI no depende de server02: el perfil requiere activación explícita fuera del build normal.
|
||
|
||
## ADR-005 — Contratos T02: REST y DSL v1 (2026-10-26)
|
||
|
||
Estado: implementado como contrato y pruebas, no como endpoints. OpenAPI 3.1.0 y JSON Schema 2020-12 en archivos separados con referencias relativas locales. No se incorpora springdoc: la documentación contractual es independiente de Boot y no habilita rutas administrativas antes de T07.
|
||
|
||
Se concreta lo no detallado por la especificación sin cambiar idempotencia, aislamiento de versiones ni autorización:
|
||
|
||
- Rutas fijas usan to/outcome; rutas calculadas usan decision/destinations, con el output de decisión como resultado de negocio. EXISTS usa value.path; NOT usa arg; AND/OR usan args. Mappings admiten exactamente path o literal.
|
||
- dataSchema e initialDataSchema permiten describir datos finales/entrada inicial. Borradores y ejemplo mínimo original pueden omitirlos estructuralmente; publicación T06 exige dataSchema de objeto. InitialDataSchema ausente utiliza dataSchema. No se confunde validez estructural con publicación válida.
|
||
- Schemas embebidos limitan el vocabulario a validación declarativa y no admiten referencias externas. Se conservan boolean schemas y combinadores. Se rechazan propiedades desconocidas de DSL/DTOs; datos configurables requieren segunda validación contra su schema de evento/flujo. Rechazo de JSON con claves duplicadas precede validación.
|
||
- JSON Pointer de updates es relativo a request.data. Restricciones de identidad/ACL permanecen fuera de ese espacio. Publicación verifica destinos solapados y schemas resultantes; runtime verifica tipos/ambigüedad. Estas comprobaciones no se simulan en T02.
|
||
- Publicar y retirar exigen If-Match adicional al exigido por eventos/edición/activación. Esto concreta su concurrencia y evita operar sobre una revisión diferente a la revisada. Alta de request_type se provisionará por migración/configuración en T03/T06; activar uno inexistente devuelve 404.
|
||
- Conciliación acepta RESUME con evidencia y resultados verificados por acción, o CLOSE_WITHOUT_TRANSITION con ausencia/compensación comprobada. Prohíbe escoger destino. RESUME reencola PENDING; cierre marca FAILED sin cambiar negocio. Idempotencia durable, autorización por scope y evidencia verificada son requisitos para T12.
|
||
- Replays de creación devuelven 201 con la misma identidad; eventos devuelven 202 con executionId estable y status actual. Los errores tienen code/correlationId; fechas UTC Z, opcionales omitidos, cursor opaco máximo 100.
|
||
- Se fijan techos estructurales auxiliares: 500 eventos/decisiones/tareas, 100 roles por transición, 200 updates, reintentos máximo 3 y tamaño documental máximo 100 MiB en DSL. Los límites operativos podrán ser menores; los 1 MiB/256 KiB y límites AST de la especificación requieren control adicional antes/durante deserialización en T06/T09.
|
||
|
||
Herramientas fijadas, únicamente scope test: networknt json-schema-validator 1.5.9 (2020-12 con format assertions) y swagger-parser-v3 2.1.35 (OpenAPI 3.1). Jackson 2 de estas herramientas convive sólo en tests con Jackson 3 del runtime Boot 4.1.2. Se comprobó compatibilidad mediante clean verify con Java 21.
|
||
|
||
Se conserva una copia del schema oficial OpenAPI 3.1 (2022-10-07), SHA256 DA01BA28852CAC0DE53893797CB8D1942BC3B05084F526DCC216717DEC314ED0, para validar sin red. Swagger Parser con resolve=true intentó expandir indefinidamente las referencias recursivas del AST: se usa resolve=false y comprobación explícita de todos los $ref locales. Networknt valida los schemas y ejemplos reales. No se relajan límites ni se ignoran referencias rotas para resolver esa incompatibilidad.
|
||
|
||
Referencias: [OpenAPI 3.1](https://spec.openapis.org/oas/v3.1.0), [schema oficial](https://spec.openapis.org/oas/3.1/schema/2022-10-07), [networknt](https://github.com/networknt/json-schema-validator), [Swagger Parser y soporte 3.1](https://github.com/swagger-api/swagger-parser). Detalles de uso en contracts/README.md y schemas/README.md.
|
||
|
||
## ADR-006 — Compatibilidad con PostgreSQL disponible (2026-10-26)
|
||
|
||
El usuario solicita adaptar la conexión al PostgreSQL existente, identificado por JDBC como 9.6.2 en server02:30432/orquestador. Esta instrucción sustituye el requisito de PostgreSQL 17 para el entorno actual. La especificación original permanece como antecedente; las migraciones de T03 deberán ser compatibles con 9.6 (incluidas las formas de DDL de triggers), sin cambiar semántica de locking, idempotencia o seguridad.
|
||
|
||
Se añade hibernate-community-dialects 7.4.13.Final, alineado al BOM/core, y application-postgres96.yaml con PostgreSQLLegacyDialect. Compose activa postgres96 por defecto y permite elegir otro perfil explícito. Spring Boot/Java/JDBC/Flyway no se degradan. Se preservan ddl-auto=validate, Flyway habilitado y clean-disabled en runtime; no se modifica JWT. .env.example contiene parámetros públicos de conexión, nunca la contraseña.
|
||
|
||
Flyway 12.4.0 inspeccionado admite desde PostgreSQL 9.0 y la validación real sobre 9.6.2 pasó; registra que 9.6 queda fuera del soporte comunitario Redgate. El dialecto legacy pertenece al módulo comunitario de Hibernate, no al conjunto de dialectos actuales soportados. Esta adaptación no promete soporte oficial para la combinación ni prueba todavía consultas de entidades/migraciones del motor.
|
||
|
||
Verificación: clean verify con Java 21 (92 tests) y postgres96-check (1 prueba de integración compuesta). La prueba inicia el servicio local con pool read-only, Flyway automático desactivado, SQL init desactivado y validación Hibernate; después invoca exclusivamente Flyway.validate() con createSchemas=false. No ejecuta migrate/create/clean ni modifica la instancia externa. La primera propuesta de arranque fue rechazada por la revisión automática por riesgo de migraciones; se usó esta alternativa explícitamente de sólo lectura, aprobada y ejecutada.
|
||
|
||
Fuentes: [dialectos y módulo comunitario Hibernate](https://docs.hibernate.org/stable/core/dialect/), [versiones de bases de datos Flyway](https://documentation.red-gate.com/fd/supported-databases-and-versions-143754067.html). La compatibilidad se comprobó con las dependencias reales del proyecto, no sólo con la documentación.
|
||
|
||
## ADR-007 — Modelo persistente y pruebas aisladas T03 (2026-10-26)
|
||
|
||
Decisión: implementar V1/V2 compatibles con PostgreSQL 9.6 y usar el esquema
|
||
orchestrator para tablas e historial Flyway. El arquetipo anterior no tenía
|
||
migraciones de negocio; si un entorno contiene historial real en public, requiere
|
||
un traslado explícito antes de actualizar, nunca baseline/repair automático.
|
||
Separar credenciales del migrador y runtime mediante DB_MIGRATION_*; conservar
|
||
fallback a DB_* para el entorno de desarrollo existente. Los roles se provisionan
|
||
externamente y grant_runtime_access concede permisos a un rol existente.
|
||
|
||
La ausencia de Docker local se resuelve ejecutando las mismas pruebas sobre la
|
||
base orquestador_test cuya creación confirmó el usuario. Cada ejecución crea y
|
||
elimina su esquema t03_<UUID>, sin tocar orquestador ni esquemas compartidos. La
|
||
prueba de permisos crea un rol NOLOGIN y revierte su transacción. La ruta normal
|
||
permanece en Testcontainers postgres:9.6.24 para CI; no se ejecutó localmente por
|
||
falta de Docker. La evidencia real corresponde a PostgreSQL 9.6.2 externo.
|
||
|
||
Se rechazó usar H2 o cerrar por compilación: se probaron FKs, JSONB, historial
|
||
inmutable, permisos, migraciones desde cero, rollback de DDL, una carrera real de
|
||
inserciones y FOR UPDATE SKIP LOCKED con conexiones independientes. Los triggers
|
||
protegen integridad de almacenamiento; T06/T09/T10/T12 aún deben implementar
|
||
validación semántica, auditoría de negocio, aceptación, fencing y conciliación.
|
||
No se cambian contratos REST ni se declaran cumplidos A01–A20 por estas pruebas.
|
||
|
||
## ADR-008 — Contratos internos inmutables (2026-10-26)
|
||
|
||
T04 utiliza records y variantes selladas de Java 21. Se elige una representación
|
||
JSON propia e inmutable con BigDecimal, NullValue explícito y Lookup.Missing
|
||
separado, en lugar de exponer JsonNode mutable o Map<String,Object> en los puertos.
|
||
Esto mantiene snapshots confiables y permite compilar dominio/puertos sin librerías
|
||
externas. Los adapters futuros deberán convertir JSON y persistencia explícitamente.
|
||
|
||
FlowDefinition modela configuración; FlowVersion modela su metadata persistida.
|
||
Las identidades FlowId/RequestId/ExecutionId/ActionExecutionId impiden intercambios
|
||
accidentales de UUID. Rutas, AST y acciones son variantes tipadas; estados/eventos
|
||
siguen siendo claves configurables. El catálogo confiable aporta clasificación
|
||
de efectos por separado, nunca mediante configuración editable del flujo.
|
||
|
||
Errores técnicos y resultados de negocio tienen variantes distintas. Los puertos
|
||
mínimos se declaran sin implementaciones simuladas; T05/T06/T11 implementarán sus
|
||
comportamientos. El DTO de validación convierte el modelo al contrato publicado
|
||
sin exponer detalles internos. No se modifican DSL, OpenAPI, SQL, idempotencia,
|
||
versionado o política de autorización. Pruebas de arquitectura y de esquema
|
||
protegen estas fronteras. Ver DOMAIN_MODEL.md para invariantes y límites.
|
||
|
||
## ADR-009 — Evaluación pura y presupuestos de AST/datos (2026-10-26)
|
||
|
||
T05 implementa el puerto sin dependencias externas ni evaluación de expresiones
|
||
libres. Los once operadores usan JSON tipado; BigDecimal.compareTo evita coerción
|
||
y diferencias por escala. La ausencia es un error salvo EXISTS; null solo participa
|
||
en EQ/NEQ. Se concreta igualdad estructural para arrays/objetos y homogeneidad total
|
||
de IN, sin ocultar tipos inválidos tras una coincidencia temprana.
|
||
|
||
El preflight iterativo limita la definición completa antes de aplicar cortocircuito:
|
||
profundidad 20 y 1000 nodos, incluyendo expresiones path/literal. Los límites pueden
|
||
reducirse por construcción. Se limita además IN a maxNodes elementos y la igualdad
|
||
estructural a maxNodes pares por comparación, para no recorrer datos arbitrariamente
|
||
grandes aunque el AST tenga pocas hojas. Exceso retorna EVALUATION_ERROR. Esta
|
||
restricción operativa queda explícita y no cambia schemas/SQL ni admite un default
|
||
como sustituto de un error. Límites de bytes de recepción quedan en T06/T09.
|
||
|
||
Alternativas descartadas: recursión durante validación de profundidad (podría
|
||
desbordar antes del rechazo), validación solo de ramas ejecutadas (permitiría omitir
|
||
límites), igualdad BigDecimal.equals (depende de escala), coerciones y evaluación
|
||
arbitraria de scripts. IntervalOverlapAnalyzer analiza solo intervalos simples;
|
||
la ambigüedad UNIQUE sigue comprobándose al ejecutar. No promete resolver SAT.
|
||
|
||
La evaluación conserva IDs de reglas para auditoría futura y snapshots intactos.
|
||
No se modifican las reglas de idempotencia, seguridad ni versionado. Detalle de
|
||
operadores, alcance de A04–A06 y conteo de límites: DECISION_EVALUATOR.md.
|
||
|
||
## ADR-010 — Publicación transaccional y exposición administrativa (2026-10-26)
|
||
|
||
T06 implementa un servicio interno de administración y un catálogo inmutable
|
||
proporcionado por el despliegue. No incluye controladores ni un catálogo ficticio
|
||
predeterminado. Aunque A16 menciona API, su evidencia en esta fase se obtiene en
|
||
la API Java de aplicación y en PostgreSQL; las rutas REST y la comprobación JWT
|
||
se realizan en T07/T16. Esta secuencia resuelve la exigencia explícita de seguridad
|
||
antes de exposición; no se da por aprobada la prueba HTTP que aún no existe.
|
||
|
||
Desviación del uso propuesto de JPA para agregados: las operaciones administrativas
|
||
se implementan con el JDBC ya incluido en el stack y TransactionTemplate, detrás
|
||
de FlowStore. El motivo es mantener explícitos los bloqueos flujo/tipo, revalidación
|
||
de referencias, JSON canónico y auditoría en una única transacción sin flush implícito.
|
||
Alternativa: entidades JPA más queries nativas y control manual de flush; añade dos
|
||
modelos de escritura al mismo protocolo sin una necesidad actual. No se elimina JPA
|
||
ni se reemplaza el stack; otros agregados podrán usarlo sin cambiar los contratos.
|
||
|
||
Activación y asignación bloquean flujo antes que tipo; retiro sigue ese orden y
|
||
limpia solo referencias que todavía apuntan a la versión. Incrementa revision de
|
||
los tipos desactivados y audita sus claves. Instancias existentes permanecen fijadas.
|
||
T08 debe completar creación/idempotencia/auditoría en la misma transacción; el puerto
|
||
no debe usarse como lectura desconectada seguida de una inserción posterior.
|
||
|
||
La canonicalización es propia, determinista, con objetos ordenados, arrays ordenados
|
||
y números BigDecimal normalizados; no se anuncia RFC 8785. Defaults y contratos se
|
||
resuelven antes del hash. Entradas iniciales/de evento cerradas y protección de rutas
|
||
escritas desde results impiden confiar en campos de proveedor recibidos del cliente.
|
||
La validación estática de tipos no sustituye validación de valores en runtime.
|
||
|
||
networknt 1.5.9 se reutiliza en runtime, con Jackson 2 aislado en infraestructura.
|
||
Schemas se empaquetan desde los archivos contractuales existentes. No cambian las
|
||
migraciones, idempotencia ni credenciales. Las pruebas reales usan exclusivamente
|
||
orquestador_test y esquemas temporales propios conforme a la autorización vigente.
|
||
Detalles, límites y protocolos: FLOW_PUBLICATION.md.
|
||
|
||
## ADR-011 — Identidad y autorización T07 (2026-10-27)
|
||
|
||
Aceptado para implementación local verificable. JWT RS256 validado por JWKS, issuer,
|
||
audience y exp; sub y un ámbito de negocio único son obligatorios. Se toma
|
||
business_scope por defecto, configurable con JWT_BUSINESS_SCOPE_CLAIM mientras se
|
||
confirma el claim real de controlms. OAuth scope no sustituye el ámbito ni concede
|
||
roles. Se admiten roles del realm y del cliente identificado por JWT_AUDIENCE.
|
||
Alternativa descartada: confiar en actor/scope enviados en el comando o usar la
|
||
clave pública estática sin posibilidad de actualización por JWKS.
|
||
|
||
Los recursos exigen propietario Y ámbito, con 404 para ausencia o acceso ajeno.
|
||
No existe bypass implícito FLOW_ADMIN. EXECUTION_OPERATOR tiene una puerta separada
|
||
de conciliación dentro de su ámbito, sin requerir ser propietario; la operación
|
||
funcional y evidencia permanecen en T12. Alternativa descartada: cualquier usuario
|
||
del ámbito puede acceder a todas las solicitudes, pues ampliaría acceso sin una
|
||
regla de negocio explícita.
|
||
|
||
El catálogo de flujos/tipos es global según el modelo actual. Su administración
|
||
requiere rol técnico y un ámbito en ADMIN_BUSINESS_SCOPES, lista vacía por defecto.
|
||
No se inventa tenancy para flow_definition. FLOW_ADMIN_ENABLED=false conserva las
|
||
rutas cerradas hasta que el operador configure catálogo, ámbito y credenciales DB
|
||
separadas. Con administración habilitada, un verificador rechaza al runtime elevado
|
||
y permisos de mutación de historiales; Flyway usa su propio usuario propietario.
|
||
No se cambia automáticamente la cuenta pgadmin existente ni permisos globales.
|
||
|
||
Las seis operaciones administrativas T06 se exponen en T07. Simulación sigue pendiente
|
||
para T14 y conciliación para T12. A15 se verifica con la puerta de autorización real,
|
||
JWT firmado, recursos persistidos y un controlador exclusivo de test no distribuido;
|
||
las rutas funcionales posteriores deben reutilizarla y T16 repetirá la aceptación
|
||
integral. A16 se comprueba ahora por HTTP. Detalles: SECURITY.md.
|
||
|
||
## ADR-012 — Creación idempotente y snapshot T08 (2026-10-27)
|
||
|
||
La clave de creación se particiona por sujeto/ámbito y el hash incluye typeKey/data
|
||
canónicos, usando la semántica numérica T06. Se serializa con advisory lock
|
||
transaccional PostgreSQL de 64 bits y búsqueda/restricción única por identidad
|
||
completa. Una colisión del lock no mezcla identidades, solo retrasa transacciones.
|
||
Alternativas: mutex JVM (no protege varias instancias), reserva anticipada de ledger
|
||
(exigiría respuesta/solicitud incompletas o una migración adicional) e intentar insertar
|
||
sin serializar (recuperación de conflicto más compleja después de abortar transacción).
|
||
|
||
La respuesta original queda durable en el ledger y se reproduce con 201/Location/ETag
|
||
originales; GET devuelve el estado actual. Se verifica acceso actual antes del replay.
|
||
La resolución de activo y validación por schema ocurren después de comprobar replay,
|
||
para que cambios posteriores de catálogo no invaliden una creación ya aceptada. La
|
||
clave distinta de contenido produce IDEMPOTENCY_CONFLICT. Fallos no consumen la clave.
|
||
|
||
Solicitud, REQUEST_CREATED y ledger se guardan en una transacción READ COMMITTED,
|
||
con una misma DataSource que FlowStore. Se conserva orden flujo/tipo de T06. El cambio
|
||
de activo detectado durante asignación retorna 409 INVALID_FLOW_STATE reintentable,
|
||
sin registro parcial. El aislamiento de usuario/scope se aplica a cada consulta.
|
||
|
||
Se extiende el adapter JDBC tras puertos de aplicación puros, en continuidad con
|
||
ADR-010, para compartir bloqueos, JSONB y commit con FlowStore. No se añade JPA para
|
||
un segundo modelo de escritura del mismo protocolo ni se altera el stack existente.
|
||
No hay nuevas migraciones: V1/V2 ya contienen ledger, FKs, auditoría y permisos.
|
||
|
||
REQUEST_API_ENABLED es independiente de administración. Ambos requieren runtime DB
|
||
restringido; PersistenceAccessConfiguration factoriza este guard y los puertos comunes.
|
||
Creación exige identidad JWT válida, sin inventar rol nuevo ni ACL por tipo; los roles
|
||
de negocio se revalidan en eventos T09. Ver REQUESTS.md y contrato actualizado.
|
||
|
||
## ADR-013 — Aceptación durable y revisión T09 (2026-10-27)
|
||
|
||
Se mantiene el protocolo de la sección 8.1: bloquear solicitud autorizada, buscar
|
||
idempotencia antes de revisión, validar transición/rol/schema/guardia, insertar
|
||
PENDING, incrementar revisión y auditar en una transacción READ COMMITTED. El índice
|
||
único de ejecución activa y la clave request_id/idempotency_key existentes son
|
||
respaldo SQL; no hay mutex en memoria ni HTTP externo dentro de aceptación.
|
||
|
||
accepted_revision guarda la revisión posterior a aceptación, If-Match + 1. El
|
||
worker deberá comparar esa revisión al confirmar; no es una revisión adicional
|
||
independiente. Hash SHA-256 de evento/data/revisión esperada canónicos, con misma
|
||
semántica decimal de T06/T08. El replay verifica acceso actual y actor original,
|
||
retorna status actual y no vuelve a exigir el rol/guardia de la aceptación previa:
|
||
no está autorizando un nuevo efecto. Otra revisión esperada con la misma clave
|
||
es otro comando y produce IDEMPOTENCY_CONFLICT.
|
||
|
||
La definición se lee por flow_id fijado, incluyendo RETIRED, sin bloquear el flujo
|
||
ni consultar el tipo activo. No se altera estado/data de negocio al aceptar. Guardias
|
||
usan results vacío y los snapshots confiables de solicitud/evento/actor; errores de
|
||
evaluación no se convierten a false. No se guarda JWT completo, solo atributos
|
||
necesarios de identidad. Persistencia JDBC tras puertos puros continúa ADR-010/012.
|
||
|
||
Alternativas descartadas: procesar acciones antes del 202 (mezcla transacción/HTTP),
|
||
revalidar revisión antes del replay (rompe reintento perdido), devolver un éxito de
|
||
negocio al aceptar y almacenar tokens para reintentos. No hay migración nueva:
|
||
V1/V2 cubren tabla, índices, FKs, permisos e inmutabilidad de auditoría.
|
||
|
||
Location conserva el contrato de ejecución; su consulta GET se incorpora como
|
||
subtarea explícita T10 para seguimiento del worker. En T09 solo se implementa POST
|
||
de aceptación y GET de solicitud T08 permite ver activeExecutionId; no se anuncia
|
||
procesamiento ni consulta de ejecución implementados. Ver EVENTS.md.
|
||
|
||
## ADR-014 — Worker, fencing y recuperación inicial T10 (2026-10-27)
|
||
|
||
WorkerStore reclama PENDING/RETRY_WAIT vencidos y RUNNING expirados con SKIP LOCKED,
|
||
tiempo DB y token creciente. Los executors locales solo despachan capacidad libre;
|
||
PostgreSQL conserva cola, leases y checkpoints. Toda mutación exige owner/token
|
||
vigentes; checkpoints bloquean ejecución, finalización/fallo bloquean solicitud y
|
||
luego ejecución. Se comprueban revisión/estado al cargar y al confirmar. Nunca se
|
||
mantiene una transacción abierta mientras el adapter ejecuta una acción.
|
||
|
||
V3 agrega effect al checkpoint, obtenido del adapter confiable y comparado al
|
||
reutilizarlo. Alternativa descartada: inferir seguridad desde el JSON editable o
|
||
suponer que un checkpoint antiguo era read-only. Los anteriores reciben clasificación
|
||
conservadora NON_IDEMPOTENT_WRITE. Hash/clave/effect son consistentes entre reintentos.
|
||
RUNNING/UNKNOWN no idempotentes requieren conciliación. Éxitos se reutilizan; cambios
|
||
de hash/effect se rechazan. Escrituras previas/potenciales impiden liberar como FAILED.
|
||
|
||
El procesamiento secuencial resuelve inputs, valida contratos, guarda checkpoint,
|
||
evalúa decisiones y aplica updates sobre copia. Commit final incluye datos/estado,
|
||
revisión, resultado y auditoría con reglas/acciones. Errores DB conservan leases y
|
||
checkpoints para recuperar; no se transforman en éxito o en liberación incierta.
|
||
JSON Pointer permite actualizar objetos y posiciones existentes de arrays, sin
|
||
crear arrays dispersos. Se valida schema/256 KiB antes de confirmar. No hay claims
|
||
de exactly-once externo; la clave executionId:actionId solo funciona si el proveedor
|
||
respeta su contrato de idempotencia.
|
||
|
||
WORKER_ENABLED independiente de API/admin, deshabilitado por defecto. Registro
|
||
productivo sin adapters hasta T11: ausencia produce INTEGRATION_UNAVAILABLE, nunca
|
||
mock de éxito. Flujos sin acciones ya pueden completarse. T12 conserva la política
|
||
completa de retry/backoff/Retry-After/conciliación; T10 implementa recuperación de
|
||
caídas y reconoce RETRY_WAIT existente. TechnicalFailure se termina de manera segura
|
||
sin anunciar retry HTTP aún. GET de ejecución ya se implementa con owner/scope y
|
||
proyección de respuesta, resolviendo la subtarea agregada en ADR-013.
|
||
|
||
Pruebas: PostgreSQL real, dos reclamantes, checkpoints, retorno tardío y heartbeats;
|
||
adapters exclusivamente de test. SimulatedCrash y reconstrucción de repositorio no
|
||
se presentan como reinicio de JVM. WORKER.md documenta configuración y límites.
|
||
|
||
## ADR-015 — T11: transporte acotado y contratos de despliegue (2026-10-27)
|
||
|
||
Se conserva Spring Boot y sus beans, usando HttpClient del JDK 21 dentro del
|
||
adapter HTTP en lugar del cliente Spring propuesto en la especificación. Motivo:
|
||
controlar cancelación y límite de bytes antes de acumular una respuesta, además
|
||
de un deadline que incluya el cuerpo completo. No se agrega otra librería.
|
||
Alternativas: cliente Spring síncrono con lectura InputStream (requiere controlar
|
||
por separado el deadline de lectura) o WebClient (agrega stack reactivo).
|
||
La API BodySubscriber documenta cuándo se completa el cuerpo y cómo cancelar la
|
||
suscripción: [documentación JDK 21](https://docs.oracle.com/en/java/javase/21/docs/api/java.net.http/java/net/http/HttpResponse.BodySubscriber.html).
|
||
BoundedHttp usa un subscriber limitado y espera finita del futuro; las pruebas
|
||
incluyen headers inmediatos con cuerpo demorado y payload excesivo.
|
||
|
||
La ruta es configuración confiable, ligada a tupla exacta de contrato/perfil.
|
||
No hay URLs, secretos ni selección de métodos HTTP en el DSL. El protocolo local
|
||
propuesto usa POST JSON y bearer opcional por referencia a variable de entorno.
|
||
No se inventa compatibilidad con proveedores existentes: ejemplos y mocks
|
||
definen el contrato que deberá confirmarse o adaptarse antes de habilitar rutas.
|
||
Nuevas versiones conviven; no cambiar el significado de una versión usada.
|
||
|
||
REGISTER_DOCUMENT usa DOCUMENTS_METADATA/1 como protocolo fijo del handler,
|
||
porque el DSL de esta acción no tiene campos de versión. Cambiar ese protocolo
|
||
requiere versionar el handler/DSL mediante otra decisión, nunca seguir un default
|
||
mutable. Guarda referencia y checkpoint juntos bajo fencing. Su efecto remoto es
|
||
READ_ONLY; el registro local es idempotente y no sube archivos. T13 completa la
|
||
exposición documental. NO_OP permanece solo en simulación.
|
||
|
||
A03 se divide explícitamente: T11 acredita transporte, clasificación y ausencia
|
||
de falsos negativos; T12 implementa programación de reintentos/backoff/Retry-After.
|
||
No se anuncia A03 integral terminado hasta T12/T16. No cambian las claves
|
||
idempotentes, versiones publicadas o autorización. Compose conserva un servicio
|
||
y PostgreSQL externo; sin despliegue ni llamadas reales.
|
||
|
||
## ADR-016 — T12: reintento durable y resolución atómica (2026-10-27)
|
||
|
||
Se programa RETRY_WAIT con reloj PostgreSQL en la misma transacción que el estado
|
||
del intento y RETRY_SCHEDULED, bajo fencing. No se duerme dentro del worker ni de
|
||
una transacción. Se conserva el límite publicado por acción, máximo tres intentos
|
||
totales; backoff exponencial con jitter 80–120 %, limitado por maxBackoff, y
|
||
Retry-After numérico/fecha HTTP con techo de 120 s.
|
||
|
||
READ_ONLY e IDEMPOTENT_WRITE pueden reintentarse tras fallo transitorio. UNKNOWN y
|
||
RUNNING recuperado de NON_IDEMPOTENT_WRITE se concilian antes de evaluar agotamiento:
|
||
alcanzar el límite no demuestra ausencia de efecto. Un intento FAILED de escritura
|
||
idempotente agotada también conserva incertidumbre. Un resultado normalizado
|
||
negativo sigue siendo SUCCEEDED. Claves externas, hashes de entrada y versiones
|
||
publicadas no cambian. El hint Retry-After se añade al resultado técnico interno,
|
||
sin alterar el contrato público de ejecución.
|
||
|
||
La evidencia de resolve es una declaración del operador autorizado con referencia
|
||
y razón; no existe servicio real configurado para verificarla automáticamente.
|
||
No fabricar una consulta de estado ni afirmar verificación remota. El operador
|
||
EXECUTION_OPERATOR accede por ámbito, incluso si no es propietario; además requiere
|
||
el interruptor administrativo y ADMIN_BUSINESS_SCOPES existentes.
|
||
|
||
RESUME valida contratos fijados, efectos persistidos y cobertura de todos los
|
||
checkpoints no exitosos. No crea acciones no iniciadas, cambia resultados exitosos
|
||
ni inserta referencias documentales manuales. Reencola PENDING; el worker decide
|
||
el destino con el flujo publicado. CLOSE_WITHOUT_TRANSITION conserva negocio y
|
||
exige declaración ABSENT_VERIFIED/COMPENSATED_VERIFIED; ausencia contradicha por
|
||
una escritura SUCCEEDED durable se rechaza. No se agregan cambios de estado manuales.
|
||
|
||
Se bloquea solicitud antes que ejecución. Checkpoints, ledger append-only,
|
||
auditoría y reencolado/cierre son atómicos; el fencing_token aumenta al resolver.
|
||
Replay se busca antes de comprobar estado actual, exige mismo comando canónico y
|
||
sujeto operador, y devuelve respuesta original. Otro sujeto con igual clave no
|
||
hereda el replay. El esquema V1 ya soporta esta semántica: no se necesita migración.
|
||
API informa 409 para estado no conciliable y 412 si se detecta revisión/estado
|
||
de solicitud incoherentes al reanudar; OpenAPI refleja ambas respuestas.
|
||
|
||
Alternativas descartadas: reintentar toda la transición (duplica efectos previos),
|
||
liberar al agotar intentos sin considerar escrituras (pierde incertidumbre) y
|
||
permitir seleccionar destino desde resolve (evade reglas publicadas). La prueba
|
||
de caída usa una JVM hija real terminada con Runtime.halt; proveedor HTTP sintético
|
||
con efecto lógico por clave. No prueba un proveedor real ni un despliegue productivo.
|
||
|
||
## ADR-017 — T13: disponibilidad orientativa y límites documentales publicados (2026-10-27)
|
||
|
||
available-events es una proyección de backend del flujo fijado a la solicitud.
|
||
No se implementa interfaz gráfica. Una sentencia SQL obtiene revisión, estado,
|
||
datos, definición inmutable y ejecución activa en el mismo snapshot MVCC; no se
|
||
bloquean filas ni se consulta disponibilidad de proveedores. Se conserva acceso
|
||
por propietario/ámbito, sin bypass FLOW_ADMIN, y se omiten transiciones de otros roles.
|
||
|
||
Con ejecución activa se ocultan todos los eventos y metadatos. Guardias que solo
|
||
usan solicitud/actor se evalúan; falso y error se proyectan como códigos genéricos.
|
||
Guardias con cualquier dependencia de event.data se difieren completas al POST.
|
||
Evaluarlas con un objeto vacío produciría falsos bloqueos, especialmente en
|
||
EXISTS/NOT. No se promete que un evento anunciado será aceptado: POST revalida
|
||
revisión, rol, guardia, estado e inactividad.
|
||
|
||
No-store y ausencia de ETag en available-events: roles y estado técnico pueden
|
||
cambiar sin variar revision. Un ETag basado solo en revisión podría producir un
|
||
304 incorrecto. Se devuelve revision en el cuerpo para la precondición del POST.
|
||
No se cambia el contrato/ETag de GET de solicitud.
|
||
|
||
DocumentMetadata extrae la verificación pura existente de T11. Se mantiene la
|
||
autoridad del servicio documental para MIME real/checksum/antimalware, sin descargar
|
||
archivos ni simular éxito productivo. El worker ahora verifica también MIME/tamaño
|
||
del DOCUMENT_UPLOAD publicado antes de guardar referencia/checkpoint y al
|
||
reutilizarlo. T11 aplicaba únicamente el límite general del catálogo; esto cerraba
|
||
insuficientemente tareas que anunciaban restricciones más estrictas. Se aplican
|
||
ambas políticas, no se amplía la autorización.
|
||
|
||
El fixture documental separa documentId de entrada y registeredDocumentId verificado,
|
||
con validation protegida como salida del proveedor. No se relaja la regla de
|
||
publicación que impide escribir resultados desde datos del cliente. Los enums
|
||
status/scanStatus del catálogo de ejemplo agregan type:string explícito para el
|
||
análisis estático; sus valores aceptados no cambian.
|
||
|
||
INVALID de DOCUMENTO_VALIDA conserva tarea/estado con razón mapeada a datos de
|
||
solicitud. Fallo técnico conserva los datos previos y sigue T12, sin fabricar
|
||
INVALID. Referencias y checkpoints conservan atomicidad/fencing T11; no se agrega
|
||
tabla ni endpoint de subida/descarga de archivos. Compose mantiene solo el servicio
|
||
con PostgreSQL externo. Proveedor documental real y antivirus real siguen fuera
|
||
de la evidencia local con mocks.
|
||
|
||
## ADR-018 — Demostración por configuración y segundo tipo (2026-10-28)
|
||
|
||
T14 entrega crédito v1/v2 y compra v1 como definiciones completas, sin modificar
|
||
src/main ni columnas. Se amplía solo el catálogo de ejemplo con INE/ESTADO_CUENTA
|
||
versión 1; LICENCIA_CONDUCIR ya existe. Todos los contratos y perfiles quedan
|
||
explícitos en JSON. Límites documentales: 5 MiB y MIME según catálogo/tarea.
|
||
|
||
La especificación no define políticas de compra. El ejemplo usa consulta de cliente
|
||
y confirmación booleana, con finales confirmada/cancelada; no cobra ni reserva.
|
||
Alternativa descartada: inventar una integración de pagos o reglas comerciales.
|
||
Crédito exige una referencia de consentimiento; no afirma validar consentimiento
|
||
real. Los cuatro proveedores HTTP son fixtures sintéticos exclusivos de pruebas;
|
||
no se empaquetan en el servicio ni se activa configuración de demo por defecto.
|
||
|
||
Se verifica la demo mediante API operativa y worker, con esquema temporal PostgreSQL,
|
||
en vez de presentar una simulación como recorrido persistente. El endpoint puro
|
||
/admin/flows/{id}/simulate sigue pendiente (anotado desde T07); no forma parte de
|
||
la evidencia A10/A18 ni se declara implementado. Se registra explícitamente para
|
||
la revisión integral T16 antes de la entrega final T17.
|
||
|
||
## ADR-019 — Historial y observabilidad operativa (2026-10-28)
|
||
|
||
El historial se proyecta desde audit_entry append-only con keyset (created_at,id),
|
||
límite 100 y filtros kind/execution/from/to. ResourceAccess autoriza propietario y
|
||
ámbito en cada página, sin bypass administrativo. El cursor codifica posición y
|
||
huella de solicitud/filtros; no es un token de acceso ni una firma criptográfica.
|
||
Se elige estabilidad entre reinicios/réplicas sin añadir secretos para una posición
|
||
que no amplía acceso. Alternativa: cursores firmados; no aporta autorización al
|
||
recurso y exige rotación compartida. Navegación no promete snapshot ante commits
|
||
concurrentes tardíos. La consulta tiene timeout SQL de 5 s.
|
||
|
||
Se entrega lista permitida de detail; evidencia de conciliación y payloads no se
|
||
proyectan. Nuevas transiciones agregan reasonCodes presentes en resultados verificados
|
||
a la misma escritura auditada; no se alteran auditorías existentes. Actor se entrega
|
||
al propietario autorizado. Sin nueva migración ni modificación de semántica de
|
||
idempotencia/versiones. Retención no borra datos sin política de organización.
|
||
|
||
Actuator metrics se habilita y protege con EXECUTION_OPERATOR + ámbito de operación
|
||
configurado, independiente de edición de flujos. Otros actuators se deniegan salvo
|
||
salud. Micrometer ya transitivo: sin dependencia nueva, Prometheus o servicio extra.
|
||
Contadores de comandos describen respuestas HTTP incluyendo replays; no representan
|
||
exactamente commits nuevos. Timers usan integrationKey confiable y resultado fijo;
|
||
estados DB son gauges agregados sin IDs/sujetos/ámbitos, con muestra compartida de
|
||
5 s y timeout SQL 3 s. Fallos dan available=0 y NaN, nunca un cero de cola ficticio.
|
||
|
||
Logs propios usan campos permitidos y códigos; decisiones/razones quedan en auditoría.
|
||
Un log de acción exitosa no equivale a commit; phase=committed se emite después del
|
||
commit durable. Correlación HTTP queda ligada a executionId por EVENT_ACCEPTED.
|
||
WorkerShutdown amplía el drenaje existente con presupuesto configurable 1–20 s y
|
||
espera adicional de 1 s tras interrupción. Mantiene renovaciones durante el drenaje,
|
||
fencing/checkpoints y recuperación de incertidumbre. No se afirma cancelar efectos
|
||
externos no cooperativos ni probar Docker productivo mediante fixtures locales.
|
||
|
||
## ADR-020 — Simulación y evidencia ejecutable de aceptación (2026-10-28)
|
||
|
||
T16 cierra el endpoint de simulación pendiente desde T07. SimulationController exige
|
||
la seguridad administrativa existente; actor/results del body son fixtures. Se lee
|
||
el flujo y se libera el lock antes de evaluar. FlowSimulation no depende de HTTP,
|
||
secretos, worker actions o puertos de escritura. Valida schemas, versiones/perfiles,
|
||
roles/guardias y mappings; NO_OP usa output configurado solo en simulación.
|
||
|
||
Se extrae mecánicamente la proyección final del worker a TransitionEvaluator,
|
||
compartiendo decisiones/updates/validación final/reglas y razones. Alternativa
|
||
rechazada: duplicar el evaluador en el endpoint, con riesgo de divergencia. La
|
||
extracción no modifica idempotencia, leases, efectos, transacciones o semántica
|
||
numérica. Simulación permite draft ambiguo para devolver AMBIGUOUS_DECISION, pero
|
||
publicación conserva su validación estricta. No crea auditoría ni registros de
|
||
negocio; es evaluación de fixtures, no evidencia de proveedor/documento real.
|
||
|
||
acceptance-cases.json liga A01–A20 a métodos concretos. verify_acceptance.py inspecciona
|
||
XML real y falla por ausencia/error/skip; registra entorno y hashes. CI exige
|
||
Testcontainers y conserva artefactos 30 días. FailIfNoTests se habilita en ambos
|
||
plugins Maven. No se cambian versiones de stack ni se incorporan librerías nuevas.
|
||
|
||
Docker no fue localizado en PATH, servicio o instalación estándar de este equipo.
|
||
Se solicitó un motor autorizado mientras se completa verificación con orquestador_test.
|
||
Una corrida externa aprobada no se rotula Docker ni satisface su criterio: T16 no
|
||
puede declararse DONE hasta verificar Testcontainers o una modificación explícita
|
||
del criterio por el usuario. CI configurado tampoco equivale a CI ejecutado.
|