# Contrato de intento y confirmación de pasos

Estado del 2026-10-06: `Siru::Paso` cubre `IntegradorGLM` y el conductor compartido `Integrador` (RK/PGLM/ROS). Se conserva la política numérica de cada familia; se comparten aislamiento, límites y norma de error. El avance M1–M3 y lo pendiente figuran en [PLAN_CAPACIDADES_MOTOR.md](PLAN_CAPACIDADES_MOTOR.md).

## Inventario de las interfaces actuales

| Componente | Interfaz / responsabilidad actual | Decisión para este bloque |
| --- | --- | --- |
| `Integrador.pm` | `integrar`; tiempo, adaptación embebida/doble, predicción, rescates de convergencia, quiebres y callbacks | Migrado: candidato y confirmado separados; pruebas de rescates, dos medios pasos y cambios de configuración. |
| `IntegradorGLM.pm` | `integrar`; coeficientes, memoria GLM, anillo físico, quiebres y rearranques | Primer camino migrado: preparar candidato y confirmar todo junto. |
| `PGLM.pm` | Validación, lectura del descriptor y adaptación al conductor existente | Usa el contrato compartido; no se cambia la fórmula ni se habilita adaptación PGLM. |
| `ROS.pm` | Selección ROS2 y adaptador al conductor | Delega la fórmula a `EtapasROS`; conserva fallos fatales y error embebido directo. |
| `Campo.pm` / `CampoSensibilidad.pm` | Campo reducido y derivadas por diferencias o SENS | Reutilizados por `ServiciosNumericos`, que controla cachés del intento, factorización y costos. |
| `Calcula.pm` | Sesión persistente; EVAL, semillas, límite de iteraciones y SENS1 | Reutilizar el protocolo, comprobando aislamiento de peticiones con Calcula real. |
| `libdin` | Único armador; ecuaciones y descriptores | Contrato GLM v2 para la adaptación, con lectura v1 fija conservada. |

## Objeto y ciclo de vida

| Operación | Entrada / salida | Regla |
| --- | --- | --- |
| `preparar(estado => HASH, proveedor => POLITICA, ...)` | Crea una transacción con copia del estado inicial | Exige declarar la política del proveedor. |
| `intentar_paso(CODEREF)` | La función recibe una copia de lo confirmado y devuelve `{ estado => HASH, ... }`; retorna copia del candidato | No modifica el confirmado. Error/diagnóstico adicionales son datos del motor, no interpretados por la transacción. |
| `candidato` | Copia del resultado provisional | Solo mientras haya un intento pendiente. |
| `rama(CODEREF, conservar => BOOL)` | Compara desde el proveedor del comienzo del intento | Solo durante evaluación; por omisión restaura el proveedor del candidato principal. `conservar => 1` conserva el de la rama elegida, como los dos medios pasos RK. |
| `aceptar_paso` | Instala el estado candidato y devuelve una copia | Exactamente una aceptación por candidato. |
| `descartar_intento` | Descarta candidato, restaura proveedor si corresponde y devuelve copia del confirmado | No avanza tiempo, memoria ni contadores físicos. |
| `reiniciar(HASH)` | Sustituye explícitamente el estado confirmado | Solo sin intento pendiente y con proveedor utilizable; no borra costos acumulados. |
| `confirmado` | Copia del estado confirmado | No expone referencias mutables internas. |
| `estadisticas` | Copia de intentos, aceptados, descartados, fallos y reinicios | Los costos no se revierten al rechazar. |
| `fase` | `listo`, `evaluando`, `pendiente`, `restaurando` o `bloqueado` | Permite diagnóstico; impide reentradas y operaciones fuera de secuencia. |

Secuencia normal: `listo → evaluando → pendiente → aceptar/descartar → listo`. Si falla la evaluación o la validación del candidato, se restaura el proveedor cuando corresponde y se propaga el error. No se decide automáticamente que una excepción permita reducir el paso.

El estado y los metadatos admiten árboles de hashes, arreglos y escalares. Se rechazan ciclos, objetos, funciones y referencias de otros tipos: una sesión de Calcula no se puede copiar como si fuera memoria numérica. Los valores físicos y su finitud los valida el motor, como ya hacía GLM; la transacción valida estructura y aislamiento, no las ecuaciones.

Ejemplo esquemático, con un proveedor de evaluaciones independientes:

```perl
my $paso = Siru::Paso->preparar(
    proveedor => 'independiente',
    estado => { t => 0, memoria => [{ x => 1 }], numero_paso => 0 },
);
my $candidato = $paso->intentar_paso(sub {
    my ($base) = @_;
    # El motor calcula y valida una instantanea completa a partir de $base.
    return { estado => $nueva_instantanea, error => $error_estimado };
});
if ($candidato->{error} <= 1) {
    my $confirmado = $paso->aceptar_paso;
    # Publicar salidas/callbacks de aceptacion desde $confirmado.
} else {
    $paso->descartar_intento;
}
```

El controlador decide si acepta, qué error tolera y qué paso propone. No hay un estimador universal: RK, GLM y ROS aportan el suyo. `ControlPaso` comparte únicamente validación, norma ponderada y cálculo limitado del paso siguiente.

## Proveedores y efectos externos

| Política | Contrato | Tratamiento al descartar o fallar |
| --- | --- | --- |
| `independiente` | Cada evaluación restablece sus datos y semillas; su resultado no depende de una evaluación descartada | No requiere comandos de restauración. |
| `restaurable` | Debe suministrar `guardar => sub {...}` y `restaurar => sub {...}`; el respaldo es también un árbol de datos | Se captura antes del intento y se restaura al descartarlo o fallar. |

- Los callbacks de guardar/restaurar deben lanzar una excepción si fallan; su valor de retorno no es un código booleano de éxito. Guardar devuelve la instantánea del proveedor.
- Si guardar falla, no se ejecuta el motor y se bloquea la transacción: no existe un respaldo fiable. Si restaurar falla, tampoco se permite otro intento ni un reinicio que oculte el fallo. El diagnóstico conserva el error original y el de restauración.
- Aceptar conserva el estado que dejó el proveedor; en este primer contrato no hay callback externo de confirmación que pueda fallar a mitad del commit.
- `reiniciar` reemplaza solo la instantánea del integrador. El llamador debe establecer previamente el modelo/proveedor y sus condiciones consistentes; no habilita por sí mismo cambios de topología.
- La transacción no revierte archivos, mensajes, procesos ni efectos arbitrarios de closures. El motor no debe publicar salidas ni ejecutar callbacks de aceptación durante el intento.
- Un timeout, EOF o respuesta fuera de secuencia obliga al conductor a abandonar la sesión; la política independiente no significa que una conexión rota se pueda reutilizar. GLM sigue abortando ante fallos de consulta: solo reintenta por error temporal excesivo. RK conserva los rescates de `SOLVER FAILURE`, pero ni el intento sin semilla ni la subdivisión pueden ocultar un fallo fatal nuevo.
- Las comparaciones de una rama no dejan el proveedor en un punto ajeno al candidato aceptado. Si falla guardar/restaurar una rama, la transacción queda bloqueada; no se intenta disimularlo con otra restauración o un paso menor.

### Calcula dinámico

Se verificó en `machine.c` que `SEMILLAS` e `ITER` se restauran después de `intentar_punto`, tanto si converge como si falla. `modulodinamico_plus.c` inicializa cada pedido desde las semillas del `.din`, salvo las explícitas de ese pedido. GLM no envía semillas heredadas y declara ese proveedor independiente.

`tests/paso_calcula.t` comprueba el contrato con el sistema `x*x=a`, con semilla positiva: una consulta con semilla negativa produce la raíz negativa, se descarta y la siguiente vuelve a la positiva. También provoca una falla con semilla negativa e `ITER=1` y comprueba que la consulta siguiente vuelve a resolver, en el mismo proceso y sin heredar esas opciones. Esto no promete pureza para cualquier módulo externo o función con efectos laterales: un proveedor distinto debe justificar su política.

## Migración GLM

La instantánea contiene:

- Tiempo confirmado y número de paso.
- Anillo físico con estados, tiempos y pasos, más su cursor.
- Memoria externa GLM, conservando las derivadas sin escalar como antes.
- Quiebres pendientes, retorno a la grilla y contador de rearranques.

La selección del tamaño del paso, el consumo de quiebres, el cálculo de coeficientes, la consulta y la validación se ejecutan sobre el candidato. Solo después de validar también la memoria se confirma. La salida se escribe después de aceptar; un fallo de escritura sigue abortando la publicación del archivo completo, no deshaciendo un paso numérico ya aceptado.

Se mantienen los cuatro IDs, sus fórmulas, el último paso desigual y los rearranques alrededor de quiebres. El anillo físico usa `Siru::Historia` y puede tener capacidad distinta de la dimensión de memoria externa GLM. En adaptación, cada comparación trabaja con copias independientes de ambas historias: ni una mitad de prueba ni un intento rechazado llegan al confirmado. El estimador y sus límites se describen en [GLM_CONTRATO.md](GLM_CONTRATO.md); no habilita listas ni `.mdin`.

