Zum Hauptinhalt springen

Versionierungsregeln für Construction Kits

CK-Modellversionen folgen SemVer, und Abhängigkeiten werden als Versionsbereiche deklariert – aber welche konkrete Version ein Bereich auflöst, hängt davon ab, wo die Auflösung stattfindet. Dies falsch zu machen ist die häufigste Ursache für ResolveFailed-Modelle und fehlgeschlagene Blueprint-Installationen, weshalb die Regeln hier an einer Stelle ausbuchstabiert werden.

Wo Bereiche aufgelöst werden – und zu welcher Version​

KontextEingabeLöst auf zu
Compile / Publish (octo-ckc)Bereiche in der Quelle ckModel.yamlHöchste veröffentlichte Version, die den Bereich erfüllt – als exakter Pin in die kompilierte Bibliothek eingefroren
Tenant-Import / FixAllExakte Pins der kompilierten BibliothekGenau die gepinnten Versionen – der Tenant muss sie präzise vorhalten
Blueprint-Apply (ckModelDependencies)Bereiche in blueprint.yamlDie Untergrenze (Floor) des Bereichs ist das Installationsziel

Zwei Schutzmechanismen mildern die Blueprint-Floor-Regel:

  • Kein Downgrade: Wenn der Tenant bereits ein Modell gleichen Namens in einer Version auf oder über dem Floor vorhält, wird der Import vollständig übersprungen.
  • Service-verwaltete Umleitung: Bei service-verwalteten Modellen (System, System.*) wird das Installationsziel auf die Version umgeleitet, die die Dienste ausliefern, sofern sie den Floor erfüllt.

Praktische Konsequenz: ein Floor muss installierbar sein​

Da die Blueprint-Engine auf einem frischen Tenant den Floor installiert, muss die Floor-Version selbst zusammen mit allen anderen deklarierten Abhängigkeiten auflösbar sein. Ein typischer Fehler: EnergyCommunity-[4.0,5.0) neben Basic.Energy-[1.3,2.0) – wenn EnergyCommunity 4.0.0 gegen Basic.Energy 1.2.x kompiliert (und daher exakt gepinnt) wurde, versucht eine frische Installation 4.0.0, dessen Pin mit dem 1.3-Floor kollidiert, und schlägt fehl mit:

CK model 'EnergyCommunity-4.0.0' could not be installed; required CK model
dependencies may be missing or still importing

Diese Meldung erscheint immer dann, wenn nach dem Importversuch kein Modell dieses Namens im Zustand Available ist – der zugrunde liegende Fehler bei der Abhängigkeitsauflösung wird vom Import-Pfad des parallelen Startvorgangs verschluckt, sodass diese Nachprüfung das einzige Signal ist. Die Lösung besteht darin, den Floor auf die erste Version anzuheben, die gegen die neue Abhängigkeit kompiliert wurde (EnergyCommunity-[4.1,5.0)).

Die Kaskadenregel​

Wenn sich die Abhängigkeit eines Modells bewegt, muss das Modell selbst neu gebaut, hochgezählt und neu veröffentlicht werden – und jeder Blueprint-Floor, der darauf zeigt, muss ebenfalls mitziehen.

Schritt für Schritt, am Beispiel Basic.Energy → EnergyCommunity:

  1. Basic.Energy veröffentlicht eine neue Version (sagen wir 1.3.0).
  2. EnergyCommunity pinnt weiterhin 1.2.x (Einfrieren zur Compile-Zeit). Es muss neu kompiliert werden, damit der Bereich neu zu 1.3.0 aufgelöst wird, und mit einem Versionssprung neu veröffentlicht werden – das SemVer-Gate (OCTO-CK100) erzwingt den Sprung, weil sich die aufgelöste Abhängigkeitsmenge geändert hat.
  3. Jedes Blueprint, das EnergyCommunity-[4.0,5.0) deklariert, sollte seinen Floor auf die erste neu gebaute Version anheben, sonst zielen frische Installationen auf eine Version, die mit dem neuen Abhängigkeits-Floor inkompatibel ist (siehe oben).
Blueprint-Manifest und Seed-Daten pinnen unabhängig voneinander

