{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Transferability Statement",
  "description": "Where something's results are valid, which reference or calibration artifacts it depends on, and what must happen to each to make the results valid elsewhere. Factored out of `ogc.focal.transferability.workflow` so the same bundle can attach to something other than a CWL Workflow \u2014 a step, a process, a delivered dataset \u2014 and carrying no CWL assumption of its own.\nThree lists, each addressable by `id`, joined by reference rather than by nesting:\n- `envelope` \u2014 the validity envelope, as\n  [`envelopeConstraint`](bblocks://ogc.focal.transferability.envelopeConstraint) statements.\n- `artifacts` \u2014 the reference/calibration artifacts, declared once. - `rules` \u2014 what happens to which artifacts under which envelope conditions.\n**Why three lists and not nesting.** An earlier draft nested rules inside artifacts and kept the envelope entirely separate, so nothing connected a rule to the boundary it was evaluated against. UP-WF2 is where that breaks: it has two different coverage footprints and three artifacts, every rule saying \"different geographic coverage\", and no way to record that the LST datasets are bounded by one and the CLMS layers by the other. Asked \"can I run this in Kyiv?\", a consumer could not tell which rule fires. Nesting rules under artifacts fixes that one case and fails the next: an artifact bounded on two axes at once needs a conjunction, which a tree cannot express. Citing ids costs one indirection and expresses both, plus the case that motivated neither \u2014 FP-WF2's four artifacts sharing a single boundary, stated once rather than four times.\n**Rules are exceptions; silence means reuse.** A statement lists what has to change. An artifact no rule fires for, over a given target, is reused unchanged. That default is what makes the model answerable rather than merely inspectable: without it, \"no rule fires\" is ambiguous between *nothing needs doing* and *nobody checked*, and every consumer has to guess. The ambiguity is closed structurally rather than by convention: `envelope`, `artifacts` and `rules` are all required, so an empty one of any of them is something an author wrote down, not something missing. Absent from the document entirely, the statement says nobody has looked; an empty array inside it says somebody looked and found nothing.\nTwo consequences worth stating plainly. A rule whose only action is `reuse-as-is` restates the default, which is worth doing where it makes a cascade legible (UP-WF2 pairs `inside` with `outside` over one constraint) and is noise otherwise. And an **empty `envelope` is a claim, not a blank**: it says the results carry no validity boundary at all, which is what a genuinely universal workflow looks like and what UP-WF1's questionnaire literally answers (\"All parts are portable\"). Record why in `transferabilityNotes` \u2014 a boundary nobody could find and a boundary that does not exist are the same empty array otherwise.\n**Conjunction and disjunction.** A rule's `when` is an AND: every condition must hold for the rule to fire. A disjunction is written as two rules. That is a deliberate limit rather than a missing feature \u2014 two conditions leading to the same action really are two statements, and keeping them separate keeps each traceable to the sentence in a questionnaire it came from, which a nested boolean expression does not. `actions` remains an OR-set: any one resolves the rule.\n",
  "allOf": [
    {
      "$ref": "https://ogcincubator.github.io/bblocks-focal/build/annotated/focal/transferability/notes/schema.json"
    },
    {
      "type": "object",
      "required": [
        "envelope",
        "artifacts",
        "rules"
      ],
      "properties": {
        "envelope": {
          "type": "array",
          "items": {
            "$ref": "https://ogcincubator.github.io/bblocks-focal/build/annotated/focal/transferability/envelopeConstraint/schema.json"
          },
          "description": "The validity envelope, as role/dimension/value statements. Required, but **an empty array is a meaningful value**, the same way it is for `rules`: it says the results were assessed and carry no validity boundary. An earlier draft required at least one entry, on the reasoning that inventing a boundary to satisfy the schema is worse than leaving a workflow unmodelled. That is still true, and the minimum did not achieve it: it made \"valid everywhere\" inexpressible except by drawing a world-sized polygon, and it left the one workflow whose source states no boundary (UP-WF1) with no honest representation at all rather than one saying exactly that. Say which case it is in `transferabilityNotes`.\n",
          "x-jsonld-id": "https://w3id.org/ogc/hosted/focal/transferability/properties/envelope",
          "x-jsonld-container": "@set"
        },
        "transferabilityNotes": {
          "type": "string",
          "description": "Why this statement is shaped as it is, where that is not self-evident \u2014 most usefully on an empty `envelope` or empty `rules`, to distinguish a boundary that does not exist from one nobody could establish. Uplifts to `rdfs:comment`. Mixed in from bblocks://ogc.focal.transferability.notes.\n",
          "x-jsonld-id": "http://www.w3.org/2000/01/rdf-schema#comment"
        },
        "artifacts": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/artifact"
          },
          "description": "The reference and calibration artifacts this statement's rules govern, each declared once and cited by `rules[].appliesTo`. May be empty when every rule is about the workflow as a whole.\n",
          "x-jsonld-id": "https://w3id.org/ogc/hosted/focal/transferability/properties/artifacts",
          "x-jsonld-container": "@set"
        },
        "rules": {
          "type": "array",
          "items": {
            "$ref": "https://ogcincubator.github.io/bblocks-focal/build/annotated/focal/transferability/rule/schema.json"
          },
          "description": "What must happen, to which artifacts, under which conditions. **An empty array is a meaningful value**: it says the artifacts were assessed and none needs adapting, which is a positive portability fact and quite different from the property being absent, which says nobody has looked. Requiring at least one entry would force anyone in the first situation to invent a rule.\n",
          "x-jsonld-id": "https://w3id.org/ogc/hosted/focal/transferability/properties/rules",
          "x-jsonld-container": "@set"
        }
      }
    }
  ],
  "$defs": {
    "artifact": {
      "title": "Artifact dependency",
      "type": "object",
      "required": [
        "id",
        "artifact",
        "artifactRole"
      ],
      "properties": {
        "id": {
          "$ref": "https://opengeospatial.github.io/bblocks/annotated-schemas/ogc-utils/iri-or-curie/schema.json",
          "description": "Identifier for this artifact, cited by `rules[].appliesTo`. An IRI, a CURIE, or a bare local name resolved against the document base (see bblocks://ogc.ogc-utils.iri-or-curie). A shared reference dataset that several workflows depend on is worth identifying globally, for the same reason a shared envelope constraint is.\n",
          "x-jsonld-id": "@id"
        },
        "artifact": {
          "type": "string",
          "description": "Label identifying the artifact, in the words the source used (e.g. \"downscaled FOCAL climate data\", \"Quitt climate-zone thresholds/limits\"). Uplifts to `dcterms:title` on a `prov:Entity`.\n",
          "x-jsonld-id": "http://purl.org/dc/terms/title"
        },
        "artifactRole": {
          "type": "string",
          "examples": [
            "workflow-input",
            "workflow-output",
            "external-resource",
            "infrastructure"
          ],
          "description": "What kind of thing this artifact is, independent of whether an executable workflow description exists that could give it an identifier yet. The eight FOCAL questionnaires' artifacts are not uniformly workflow inputs: some are inputs, some are outputs later reused as another run's input (a trained model), and some never appear in an executable graph at all (physical infrastructure to be re-deployed; an optional validation reference). Open vocabulary \u2014 see bblocks://ogc.focal.transferability.vocab.\n",
          "x-jsonld-id": "https://w3id.org/ogc/hosted/focal/transferability/properties/artifactRole",
          "x-jsonld-type": "@id",
          "x-jsonld-base": "https://w3id.org/ogc/hosted/focal/transferability/artifact-roles/"
        },
        "acceptanceCriteria": {
          "$ref": "https://ogcincubator.github.io/bblocks-focal/build/annotated/focal/transferability/acceptanceCriteria/schema.json",
          "description": "What a dataset must satisfy to serve as this artifact: the variable it must carry, the units that variable may be in, the axes it must have, the grids it may be on, any schema it must conform to. See bblocks://ogc.focal.transferability.acceptanceCriteria.\n**This is what makes a `replace-with-local-equivalent` rule actionable.** The action says something must change; these say what would count as having changed it correctly, which is what a platform needs in order to accept or reject a candidate dataset on the user's behalf rather than hand the question back to a person.\nIt lives on the artifact rather than on the rule because it is a standing property of the interface, true whether or not anything is being transferred. A substitution is merely when it becomes visible. Optional, and thinly evidenced (UP-WF3, and loosely UP-WF2's planned Eurostat input) because the questionnaires never asked.\n",
          "x-jsonld-id": "https://w3id.org/ogc/hosted/focal/transferability/properties/acceptanceCriteria"
        },
        "artifactRef": {
          "type": "string",
          "format": "json-pointer",
          "pattern": "^/",
          "examples": [
            "/inputs/climate_data",
            "/outputs/trained_growth_model"
          ],
          "description": "JSON Pointer (RFC 6901) locating the artifact inside the document this statement annotates. For the CWL profile in bblocks://ogc.focal.transferability.workflow that means `/inputs/<id>` or `/outputs/<id>`, but the pointer carries no CWL assumption. Optional: meaningful only for the `workflow-input` and `workflow-output` roles, and only fillable once a real Application Package exists to point into. Omit it rather than guess.\n",
          "x-jsonld-id": "https://w3id.org/ogc/hosted/focal/transferability/properties/artifactRef"
        },
        "transferabilityNotes": {
          "type": "string",
          "description": "Free-text note about the artifact. Uplifts to `rdfs:comment`.",
          "x-jsonld-id": "http://www.w3.org/2000/01/rdf-schema#comment"
        }
      }
    }
  },
  "x-jsonld-prefixes": {
    "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
    "focal-transf-prop": "https://w3id.org/ogc/hosted/focal/transferability/properties/",
    "dcterms": "http://purl.org/dc/terms/",
    "focal-transf": "https://w3id.org/ogc/hosted/focal/transferability/",
    "prov": "http://www.w3.org/ns/prov#"
  }
}