Schema-Evolution bricht, wenn der Versions-Overlap ungemessen ist
Eine Schema-Änderung bricht Produktion nicht, weil die Migration falsch ist, sondern weil der Versions-Overlap ungemessen ist. Theorem 3 zu Backward- und Forward-Kompatibilität, Expand-and-Contract und dem Wire-Contract an der Grenze.

Schema-Evolution bricht, wenn der Versions-Overlap ungemessen ist
Eine Schema-Änderung ist gewöhnlich eine der schwierigsten Änderungen für ein Softwaresystem, und ByteByteGos Artikel „Schema Evolution: Changing the Contract Without Breaking What Runs" eröffnet mit dem ehrlichen Grund, warum: die Migration läuft sauber in Staging, und unabhängige Services beginnen in Produktion zu scheitern, und mit der Migration selbst war nichts falsch (ByteByteGo, „Schema Evolution: Changing the Contract Without Breaking What Runs", 20. Aug. 2026, https://blog.bytebytego.com/p/schema-evolution-changing-the-contract). Das Versagen ist nicht die Änderung. Das Versagen ist die Annahme, dass nur eine Schema-Version im Spiel ist. Zeilen, die vor Jahren geschrieben wurden, werden von Code gelesen, der inzwischen ersetzt wurde. Nachrichten, die in einer Queue liegen, wurden veröffentlicht, bevor der aktuelle Consumer geschrieben wurde. Mobile-App-Versionen von vor achtzehn Monaten sind noch installiert und rufen weiterhin die API auf. Die Eigenschaft „kein Bruch bei Schema-Änderung" ist genau dann garantiert, wenn der Mechanismus — Backward- und Forward-Kompatibilität plus Expand-and-Contract-Sequenzierung — implementiert ist und misst, ob zwei Versionen noch leben. Theorem 3: Eine Eigenschaft ist genau dann garantiert, wenn ihr Mechanismus implementiert ist und misst.
Schlüsselerkenntnisse
- Schema-Änderungen brechen die Produktion nicht, weil die Migration falsch ist, sondern weil sie wirksam wird, während zwei Versionen der Applikation noch gegen dieselbe Datenbank laufen, und nur eine dieser Versionen das geänderte Schema referenzierte (ByteByteGo, 20. Aug. 2026).
- Es ist immer mehr als eine Schema-Version im Spiel: Zeilen, die vor Jahren geschrieben wurden, Nachrichten, die vor dem aktuellen Consumer in die Queue gelegt wurden, Mobile-Apps, die achtzehn Monate alt sind und noch die API aufrufen — Daten, die unter einer Schema-Version geschrieben wurden, werden unter einer anderen gelesen.
- „Kein Bruch" ist eine Eigenschaft, die genau dann gilt, wenn Backward- und Forward-Kompatibilität als Mechanismen implementiert sind und der Versions-Overlap gemessen wird. Eine Schema-Änderung ohne Kompatibilitätsmechanismus ist eine Vertragsänderung ohne Garantie.
- Theorem 3: Eine Eigenschaft ist genau dann garantiert, wenn ihr Mechanismus implementiert ist und misst. Expand-and-Contract ist der Mechanismus; die Deprecation-Timeline, die den letzten alten Reader trackt, ist die Messung.
Es ist immer mehr als eine Schema-Version im Spiel
Die ByteByteGo-Einleitung benennt die strukturelle Tatsache, die jedes Schema-Änderungs-Postmortem wiederentdeckt: die Migration läuft reibungslos in Staging, und unabhängige Services scheitern in Produktion, und die Untersuchung findet nichts falsch mit der Migration — sie wurde wirksam, während zwei Versionen der Applikation noch gegen dieselbe Datenbank liefen, und nur eine dieser Versionen referenzierte das geänderte Schema. Das ist keine Staging-Produktions-Lücke. Das ist eine Ein-Versions-Annahme, die auf eine Mehr-Versions-Realität trifft. Staging testet die Migration gegen den neuen Code. Produktion führt die Migration aus gegen den neuen Code und den alten Code und die alten Daten, die der alte Code geschrieben hat, und die Queue-Nachrichten, die der alte Publisher geschrieben hat. Die Staging-Umgebung ist eine Ein-Versions-Topologie; Produktion ist eine Versions-Overlap-Topologie.
[UNIQUE INSIGHT] Der Versions-Overlap wird nicht durch das Deploy-Fenster begrenzt. Die ByteByteGo-Einleitung ist explizit: Zeilen, die vor Jahren geschrieben wurden, können von Applikationscode produziert worden sein, der inzwischen ersetzt wurde. Nachrichten, die in einer Queue liegen, wurden veröffentlicht, bevor die aktuelle Version des Consumers geschrieben wurde. Mobile-App-Versionen von vor achtzehn Monaten sind noch auf echten Geräten installiert und rufen noch die API auf. Das Deploy-Fenster ist der kleinste Overlap; der Durable-State-Overlap — alte Zeilen, Queue-Nachrichten, installierte Mobile-Clients — ist der Overlap, der Sie tatsächlich bricht. Ein Schema-Änderungsplan, der nur das Deploy-Fenster berücksichtigt, misst den kleinsten Versions-Overlap und behauptet die Eigenschaft über den größten. Das ist die Lücke zwischen dem Mechanismus, der implementiert ist (Deploy-Fenster-Koordination), und dem Mechanismus, der die Eigenschaft garantieren würde (vollständiges Versions-Overlap-Tracking, einschließlich Durable State und installierter Clients).
Der Honest Architect liest die ByteByteGo-Behauptung als Topologie-Behauptung, nicht als Prozess-Behauptung. „More than one schema version is always in play at the same time" ist eine Aussage über die Form eines verteilten Systems: Writer und Reader sind in der Zeit entkoppelt, und das Schema ist der Vertrag, der die Zeitlücke überspannt. Eine Änderung des Vertrags ist nur sicher, wenn sie jeden Reader überspannt, der noch lebt, einschließlich Readern, die lebten, als die Daten geschrieben wurden, und Readern, die leben werden, wenn die Daten gelesen werden. Backward- und Forward-Kompatibilität sind zwei verschiedene Mechanismen, nicht einer.
Backward- und Forward-Kompatibilität sind zwei verschiedene Mechanismen
Backward-Kompatibilität ist die Eigenschaft, dass neuer Code alte Daten liest. Forward-Kompatibilität ist die Eigenschaft, dass alter Code neue Daten liest. Sie sehen im Namen symmetrisch aus und sind im Mechanismus nicht symmetrisch. Backward-Kompatibilität ist eine Eigenschaft, die der neue-Code-Autor garantieren kann, indem er fehlende Felder toleriert — der neue Code weiß, wie das alte Schema aussah. Forward-Kompatibilität ist eine Eigenschaft, die der neue-Code-Autor nicht allein garantieren kann, weil der alte Code bereits deployed ist; die einzige Garantie ist, die Änderung so zu machen, dass der alte Code sie bereits toleriert (optionale Felder hinzufügen, keine Felder entfernen, die der alte Code liest, keine Feldsemantik ändern). Backward-Kompatibilität ist eine Schreibzeit-Garantie; Forward-Kompatibilität ist eine Entwurfszeit-Einschränkung für die Änderung selbst.
Der ByteByteGo-Artikel verspricht zu behandeln, „which changes break consumers, which do not, and the qualifiers that decide it" — und die Qualifier sind der Mechanismus. Ein optionales Feld hinzuzufügen ist backward-kompatibel (neuer Code liest alte Daten, denen das Feld fehlt) und forward-kompatibel (alter Code liest neue Daten, die ein zusätzliches Feld haben, das er ignoriert). Ein Feld umzubenennen ist keines von beiden: alter Code liest neue Daten und sucht nach dem alten Feldnamen, findet ihn nicht, bricht. Ein Feld zu entfernen, das der alte Code liest, ist forward-inkompatibel. Den Typ oder die Semantik eines Felds zu ändern, ist sowohl backward- als auch forward-inkompatibel, selbst wenn die Wire-Bytes identisch sind, weil der Vertrag die Bedeutung ist, nicht die Bytes. Der Honest Architect behandelt eine Umbenennung oder Typänderung als Vertragsbruch, nicht als Schema-Änderung — sie verletzt eine Annahme, die ein lebender Reader macht.
[PERSONAL EXPERIENCE] Everythinks Wire-Typen sind einmal definiert, in Zod, in @everythink/types, und Antworten werden an der Netzwerkgrenze geparst. Das ist eine Schema-Registry an der Grenze, nicht nur eine Typdefinition. Das Zod-Schema ist der Vertrag; das Parse-an-der-Grenze ist die Messung — ein Payload, das nicht zum Schema passt, taucht als typisierter ApiError auf, nie als Crash. Wir taggen das Production ✅, weil der Mechanismus (Parse-at-Boundary) implementiert ist und die Messung (der typisierte Fehler) auf jeder Antwort läuft. Eine Schema-Änderung am Backend ohne eine entsprechende Zod-Schema-Änderung ist eine Vertragsänderung ohne konsumentenseitige Messung — Partial ⚠️ bis das Zod-Schema aktualisiert ist und das Parse-at-Boundary den Drift fängt.
Die Invariante des Oracle — Wahrscheinlichkeiten werden an genau einer Stelle normalisiert, everythink-oracle::ensemble, sodass Konsumenten sich auf sum(probability) ≈ 1.0 verlassen können — ist ein Schema-Vertrag, den Downstream-Code liest. Eine Änderung der Normalisierungsstelle oder der Sortierreihenfolge wäre ein Vertragsbruch, selbst wenn die Wire-Bytes identisch aussähen, weil der Vertrag die Garantie ist, auf die Konsumenten sich verlassen. Wir taggen diese Invariante Production ✅, weil der Mechanismus (einzige Normalisierungsstelle) implementiert ist und die Messung (die Ensemble-Tests) läuft. Die Schema-Evolutions-Disziplin für diese Invariante lautet: die Normalisierungsstelle nie ohne eine Expand-and-Contract-Sequenz verschieben, die alten Konsumenten erlaubt, weiter die alte Garantie zu lesen, während neue Konsumenten die neue lesen.
Expand and Contract — der Topologie-Move
Expand and Contract ist der Mechanismus, der eine Vertragsänderung unter Versions-Overlap sicher macht. Expand: das neue Schema-Element so hinzufügen, dass es sowohl backward- als auch forward-kompatibel ist. Alte Reader weiter den alten Vertrag lesen lassen und neue Reader beginnen, den neuen zu lesen. Warten, bis der Versions-Overlap abtrocknet — alte Clients sich updaten, alte Nachrichten konsumiert werden, alte Zeilen ausaltern. Contract: das alte Schema-Element entfernen, sobald kein lebender Reader es referenziert. Die Expand-Phase ist die Topologie-Erweiterung (zwei Routen koexistieren); die Contract-Phase ist die Topologie-Verengung (eine Route bleibt).
Die Messung, die die Contract-Phase steuert, ist die Deprecation-Timeline, die den letzten alten Reader trackt. ByteByteGo verspricht „versioning strategies and deprecation timelines" — und die Deprecation-Timeline ist die Messung, die Expand-and-Contract zu einer garantierten Eigenschaft macht statt zu einer Hoffnung. Der Honest Architect taggt einen Expand-and-Contract-Plan ohne eine Last-Old-Reader-Messung als Partial ⚠️: der Mechanismus (Expand, Warten, Contract) ist implementiert, aber die Messung, die den Contract steuert, fehlt. Ein Plan, der den letzten alten Reader trackt — über Client-Version-Telemetrie, über Queue-Nachrichtenalter, über Zeilen-Schema-Version-Tags — und erst kontrahiert, wenn dieser Zähler null erreicht, ist Production ✅.
[ORIGINAL DATA] Die Everythink-Migrationsdisziplin taggt das direkt. Jede .up.sql-Migration hat eine entsprechende .down.sql — das ist der Rollback-Pfad, der Vertrag, dass ein gescheitertes Expand rückgängig gemacht werden kann. Die .down.sql ist das Sicherheitsnetz der Expand-Phase: wenn das Expand einen lebenden Reader bricht, kontrahieren Sie die Schema-Änderung (die Down-Migration ausführen) und die alten Reader nehmen den Betrieb wieder auf. Wir taggen den Rollback-Pfad Production ✅, weil jede Migration einen hat und der Migrator das Pairing erzwingt. Eine Migration, die in einem Schritt hinzufügt und droppt, ist ein Cutover, kein Expand-and-Contract — Partial ⚠️, wenn der alte Code noch live ist, weil die Contract-Phase innerhalb des Versions-Overlaps läuft.
Der World-Monitor-Geo-Cache trägt dieselbe Disziplin in anderer Form. GeoSignal-IDs sind deterministische uuidv5(source, native_id) — Re-Ingest updatet, erzeugt nie Duplikate. Das ist ein Forward-Kompatibilitäts-Mechanismus für den Cache: ein neuer Ingest desselben Signals updatet die Zeile, statt eine zweite Zeile zu erzeugen, sodass ein Reader, der die alte ID sah, und ein Reader, der die neue ID sieht, dieselbe Zeile lesen. Die ID-Stabilität ist der Vertrag; das deterministische uuidv5 ist der Mechanismus; das Upsert ist die Messung (die Zeilenzahl wächst beim Re-Ingest nicht). Wir taggen das Production ✅, weil der Mechanismus implementiert ist und die Zeilenzahl-Stabilität beobachtbar ist. Eine Schema-Änderung am ID-Schema wäre eine Umbenennung des Primärschlüssels — die forward-inkompatibelste Änderung, die es gibt — und würde ein Expand-and-Contract erfordern, das beide IDs schreibt und Reader migriert, bevor die alte gedroppt wird.
Was ein Honest Architect in einem Paywall-Intro liest
Der ByteByteGo-Artikel ist hinter der „Version Overlap"-Abschnittsüberschrift paywallt, und der Honest Architect fabriziert den Body nicht. Was sichtbar ist, ist die strukturelle Behauptung — mehr als eine Schema-Version ist immer im Spiel, die Migration ist sauber in Staging und bricht in Produktion, das Versagen ist nicht die Migration, sondern der Versions-Overlap — und diese Behauptung reicht aus, um die Tagging-Disziplin anzuwenden. Das sichtbare Intro gibt: die Mehr-Versions-Realität (Production ✅ als strukturelle Tatsache verteilter Systeme), die Staging-Produktions-Lücke als Ein-Versions-vs-Mehr-Versions-Topologieunterschied (Production ✅ als Framing) und das Versprechen von Backward-/Forward-Kompatibilität, Expand/Contract, Schema-Registries und Deprecation-Timelines als Mechanismen.
Die Honest-Architect-Regel: die echte Quelle zitieren, nie eine URL oder Metrik fabrizieren, nie behaupten, der Artikel habe etwas gesagt, das er nicht sagte. Das Intro sagt, die Migration läuft sauber in Staging und bricht in Produktion, weil zwei Versionen gegen dieselbe Datenbank laufen. Das ist die zitierte Behauptung. Der Rest der Analyse ist der auf Everythinks eigenen Stack angewandte Mechanismus, gegen unsere eigene Implementierung getaggt, nicht ByteByteGo zugeschrieben. Die Cross-Domain-Behauptung (Expand-and-Contract ist derselbe Topologie-Move in einem Datenbank-Schema und in einem Forecast-Ensemble) ist Partial ⚠️, weil die Form geteilt ist und die Domänen getrennt sind.
Die Scope-Grenze: Everythink ist eine zivile und defensive Forecasting-Plattform, keine Datenbank-Beratung. Die Schema-Evolutions-Lektion ist cross-domain — eine Vertragsänderung ist nur sicher, wenn der Versions-Overlap gemessen ist — und sie gilt, ob der Vertrag ein Datenbank-Schema, ein API-Payload, ein Zod-Typ oder eine Forecast-Ensemble-Invariante ist. Kein Token-, Wallet- oder Community-Credit-Ergebnis wird versprochen; diese sind Roadmap 🔵, Howey-Review vorbehalten. Ein Roadmap-Item wird nie leise auf Production befördert aufgrund einer Schema-Evolutions-Form.
Häufig gestellte Fragen
Warum bricht eine Schema-Änderung die Produktion, wenn die Migration sauber in Staging lief?
Weil Staging die Migration nur gegen den neuen Code testet und Produktion den neuen Code neben altem Code, alten Daten, Queue-Nachrichten und installierten Mobile-Clients laufen lässt, die unter dem alten Schema geschrieben wurden. Die Migration ist sauber; der Versions-Overlap ist es nicht. Das Versagen ist nicht die Änderung — es ist die Annahme, dass nur eine Schema-Version im Spiel ist. Theorem 3: Die Eigenschaft „kein Bruch" ist nur garantiert, wenn der Versions-Overlap-Mechanismus implementiert ist und misst.
Was ist der Unterschied zwischen Backward- und Forward-Kompatibilität?
Backward-Kompatibilität ist die Eigenschaft, dass neuer Code alte Daten liest — der neue-Code-Autor garantiert sie, indem er fehlende Felder toleriert. Forward-Kompatibilität ist die Eigenschaft, dass alter Code neue Daten liest — der neue-Code-Autor kann den alten Code nicht ändern, also ist die einzige Garantie, die Änderung so zu machen, dass der alte Code sie bereits toleriert (optionale Felder hinzufügen, keine Felder entfernen oder umbenennen, die der alte Code liest). Backward-Kompatibilität ist eine Schreibzeit-Garantie; Forward-Kompatibilität ist eine Entwurfszeit-Einschränkung für die Änderung selbst.
Was ist Expand and Contract?
Expand: das neue Schema-Element so hinzufügen, dass es sowohl backward- als auch forward-kompatibel ist. Alte und neue Reader koexistieren lassen. Warten, bis der Versions-Overlap abtrocknet — alte Clients sich updaten, alte Nachrichten konsumiert werden, alte Zeilen ausaltern. Contract: das alte Schema-Element entfernen, sobald kein lebender Reader es referenziert. Die Expand-Phase ist eine Topologie-Erweiterung (zwei Vertragsversionen koexistieren); die Contract-Phase ist eine Topologie-Verengung (eine Version bleibt).
Wie setzt Everythink Schema-Evolution an der Wire-Grenze durch?
Wire-Typen sind einmal definiert, in Zod, in @everythink/types. Antworten werden an der Netzwerkgrenze geparst; ein Payload, das nicht zum Schema passt, taucht als typisierter ApiError auf, nie als Crash. Das Zod-Schema ist der Vertrag; das Parse-at-Boundary ist die Messung. Eine Backend-Schema-Änderung ohne eine entsprechende Zod-Schema-Änderung ist eine Vertragsänderung ohne konsumentenseitige Messung — Partial ⚠️ bis das Zod-Schema aktualisiert ist.
Verspricht Everythink, dass Schema-Änderungen niemals Konsumenten brechen?
Nein. Wir versprechen den Mechanismus: Zod-Parse-at-Boundary, .up.sql/.down.sql-Pairing, Single-Normalization-Site-Oracle-Invariante, deterministisches uuidv5 für den World-Monitor-Cache. Die Eigenschaft „kein Bruch bei einer gegebenen Änderung" gilt, wenn die Änderung Expand-and-Contract folgt und die Deprecation-Timeline den letzten alten Reader trackt. Eine Änderung, die innerhalb des Versions-Overlaps cuttover, ist Partial ⚠️. Kein Token-, Wallet- oder Community-Credit-Ergebnis wird versprochen; diese sind Roadmap 🔵.
Sources
- ByteByteGo, „Schema Evolution: Changing the Contract Without Breaking What Runs", 20. Aug. 2026, abgerufen 2026-08-23, https://blog.bytebytego.com/p/schema-evolution-changing-the-contract
Wenn Ihr Team bereit ist, den Versions-Overlap zu messen, nicht nur das Deploy-Fenster, erstellt Euer Network — die Topologie routet zwei Vertragsversionen, die Grenze parst, der Rollback-Pfad macht rückgängig.

