Standard steps
1
Build the execution artifact
Build the training image for the new version (K8s/Docker: OCI digest-pinned) or SIF/SQSH (Slurm), publish it to the runtime registry, and assign a
runtime_id.2
Declare the version variant
Add a new version entry under
runtime.versions in the recipe YAML: runtime_id, dependencies, and the version-bound differences — entrypoint override (entrypoint), parameter path overrides (path_overrides), and certified observer patch versions (observer_versions).3
Run adaptation tests
SDK unit tests cover the version matrix (entrypoint / parameter paths / observers asserted per version); full regression via
tests/.4
Canary release
Don’t make the new version
default_version at first: early adopters opt in explicitly with sf new --framework-version X / sf recipe upgrade --framework-version X. Switch the default once it’s stable.5
User upgrade
After the catalog is published, existing experiment locks show drift hints; users upgrade explicitly with
sf recipe upgrade — there is no silent switching.Framework-specific notes
What not to do
- ❌ Write
if version >= Xbranches in adapter code — version differences belong in recipe declarations; - ❌ Use latest / branch names as versions — only exact semver or full commits are accepted;
- ❌ Reuse an old
runtime_idto point at a new image — artifacts are immutable; new image, new id.
The full evaluation of this mechanism (why pinning is not over-coupling) is in the repo’s
docs/ops/upstream-version-adoption.md.