> ## 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.

# Programmdienste

> Dienste, die den Kontozustand off-chain aus der festgeschriebenen Handelshistorie ableiten und das Ergebnis über Protokolltransaktionen zurück auf die Chain schreiben.

Manches, was ein Handelsplatz über ein Konto wissen muss, lässt sich nicht während der Blockausführung berechnen. Eine Volumenstufe hängt an dreißig Tagen Handel. Eine Prämie hängt an einem Zeitfenster, das noch nicht geschlossen ist. Eine Empfehlungszuordnung hängt an einer Beziehung, die vor Monaten entstanden ist.

Diese Arbeit in die Blockausführung zu verlagern, wäre gleich doppelt falsch: Jeder Block müsste für eine Berechnung zahlen, die fast kein Block braucht, und der Kernel müsste Historie mitführen, für die er sonst keinen Grund hat.

Programmdienste lösen das, indem sie die Richtung umkehren. Die Berechnung läuft **außerhalb** des Blocks, über den festgeschriebenen Datensatz. Ihr *Ergebnis* wird anschließend **zurück** auf die Chain geschrieben, als Protokollzustand, den die Ausführung wie jede andere Konfiguration in konstanter Zeit lesen kann.

<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">Festgeschriebene Handelshistorie</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">Programmdienst</span><span className="dg-s">Fensterberechnung, außerhalb des Blocks</span><span className="dg-n">liest die Gebührentabelle live von der Chain</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">Seit letzter Anwendung geändert?</span></div>
    <div className="dg-b" style={{left:"79.1667%",top:"2.8736%",width:"20.8333%",height:"13.7931%"}}><span className="dg-t">Nichts geschrieben</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">Protokolltransaktion</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">Chain-Zustand</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">Bei der Ausführung gelesen</span><span className="dg-s">in konstanter Zeit</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">Verglichen wird an Sätzen, nicht an Stufenpositionen</span><span className="dg-s">Eine verschobene Schwelle oder eine neu bepreiste Stufe ändert, was ein Konto zahlt, ohne seinen Stufenindex zu ändern.</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">Den endgültigen Satz löst die Chain auf</span><span className="dg-s">Eine Periode gilt erst als angewendet, wenn jeder Stapel festgeschrieben ist; ein Absturz wiederholt die ganze Periode – gefahrlos, weil die Berechnung idempotent ist.</span></div>
  </div>
</div>

Maßgeblich bleibt die Chain. Ein Dienst hält keinen Zustand, von dem das Netzwerk abhängt – er schlägt einen Wert vor, und real ist nur, was die Chain angenommen hat.

<h2 id="what-runs-today">
  Was heute läuft
</h2>

**Volumenbasierte Gebührenstufen.** Der Dienst konsumiert die Handelshistorie, die eine Node streamt, summiert das Volumen je Konto und legt nach Zeitplan Snapshots an. Schließt eine Periode, berechnet er für jedes Konto das Volumen im gleitenden Fenster, bildet es über die **live von der Chain gelesene** Gebührenkonfiguration ab und schreibt geänderte Konten in Stapeln zurück.

Mehrere Details in diesem Satz sind tragend:

* **Die Stufentabelle wird von der Chain gelesen, nie fest einprogrammiert.** Ein Dienst mit eigener Kopie würde weiter die gestrige Staffel anwenden, nachdem das Netzwerk sie geändert hat.
* **Verglichen wird mit den Sätzen, nicht mit den Stufenpositionen.** Ein Vergleich der Stufen*indizes* übersieht zwei reale Fälle: Eine Schwelle verschiebt sich, sodass ein unverändertes Konto in einer anderen Stufe landet, oder eine Stufe erhält einen neuen Satz, während ihr Index gleich bleibt. Beides ändert, was ein Konto zahlt; keines ändert seinen Index.
* **Den endgültigen Satz löst die Chain auf.** Die Transaktion enthält einen Stufenindex; die Ausführung löst ihn gegen die aktuelle Gebührenkonfiguration auf. Ein Stufenindex außerhalb des gültigen Bereichs lässt den gesamten Stapel scheitern, statt teilweise angewendet zu werden.
* **Eine Periode gilt erst als angewendet, wenn jeder Stapel festgeschrieben ist.** Ein Absturz mitten in der Periode führt zum Replay der ganzen Periode, was gefahrlos ist, weil die Berechnung idempotent ist – dasselbe Fenster liefert dasselbe Ergebnis.

