Adding compatibility to model.yaml
To make a model’s ports comparable, add two things to its model.yaml:
- a top-level
compatibilityblock that lists the profiles the model uses - a
contracton each port you want to describe
Nothing else in the file changes, and schema_version stays "2.0". Structural fields such as signal_type, dtype and shape stay where they are. The contract adds what the data means.
schema_version: "2.0"
standard: other
biosim:
entrypoint: src.model:Model
communication_step: 1.0
io:
inputs:
- name: expression
signal_type: array
dtype: float32
shape: ["*"]
outputs: []What the example says
compatibility.profilesimports the gene expression counts profile, pinned by itssha256. You can find a profile’srefandsha256in the catalogue or withbiosimulant compatibility profiles list.profile_refsapplies that profile to theexpressioninput.semanticsays the values are gene expression measured in a biological sample.representation.kind: dense_vectorsays there’s one value per gene.identifierssays genes are named with Ensembl gene IDs. In a real model, setnamespace_versionto the Ensembl release you used.biological_context.species: NCBITaxon:9606says the data is from humans, using the NCBI Taxonomy ID.
The gene expression counts profile requires all six of these contract fields. Check the file with:
biosimulant compatibility validate model.yamlIf the file is valid, the command prints:
{
"findings": [],
"opted_in": true,
"valid": true
}If a required field is missing or a profile isn’t imported, valid is false, each problem is listed under findings, and the command exits with status 1.
Rules for contracts
compatibility.profileslists every profile the model uses, each pinned bysha256.contract.profile_refsapplies profiles to one port. A port can only use profiles listed incompatibility.profiles.- An input’s
contractdescribes what the input accepts, whatever form the data arrives in. - If an input lists
accepted_profiles, each entry can have its owncontractthat narrows the input’s contract for that form. It can’t loosen it. - An output’s
contractdescribes what the output guarantees to send. - A contract written inline can add detail to a referenced contract, but can’t loosen it.
- A published profile reference needs a versioned URL and a matching
sha256. - Namespaced
extensionsare kept. Comparison ignores them unless it supports that namespace.
Your Python code still defines how the model runs. When Biosimulant loads a packaged model, it checks that the ports in model.yaml match the ports your code declares, including signal type, data type and shape. If they don’t match, loading fails. If they match, the contracts from model.yaml are attached to the model’s ports.
Models with and without compatibility
model.yaml | Validation | Comparing its ports | Running the model |
|---|---|---|---|
No compatibility block | Existing checks only | UNKNOWN (not enough information to decide) | Unchanged |
Valid compatibility block | Existing checks plus compatibility checks | A report with a status and findings | Unchanged |
Invalid compatibility block | The package build fails | Not available | The package isn’t built |
Building a model that has a compatibility block needs the compatibility extra: pip install 'biosimulant[compatibility]'. The built package includes payload/compatibility.lock.json, and your source model.yaml isn’t changed.
For every other model.yaml field, see the model.yaml schema.