$schema: https://json-schema.org/draft/2020-12/schema
title: Transferability Envelope Constraint
description: "A single statement bounding where a workflow's results are valid: which
  `role` this fact plays (what the workflow was trained on vs. what its results are
  valid for vs. where it can technically run), which `dimension` it concerns (spatial,
  temporal, ecological, climatic, jurisdictional, grid-structure, ... \u2014 an open
  vocabulary), and the `value` itself.\nRepeatable, and `id`-addressable: rules cite
  a constraint by `id` to say which boundary they are evaluated against, so a workflow
  with two different footprints can state which artifact each one governs. FP-WF1
  needs three constraints at once (trained-on/spatial, valid-for/ecological, can-run-on/climatic),
  which is why role and dimension are independent axes rather than a single enum choice.\n**Values
  bind to published vocabularies rather than to FOCAL terms wherever one exists**,
  so a consumer that already understands GeoSPARQL or DCAT can evaluate the constraint
  without knowing anything about FOCAL: a spatial extent is a `geo:Geometry` carrying
  `geo:asWKT`, a calendar span is a `dcterms:PeriodOfTime` carrying `dcat:startDate`/`dcat:endDate`.
  That is what makes \"can I run this workflow over my area of interest?\" a query
  a GeoSPARQL engine can answer with `geof:sfWithin`, rather than a sentence a person
  has to read.\n"
