# Reintentos y conciliación — T12 ## Reintentos durables Los fallos TRANSIENT de READ_ONLY e IDEMPOTENT_WRITE se reencolan en RETRY_WAIT. La programación, el fallo del intento y RETRY_SCHEDULED se confirman juntos, con fencing y tiempo de PostgreSQL. No hay un sleep del worker ni una cola en memoria. La solicitud permanece ocupada y conserva estado/datos de negocio. La política publicada limita a tres intentos totales por acción (incluido el primero). Defaults: base exponencial 2 s/4 s, jitter entre 80 % y 120 %, limitado por maxBackoff. Se respeta Retry-After numérico o fecha HTTP, acotado a 120 s; valores inválidos se ignoran. El mayor de backoff con jitter y Retry-After define el retraso. Los checkpoints SUCCEEDED no se repiten y la clave externa executionId:actionId permanece estable. Al agotar intentos READ_ONLY sin escrituras pendientes se termina FAILED. Escrituras inciertas, incluyendo una IDEMPOTENT_WRITE agotada, mantienen RECONCILIATION_REQUIRED. Una operación NON_IDEMPOTENT_WRITE RUNNING al perder lease jamás se repite automáticamente; incluso una caída antes del envío exige conciliación si no existe prueba durable de ausencia de efecto. El límite de intentos no puede liberar esa incertidumbre. ## Resolución por operador POST /api/v1/admin/executions/{id}/resolve requiere: - FLOW_ADMIN_ENABLED=true y runtime DB restringido. - JWT válido, rol EXECUTION_OPERATOR, ámbito en ADMIN_BUSINESS_SCOPES y coincidente con la solicitud. El operador puede diferir de su propietario. - Idempotency-Key obligatorio y comando ReconciliationCommand del contrato. - Ejecución RECONCILIATION_REQUIRED para una resolución nueva. RESUME registra resultados verificados de acciones existentes y reencola PENDING. La salida debe cumplir el contrato/perfil fijado y el efecto del checkpoint debe coincidir con el catálogo confiable. No se permiten acciones inventadas, IDs duplicados, incertidumbres pendientes ni sobrescribir un checkpoint exitoso con otro resultado. Una acción ya exitosa puede incluirse únicamente con el mismo resultado; no vuelve a ejecutarse. No se inyectan resultados manuales de REGISTER_DOCUMENT: sus referencias deben provenir de la verificación documental. La solicitud debe conservar estado y revisión aceptados. CLOSE_WITHOUT_TRANSITION exige ABSENT_VERIFIED o COMPENSATED_VERIFIED y cierra FAILED sin transición, cambios de datos ni incremento de revisión. ABSENT_VERIFIED se rechaza cuando existe una escritura SUCCEEDED durable; en ese caso corresponde documentar compensación. La solicitud vuelve a admitir eventos. La evidencia exige reference y reason no vacíos. **La verificación la realiza el operador fuera del servicio**: estos campos son una declaración autorizada y auditada, no una consulta automática al proveedor. Usar una referencia a un caso verificable; no adjuntar documentos personales, JWT o secretos. Resolución, checkpoints, cola y EXECUTION_RESOLVED comparten transacción. El ledger es append-only. Idempotencia por executionId/clave; replay exige mismo comando canónico y mismo sujeto operador, y conserva respuesta original incluso tras completar la ejecución. Otro comando u operador con esa clave recibe 409. Dos operadores con claves distintas no pueden aplicar simultáneamente dos resoluciones nuevas. La resolución incrementa fencing_token. No existe campo para elegir un estado destino. El worker continúa aplicando la definición publicada y confirma la transición de forma normal. ## Pruebas RetryPolicyTest cubre límites y parsing. RetryReconciliationIT usa HTTP/JWT, PostgreSQL real y triggers de fallos de auditoría. CrashWorkerProcess es una JVM exclusiva de test que termina con Runtime.halt antes/después de llamar a un mock HTTP: el proceso padre reconstruye el worker y recupera desde DB. El mock registra un efecto lógico por clave; no acredita idempotencia de un proveedor real. WorkerIT conserva las pruebas de lease vencido, worker obsoleto, fallo después del checkpoint y rollback de confirmación final. HttpIntegrationIT ahora espera RETRY_WAIT en timeout/503 y FAILED en salida inválida. Ejecutar mvnw.cmd clean verify -Pmigration-tests-external con MIGRATION_TEST_DB_* en el proceso y base orquestador_test. Sin ese perfil se requiere Docker para Testcontainers. No se despliega ni se utiliza un proveedor real.