Die blueprint.yaml eines Blueprints (ckModelDependencies) und seine Seed-Daten-Datei (dependencies:-Header in der Runtime-Model-YAML) deklarieren CK-Versionsbeschränkungen unabhängig voneinander und werden von unterschiedlichen Code-Pfaden aufgelöst. Wenn Sie einen Floor bewegen, bewegen Sie ihn in beiden Dateien – ein hinterherhinkender Seed-Pin führt die inkompatible Paarung klammheimlich wieder ein.

Das Upgrade eines bereits bereitgestellten Tenants folgt derselben Reihenfolge: Veröffentlichen Sie das neu gebaute abhängige Modell im Katalog, bevor Sie die Abhängigkeit auf dem Tenant upgraden. Wird FixAll ausgeführt, nachdem nur die Abhängigkeit veröffentlicht wurde, upgradet dies die Abhängigkeit, lässt das abhängige Modell aber in einer Version zurück, deren Pins nicht mehr auflösen – das abhängige Modell springt auf ResolveFailed und seine Typen verschwinden aus dem GraphQL-Schema des Tenants. Wiederherstellung: das neu gebaute abhängige Modell veröffentlichen, RefreshCatalogs, FixAll, dann ClearCache.

Das SemVer-Gate (octo-ckc ValidateVersion)​

CI validiert jede CK-Bibliothek vor der Veröffentlichung gegen ihre veröffentlichte Baseline. Das Gate klassifiziert das Modell-Diff (major / minor / patch) und erzwingt einen ausreichenden Versionssprung:

CodeBedeutung
OCTO-CK100Die deklarierte Version erfüllt den erforderlichen Sprung über die veröffentlichte Baseline nicht – Version zu niedrig. Wird auch ausgelöst, wenn sich die aufgelöste Abhängigkeitsmenge geändert hat (siehe Kaskadenregel).
OCTO-CK101Die deklarierte Version ist niedriger als die Baseline (die neueste veröffentlichte Version derselben Major-Version) – Downgrade, nicht erlaubt.
OCTO-CK102Die Katalogquelle ist nicht erreichbar – die Baseline konnte nicht bestimmt werden. Wird nie als Erstveröffentlichung behandelt.
OCTO-CK103Ein deklarierter Abhängigkeitsbereich wird von keiner veröffentlichten Version erfüllt (und von keinem Geschwisterpaket, das früher im selben Lauf validiert wurde).
OCTO-CK104Das Diff erfordert einen Major-Sprung, aber kein Migrationsskript zielt auf die deklarierte Version (nur mit --requireMigrationForMajor ein Fehler, andernfalls eine Warnung).

Hinweise:

  • Geschwisterpakete, die im selben Lauf validiert werden, gelten für die OCTO-CK103-Prüfung als veröffentlicht – sodass Abhängigkeitssprünge im selben Commit über Geschwistermodelle in einem Repository hinweg funktionieren.
  • Jeder OCTO-CK1xx-Befund lässt den Befehl mit einem Wert ungleich null beenden (-6, was sich in den meisten Shells als 250 zeigt). Gaten Sie CI auf exit code != 0, niemals auf == 1.
  • Eine separate Lint-Familie (OCTO-CK001 / OCTO-CK002) validiert Runtime-State-Marker zur Build-Zeit und ist unabhängig vom SemVer-Gate.

Welche Version die Baseline ist​

Das Gate vergleicht ein Modell mit seiner Baseline, die pro Major-Linie bestimmt wird:

  1. Gleiche Major-Version. Die Baseline ist die neueste veröffentlichte Version der deklarierten Major-Version. Sind von EnergyCommunity 3.3.0 und 4.5.0 veröffentlicht, wird ein deklariertes 3.4.0 mit 3.3.0 verglichen. Ein Wartungsrelease auf einer älteren Major-Linie (Tenants laufen noch auf 3.x, 4.x existiert bereits) besteht damit das normale CI-Gate; manuelles Kompilieren und Veröffentlichen ist nicht nötig. Ein deklariertes 3.2.0 scheitert mit OCTO-CK101 gegen 3.3.0.
  2. Neue Major-Version. Hat die deklarierte Major-Version noch keine veröffentlichte Version, ist die Baseline die neueste Version der vorherigen Major-Linie: 4.0.0 wird mit dem neuesten 3.x verglichen, damit die Migrationsprüfung (OCTO-CK104) und das Changelog weiter funktionieren. Ein Major-Sprung erlaubt jede Änderung; würden die Änderungen nur einen Minor-Sprung erfordern, sagt der Bericht das ("valid major bump without structural need"). Nur ein Modell, das nie veröffentlicht wurde, ist eine Erstveröffentlichung.
  3. Nie das zu prüfende Modell selbst. Einträge im lokalen Dateisystem-Katalog ab der deklarierten Version stammen aus früheren lokalen Builds, nicht aus einer Veröffentlichung. Sie sind nie die Baseline und werden im Bericht als ignoriert aufgeführt; zwei Läufe von ValidateVersion liefern daher dasselbe Ergebnis. Eine veröffentlichte Version gleich der deklarierten zählt weiterhin: Wer ein Modell ändert, ohne die Version zu erhöhen, scheitert mit OCTO-CK100.

