StandardsModel CompatibilityAdding to model.yaml

Adding compatibility to model.yaml

To make a model’s ports comparable, add two things to its model.yaml:

  • a top-level compatibility block that lists the profiles the model uses
  • a contract on 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.profiles imports the gene expression counts profile, pinned by its sha256. You can find a profile’s ref and sha256 in the catalogue or with biosimulant compatibility profiles list.
  • profile_refs applies that profile to the expression input.
  • semantic says the values are gene expression measured in a biological sample.
  • representation.kind: dense_vector says there’s one value per gene.
  • identifiers says genes are named with Ensembl gene IDs. In a real model, set namespace_version to the Ensembl release you used.
  • biological_context.species: NCBITaxon:9606 says 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.yaml

If 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.profiles lists every profile the model uses, each pinned by sha256.
  • contract.profile_refs applies profiles to one port. A port can only use profiles listed in compatibility.profiles.
  • An input’s contract describes what the input accepts, whatever form the data arrives in.
  • If an input lists accepted_profiles, each entry can have its own contract that narrows the input’s contract for that form. It can’t loosen it.
  • An output’s contract describes 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 extensions are 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.yamlValidationComparing its portsRunning the model
No compatibility blockExisting checks onlyUNKNOWN (not enough information to decide)Unchanged
Valid compatibility blockExisting checks plus compatibility checksA report with a status and findingsUnchanged
Invalid compatibility blockThe package build failsNot availableThe 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.