Specification
This page describes each object in the standard and what its fields are for. It’s for people building tools that read, write or check port contracts. If you only want to describe a model’s ports, start with Adding compatibility to model.yaml.
The JSON Schema files in the release define these objects exactly, and this page summarizes them. If this page and a schema disagree, the schema is correct. This page covers version 0.1.0-alpha.5, bundle sha256 sha256:6d0d9305eb16cf05749c94c04c16fb1ee9b8213957ef19cddaa95a961f665521.
All schemas use JSON Schema Draft 2020-12. You can write contracts in YAML, but they must convert to plain JSON, so values such as NaN or infinity aren’t allowed.
The compatibility block
| Field | Type | Required | What it does |
|---|---|---|---|
standard | URI | Yes | The version of the standard the model uses: https://biosimulant.com/standards/model-compatibility/v0.1 |
profiles | list of profile references | No | The profiles the model uses. Each reference can appear only once. |
extensions | object | No | Your own data, under a namespace. It’s kept, and comparison ignores namespaces it doesn’t support. |
Each profile reference has these fields:
| Field | Type | Required | What it does |
|---|---|---|---|
ref | URI | Yes | The profile’s versioned URL |
sha256 | string | No | The sha256 of the profile definition, written sha256: followed by 64 hex characters |
required | boolean | No | Defaults to true |
The schema lets you leave out sha256, but a published reference needs both a versioned URL and a matching sha256, so the profile can’t change without you noticing. Validators compare it with the installed profile.
Port contract
A port contract describes what a port’s data means. The standard itself doesn’t require any section. The profiles a port uses decide which fields are required. That way a port with only a partial description is still valid, and comparing a field that one side leaves out returns UNKNOWN.
| Section | Example fields | What it describes |
|---|---|---|
profile_refs | profile URLs | Which profiles apply to this port |
ref, sha256 | URL and hash of a shared contract | Where to find a contract defined elsewhere, and how to check it hasn’t changed |
semantic | concept, subject, process, role, endpoint, ontology terms | What the data is about biologically |
representation | kind, encoding, layout, feature space, ordering, sparsity | How the values are laid out |
dimensions | axes, labels, cardinality, coordinates | What each axis means and in what order |
identifiers | namespace, version, mappings | Which identifier system is used, such as Ensembl gene IDs |
measurement | quantity, unit, scale, normalization, detection limits | How to read the numbers |
biological_context | species, strain, tissue, cell type, disease, assay | Which organism, sample or experiment the data applies to |
lifecycle | state or event, sampling, interpolation, freshness | How the data behaves over time during a run |
origin | measured, curated, simulated, inferred, synthetic | Where the data came from |
uncertainty | distribution, variance, confidence, missing values | How reliable the values are |
artifact | media type, format, compression, checksum | How a file-based value is stored |
constraints | extra rules built from the standard operators | Checks beyond those in the profile |
security | classification, data use, residency, license, retention | Who may use the data, and where it may be stored |
extensions | namespaced object | Additions from third parties |
All 266 contract fields and their schemas are listed in items.json. To validate a whole contract, use the port contract schema.
Profiles
A profile is a reusable set of rules for one kind of data, such as gene expression counts. A profile definition has these required fields:
| Field | What it holds |
|---|---|
$id, profile_id, version | The profile’s identity |
domain, name, label, description | Where it sits in the catalogue, and what it’s for |
stage, review | Its release stage and scientific review record. See Stage and Review. |
applies_to | The signal types it can describe, such as scalar or array |
item_packs | The groups of contract fields it builds on |
requirements | Which contract fields must or should be present |
comparison_rules | How to compare each field between a source and a target |
transformation_policy | Whether lossless conversions, lossy conversions and inference are allowed or need approval |
scientific_claim | A plain statement of what the profile does and doesn’t claim |
Each requirement names a field path, a level (required, conditional, recommended or optional), and optionally a JSON Schema for the value:
{ "path": "biological_context.species", "level": "required", "schema": { "type": "string" } }Each comparison rule names a field in the source and target contracts, an operator, what to do when a value is missing, a reason code and a severity. See Rules and statuses for the operators and an example rule.
A profile can build on others with extends, and can set fixed and allowed values. Profiles can’t extend each other in a loop. A child profile can add requirements or make them stricter. It can’t remove a parent’s requirement, loosen a fixed value, or relax how missing values are handled.
The reference implementations don’t expand extends yet. In this release, each profile lists its own requirements and rules in full.
Adapter and inference capabilities
A capability is a JSON description of one conversion step that a plan can use. See Adapters and inference models for a worked example.
| Object | What it describes | Required fields |
|---|---|---|
AdapterCapability | A conversion from one form to another, such as nM to µM | schema_version, ref, sha256, source, target, state, transformation_class, information_loss, release |
InferenceCapability | A model that estimates data the source doesn’t contain, such as expression from genotype | schema_version, ref, sha256, source, target, state, inferred_modality, assumptions, uncertainty, release |
Both can also list preconditions, evidence, limitations, loss_score and execution_cost. Describing a capability doesn’t give anyone permission to use it. The policy decides that.
Policy
A CompatibilityPolicy sets the decision for each kind of result. It must set unknown, conditional, lossless, lossy and inference, and can also set rules for license, security, cost, data_boundary (where data may go) and extensions.
Findings and reports
A CompatibilityFinding is the result of one rule. It has dimension, state, severity, reason_code and explanation. It can also include evidence (the values compared), source_path, target_path and remediation.
A CompatibilityReport is the full result of one comparison. It has:
schema_version,standardandbundle_sha256sourceandtarget, each with the sha256 of its contract and the profiles it usesstatus, the comparison statuspolicy_decisionfindingsdigest, the report’s own sha256
It can also include paths (candidate plans), snapshots, and quality_reference, a link to a Passport quality result. A report never replaces the Passport quality decision.
Plans, signal envelopes, locks and conformance records
| Object | What it is | Required fields |
|---|---|---|
ResolutionPlan | A plan: the chain of adapters or inference models chosen to connect a source to a target. A plan doesn’t change after it’s created, and its digest identifies it. | schema_version, standard, bundle_sha256, nodes, edges, reports, policy, approvals, digest |
SignalEnvelope | A value or file sent between ports during a run, with its actual context, origin, uncertainty, provenance and observation time | schema_version, contract_digest |
CompatibilityLock | The lock file compatibility.lock.json, which pins the exact profiles and contracts a package was built with | schema_version, standard, bundle_sha256, contracts, resolved_references, canonicalization, digest |
ConformanceManifest | A record of the conformance tests an implementation passed | schema_version, implementation, standard, bundle_sha256, supported_levels, fixture_results, digest |
How hashes are computed
Contracts, reports, locks and plans are identified by a hash written as sha256:<hex>. The specification computes it in these steps:
- Check the structural
iofields. - Load each referenced profile and check its sha256.
- Apply inherited fields and defaults.
- Merge the port’s own declarations and refinements.
- Apply only the normalization rules the standard declares.
- Keep ordered lists in order, and sort only lists declared as sets.
- Reject anything that isn’t plain JSON, such as
NaN, infinity or reference loops. - Serialize with the JSON Canonicalization Scheme, RFC 8785.
- Take the SHA-256 of those bytes.
The Python and TypeScript implementations apply the same profile inheritance, defaults, set sorting, canonical JSON and hashing rules. Their shared tests compare the final bytes and digests.
Adding compatibility doesn’t change how package, run or Passport hashes are computed. Compatibility hashes are stored alongside those records.
Schema files
- Manifest extension
- Profile reference
- Port contract
- Profile definition
- Catalogue
- Comparison rule
- Adapter capability
- Inference capability
- Policy
- Finding
- Report
- Resolution plan
- Signal envelope
- Compatibility lock
- Conformance manifest
The bundle manifest lists every file in the release with its sha256.