--catalogName beschränkt die Suche nach der Baseline auf einen Katalog; ohne die Option wird jeder lesbare Katalog gefragt. Ist eine Katalogquelle nicht erreichbar und wurde keine Baseline der deklarierten Major-Version gefunden, meldet das Gate OCTO-CK102, statt auf eine ältere Major-Version auszuweichen.

Compile-Gate​

Für Modelle mit ckLanguage: 2 ist der Build selbst ein Gate: dotnet build (Task CkCompile) vergleicht das frisch kompilierte Modell vor jeder Veröffentlichung mit seiner Baseline und scheitert für jede Änderung, die die deklarierte Version nicht abdeckt. Das Gate schreibt in keinen Katalog; eine inkompatible Version verlässt weder den Rechner noch einen CI-Build. Es verwendet dasselbe Urteil wie ValidateVersion (gleiche Baseline-Regeln, gleiches erforderliches Level, gleiche Mindestversion).

CodeBedeutung
OCTO-CK200Eine Änderung wird von der deklarierten Version nicht abgedeckt. Ein Fehler pro Änderung, mit Element, Änderung, erforderlichem Level und Mindestversion.
OCTO-CK201Die deklarierte Version ist niedriger als die Baseline derselben Major-Version.
OCTO-CK202Die Baseline-Quelle war nicht erreichbar und keine Baseline bekannt: Fehler bei Remote, nur eine Meldung bei Local.

Die MSBuild-Property OctoCkCompatibilityBaseline wählt die Quelle der Baseline:

WertBaseline ausStandard
Localdem lokalen Dateisystem-Katalog plus den zwischengespeicherten Remote-Katalogen; funktioniert ohne Netzwerkaußerhalb von CI (DebugL)
Remotenur den GitHub-Katalogen; der lokale Katalog wird ignoriertwenn TF_BUILD oder ContinuousIntegrationBuild true ist

Eine gesetzte Property überschreibt den Standard. Im Modus Local sind Einträge des lokalen Katalogs ab der deklarierten Version nie die Baseline (sie stammen aus früheren Builds desselben Modells); zwei Builds oder zwei Target Frameworks liefern daher dasselbe Ergebnis, und eine brechende Änderung bei unveränderter Version scheitert beim nächsten Build erneut. Jeder Build protokolliert eine Zeile mit Modell, deklarierter Version, Baseline (mit Katalog und ggf. "local, not published") und erforderlichem Level. Modelle mit ckLanguage 1 erhalten nur diese Zeile; ihr Gate bleibt ValidateVersion in CI.

Änderungen bestätigen​

Zwei Arten von Änderungen werden nur akzeptiert, wenn der Herausgeber sie ausdrücklich bestätigt: das Verschärfen von access auf einem sicherheitsrelevanten Attribut (Minor statt Major) und ein Unique-Index auf einer stabilen Basis (Major). Ohne Bestätigung scheitert der Build mit OCTO-CK203; die Meldung enthält den Änderungsschlüssel und einen Beispieleintrag. Tragen Sie ihn in ckModel.yaml ein (ckLanguage: 2):