## Conductor compartido RK/PGLM/ROS

| Estado o efecto | Regla implementada |
| --- | --- |
| Instantánea | Tiempo, estado físico, historia del predictor, número de paso, paso propuesto, quiebres, retorno a grilla, parámetros y generación de configuración. |
| Dos medios pasos RK | Se acepta su solución y también su historia/semilla, no la del paso completo usado como comparación. |
| Predictor | La razón de extrapolación es paso solicitado / último paso aceptado, no último / penúltimo. |
| Configuración | Los callbacks iniciales se ejecutan una vez por paso físico, no por rechazo. Cambiar sesión, parámetros o estado invalida el predictor y reinicia en el extremo confirmado; se actualiza la lista de incógnitas. |
| Historia DC | Se conserva al iniciar si no hubo una transición real de configuración. |
| Convolución y salidas | Se conservan sus ganchos; no se confirman historia física ni filas de salida durante ensayos rechazados. |
| Fallos | ROS sigue abortando si falla campo/Jacobiano; RK mantiene su política de convergencia. No se clasifica cualquier excepción como recuperable. |
| Costos | Intentos, descartes y consultas, incluso fallidas/de comparación, no se revierten. `.informe` registra `estadisticas ultima integracion:`; ROS conserva `estadisticas ROS:`. No se presenta la última integración como agregado de RERUN/CONTINUE. |

La transacción no copia una sesión ni restaura por sí sola una topología. GLM sigue sin admitir cambios de modelo/topología; `reiniciar` es una operación de memoria, no un resolvedor de consistencia.

## Pruebas y alcance del cierre

| Prueba | Comprueba |
| --- | --- |
| `tests/paso.t` | Aislamiento de referencias, aceptación única, descarte/reintento, error del motor, bloqueo por restauración fallida, reinicio y costos acumulados. |
| `tests/paso_glm.t` | Uso real del contrato en GLM; recurrencia BDF2, error de consulta, memoria inválida, no publicación parcial y quiebres no consumidos al fallar. |
| `tests/paso_calcula.t` | Semillas y límite de iteraciones no contaminan consultas posteriores de Calcula real. |
| `tests/paso_integrador.t` | Historia y predictor correctos, rechazos, mitad fallida, cambio de sesión, rescates fijos, fallos fatales, ramas y proveedores restaurables. |
| `tests/glm_adaptativo.t`, `tests/glm_adaptativo_din.t` | Historia general, rechazos/rearranques, tolerancias, proveedor aislado, corrida desde fuente y `.din` autosuficiente, compatibilidad v1. |
| `tests/servicios_numericos.t` y suites ROS | Cachés, invalidación, varios segundos miembros, motor de etapas y conservación de ROS2. |
| Suites GLM/BDF2/quiebres existentes | Fórmulas, orden, casos dependientes del tiempo, circuito y ejecución fuente/din sin regresión. |
| Suite completa siru | Regresión conjunta, incluyendo llaves, convolución, DC, AC y análisis existentes. |

Comandos desde `siru`:

```sh
prove -Ilib tests/paso.t tests/paso_glm.t tests/paso_calcula.t
prove -Ilib tests/*.t
```

Verificación histórica del primer bloque (2026-10-04): 106 comprobaciones nuevas y 1087 en 32 archivos de la suite completa. Las pruebas con Calcula declaran omisión si no está compilado; en las verificaciones de esta ampliación se ejecutaron. La verificación actual se registra en el ChangeLog.

## Continuación

SPLIT usa el conductor transaccional compartido: cada subflujo recibe una copia del estado del anterior, pero sólo se confirma la composición completa. Un fallo no publica estados parciales ni avanza el reloj. Los costos de consultas/subavances se conservan aun si falla el intento. El alcance inicial es fijo y autónomo; no agrega rechazo adaptativo ni eventos entre subflujos. Ver `tests/split_nucleo.t` y `tests/split.t`.

1. Definir reinicio completo por modelo/topología antes de habilitar esos cambios en GLM. El reemplazo de una instantánea no calcula estados consistentes.
2. Ampliar historia y estimadores para otros órdenes y representaciones, sin cambiar las fórmulas ya verificadas.
3. Añadir servicios numéricos solo con capacidades explícitas; EVAL/SENS1 y LU densa no son una interfaz DAE/dispersa general.
4. Continuar por M4 (particiones/subflujos declarados), conservando este contrato y sus pruebas.
