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
| Kontext | Eingabe | Löst auf zu |
|---|---|---|
Compile / Publish (octo-ckc) | Bereiche in der Quelle ckModel.yaml | Höchste veröffentlichte Version, die den Bereich erfüllt – als exakter Pin in die kompilierte Bibliothek eingefroren |
| Tenant-Import / FixAll | Exakte Pins der kompilierten Bibliothek | Genau die gepinnten Versionen – der Tenant muss sie präzise vorhalten |
Blueprint-Apply (ckModelDependencies) | Bereiche in blueprint.yaml | Die 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:
Basic.Energyveröffentlicht eine neue Version (sagen wir1.3.0).EnergyCommunitypinnt weiterhin1.2.x(Einfrieren zur Compile-Zeit). Es muss neu kompiliert werden, damit der Bereich neu zu1.3.0aufgelö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.- 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).
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:
| Code | Bedeutung |
|---|---|
OCTO-CK100 | Die 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-CK101 | Die deklarierte Version ist niedriger als die Baseline (die neueste veröffentlichte Version derselben Major-Version) – Downgrade, nicht erlaubt. |
OCTO-CK102 | Die Katalogquelle ist nicht erreichbar – die Baseline konnte nicht bestimmt werden. Wird nie als Erstveröffentlichung behandelt. |
OCTO-CK103 | Ein deklarierter Abhängigkeitsbereich wird von keiner veröffentlichten Version erfüllt (und von keinem Geschwisterpaket, das früher im selben Lauf validiert wurde). |
OCTO-CK104 | Das 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 als250zeigt). Gaten Sie CI aufexit 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:
- Gleiche Major-Version. Die Baseline ist die neueste veröffentlichte Version der deklarierten Major-Version.
Sind von
EnergyCommunity3.3.0und4.5.0veröffentlicht, wird ein deklariertes3.4.0mit3.3.0verglichen. 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 deklariertes3.2.0scheitert mitOCTO-CK101gegen3.3.0. - 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.0wird mit dem neuesten3.xverglichen, 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. - 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
ValidateVersionliefern daher dasselbe Ergebnis. Eine veröffentlichte Version gleich der deklarierten zählt weiterhin: Wer ein Modell ändert, ohne die Version zu erhöhen, scheitert mitOCTO-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).
| Code | Bedeutung |
|---|---|
OCTO-CK200 | Eine Änderung wird von der deklarierten Version nicht abgedeckt. Ein Fehler pro Änderung, mit Element, Änderung, erforderlichem Level und Mindestversion. |
OCTO-CK201 | Die deklarierte Version ist niedriger als die Baseline derselben Major-Version. |
OCTO-CK202 | Die 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:
| Wert | Baseline aus | Standard |
|---|---|---|
Local | dem lokalen Dateisystem-Katalog plus den zwischengespeicherten Remote-Katalogen; funktioniert ohne Netzwerk | außerhalb von CI (DebugL) |
Remote | nur den GitHub-Katalogen; der lokale Katalog wird ignoriert | wenn 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"
| Code | Bedeutung |
|---|---|
OCTO-CK203 | Für eine Änderung, die eine Bestätigung braucht, fehlt der passende Eintrag. |
OCTO-CK204 | Ein 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
reasonist Pflicht und erscheint im Urteil, im Build-Log und imCHANGELOG.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
| Änderung | Klassifizierung |
|---|---|
| Neuer Typ, neues Attribut oder neues Enum-Mitglied | MINOR |
Kennzeichnen eines bestehenden Attributs als isRuntimeState: true | MINOR |
Ändern des valueType eines Attributs von String auf Secret (Secret-Attribute) | MINOR |
Setzen, Entfernen oder Ändern des recordKey eines Records | MINOR |
Entfernen oder Umbenennen eines Typs/Attributs, Ändern des Typs eines Attributs (außer String → Secret) | MAJOR |
| Nur Beschreibungs-/Metadatenänderungen | PATCH |
Ändern der displayNameRule / displayDescriptionRule eines Typs | PATCH |
Ä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):
| Änderung | Klassifizierung |
|---|---|
Neues Interface, neuer implements-Eintrag an einem Typ, neue Methode | MINOR |
Interface entfernt, implements-Eintrag entfernt, Methode entfernt | MAJOR |
| Optionales Interface-Attribut oder optionale Interface-Assoziation hinzugefügt | MINOR – 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ügt | MAJOR – stattdessen eine neue Interface-Version (Named-2) neben der alten veröffentlichen |
| Interface-Mitglied optional gemacht | MINOR |
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 entfernt | MAJOR – 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 entfernt | MINOR |
targetCkInterfaceId einer Typ-Assoziation gesetzt oder geändert / entfernt | MAJOR / MINOR |
visibility Public → Internal / Internal → Public | MAJOR / MINOR |
derivable Any → Model / Model → Any | MAJOR / MINOR |
access einer Attributzuweisung verschärft (ReadWrite < ReadOnly < MethodOnly < Hidden) / gelockert | MAJOR / MINOR, mit einem Hinweis „Zugriff/Sicherheit" im Changelog |
access eines in beiden Versionen mit securitySensitive: true markierten Attributs verschärft | MINOR + Bestätigung erforderlich (Sicherheitsausnahme) |
securitySensitive gesetzt oder entfernt | MINOR |
ckLanguage von 1 auf 2 angehoben | MINOR – 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 gesenkt | MAJOR |
description einer Methode, Beschreibungen von Parametern und Fehlern, description eines Interfaces | PATCH |
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.
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 installiert | Entscheidung | Log |
|---|---|---|
| nichts oder eine ältere Version | importieren (Upgrade, Migrationen laufen wie üblich) | INFO |
| dieselbe Version | nichts zu tun (ausstehende Migrationen werden erneut versucht) | DEBUG |
| eine neuere Version derselben Major-Version | überspringen – der Tenant behält sein neueres Modell | INFO downgrade prevented |
| eine höhere Major-Version | überspringen – der Service läuft gegen das neuere Modell weiter | WARN 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
Systemdes 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.0kompiliertesSystem.Bot) wirdResolveFailed, solange der TenantSystem 2.6.0besitzt, 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 bleibenAvailable. - 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, wirdAvailable(INFO), seine Collections und Indizes werden wiederhergestellt und der CK-Cache neu geladen; - ein
Available-Modell, das sich nicht mehr auflösen lässt, wirdResolveFailed(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):
| Metrik | Labels | Bedeutung |
|---|---|---|
octo_ck_embedded_import_skipped_total | model, reason = newer_installed | newer_major_installed | Eingebettete Importe, die übersprungen wurden, weil der Tenant eine neuere Version besitzt |
octo_ck_explicit_import_downgraded_total | model | Explizite Importe, die eine ältere Version installiert haben |
octo_ck_model_revalidated_total | result = recovered | still_failed | Ergebnisse 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
- Library Management — Kataloge, Kompatibilitätsprüfungen, Import-Pipeline
- Blueprints —
ckModelDependencies, Semantik des erzwungenen erneuten Anwendens - CK-Modell-Migrationen — Migrationsskripte für Major-Änderungen