Skip to main content

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

ContextInputResolves to
Compile / publish (octo-ckc)Ranges in the source ckModel.yamlHighest published version satisfying the range — frozen into the compiled library as an exact pin
Tenant import / FixAllExact pins of the compiled libraryExactly the pinned versions — the tenant must hold them precisely
Blueprint apply (ckModelDependencies)Ranges in blueprint.yamlThe 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.EnergyEnergyCommunity as the example:

  1. Basic.Energy publishes a new version (say 1.3.0).
  2. EnergyCommunity still pins 1.2.x (compile-time freeze). It must be recompiled so the range re-resolves to 1.3.0, and republished with a version bump — the SemVer gate (OCTO-CK100) enforces the bump because the resolved dependency set changed.
  3. 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).
Blueprint manifest and seed data pin independently

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:

CodeMeaning
OCTO-CK100Declared 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-CK101Declared version is lower than the published version — downgrade, not allowed.
OCTO-CK102Catalog source unreachable — the baseline could not be determined. Never treated as a first publication.
OCTO-CK103A declared dependency range is satisfied by no published version (and by no sibling package validated earlier in the same run).
OCTO-CK104The 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-CK103 check — so same-commit dependency bumps across sibling models in one repository work.
  • Any OCTO-CK1xx finding makes the command exit non-zero (-6, which surfaces as 250 in most shells). Gate CI on exit 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

ChangeClassification
New type, attribute, or enum memberMINOR
Flagging an existing attribute isRuntimeState: trueMINOR
Removing or renaming a type/attribute, changing an attribute's typeMAJOR
Description/metadata-only changesPATCH
Changing a type's displayNameRule / displayDescriptionRulePATCH

See Also