$schema: https://json-schema.org/draft/2020-12/schema
title: Transferability Rule
description: "What must happen, to which artifacts, under which envelope conditions.\n-
  `appliesTo` \u2014 the artifacts this rule governs, by `id`. Omit it for a rule
  about the workflow\n  as a whole.\n- `when` \u2014 the conditions, each citing an
  envelope constraint by `id` and how the target is\n  tested against it (`inside`/`outside`).
  **Conjunctive: all of them must hold.** A disjunction\n  is written as two rules.\n-
  `actions` \u2014 an **OR-set**: any one resolves the rule. Never a sequence, never
  a combination to\n  apply together.\n- `affects` \u2014 which parts of the annotated
  document stop working, or work differently, if this\n  rule's outcome is the terminal
  one.\n- `mandatory` \u2014 whether applying one is required once the conditions
  hold.\n**Rules are exceptions, not a complete decision table.** A statement's rules
  say what has to change; anything they do not mention is reusable unchanged. So an
  artifact with no rule firing for a given target is reused as-is, and a rule stating
  `reuse-as-is` explicitly is documenting the default rather than adding to it (worth
  doing where it makes a cascade legible, as UP-WF2's inside/outside pair does, and
  redundant otherwise). See bblocks://ogc.focal.transferability.transferabilityStatement
  for why that default is safe here: a statement cannot omit `rules`, so writing none
  is a deliberate act rather than an oversight.\n**`when` is what makes a rule evaluable
  rather than merely readable.** `triggeredBy: different-geographic-coverage` is a
  string a person reads; `when: [{constraint: clms-coverage, test: outside}]` names
  the boundary, and if that constraint's dimension is spatial its value is a `geo:asWKT`
  geometry, so a GeoSPARQL engine can settle the question with `geof:sfWithin`. Where
  the cited constraint is prose-valued (a comparable ecological range), the same structure
  records a judgement a person still has to make \u2014 which is honest about where
  automation stops rather than pretending the whole model is machine-decidable.\n`triggeredBy`
  is kept, but optional: not every evidenced FOCAL case has a constraint precise enough
  to cite, and forcing one would mean inventing boundaries. At least one of `when`
  or `triggeredBy` is required, so no rule is left with no stated condition at all.
  Prefer `when`.\n"
allOf:
- $ref: https://ogcincubator.github.io/bblocks-focal/build/annotated/focal/transferability/notes/schema.yaml
- type: object
  required:
  - actions
  anyOf:
  - required:
    - when
  - required:
    - triggeredBy
  properties:
    appliesTo:
      type: array
      minItems: 1
      items:
        $ref: https://opengeospatial.github.io/bblocks/annotated-schemas/ogc-utils/iri-or-curie/schema.yaml
      description: "Identifiers of the artifacts this rule governs, from the enclosing
        statement's `artifacts`. Several artifacts may share one rule \u2014 FP-WF2's
        four Czechia-specific reference files do. Omit for a rule that applies to
        the workflow as a whole.\n"
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/appliesTo
      x-jsonld-type: '@id'
      x-jsonld-container: '@set'
    when:
      type: array
      minItems: 1
      items:
        $ref: '#/$defs/condition'
      description: 'The conditions under which this rule fires, ANDed together. Two
        conditions here mean both must hold; two rules mean either suffices.

        '
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/when
      x-jsonld-container: '@set'
    triggeredBy:
      type: string
      examples:
      - different-geographic-coverage
      - different-ecological-range
      - different-climate-regime
      - different-dataset
      description: "A coarse statement of what fires this rule, for cases where no
        envelope constraint can be cited precisely. Open vocabulary \u2014 see bblocks://ogc.focal.transferability.vocab.\n"
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/triggeredBy
      x-jsonld-type: '@id'
      x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/triggers/
    affects:
      type: array
      minItems: 1
      items:
        type: string
        format: json-pointer
        pattern: ^/
      description: "JSON Pointers (RFC 6901) to the parts of the annotated document
        this rule's outcome bears on \u2014 for the CWL profile in bblocks://ogc.focal.transferability.workflow,
        typically `/steps/<id>` or `/outputs/<id>`, though the pointer carries no
        CWL assumption.\n**This is what `component-not-executable` needs to be actionable.**
        Without it the action names no component, so \"hot-spot characterization cannot
        run\" and \"the workflow cannot run\" are the same statement, and per-artifact
        answers cannot be assembled into the per-workflow verdict (*runs as is* /
        *runs in part* / *cannot run here*) that a deployment platform actually has
        to produce. UP-WF2 is the evidenced case: losing CLMS costs it one step, not
        the run.\nOptional, and meaningful for any action: a `replace-with-local-equivalent`
        rule may equally name the outputs whose quality changes. Omit it rather than
        guess, the same way `artifactRef` is omitted where no real Application Package
        exists to point into.\n"
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/affects
      x-jsonld-container: '@set'
    actions:
      type: array
      minItems: 1
      items:
        type: string
        examples:
        - reuse-as-is
        - replace-with-local-equivalent
        - retrain
        - replace-with-alternative-published-model
        - component-not-executable
      description: "One or more actions, any of which resolves the rule \u2014 an
        OR-set, not a required combination. No evidenced case needs two applied simultaneously.\n"
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/actions
      x-jsonld-type: '@id'
      x-jsonld-container: '@set'
      x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/actions/
    mandatory:
      type: boolean
      default: true
      description: "Whether applying one of `actions` is mandatory once the conditions
        hold. Defaults to true. When false, skipping is allowed but degrades result
        quality or trust rather than blocking execution \u2014 say what degrades in
        `transferabilityNotes`.\nSays nothing on a rule whose only action is `reuse-as-is`:
        \"you must do nothing\" and \"you may do nothing\" are the same instruction.
        Omit it there.\nNamed `mandatory` rather than `required`: a data property
        spelled like a JSON Schema keyword reads as the keyword, and this one sits
        beside real `required` lists.\n"
      x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/mandatory
$defs:
  condition:
    title: Envelope condition
    type: object
    required:
    - constraint
    - test
    additionalProperties: false
    properties:
      constraint:
        $ref: https://opengeospatial.github.io/bblocks/annotated-schemas/ogc-utils/iri-or-curie/schema.yaml
        description: "The `id` of an envelope constraint in the enclosing statement's
          `envelope`, written the same way it is declared there \u2014 an IRI, a CURIE,
          or a bare local name. Whichever form is used, the constraint must still
          be declared in the statement, so a reader has the extent in front of them
          rather than a bare identifier: a global identifier makes a boundary shareable,
          it does not make it fetchable.\n"
        x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/constraint
        x-jsonld-type: '@id'
      test:
        type: string
        examples:
        - outside
        - inside
        description: "How the target is compared against that constraint. `outside`
          is the condition under which almost every evidenced FOCAL rule fires; `inside`
          states the complementary case, which is what lets a cascade be written without
          losing its connecting condition \u2014 UP-WF2's \"reuse within the domain,
          otherwise substitute or fail\" is two rules over the same constraint. Open
          vocabulary \u2014 see bblocks://ogc.focal.transferability.vocab, where each
          term also records how it is evaluated per dimension.\n"
        x-jsonld-id: https://w3id.org/ogc/hosted/focal/transferability/properties/test
        x-jsonld-type: '@id'
        x-jsonld-base: https://w3id.org/ogc/hosted/focal/transferability/tests/
x-jsonld-prefixes:
  focal-transf-prop: https://w3id.org/ogc/hosted/focal/transferability/properties/
