<!-- Source: https://docs.biosimulant.com/standards/model-compatibility/rules -->

# Rules and statuses

When you compare a source port with a target port, the comparison rules from each profile run against the two port contracts. Each rule produces a finding, and the findings combine into one status. This page lists the operators rules can use, what each status means, and what a finding looks like.

Rules are data, not code. A rule names a field in each contract using a JSON Pointer path, such as `/contract/measurement/unit`, and picks one operator from the list below. It can't contain JavaScript, Python, templates or other expressions, so loading a profile never runs code. Field values are checked against JSON Schema (Draft 2020-12) first.

Here is a rule from the gene expression counts profile:

```json
{
  "source": "/contract/biological_context/species",
  "target": "/contract/biological_context/species",
  "operator": "context-compatible",
  "missing": "unknown",
  "reason_code": "BMCS_VALUE_MISMATCH",
  "severity": "error"
}
```

It reads the species from both contracts and compares them. If either side leaves the species out, the result is `UNKNOWN`. The `missing` field can also be `conditional`, `incompatible` or `ignore`.

## Operators

| Operator | Passes when |
|---|---|
| `equal` | Both values are the same |
| `not-equal` | The values differ |
| `in` | The source value is one of the target's listed values |
| `not-in` | The source value isn't in the target's list |
| `subset` | Every item in the source list is in the target list |
| `superset` | The source list contains every item in the target list |
| `range` | The source range (`minimum` to `maximum`) sits inside the target range |
| `pattern` | The value matches a pattern |
| `same-dimension` | Both quantities have the same physical dimension, for example both are concentrations |
| `labels-equal` | Both label lists are identical and in the same order |
| `labels-permutation` | Both lists have the same labels in a different order, so a reorder can connect them |
| `unit-convertible` | The units are the same, or the release's unit table has a conversion between them (currently nM, µM and mM) |
| `term-equivalent` | Two ontology terms mean the same thing |
| `term-subsumes` | One ontology term includes the other, for example a broader cell type |
| `mapping-total` | Every source identifier maps to a target identifier |
| `mapping-bijective` | Identifiers map one-to-one in both directions |
| `context-compatible` | The contexts match, or the target accepts any context (`any`, `unspecified` or null) |
| `digest-equal` | Two sha256 hashes match |

**Info:**

  Version 0.1.0-alpha.5 implements every operator above in both Python and TypeScript. Ontology and identifier-mapping rules need an exact, sha256-pinned snapshot when equality alone is not enough. If a needed snapshot is missing or invalid, the result is `UNKNOWN` with a stable reason code. Reports and plans record the snapshots they used.

  Pattern checks are limited in length and reject unsafe forms. This keeps profile rules useful without letting a profile run arbitrary or expensive code.

### For maintainers

A new profile that only uses existing operators needs a new data release and nothing else. A new operator needs code and conformance tests in both the Python and TypeScript implementations.

## Order of checks

The specification groups checks from structure to policy:

1. Port direction and name
2. Whether the port carries a state or an event, and when data is produced and used
3. Signal type, data type, shape and schema
4. Dimensions, axes and feature order
5. Units, scale, normalization and endpoint
6. Biological meaning
7. Identifier namespace and mappings
8. Biological and experimental context
9. Time context
10. Origin, provenance, uncertainty and missing values
11. File format
12. Security, licensing, where data may be stored, and workspace policy

In this release, the reference implementations run each profile's rules in the order the profile lists them.

## Statuses

| Status | Meaning | Default policy decision |
|---|---|---|
| `EXACT` | The two contracts are identical (same sha256) | `ALLOW` |
| `DIRECT_COMPATIBLE` | The source satisfies the target as it is, with no conversion | `ALLOW` |
| `LOSSLESS_CONVERSION_AVAILABLE` | A conversion that loses no information can connect them, such as nM to µM | `ALLOW` |
| `LOSSY_CONVERSION_REQUIRES_APPROVAL` | A conversion exists, but it may lose information | `APPROVAL_REQUIRED` |
| `INFERENCE_MODEL_REQUIRED` | The target needs data the source doesn't have, so a model must estimate it | `APPROVAL_REQUIRED` |
| `CONDITIONAL` | Compatibility depends on a condition that hasn't been checked | `APPROVAL_REQUIRED` |
| `INCOMPATIBLE` | At least one field contradicts the target, for example mouse data sent to a human-only input | `BLOCK` |
| `UNKNOWN` | Not enough information to decide, usually because a required field is missing | `BLOCK` |

When you build a plan, a policy can change the decision for `UNKNOWN`, `CONDITIONAL`, and the conversion and inference statuses.

How findings combine:

- If any rule finds a contradiction, the status is `INCOMPATIBLE`, even if other fields are missing.
- Otherwise, if any rule lacks the information it needs, the status is `UNKNOWN`.
- If either port has no contract at all, the status is `UNKNOWN` with reason code `BMCS_CONTRACT_NOT_DECLARED`.

## Findings

Every finding has:

- `dimension`: the part of the contract that was checked, such as `biological_context`
- `state`: the result of this rule
- `severity`: `error`, `warning` or `info`
- `reason_code`: a stable `BMCS_*` code that you can match on in code
- `explanation`: a short message for people

A finding can also include `evidence` (the two values that were compared), `source_path`, `target_path` and `remediation`.

Here the source outputs mouse data and the target expects human data. Both ports use the gene expression counts profile:

```json
{
  "dimension": "biological_context",
  "state": "INCOMPATIBLE",
  "severity": "error",
  "reason_code": "BMCS_VALUE_MISMATCH",
  "explanation": "/contract/biological_context/species: 'context-compatible' check failed.",
  "evidence": {
    "source": "NCBITaxon:10090",
    "target": "NCBITaxon:9606"
  }
}
```

If the source leaves out the species instead, the finding is `UNKNOWN`:

```json
{
  "dimension": "biological_context",
  "state": "UNKNOWN",
  "severity": "info",
  "reason_code": "BMCS_REQUIRED_EVIDENCE_MISSING",
  "explanation": "/contract/biological_context/species is missing from the source or target contract."
}
```

Every reason code and its meaning is listed in [reason-codes.json](/standards/model-compatibility/v0.1/rules/reason-codes.json).
