Construction Kit Versioning Rules
CK model versions follow SemVer, and dependencies are declared as version ranges — but which concrete version a range resolves to depends on where the resolution happens. Getting this wrong is the most common cause of ResolveFailed models and failed blueprint installs, so the rules are spelled out here in one place.
Where Ranges Are Resolved — and to Which Version
| Context | Input | Resolves to |
|---|---|---|
Compile / publish (octo-ckc) | Ranges in the source ckModel.yaml | Highest published version satisfying the range — frozen into the compiled library as an exact pin |
| Tenant import / FixAll | Exact pins of the compiled library | Exactly the pinned versions — the tenant must hold them precisely |
Blueprint apply (ckModelDependencies) | Ranges in blueprint.yaml | The range's lower bound (floor) is the install target |
Two safeguards soften the blueprint floor rule:
- No downgrade: if the tenant already holds a model of the same name at a version at or above the floor, the import is skipped entirely.
- Service-managed redirect: for service-managed models (
System,System.*), the install target is redirected to the version the services ship, provided it satisfies the floor.
Practical consequence: a floor must be installable
Because the blueprint engine installs the floor on a fresh tenant, the floor version itself must be resolvable together with all other declared dependencies. A typical failure: EnergyCommunity-[4.0,5.0) next to Basic.Energy-[1.3,2.0) — if EnergyCommunity 4.0.0 was compiled (and therefore exactly pinned) against Basic.Energy 1.2.x, a fresh install tries 4.0.0, whose pin conflicts with the 1.3 floor, and fails with:
CK model 'EnergyCommunity-4.0.0' could not be installed; required CK model
dependencies may be missing or still importing
This message fires whenever, after the import attempt, no model of that name is in state Available — the underlying dependency-resolution error is swallowed by the parallel-startup import path, so this post-check is the only signal. The fix is to raise the floor to the first version that was compiled against the new dependency (EnergyCommunity-[4.1,5.0)).
The Cascade Rule
When a model's dependency moves, the model itself must be rebuilt, bumped, and republished — and every blueprint floor that points at it must move too.
Step by step, using Basic.Energy → EnergyCommunity as the example:
Basic.Energypublishes a new version (say1.3.0).EnergyCommunitystill pins1.2.x(compile-time freeze). It must be recompiled so the range re-resolves to1.3.0, and republished with a version bump — the SemVer gate (OCTO-CK100) enforces the bump because the resolved dependency set changed.- Any blueprint declaring
EnergyCommunity-[4.0,5.0)should raise its floor to the first rebuilt version, or fresh installs will target a version that is incompatible with the new dependency floor (see above).
A blueprint's blueprint.yaml (ckModelDependencies) and its seed-data file (dependencies: header in the runtime-model YAML) declare CK version constraints independently and are resolved by different code paths. When you move a floor, move it in both files — a lagging seed pin quietly reintroduces the incompatible pairing.
Upgrading an already-provisioned tenant follows the same order: publish the rebuilt dependent model to the catalog before upgrading the dependency on the tenant. Running FixAll after only the dependency was published upgrades the dependency but leaves the dependent at a version whose pins no longer resolve — the dependent flips to ResolveFailed and its types vanish from the tenant's GraphQL schema. Recovery: publish the rebuilt dependent, RefreshCatalogs, FixAll, then ClearCache.
The SemVer Gate (octo-ckc ValidateVersion)
CI validates every CK library against its published baseline before publishing. The gate classifies the model diff (major / minor / patch) and enforces a sufficient version bump:
| Code | Meaning |
|---|---|
OCTO-CK100 | Declared version does not satisfy the required bump over the published baseline — version too low. Also triggered when the resolved dependency set changed (see cascade rule). |
OCTO-CK101 | Declared version is lower than the published version — downgrade, not allowed. |
OCTO-CK102 | Catalog source unreachable — the baseline could not be determined. Never treated as a first publication. |
OCTO-CK103 | A declared dependency range is satisfied by no published version (and by no sibling package validated earlier in the same run). |
OCTO-CK104 | The diff requires a major bump but no migration script targets the declared version (error only with --requireMigrationForMajor, otherwise a warning). |
Notes:
- Sibling packages validated in the same run count as published for the
OCTO-CK103check — so same-commit dependency bumps across sibling models in one repository work. - Any
OCTO-CK1xxfinding makes the command exit non-zero (-6, which surfaces as250in most shells). Gate CI onexit code != 0, never on== 1. - A separate lint family (
OCTO-CK001/OCTO-CK002) validates runtime-state markers at build time and is unrelated to the SemVer gate.
Change classification examples
| Change | Classification |
|---|---|
| New type, attribute, or enum member | MINOR |
Flagging an existing attribute isRuntimeState: true | MINOR |
| Removing or renaming a type/attribute, changing an attribute's type | MAJOR |
| Description/metadata-only changes | PATCH |
Changing a type's displayNameRule / displayDescriptionRule | PATCH |
See Also
- Library Management — catalogs, compatibility checks, import pipeline
- Blueprints —
ckModelDependencies, force re-apply semantics - CK Model Migrations — migration scripts for major changes