> ## Documentation Index
> Fetch the complete documentation index at: https://docs.intention.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Servicios de programa

> Servicios que derivan el estado de las cuentas a partir del historial de operaciones confirmado, fuera del bloque, y confirman el resultado de vuelta en la cadena mediante transacciones de protocolo.

Hay cosas que un exchange necesita saber sobre una cuenta y que no se pueden calcular mientras se ejecuta un bloque. Un nivel por volumen depende de treinta días de trading. Una recompensa depende de una ventana que aún no se ha cerrado. Una atribución de referido depende de una relación establecida hace meses.

Meter ese trabajo dentro de la ejecución del bloque sería un error por partida doble: haría que todos los bloques pagaran por un cálculo que casi ningún bloque necesita, y obligaría al kernel a cargar con un historial que no tiene ninguna otra razón para guardar.

Los servicios de programa lo resuelven invirtiendo la dirección. El cálculo se ejecuta **fuera** del bloque, sobre el registro confirmado. Su *resultado* se confirma después **de vuelta** en la cadena como estado de protocolo, donde la ejecución puede leerlo en tiempo constante como cualquier otra configuración.

<div className="dg" data-dg="program-writeback">
  <div className="dg-c" style={{aspectRatio:"720 / 348"}}>
    <svg className="dg-w" viewBox="0 0 720 348" aria-hidden="true">
      <path className="dg-wire" d="M 144.00 70.00 L 169.60 70.00" />

      <path className="dg-head" d="M 176.00 70.00 L 169.60 74.40 L 169.60 65.60 Z" />

      <path className="dg-wire dg--sky" d="M 344.00 70.00 L 369.60 70.00" />

      <path className="dg-head dg--sky" d="M 376.00 70.00 L 369.60 74.40 L 369.60 65.60 Z" />

      <path className="dg-wire" d="M 534.00 70.00 L 561.75 38.78" />

      <path className="dg-head" d="M 566.00 34.00 L 565.04 41.71 L 558.46 35.86 Z" />

      <path className="dg-wire dg--blue" d="M 534.00 70.00 L 561.33 95.62" />

      <path className="dg-head dg--blue" d="M 566.00 100.00 L 558.32 98.83 L 564.34 92.41 Z" />

      <path className="dg-wire dg--blue" d="M 645.00 128.00 L 645.00 136.00 L 465.00 136.00 L 465.00 142.00" />

      <path className="dg-head dg--blue" d="M 465.00 142.00 L 460.60 135.60 L 469.40 135.60 Z" />

      <path className="dg-wire dg--green" d="M 554.00 181.00 L 567.60 181.00" />

      <path className="dg-head dg--green" d="M 574.00 181.00 L 567.60 185.40 L 567.60 176.60 Z" />
    </svg>

    <div className="dg-b" style={{left:"0.0000%",top:"11.4943%",width:"19.4444%",height:"17.2414%"}}><span className="dg-t">Historial confirmado de operaciones</span></div>
    <div className="dg-b dg--sky" style={{left:"25.0000%",top:"5.7471%",width:"22.2222%",height:"28.7356%"}}><span className="dg-t">Servicio de programa</span><span className="dg-s">cálculo por ventanas, fuera del bloque</span><span className="dg-n">lee las comisiones en vivo desde la cadena</span></div>
    <div className="dg-b dg--yellow dg-round" style={{left:"52.7778%",top:"10.3448%",width:"20.8333%",height:"19.5402%"}}><span className="dg-t">¿Cambió desde lo aplicado?</span></div>
    <div className="dg-b" style={{left:"79.1667%",top:"2.8736%",width:"20.8333%",height:"13.7931%"}}><span className="dg-t">No se escribe nada</span></div>
    <div className="dg-b dg--blue" style={{left:"79.1667%",top:"21.8391%",width:"20.8333%",height:"13.7931%"}}><span className="dg-t">Transacción de protocolo</span></div>
    <div className="dg-b dg--green" style={{left:"52.7778%",top:"41.9540%",width:"23.6111%",height:"20.1149%"}}><span className="dg-t">Estado de la cadena</span></div>
    <div className="dg-b dg--green" style={{left:"80.2778%",top:"41.9540%",width:"19.7222%",height:"20.1149%"}}><span className="dg-t">Se lee al ejecutar</span><span className="dg-s">en tiempo constante</span></div>
    <div className="dg-b dg-dashed dg-left" style={{left:"0.0000%",top:"70.1149%",width:"48.8889%",height:"24.1379%"}}><span className="dg-t">Se compara por comisiones, no por nivel</span><span className="dg-s">Un umbral que se mueve, o un nivel al que se cambia el precio, altera lo que paga una cuenta sin cambiar su índice de nivel.</span></div>
    <div className="dg-b dg-dashed dg-left" style={{left:"51.1111%",top:"70.1149%",width:"48.8889%",height:"24.1379%"}}><span className="dg-t">La cadena resuelve la comisión final</span><span className="dg-s">Un periodo se registra como aplicado solo tras confirmarse todos los lotes; una caída reejecuta el periodo entero, y es seguro porque el cálculo es idempotente.</span></div>
  </div>