compatibility:
acknowledge:
- change: "RecordAttribute:Login-1/Secret#Modified:access"
reason: "Close accepted risk R13: password hash readable via GraphQL"
CodeBedeutung
OCTO-CK203Für eine Änderung, die eine Bestätigung braucht, fehlt der passende Eintrag.
OCTO-CK204Ein Eintrag passt zu keiner Änderung dieses Releases, die eine Bestätigung braucht (veraltet, oder er nennt eine gewöhnliche Änderung). Entfernen Sie ihn.
  • Der Schlüssel ist stabil und enthält keine Modellversion: {ElementKind}:{ElementId}#{ChangeKind}, bei einer Änderung zusätzlich :{property}. Kopieren Sie ihn aus der Fehlermeldung; er wird exakt verglichen, Platzhalter sind nicht erlaubt.
  • Der reason ist Pflicht und erscheint im Urteil, im Build-Log und im CHANGELOG.md ("Acknowledged changes").
  • Eine Bestätigung senkt nie die erforderliche Erhöhung: ein Unique-Index auf einer stabilen Basis braucht weiterhin eine Major-Version, und eine gewöhnliche brechende Änderung scheitert trotz Eintrag mit OCTO-CK200.
  • Sie gilt nur für ein Release: im nächsten Release darf der Eintrag nicht mehr stehen (OCTO-CK204).
  • Die Bestätigungen sind Teil des kompilierten Modells, sodass die Veröffentlichungsprüfung sie ohne Quelltext prüfen kann.

Die Mindestversion in ckModel.yaml schreiben​

Der Build ändert ckModel.yaml nie. Meldet das Compile-Gate oder ValidateVersion, dass die deklarierte Version zu niedrig ist, schreibt ein expliziter Befehl die kleinste gültige Version:

octo-ckc -c ValidateVersion -p src/ConstructionKit --apply

Er berechnet die Mindestversion mit demselben Urteil wie die Gates, ersetzt nur die Version in der modelId-Zeile (Kommentare und Formatierung bleiben erhalten), gibt 2.5.0 → 3.0.0 aus und validiert das Paket erneut. Es wird nichts geschrieben, wenn die Version bereits gültig ist, bei einem Downgrade (OCTO-CK101/OCTO-CK201), bei fehlender oder veralteter Bestätigung (OCTO-CK203/OCTO-CK204) oder wenn das Modell nicht kompiliert. Mehrere -p-Pfade werden in Abhängigkeitsreihenfolge übergeben: Ein abhängiges Paket wird gegen die neue Version seines Vorgängers geprüft. Hat eine Abhängigkeit eine neuere Major-Version als Ihr Bereich erlaubt, meldet der Befehl not reconciled automatically: range … excludes … und lässt den Bereich unverändert; passen Sie den Bereich an und führen Sie den Befehl erneut aus.

Trockenlauf eines Basismodells gegen seine Abhängigen​

Prüfen Sie vor der Veröffentlichung der nächsten Version eines Basismodells (System, Basic, …), was sie bei jedem Modell bewirkt, das davon abhängt. Es wird nichts veröffentlicht, registriert oder geschrieben:

octo-ckc -c ValidateCascade -p src/ConstructionKit -o cascade.md

Der Befehl kompiliert den Kandidaten im Speicher, findet die Abhängigen in den lokalen und zwischengespeicherten Katalogen (neueste Version je Major-Linie, transitiv Abhängige eingeschlossen) und gibt je Abhängigem ein Urteil aus: Compatible, NeedsRepin (ein exakt gepinntes Modell, das neu kompiliert und veröffentlicht werden muss, mit der Erhöhungsstufe), Breaks (mit dem Element oder Mitglied, das nicht mehr bindet, einem nicht erreichten Floor oder einer Namenskollision mit einem Mitglied eines abgeleiteten Typs) und NotInRange (Bereich oder Pin des Abhängigen deckt die Major-Version des Kandidaten nicht ab). Der Exit-Code ist ungleich null, wenn mindestens ein Abhängiger bricht. Es gelten dieselben Katalogoptionen wie bei ValidateVersion (-cn, -rf, -lce, -lcr).

Candidate: System-2.3.0
Baseline: System-2.2.0 (LocalFileSystemCatalog, local, not published)
Candidate change level: MINOR (minimum version 2.3.0, declared 2.3.0: ok)

Breaks PlantE-1.0.0 (exact pins)
PlantE-1.0.0 uses System-2.2.0/Description-1, which System-2.3.0 does not define (attribute removed or re-identified)
Compatible LineR-1.0.0 (range-retaining)
no references into the candidate

