Ein Data Contract ist eine versionierte, erzwungene Vereinbarung über einen Feed: sein Schema, die Bedeutung jedes Felds, Freshness- und Null-Erwartungen, zulässige Wertebereiche und seinen Owner. In einer Finance-KI-Pipeline sitzt er dort, wo der Feed in deinen Kontrollbereich eintritt, und schlägt laut fehl, sobald die Realität von der Vereinbarung abweicht – damit eine Änderung drei Teams weiter upstream nicht klammheimlich ein Produktionsmodell vergiften kann.
Das Versagen, das er verhindert, ist konkret und weit verbreitet. Ein Anbieter benennt eine Spalte um, wechselt einen Währungscode von ISO-Alpha auf numerisch oder fängt an, Preise als Strings mit Tausendertrennzeichen zu senden. Nichts wirft einen Fehler. Der Load-Job läuft durch, der Feature-Job läuft durch, das Modell scored. Zwei Wochen später bemerkt jemand, dass die False-Positive-Rate eines Screening-Modells gestiegen ist, oder dass eine Exposure-Zahl in einem Report um einen Faktor danebenliegt, den niemand erklären kann. Bis dahin sitzen die fehlerhaften Werte in deinem Feature Store, in deinen Eval-Sets und wahrscheinlich in ein paar Entscheidungen, die du nicht mehr rückgängig machen kannst. Das Teure ist selten die Ausfallzeit. Es sind die Tage, die man damit verbringt, nachzuweisen, welches von vierzig Upstream-Feldern sich wann verändert hat.
Was ein Contract tatsächlich enthält
Ein Schema sagt dir, dass ein Feld settlement_amount heißt und ein Decimal ist. Das ist der einfache Teil, und dort tut Finanzdaten dir nicht weh. Der Schaden lebt in der Semantik und im Timing, deshalb muss der Contract mehr abdecken als die Form.
- Bedeutung, nicht nur Typ.
priceist bedeutungslos, ohne zu wissen, ob es clean oder dirty ist, mid oder last-trade, in welcher Währung und pro welche Menge. Wir schreiben das als Assertions auf Feldebene fest und weisen Zeilen zurück, die dagegen verstoßen. - Freshness und Vollständigkeit. Ein Feed, der normalerweise 30 Sekunden hinterherhinkt und plötzlich sechs Stunden veraltet ist, ist kaputt – auch wenn jeder Wert wohlgeformt ist. Der Contract legt den erwarteten Lag und die erwartete Zeilenzahl pro Fenster fest, und ein Defizit lässt die Prüfung fehlschlagen.
- Wertebereichs- und Referenzregeln. Währungscodes müssen aus einer bekannten Menge stammen. Instrumentenkennungen müssen sich gegen den Security Master auflösen lassen. Eine negative Menge auf einem Feed, der niemals Shorts führt, ist ein Defekt, kein Datenpunkt.
- Point-in-Time-Semantik. Für jedes Feld, das restated wird, hält der Contract fest, ob ein Wert final oder vorläufig ist, und verbietet ein stilles Überschreiben der Historie. Das ist der Teil, der dich vor Lookahead schützt: Wenn eine restated Zahl klammheimlich ersetzen kann, was zum Entscheidungsdatum als-of galt, ist dein Backtest Fiktion.
- Ein Owner und eine Version. Jeder Contract benennt einen Menschen oder ein Team, das für Änderungen verantwortlich ist, und eine Versionsnummer. Breaking Changes erfordern einen Version-Bump – und genau das ist der Haken, an dem der Rest des Systems hängt.
An der Grenze erzwingen und Brüche laut machen
Die Regel, an der wir festhalten: Validiere einen Feed in dem Moment, in dem er in deinen Kontrollbereich eintritt, bevor auch nur ein einziges Feature ihn liest. Schiebst du das Enforcement downstream, untersuchst du den Patienten erst, nachdem sich die Infektion ausgebreitet hat. Fängst du es beim Ingest ab, ist der Blast Radius ein Feed an einem Tag.
Konkret heißt das: eine Validierungsstufe zwischen Raw Landing und allem, was deine Modelle berühren. Sie prüft eingehende Batches oder Messages gegen den Contract und leitet Fehler in eine Quarantäne statt in die Haupttabelle. Ein Batch in Quarantäne verschwindet nicht stillschweigend und geht auch nicht stillschweigend durch. Er hält die betroffene Partition an und alarmiert den Owner mit exakt der Assertion, die fehlgeschlagen ist, plus drei Beispielzeilen, die sie gebrochen haben. Der Punkt ist, eine Contract-Verletzung genauso sichtbar zu machen wie einen fehlgeschlagenen Unit-Test – denn genau das ist sie.
Zwei Design-Entscheidungen zählen hier. Erstens: Unterscheide zwischen einem Hard Stop und einem Soft Flag. Ein Währungscode, den du noch nie gesehen hast, ist ein Hard Stop; da willst du nicht raten. Ein Freshness-Lag, der leicht über Budget liegt, kann eine Warnung sein, die das Scoring in einem Degraded-Mode-Flag trotzdem weiterlaufen lässt. Kodiere diese Policy pro Assertion, statt jede Abweichung als Ausfall zu behandeln. Zweitens: Halte die Prüfung günstig genug, um sie auf jedem Batch laufen zu lassen. Ist die Validierung teuer, wird sie gesampelt – und eine gesampelte Prüfung übersieht genau die intermittierende Korruption, die sich später am schwersten zurückverfolgen lässt.
Contracts geben dir außerdem eine echte Lineage-Story. Wenn eine Zahl downstream falsch aussieht, kannst du auf die Grenze zeigen, an der ein bestimmtes Feld zuletzt seinen Contract bestanden hat und wo es zuerst durchgefallen ist – mit Zeitstempel. Das schrumpft die Untersuchung von „durchsuche die gesamte Pipeline” auf „lies das Quarantäne-Log”. Für alles, was einem Audit Trail standhalten muss, zeigen dieselben Aufzeichnungen einem Prüfer, dass der Feed, der eine Entscheidung gespeist hat, an dem Tag, an dem die Entscheidung getroffen wurde, seine erklärten Erwartungen erfüllt hat.
Versionierung ist der schwere Teil, nicht die Validierung
Assertions zu schreiben ist unkompliziert. Die Engineering-Arbeit, die sich auszahlt, ist der Umgang mit dem Tag, an dem der Upstream-Owner einen legitimen Grund hat, den Feed zu ändern. Und den wird es geben. Ein Anbieter fügt ein Feld hinzu, teilt eines in zwei auf oder ändert eine Codeliste. Ein Contract, der das nicht absorbieren kann, wird zu etwas, um das die Leute herumrouten – und ein umgangener Contract ist schlimmer als gar keiner, weil er falsches Vertrauen verleiht.
Deshalb behandeln wir einen Contract als versioniertes Interface mit einem Deprecation-Pfad. Eine additive Änderung ist rückwärtskompatibel und bumpt eine Minor-Version; Consumer ignorieren das neue Feld, bis sie sich entscheiden, es zu lesen. Ein Breaking Change bumpt eine Major-Version, und beide Versionen laufen für ein vereinbartes Fenster parallel, während die Consumer migrieren. Der Producer kann die alte Version nicht einseitig brechen. Genau diese Verhandlung ist der ganze Grund, es einen Contract zu nennen und nicht ein Validierungsskript.
Ein paar Gewohnheiten verhindern, dass das verrottet:
- Teste den Contract gegen echte Historie. Spiele einen Monat vergangener Feeds durch eine neue Contract-Version, bevor sie live geht. Wenn die legitimen Daten von gestern an den Regeln von morgen scheitern, sind die Regeln falsch – und du findest es heraus, bevor es die Produktion tut.
- Versioniere den Contract mit den Daten, nicht separat. Die Version, die einen Batch validiert hat, sollte neben diesem Batch festgehalten werden, damit du ein Jahr später exakt rekonstruieren kannst, welche Regeln in Kraft waren.
- Halte ein enges False-Positive-Budget auf den Prüfungen selbst. Ein Contract, der bei normalen Volumenspitzen zum Quartalsende Zeter und Mordio schreit, wird stummgeschaltet – und ein stummgeschalteter Contract erzwingt nichts. Justiere Wertebereiche an der saisonalen Realität, einschließlich der Corporate-Actions- und Monatsend-Muster, die Finanzdaten-Feeds klumpig machen.
Nichts davon macht die Upstream-Welt stabil. Es macht Upstream-Instabilität zu etwas, das deine Pipeline beobachtet und in einem Takt, den du kontrollierst, darauf reagiert – statt zu etwas, das ein Modell im Nachhinein für dich entdeckt.
Häufige Fragen
Ist ein Data Contract dasselbe wie ein Schema?
Nein. Ein Schema beschreibt die Form. Ein Contract ergänzt Semantik, Freshness-Erwartungen, zulässige Wertebereiche, einen Owner und eine Versionierungsrichtlinie – und lässt den Build fehlschlagen, sobald eines davon verletzt wird.
Wo erzwingt man einen Contract in der Pipeline?
An der Grenze, an der ein Feed in deinen Kontrollbereich eintritt, bevor irgendein Feature oder Modell ihn liest. Erzwingst du ihn später, haben sich die fehlerhaften Daten bereits verbreitet, und du debuggst Symptome statt der Ursache.
Helfen Contracts bei Point-in-Time-Korrektheit?
Sie helfen dir, die Voraussetzungen für Leakage abzufangen – etwa einen restated Wert, der die Historie überschreibt, oder ein verspätet eintreffendes Feld. Sie ersetzen keinen As-of-Store, aber sie machen die Annahmen des Stores überprüfbar.