<h2 id="the-failure-model">
  Das Fehlermodell
</h2>

Diese Dienste sitzen zwischen zwei Systemen, die beide zeitweise nicht verfügbar sein werden. Das Design setzt das voraus, statt es als Ausnahme zu behandeln.

Ausfälle von Abhängigkeiten – die Datenbank, der Stream der Node, die API der Node – werden mit Backoff wiederholt. Sie beenden den Prozess nicht, denn ein Neustart repariert keine unerreichbare Abhängigkeit; er fügt dem Ausfall nur einen Kaltstart hinzu. Fatal bleibt, was ein Neustart *beheben* kann oder was ein Betreiber sehen muss: ungültige Konfiguration beim Start, ein nicht bindbarer Health-Endpunkt und Panics.

Während eines Ausfalls läuft der Prozess weiter, meldet sich als nicht bereit und zählt Fehler. Das operative Signal lautet deshalb **„ist das seit N Minuten nicht bereit“** statt **„lebt der Prozess“** – und das ist die nützliche Frage, denn ein lebender Prozess, der seit einer Stunde nichts mehr aufnimmt, ist der eigentliche Vorfall.

Auf die Signale eines Orchestrators fährt der Dienst geordnet herunter: Die Arbeit stoppt, Checkpoints werden geschrieben, und der Prozess endet sauber. Ohne das würde jedes Routine-Deployment ein nicht geschriebenes Fenster und ein Replay kosten.

<Note>
  Eine berechnete, aber noch nicht angewendete Periode ist keine verlorene Periode. Weil die Berechnung idempotent ist und die angewendete Periode erst nach erfolgreichem Schreiben vermerkt wird, nimmt ein unterbrochener Lauf die Arbeit wieder auf, indem er das Fenster erneut rechnet, statt es zu überspringen.
</Note>

<h2 id="why-the-pattern-generalizes">
  Warum sich das Muster verallgemeinern lässt
</h2>

Der Rückschreibpfad ist generisch. Es gibt Protokolltransaktionen zum Setzen kontobezogener und zum Setzen globaler Konfiguration, und ein Programmdienst ist jeder Prozess, der aus festgeschriebener Historie einen Wert für eine davon berechnet.

Die Gebührenstufen sind der einzige laufende Dienst. Anreizprogramme, Empfehlungszuordnung und Kampagnenberechtigung hätten dieselbe Form: eine Fensterberechnung über die Handelshistorie, ein Abgleich gegen das aktuell Angewendete und ein gestapeltes Zurückschreiben. Sie gehörten hierher und nicht in den Kernel, aus demselben Grund wie die Gebührenstufen – die Berechnung ist periodisch und historisch, während die Ausführung die Antwort als Lookup in konstanter Zeit braucht. Keines davon ist gebaut; verallgemeinerbar ist das Muster, nicht die Zusage, dass sie es nutzen werden.

Die kommerziellen Konditionen dieser Programme stehen unter [Gebühren & Programme](/de/programs/fees). Diese Seite handelt davon, wie das Ergebnis auf die Chain gelangt.

<h2 id="where-to-go-next">
  Wie es weitergeht
</h2>

<CardGroup cols={2}>
  <Card title="Indexer" href="/de/protocol/architecture/indexer">
    Der Stream, den diese Dienste konsumieren.
  </Card>

  <Card title="Gebühren" href="/de/programs/fees">
    Die kommerzielle Seite: welche Stufen es gibt und was sie kosten.
  </Card>

  <Card title="IntentionKernel" href="/de/protocol/architecture/kernel">
    Wie zurückgeschriebene Konfiguration bei der Ausführung gelesen wird.
  </Card>

  <Card title="Zustandsmodell" href="/de/protocol/architecture/state/model">
    Warum Konfigurationsschlüssel versioniert sind und warum Clients sie live auflösen sollten.
  </Card>
</CardGroup>