2 dependent(s): 1 Breaks, 0 NeedsRepin, 1 Compatible, 0 NotInRange

Der Trockenlauf beweist, dass die referenzierte Oberfläche weiterhin bindet. Er beweist keine Verhaltensänderungen (Standardwerte, Anzeigeregeln, nicht eindeutige Indizes) und nicht die Kompatibilität bestehender Laufzeitdaten.

Beispiele für die Änderungsklassifizierung​

ÄnderungKlassifizierung
Neuer Typ, neues Attribut oder neues Enum-MitgliedMINOR
Kennzeichnen eines bestehenden Attributs als isRuntimeState: trueMINOR
Ändern des valueType eines Attributs von String auf Secret (Secret-Attribute)MINOR
Setzen, Entfernen oder Ändern des recordKey eines RecordsMINOR
Entfernen oder Umbenennen eines Typs/Attributs, Ändern des Typs eines Attributs (außer String → Secret)MAJOR
Nur Beschreibungs-/MetadatenänderungenPATCH
Ändern der displayNameRule / displayDescriptionRule eines TypsPATCH

Änderungen in CK-Sprache 2​

Für Modelle mit ckLanguage: 2 klassifiziert das Gate die neuen Elemente und Modifizierer wie folgt (verglichen werden die aufgelösten Werte, ein weggelassener Modifizierer zählt also als sein Standardwert):

ÄnderungKlassifizierung
Neues Interface, neuer implements-Eintrag an einem Typ, neue MethodeMINOR
Interface entfernt, implements-Eintrag entfernt, Methode entferntMAJOR
Optionales Interface-Attribut oder optionale Interface-Assoziation hinzugefügtMINOR – das Interface wächst innerhalb seiner Version. Ein optionales Attribut-Mitglied ist nur mit einer Attributdefinition MINOR, die in diesem Release neu (oder bisher intern) ist; eine bereits öffentliche Definition wiederzuverwenden ist MAJOR, weil ein Typ eines anderen Modells sie schon als Hidden oder unter anderem Namen zuweisen kann
Pflichtmitglied eines Interfaces hinzugefügt, Mitglied entfernt oder umbenannt, Attribut eines Mitglieds geändert, Ziel oder Multiplizität einer Assoziation geändert, Mitglied zur Pflicht gemacht; extends-Eintrag hinzugefügt oder entfernt; Methode zu einem Interface hinzugefügtMAJOR – stattdessen eine neue Interface-Version (Named-2) neben der alten veröffentlichen
Interface-Mitglied optional gemachtMINOR
Methode: optionaler Parameter hinzugefügt, Parameter optional gemacht, idempotent false → true, Timeout geändert, sensitive geändert, Autorisierung gelockert (Rolle hinzugefügt – auch zu einer leeren Liste –, Scope entfernt, allowSelf gesetzt, ein Block hinzugefügt, der nur Rollen gewährt)MINOR (bei einer Interface-Methode sind die Parameter- und sensitive-Änderungen MAJOR, siehe unten); gelockerte Autorisierung steht unter „Behavioural changes“ als security: method access widened
Autorisierungssemantik: Rollen gelten als „eine genügt“ (Rollennamen werden ohne Beachtung der Groß-/Kleinschreibung verglichen, Admin = admin), Scopes als „alle erforderlich“ (zusätzlich zu octo_api), und Autorisierung ist default-deny – eine Methode ohne Autorisierungsblock oder mit leeren Rollen können nur Administratoren aufrufen.
Interface-Methode: jede Änderung ihres Aufrufvertrags – kind, Parameter hinzugefügt oder entfernt, Typ, Optionalität oder sensitive eines Parameters, das Ergebnis, ein Fehlercode hinzugefügt oder entferntMAJOR – ein Typ, der die Methode neu deklariert, behält den alten Vertrag und kompiliert nicht mehr (Meldung 122); Beschreibungen, Autorisierung und Ausführung gehören nicht zum Vertrag
Methode: Pflichtparameter hinzugefügt, Parameter entfernt, umbenannt oder im Typ geändert, Parameter zur Pflicht gemacht, Ergebnis geändert, Fehlercode hinzugefügt oder entfernt, kind geändert, idempotent true → false, Autorisierung verschärft (Rolle entfernt oder Rollen geleert, Scope hinzugefügt, allowSelf entfernt, Autorisierungsblock entfernt)MAJOR – stattdessen eine neue Methodenversion (ChangePassword-2) veröffentlichen
deprecated eines Interfaces gesetzt oder entferntMINOR
targetCkInterfaceId einer Typ-Assoziation gesetzt oder geändert / entferntMAJOR / MINOR
visibility Public → Internal / Internal → PublicMAJOR / MINOR
derivable Any → Model / Model → AnyMAJOR / MINOR
access einer Attributzuweisung verschärft (ReadWrite < ReadOnly < MethodOnly < Hidden) / gelockertMAJOR / MINOR, mit einem Hinweis „Zugriff/Sicherheit" im Changelog
access eines in beiden Versionen mit securitySensitive: true markierten Attributs verschärftMINOR + Bestätigung erforderlich (Sicherheitsausnahme)
securitySensitive gesetzt oder entferntMINOR
ckLanguage von 1 auf 2 angehobenMINOR – aber MAJOR, sofern nicht jeder Typ und jeder Record derivable: Any deklariert, weil der Standardwert von derivable auf Model wechselt (pro Element gemeldet)
ckLanguage von 2 auf 1 gesenktMAJOR
description einer Methode, Beschreibungen von Parametern und Fehlern, description eines InterfacesPATCH