</div>

La cadena sigue siendo la autoridad. Un servicio no guarda estado del que dependa la red: propone un valor, y solo lo que la cadena aceptó es real.

<h2 id="what-runs-today">
  Qué funciona hoy
</h2>

**Niveles de comisiones por volumen.** El servicio consume el historial de operaciones que un nodo transmite, acumula el volumen por cuenta y toma instantáneas según un calendario. Cuando un periodo se cierra, calcula el volumen de la ventana móvil de cada cuenta, lo mapea contra la configuración de comisiones **leída en vivo desde la cadena** y escribe de vuelta por lotes las cuentas que cambiaron.

Varios detalles de esa frase son estructurales:

* **La tabla de niveles se lee de la cadena, nunca está codificada en el servicio.** Un servicio que guardara su propia copia seguiría aplicando el esquema de ayer después de que la red lo cambiara.
* **La comparación se hace contra las comisiones, no contra la posición en la tabla de niveles.** Comparar *índices* de nivel deja fuera dos casos reales: que un umbral se mueva y una cuenta sin cambios acabe en otro nivel, y que se cambie el precio de un nivel mientras su índice sigue igual. Ambos cambian lo que paga una cuenta; ninguno cambia su índice.
* **La cadena resuelve la comisión final.** La transacción lleva un índice de nivel; la ejecución lo resuelve contra la configuración de comisiones vigente. Un índice de nivel fuera del rango válido hace fallar el lote entero en lugar de aplicarse parcialmente.
* **Un periodo se registra como aplicado solo después de que todos los lotes se confirmen.** Una caída a mitad de un periodo hace que se reejecute el periodo entero, lo cual es seguro porque el cálculo es idempotente: la misma ventana produce el mismo resultado.

<h2 id="the-failure-model">
  El modelo de fallos
</h2>

Estos servicios se sitúan entre dos sistemas que, cada uno por su lado, a veces no estarán disponibles. El diseño lo da por supuesto en lugar de tratarlo como algo excepcional.

Los fallos de dependencias (la base de datos, el flujo del nodo, la API del nodo) se reintentan con espera creciente (backoff). No terminan el proceso, porque reiniciar no arregla una dependencia inalcanzable; solo añade un arranque en frío a la interrupción. Lo que sigue siendo fatal es aquello que un reinicio *sí* puede arreglar o que un operador tiene que ver: configuración inválida al arrancar, no poder abrir el endpoint de salud, y los panics.

Durante una interrupción el proceso sigue vivo, se declara no listo y cuenta los errores. La señal operativa útil es por tanto **“¿lleva esto N minutos sin estar listo?”** y no **“¿está vivo el proceso?”**, porque un proceso vivo que lleva una hora sin poder ingerir datos es el incidente de verdad.

El apagado es ordenado ante las señales que envía un orquestador: el trabajo se detiene, los puntos de control se vuelcan y el proceso termina limpiamente. Sin eso, cada despliegue rutinario costaría una ventana sin volcar y una reejecución.

<Note>
  Un periodo que se ha calculado pero aún no se ha aplicado no es un periodo perdido. Como el cálculo es idempotente y el periodo aplicado se registra solo después de que la escritura tenga éxito, una ejecución interrumpida se reanuda rehaciendo la ventana en lugar de saltársela.
</Note>

<h2 id="why-the-pattern-generalizes">
  Por qué el patrón generaliza
</h2>

La ruta de escritura de vuelta es genérica. Existen transacciones de protocolo para fijar configuración a nivel de cuenta y para fijar configuración global, y un servicio de programa es cualquier proceso que calcule un valor para alguna de ellas a partir del historial confirmado.

Los niveles de comisiones son el único que está en marcha. Los programas de incentivos, la atribución de referidos y la elegibilidad para campañas tendrían la misma forma: un cálculo por ventanas sobre el historial de operaciones, una comparación contra lo que está aplicado ahora mismo y una escritura de vuelta por lotes. Pertenecerían aquí y no al kernel por la misma razón que los niveles de comisiones: el cálculo es periódico e histórico, mientras que la ejecución necesita que la respuesta sea una consulta en tiempo constante. Ninguno está construido; lo que generaliza es el patrón, no un compromiso de que vayan a usarlo.

Las condiciones comerciales de estos programas viven en [Comisiones y programas](/es/programs/fees). Esta página trata de cómo el resultado llega a la cadena.

<h2 id="where-to-go-next">
  Qué leer a continuación
</h2>

<CardGroup cols={2}>
  <Card title="Indexador" href="/es/protocol/architecture/indexer">
    El flujo que consumen estos servicios.
  </Card>

  <Card title="Comisiones" href="/es/programs/fees">
    El lado comercial: cuáles son los niveles y cuánto cuestan.
  </Card>

  <Card title="IntentionKernel" href="/es/protocol/architecture/kernel">
    Cómo se lee durante la ejecución la configuración escrita de vuelta.
  </Card>

  <Card title="Modelo de estado" href="/es/protocol/architecture/state/model">
    Por qué las claves de configuración están versionadas y por qué los clientes deberían resolverlas en vivo.
  </Card>
</CardGroup>