allOf:
- $ref: https://ogcincubator.github.io/bblocks-focal/build/annotated/focal/transferability/notes/schema.yaml
- type: object
  required:
  - role
  - dimension
  - value
  properties:
    id:
      $ref: https://opengeospatial.github.io/bblocks/annotated-schemas/ogc-utils/iri-or-curie/schema.yaml
      description: 'Identifier for this constraint, so a rule can cite it in `when[].constraint`.
        Optional only for a constraint no rule refers to.

        An **IRI, a CURIE, or a bare local name** (see bblocks://ogc.ogc-utils.iri-or-curie).
        A local name is resolved against the document''s base URI and is right for
        a constraint specific to one workflow. An IRI or CURIE gives the constraint
        a **global identity**, which is what makes a boundary shareable: the EURO-CORDEX
        EUR-11 domain is the same extent for several FOCAL workflows, and each restating
        it as a private local name leaves nothing able to tell that they are the same
        boundary. Declaring it here under its global identifier says so.

        A CURIE expands only if its prefix is declared in the JSON-LD context (via
        `x-jsonld-prefixes` or an imported block); an undeclared prefix is read as
        a URI scheme and `acme:eur11` stays `acme:eur11`, which validates and means
        nothing. Use a full IRI unless the prefix is known to be in scope.

        Giving a constraint a global identifier makes the boundary shareable, not
        fetchable: it is still declared in full in every statement that cites it,
        so a reader always has the extent in front of them. What the identifier buys
        is being able to ask which workflows are bounded by this exact domain.

        '
      x-jsonld-id: '@id'
    role:
      type: string
      examples:
      - trained-on
      - derived-from
      - valid-for
      - can-run-on
      description: "Which aspect of the envelope this statement describes. Open vocabulary
        \u2014 see bblocks://ogc.focal.transferability.vocab.\n"
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/role
      x-jsonld-type: '@id'
      x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/roles/
    dimension:
      type: string
      examples:
      - spatial
      - temporal
      - ecological
      - climatic
      - jurisdictional
      - grid-structure
      description: 'Which axis of variation this statement constrains, and therefore
        what shape `value` takes. Open vocabulary, seeded from the eight FOCAL pilot
        questionnaires and expected to grow; a new term needs no schema change unless
        it also needs a new `value` shape.

        '
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/dimension
      x-jsonld-type: '@id'
      x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/dimensions/
    transferabilityNotes:
      type: string
      description: 'Why this value is what it is, where that is not self-evident:
        an approximated geometry, a fact inferred rather than stated by the source,
        a granularity the source left open. Uplifts to `rdfs:comment`. Mixed in from
        bblocks://ogc.focal.transferability.notes.

        '
      x-jsonld-id: http://www.w3.org/2000/01/rdf-schema#comment
    value:
      description: "The constraint value, shaped by `dimension`:\n- `spatial`/`jurisdictional`
        \u2014 a geometry, as `{\"asWKT\": \"POLYGON((...))\"}`. WKT rather\n  than
        GeoJSON coordinate arrays: it uplifts to a real `geo:wktLiteral`, which is
        the\n  form GeoSPARQL's topological functions actually operate on, it is one
        value rather than\n  a nested array so nothing is lost or reshaped in uplift,
        and it is dramatically more\n  compact (UP-WF2's European coverage MultiPolygon
        costs a few hundred characters\n  instead of 1,283 lines of Turtle). An approximate
        extent is expected and fine \u2014 a\n  published bounding box for a model
        domain, say \u2014 but it must be a real extent, since a\n  free-text place
        name cannot answer the containment question this dimension exists for.\n-
        `temporal` \u2014 either `{\"startDate\", \"endDate\"}` (a calendar span,
        uplifting to\n  `dcat:startDate`/`dcat:endDate` on a `dcterms:PeriodOfTime`)
        or `{\"scenarioMarker\"}`\n  for results that are not calendar-indexed at
        all. A Global Warming Level is the\n  evidenced case: it is reached in different
        years under different emissions scenarios\n  and ensemble members, so a calendar
        interval would be a fabrication rather than a\n  simplification. Markers are
        concepts, not free text, so `GWL+1.5` written two ways by\n  two pilots is
        one thing rather than two.\n- `grid-structure` \u2014 the set of grid types
        the workflow's gridded inputs may be on, as\n  `{\"gridTypes\": [\"regular-latlon\",
        \"rotated-pole\"]}`. A whitelist rather than a\n  description: `inside` means
        the target data's grid is one of these, `outside` that it\n  is not. This
        is a structured branch and not prose because UP-WF3's constraint (\"other\n
        \ projections are not handled\") is a hard interface requirement over a small
        enumerable\n  set \u2014 mechanically checkable, and *more* so than a bounding
        box, since the terms carry\n  the CF-conventions `grid_mapping_name` as their
        `skos:notation` and the datasets in\n  question declare exactly that.\n- **any
        dimension, as an analogy** \u2014 `{\"scheme\": ..., \"sameClassAs\": ...}`,
        saying the\n  target must fall in the same class of a published classification
        as some reference\n  does. This is the shape of every \"comparable to where
        we calibrated\" claim in the\n  corpus, and it is a *relation*, not a value:
        the source says the target must resemble\n  the training area, and says nothing
        about which classes the training area is in.\n  Enumerating those classes
        would state something the source never said and would go\n  stale the moment
        the training geometry is corrected, so the default is to name the\n  reference
        and let a platform derive the rest. Tested with `same-class-as` /\n  `different-class-from`
        rather than `inside`/`outside`.\n- `ecological`/`climatic`/anything else \u2014
        a plain string, where no classification\n  captures the claim. \"A comparable
        ecological range\" does not become machine-checkable\n  by being wrapped in
        coordinates it does not have. A rule may still cite such a\n  constraint;
        the condition is then a judgement a person makes, stated in the same\n  structure,
        which is honest about where automation stops. Prefer the analogy shape above\n
        \ where a scheme does capture it: it says the same thing and a machine can
        settle it.\n"
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/value
oneOf:
- title: Spatial or jurisdictional extent (geometry-valued)
  properties:
    dimension:
      enum:
      - spatial
      - jurisdictional
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/dimension
      x-jsonld-type: '@id'
      x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/dimensions/
    value:
      $ref: '#/$defs/geometry'
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/value
  required:
  - dimension
  - value
- title: Temporal extent (period- or marker-valued)
  properties:
    dimension:
      enum:
      - temporal
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/dimension
      x-jsonld-type: '@id'
      x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/dimensions/
    value:
      oneOf:
      - $ref: '#/$defs/period'
      - $ref: '#/$defs/scenarioMarker'
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/value
  required:
  - dimension
  - value
- title: Grid structure (set of accepted grid types)
  properties:
    dimension:
      enum:
      - grid-structure
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/dimension
      x-jsonld-type: '@id'
      x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/dimensions/
    value:
      $ref: '#/$defs/gridStructure'
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/value
  required:
  - dimension
  - value
- title: Classification analogy (any dimension)
  description: 'Available on every dimension, including spatial ones: "the same biogeographical
    region as the training area" is a different claim from "inside the training area''s
    bounding box", and both are legitimate.

    '
  properties:
    value:
      $ref: '#/$defs/analogy'
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/value
  required:
  - value
- title: Any other dimension (string-valued)
  properties:
    dimension:
      not:
        enum:
        - spatial
        - jurisdictional
        - temporal
        - grid-structure
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/dimension
      x-jsonld-type: '@id'
      x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/dimensions/
    value:
      type: string
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/value
  required:
  - dimension
  - value
$defs:
  geometry:
    title: Geometry
    type: object
    required:
    - asWKT
    additionalProperties: false
    properties:
      asWKT:
        type: string
        pattern: ^ *(<[^>]*> *)?(POINT|MULTIPOINT|LINESTRING|MULTILINESTRING|POLYGON|MULTIPOLYGON|GEOMETRYCOLLECTION)
          *[ZM]{0,2} *\(
        examples:
        - POLYGON((12.09 48.55,18.87 48.55,18.87 51.06,12.09 51.06,12.09 48.55))
        - <http://www.opengis.net/def/crs/OGC/1.3/CRS84> POINT(14.42 50.09)
        description: 'The extent as a WKT literal, uplifting to `geo:asWKT` with datatype
          `geo:wktLiteral`. An optional leading CRS URI is permitted, per GeoSPARQL;
          without one, CRS84 (longitude/latitude in degrees) is assumed, as GeoSPARQL
          specifies.

          '
        x-jsonld-id: http://www.opengis.net/ont/geosparql#asWKT
        x-jsonld-type: http://www.opengis.net/ont/geosparql#wktLiteral
  period:
    title: Calendar period
    type: object
    required:
    - startDate
    - endDate
    additionalProperties: false
    properties:
      startDate:
        type: string
        pattern: ^\d{4}(-\d{2}(-\d{2})?)?$
        examples:
        - '2022'
        - 2022-06
        - '2022-06-01'
        description: 'Start of the period, as an ISO 8601 year, year-month, or date.
          Granularity is workflow-specific and deliberately not fixed, but the format
          is, so two periods stated at the same granularity compare correctly as plain
          string ordering.

          '
        x-jsonld-id: http://www.w3.org/ns/dcat#startDate
      endDate:
        type: string
        pattern: ^\d{4}(-\d{2}(-\d{2})?)?$
        examples:
        - '2025'
        description: End of the period, in the same form as `startDate`.
        x-jsonld-id: http://www.w3.org/ns/dcat#endDate
  gridStructure:
    title: Accepted grid types
    type: object
    required:
    - gridTypes
    additionalProperties: false
    properties:
      gridTypes:
        type: array
        minItems: 1
        items:
          type: string
          examples:
          - regular-latlon
          - rotated-pole
        description: 'The grid types the workflow accepts, as concepts from the FOCAL
          grid-types scheme (see bblocks://ogc.focal.transferability.vocab). The whole
          array is the constraint: a target is `inside` it if its grid is one of these.
          Open vocabulary, seeded only with the two terms UP-WF3 evidences and cross-walked
          to CF-conventions `grid_mapping_name` values, so adding a projection is
          a lookup in the CF table rather than a judgement.

          '
        x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/gridType
        x-jsonld-type: '@id'
        x-jsonld-container: '@set'
        x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/grid-types/
  analogy:
    title: Classification analogy
    type: object
    required:
    - scheme
    additionalProperties: false
    anyOf:
    - required:
      - sameClassAs
    - required:
      - classes
    properties:
      scheme:
        type: string
        examples:
        - koppen-geiger
        - eunis-habitats
        - eea-biogeographical-regions
        description: 'The published classification system this constraint is evaluated
          in, as a concept from the FOCAL classification-schemes vocabulary (see bblocks://ogc.focal.transferability.vocab).
          FOCAL names the scheme and records where its terms live; it does not restate
          them, the same discipline applied to QUDT units and CF grid mappings.

          '
        x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/classificationScheme
        x-jsonld-type: '@id'
        x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/classification-schemes/
      sameClassAs:
        $ref: https://opengeospatial.github.io/bblocks/annotated-schemas/ogc-utils/iri-or-curie/schema.yaml
        description: "The reference whose classification the target must share, normally
          the `id` of another constraint in the same envelope \u2014 typically the
          `trained-on` extent. **This is the preferred form**, and the only one usable
          with a scheme that publishes no term identifiers: nothing has to name a
          class, so a platform classifies the reference geometry and the target and
          compares. It also stays correct when the reference geometry is replaced
          by a better one, which an enumerated class list would not.\n"
        x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/sameClassAs
        x-jsonld-type: '@id'
      classes:
        type: array
        minItems: 1
        items:
          type: string
        examples:
        - - Cfb
          - Dfb
        - - http://eunis.eea.europa.eu/eunishabitats/G1
        description: "Explicitly stated classes, as an alternative to naming a reference.
          Use only where the source actually states them: deriving them from a reference
          and writing them here turns an inference into an assertion. Cite the scheme's
          own identifiers \u2014 EUNIS habitats are published by the EEA, and Koppen-Geiger
          classes are published by FOCAL itself (`.../koppen-geiger/Cfb`) precisely
          because no maintainer publishes them. Each classification-schemes concept
          records where its terms live.\n"
        x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/class
        x-jsonld-container: '@set'
  scenarioMarker:
    title: Scenario-indexed marker
    type: object
    required:
    - scenarioMarker
    additionalProperties: false
    properties:
      scenarioMarker:
        type: string
        examples:
        - gwl-1.5
        - gwl-2.0
        description: 'A non-calendar, scenario-indexed temporal position, as a concept
          from the FOCAL scenario-markers scheme (see bblocks://ogc.focal.transferability.vocab).
          Open: other scenario indices may follow.

          '
        x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/scenarioMarker
        x-jsonld-type: '@id'
        x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/scenario-markers/
x-jsonld-prefixes:
  focal-transf-prop: https://w3id.org/ogc/hosted/focal/transferability/properties/
  geo: http://www.opengis.net/ont/geosparql#
  dcat: http://www.w3.org/ns/dcat#
  rdfs: http://www.w3.org/2000/01/rdf-schema#
  dcterms: http://purl.org/dc/terms/