Interne Elemente gehören nicht zur Kompatibilitätsoberfläche. Andere Modelle können ein Element mit visibility: Internal nie referenzieren. Änderungen daran – oder an Mitgliedern eines internen Typs, Records, Enums, Interfaces oder einer internen Methode – sind daher höchstens MINOR (Beschreibungen bleiben PATCH). Das gilt nur, wenn das Element in beiden Versionen intern ist: Ein Element zu entfernen, das öffentlich war, ein öffentliches Element intern zu machen oder ein Element im selben Release öffentlich zu machen und zu ändern, folgt den öffentlichen Regeln. Beispiel: Ein interner Hilfstyp darf in einem Minor-Release ein Attribut verlieren, ein öffentlicher nicht.

Das ist nur deshalb sicher, weil kein öffentliches Element ein internes erreichen darf: In einem Modell mit ckLanguage: 2 weist der Compiler einen öffentlichen Typ, ein öffentliches Attribut, einen Record, eine Assoziationsrolle, ein Interface oder eine öffentliche Methode zurück, die ein internes Element des eigenen Modells referenzieren (Basistyp, implementiertes Interface, zugewiesenes Attribut, Assoziationsrolle oder -ziel, Wert- oder Parameter-Record/-Enum, extends, Interface-Mitglied), ebenso ein öffentliches Interface mit einer internen Methode und einen Typ, der eine Methode eines öffentlichen Interfaces als intern neu deklariert – Meldung 129 („inkonsistente Sichtbarkeit“). Abhilfe: das referenzierte Element öffentlich oder den Verweisenden intern machen. Intern → öffentlich, intern → intern und interne Methoden auf öffentlichen Typen bleiben erlaubt.

Verhaltensänderungen. Änderungen, die das Schema kompatibel lassen, aber das Laufzeitverhalten ändern – Standardwerte, Anzeigeregeln, Einstellungen für Autovervollständigung und Autoinkrement, Change Streams, nicht eindeutige Indizes, Methoden-Timeouts –, behalten ihre Stufe und stehen im Bericht und in CHANGELOG.md in einem eigenen Abschnitt „Behavioural changes", zusammen mit Änderungen, die eine Bestätigung erfordern. Ein eindeutiger Index auf einer stabilen Basis (ein Typ, von dem andere Modelle ableiten dürfen: öffentlich, nicht final, derivable: Any; in CK-Sprache 1 System/Entity und System/Configuration) bleibt MAJOR und erfordert zusätzlich eine Bestätigung, weil jeder abgeleitete Typ in jedem abhängigen Modell den Index erhält. securitySensitive: true markiert Passwort-Hashes, Security-Stamps, Tokens und 2FA-Geheimnisse (nur CK-Sprache 2). Eine Standardwert-Änderung ist nicht verhaltensbezogen, sondern brechend: Die Standardwerte einer Attributdefinition zu entfernen, die als Pflichtattribut zugewiesen oder öffentlich ist (ein anderes Modell kann sie als Pflicht zuweisen), ist MAJOR – sonst entstünde ein Pflichtattribut ohne Standardwert in zwei Minor-Releases. In CK-Sprache 2 wird ein Index über seine Feldpfade (ohne Groß-/Kleinschreibung) zugeordnet: Nur die Schreibweise eines Pfads zu ändern ist keine Änderung, Unique → UniqueNotDeleted oder eindeutig → nicht eindeutig ist MINOR, und UniqueNotDeleted → Unique oder einen Index eindeutig zu machen ist MAJOR.

