{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/eudr-dev/json-schema/eudr-dev-spatial-verify-response-schema.json",
  "title": "SpatialVerifyResponse",
  "description": "The verdict, what was inspected to reach it, and what was NOT checked. Every response names the unresolved checks so a clean deforestation result is never read as a clean due-diligence file.",
  "x-generated": "2026-11-07",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/eudr-dev-openapi.json#/components/schemas/SpatialVerifyResponse",
  "type": "object",
  "properties": {
    "deforestation_free": {
      "type": [
        "boolean",
        "null"
      ]
    },
    "post_cutoff_loss_cells": {
      "type": "integer",
      "description": "Signed population tally of cells with post-cut-off canopy loss, not the shipped sample. This is loss OBSERVED, not deforestation found: see `in_scope_loss_cells`."
    },
    "in_scope_loss_cells": {
      "type": "integer",
      "description": "Cells with post-cut-off loss on the plots that trip the Art. 2(13) gate — the loss the Regulation counts as deforestation. Below `post_cutoff_loss_cells` whenever the responder cleared a plot as non-forest at the cut-off, or under the 0.5 ha the Art. 2(4) forest definition requires. A row the responder cleared does not bar the consignment."
    },
    "sub_mmu_loss_ha": {
      "type": "number",
      "x-conditional": true,
      "description": "Hectares of sub-floor loss across the consignment, present only when they reach the floor together and that is why the verdict is indeterminate. One patch below 0.5 ha is not forest; a clearing split across twenty plots is."
    },
    "forest_baseline": {
      "type": "string",
      "description": "The forest baseline the responder actually read, as it named it (e.g. `jrc_gfc2020_v4`)."
    },
    "precision_warnings": {
      "type": "array",
      "items": {
        "type": "object"
      },
      "x-conditional": true,
      "description": "The responder's warnings, verbatim, that a plot's coordinates carry fewer than the six decimal digits Art. 2(28) requires of a geolocation. Omitted when there are none."
    },
    "total_cells": {
      "type": "integer"
    },
    "verdict": {
      "type": "string",
      "enum": [
        "negligible",
        "non_negligible",
        "not_in_scope",
        "indeterminate"
      ],
      "description": "Consignment verdict. `not_in_scope` here means the commodity is outside Annex I. A per-plot row's `not_in_scope` means something else: the land was not forest at the 2020 cut-off, so the plot is deforestation-free by definition, and the consignment verdict can still be `negligible`."
    },
    "risk_score": {
      "type": [
        "number",
        "null"
      ]
    },
    "country_tier": {
      "type": "string",
      "enum": [
        "low",
        "standard",
        "high"
      ]
    },
    "cut_off_date": {
      "type": "string"
    },
    "per_plot": {
      "type": "array",
      "description": "One row per submitted plot, in submission order. A single-plot request still gets one row.",
      "items": {
        "type": "object",
        "properties": {
          "plot_id": {
            "type": "string"
          },
          "verdict": {
            "type": "string"
          },
          "cells_evaluated": {
            "type": "integer"
          },
          "cells_with_post_cutoff_loss": {
            "type": "integer"
          },
          "area_ha_approx": {
            "type": [
              "number",
              "null"
            ]
          },
          "loss_assessment": {
            "type": "string",
            "enum": [
              "in_scope_deforestation",
              "not_forest_at_cut_off",
              "below_minimum_mapping_unit",
              "no_loss",
              "undecided"
            ],
            "description": "What the loss on this plot amounts to in law. A cell count alone does not say, and reading it as though it did barred consignments the same response cleared."
          },
          "loss_area_ha": {
            "type": "number",
            "description": "Hectares of post-cut-off loss, as the responder measured it. Omitted when it did not report one."
          },
          "precision_warning": {
            "type": "string",
            "description": "The responder's warning that this plot's coordinates are below the six decimal digits Art. 2(28) requires. Omitted when clean."
          }
        }
      }
    },
    "coverage": {
      "type": "object",
      "description": "What was actually inspected. A verdict over 2 % of a polygon and a verdict over all of it are different claims.",
      "properties": {
        "cells_evaluated": {
          "type": "integer"
        },
        "cell_size_m": {
          "type": "number"
        },
        "sampled_area_ha": {
          "type": [
            "number",
            "null"
          ]
        },
        "plot_area_ha": {
          "type": [
            "number",
            "null"
          ]
        },
        "sampled_polygon_fraction": {
          "type": [
            "number",
            "null"
          ],
          "description": "1.0 is a full sweep."
        },
        "sampling_note": {
          "type": [
            "string",
            "null"
          ],
          "description": "The upstream responder's own disclosure, verbatim."
        },
        "per_cell_rows_returned": {
          "type": "integer",
          "description": "How many per-cell rows came back with the answer. `cells_evaluated` is the responder's signed population tally and is what every count here is on; these rows are the sample it shipped, and they are fewer."
        }
      }
    },
    "loss_years_observed": {
      "type": "array",
      "items": {
        "type": "integer"
      },
      "description": "Distinct Hansen loss years in the shipped sample, ascending. Dates what was found; never counts it."
    },
    "unresolved_checks": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Checks this engine does not perform. Art. 3(b) legality is documentary and unobserved here."
    },
    "evidence": {
      "type": "object",
      "description": "Note the nesting: `evidence_cid` lives HERE, not at the top level. An earlier revision of this document put it at the top level, which is a field the response has never carried.",
      "properties": {
        "evidence_cid": {
          "type": [
            "string",
            "null"
          ],
          "description": "Content address of THIS response's fact list. BLAKE3 over its canonical JSON, so a caller can re-derive it from the returned CIDs. It is not a fingerprint of the question: emem signs each fact with the moment it was signed, so re-running the same check returns the same measurements under new addresses. Resolve at /v1/evidence/{evidence_cid}."
        },
        "fact_count": {
          "type": "integer",
          "description": "How many facts the check resolved. Always present."
        },
        "fact_cids": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Omitted entirely when `evidence_detail: \"anchor\"` was sent."
        },
        "responder_pubkey_b32": {
          "type": [
            "string",
            "null"
          ]
        },
        "algorithm": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "engine": {
      "type": "string"
    }
  }
}