Anpassung ist die Mechanismentrennung, nicht die offenen Gewichte
Inkling ist nicht wegen seiner Apache 2.0 Lizenz für Anpassung entworfen, sondern weil jede architektonische Entscheidung eine messbare Eigenschaft hinter ihrem eigenen Mechanismus isoliert. Der bias-basierte Lastausgleich ist die reinste Theorem 3 Instanz: eine Eigenschaft, garantiert durch einen Mechanismus, der nicht mit dem Hauptziel konkurriert.
→ →
MAC-Geolokalisierung braucht den Mechanismus, nicht den Identifikator
Eine MAC-Adresse enthält kein GPS, aber eine Wardriving-Datenbank plus eine signalgewichtete Centroide-Merge kann einen festen Access Point geolokalisieren. Theorem 3: die Eigenschaft kommt vom Mechanismus, nicht vom Identifikator.
→ →
Data-Enrichment ist Kohärenz, nicht nur Volumen
Mehr Daten bedeuten nicht automatisch besseren Insight. Theorem 3: die Eigenschaft (besserer Insight) kommt vom Mechanismus (Kohärenz-Check über Datenpunkte), nicht vom Volumen. Der Wert ist bessere Fragen, nicht Gewissheit.
→ →Baue deine Welt auf einer Engine, die beweist, was sie behauptet.
Erstelle dein eigenes Netzwerk auf der Engine, die seit 2016 läuft — oder sprich mit dem Team hinter den 21 Papieren.