Optionales Mitglied hinzufügen oder X-2 veröffentlichen? Fügen Sie das Mitglied zu Named-1 hinzu, wenn Implementierungen es nicht bereitstellen müssen (isOptional: true). Müssen alle Implementierungen es bereitstellen oder ändert sich ein bestehendes Mitglied, veröffentlichen Sie Named-2 neben Named-1; Implementierungen wechseln dann in ihrem eigenen Tempo.

Betriebsregel: gemeinsame Kataloge

Veröffentlichen Sie keine ckLanguage: 2- oder bereichserhaltende Version eines Basismodells (zum Beispiel System oder Basic) in einen gemeinsamen Katalog – die GitHub-Kataloge (octo-ckc) oder jeden Katalog, gegen den andere Teams kompilieren –, solange nicht jeder Service, der diesen Katalog nutzt, die CK-v2-Engine ausführt. Nach einer solchen Veröffentlichung erbt jedes gegen den Katalog kompilierte abhängige Modell die minEngineVersion der Basis und wird unter ck-models/v3/ veröffentlicht, das ältere Engines nicht lesen. Siehe CK-Sprache 2.

Für bereichserhaltende Modelle werden die deklarierten Bereiche (dependencyRanges) pro Abhängigkeit verglichen: Ein angehobener oder gesenkter Floor und ein innerhalb derselben Major-Version erweiterter oder verengter Bereich sind MINOR – außer der neue Bereich oder Floor schließt die Abhängigkeitsversion aus, die das vorherige Release aufgelöst hat: das ist MAJOR, weil ein Tenant, der das vorherige Release mit dieser Version installiert hat, ein Downgrade bräuchte –, ein Bereich oder Floor, der in eine andere Major-Version wechselt, ist MAJOR, eine neue Bereichsabhängigkeit ist MINOR und eine entfernte MAJOR. Der Wechsel eines Modells von exakten Pins zur Bereichserhaltung (oder zurück) ist MINOR – außer der Wechsel zurück pinnt eine andere Version als die, die das vorherige Release aufgelöst hat; das ist MAJOR. Ein angehobener Floor schließt die bisherige Auflösung aus, sobald er über sie hinausgeht. Jede deklarierte Abhängigkeit trägt außerdem usedSurface: die Elemente und Mitglieder der Abhängigkeit, die das Modell verwendet (Basistypen und -Records, implementierte und erweiterte Interfaces, wiederverwendete Attributdefinitionen, Records und Enums als Werttypen, Assoziationsrollen und -ziele, sowie Attributpfade von Indizes und ownerAttributePath in einen geerbten Typ der Abhängigkeit), mit einem sha256-Hash usedSurfaceHash. usedSurface wird nicht selbst klassifiziert; es zeigt später beim Import (F2.5), welchen Verbraucher eine Änderung brechen würde. Verhaltens- und Bedeutungsänderungen (Standardwerte, Anzeigeregeln, Bedeutung eines Werts) kann es nicht erkennen. Der exakte dependencies-Abschluss wird weiter wie bisher verglichen; die Regel „aufgelöste Abhängigkeit geändert → MINOR" entfällt für bereichserhaltende Modelle erst mit einem späteren Release (F2.4).

Eingebettete Modelle: Downgrade-Schutz und Neuvalidierung​

Services betten die CK-Modelle ein, die sie benötigen (System, System.StreamData, System.Identity, service-verwaltete Modelle wie System.UI), und importieren sie in einen Tenant, wenn der Tenant aufgelöst oder eingerichtet wird. Während eines Rolling Updates oder wenn Services unterschiedlicher Versionen parallel laufen, kann ein Service eine ältere Version einbetten, als der Tenant bereits besitzt. Jeder eingebettete Import und jeder Import beim Start durchläuft daher einen Downgrade-Schutz, der das installierte Modell anhand des Namens vergleicht:

Im Tenant installiertEntscheidungLog
nichts oder eine ältere Versionimportieren (Upgrade, Migrationen laufen wie üblich)INFO
dieselbe Versionnichts zu tun (ausstehende Migrationen werden erneut versucht)DEBUG
eine neuere Version derselben Major-Versionüberspringen – der Tenant behält sein neueres ModellINFO downgrade prevented
eine höhere Major-Versionüberspringen – der Service läuft gegen das neuere Modell weiterWARN this service is too old for the tenant

Ein übersprungener Import sendet keine Tenant-Update-Benachrichtigung, führt keine Migration aus und lässt den CK-Cache unverändert. Jedes Überspringen wird einmal pro Prozess protokolliert (Wiederholungen auf DEBUG). Die Entscheidung wird unter der Modell-Import-Sperre wiederholt, sodass sich zwei parallel startende Services nicht gegenseitig downgraden können.

Konsequenzen:

  • Ein älterer Service läuft gegen das neuere System des Tenants – der Laufzeitcode arbeitet mit versionslosen IDs, und der CK-Cache wird aus dem Installierten aufgebaut.
  • Sein eigenes exakt gepinntes Service-Modell (zum Beispiel ein gegen System-2.5.0 kompiliertes System.Bot) wird ResolveFailed, solange der Tenant System 2.6.0 besitzt, und seine Typen verschwinden aus dem Schema des Tenants, bis der Service aktualisiert ist. In Produktion werden alle Services gemeinsam released, daher ist dieses Fenster der Rollout. Bereichserhaltende Service-Modelle bleiben Available.
  • Blueprint-Installationen verwenden denselben Schutz für ihre ckModelDependencies (siehe oben).

Explizite Importe dürfen downgraden. ImportCk über octo-cli oder die API ist eine Entscheidung des Betreibers und wird nicht geschützt: Es kann eine ältere Version installieren, protokolliert als WARN Explicit downgrade of CK model ... from X to Y. Bettet ein laufender Service eine neuere Version dieses Modells ein, wird es bei der nächsten Tenant-Auflösung wieder hochgezogen.

Neuvalidierung von ResolveFailed-Modellen​

Am Ende jedes Imports in einen Tenant validiert die Engine alle Modelle im Zustand Available und ResolveFailed neu:

  • ein ResolveFailed-Modell, dessen Abhängigkeiten wieder aufgelöst werden, wird Available (INFO), seine Collections und Indizes werden wiederhergestellt und der CK-Cache neu geladen;
  • ein Available-Modell, das sich nicht mehr auflösen lässt, wird ResolveFailed (WARN mit der nicht erfüllten Abhängigkeit, z. B. exact pin System-2.5.0: installed System-2.6.0);
  • ein Modell, das weiterhin fehlschlägt, bleibt ohne weitere Logzeilen ResolveFailed.

Ein eingebetteter Import, der sein Modell bereits im Zustand ResolveFailed installiert vorfindet, löst die Neuvalidierung ebenfalls aus, sodass ein Neustart ein solches Modell auch ohne Import heilt. Früher erholte sich ein ResolveFailed-Modell nur, wenn es erneut importiert wurde.

Metriken​

Der Schutz und die Neuvalidierung erzeugen Zähler auf dem Meter Meshmakers.Octo.MongoDb (Prometheus-Namen, kein Tenant-Label – der Tenant steht in der Logzeile):

MetrikLabelsBedeutung
octo_ck_embedded_import_skipped_totalmodel, reason = newer_installed | newer_major_installedEingebettete Importe, die übersprungen wurden, weil der Tenant eine neuere Version besitzt
octo_ck_explicit_import_downgraded_totalmodelExplizite Importe, die eine ältere Version installiert haben
octo_ck_model_revalidated_totalresult = recovered | still_failedErgebnisse der Neuvalidierung von ResolveFailed-Modellen

Eine steigende Anzahl newer_major_installed bedeutet, dass ein Service für einen Tenant zu alt ist und aktualisiert werden sollte.

Siehe auch​