{
 "$schema": "https://json-schema.org/draft/2020-12/schema",
 "$id": "https://rco-a2a.ai/schema/v1.3/rco-record-v1.json",
 "title": "Regulatory Compliance Object (RCO) v1 - spec v1.3 constraints",
 "$comment": "Record wire version stays 1.0. Cross-field checks a JSON Schema cannot express are normative in the specification and enforced by the published validator: (a) resolved_at < valid_until; (b) record_id's issuer/object/jurisdiction segments equal issuer.id, object_id and jurisdiction; (c) supersedes, when present, differs from record_id only in its trailing sequence number, which is exactly one lower; (d) GTINs are zero-padded GTIN-14 with a valid GS1 check digit; (e) host object_ids are lowercase, punycode-encoded, no trailing dot. record_id keeps its colons on the wire; a filesystem mirror replaces each colon with an underscore (CEO ruling 2026-08-29). GB is rejected as invalid_jurisdiction naming the valid set — UK is the member code (permanent GB=UK rule). Verification VERIFIES every byte of the canonical signing payload; nothing claims to reproduce signature bytes (ECDSA is randomized). v1.3 adds the optional case_study boolean and the unit rule: record-holders are keyed GTIN x jurisdiction only (NG-11 s2k).",
 "type": "object",
 "additionalProperties": false,
 "required": [
  "rco_version",
  "record_id",
  "object_id",
  "jurisdiction",
  "signal",
  "state",
  "resolved_at",
  "valid_until",
  "supersedes",
  "eco_ref",
  "rule_set",
  "evidence_refs",
  "issuer",
  "key_id",
  "verification_url",
  "signature"
 ],
 "properties": {
  "rco_version": {
   "const": "1.0"
  },
  "record_id": {
   "type": "string",
   "pattern": "^rco:[a-z0-9-]+:(gtin:[0-9]{14}|host:([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}):([A-Z]{2}-ECO-10060|apex):[1-9][0-9]*$"
  },
  "object_id": {
   "type": "string",
   "pattern": "^(gtin:[0-9]{14}|host:([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63})$"
  },
  "jurisdiction": {
   "enum": [
    "EU-ECO-10060",
    "FR-ECO-10060",
    "DE-ECO-10060",
    "ES-ECO-10060",
    "IT-ECO-10060",
    "NL-ECO-10060",
    "PL-ECO-10060",
    "CH-ECO-10060",
    "UK-ECO-10060",
    "BE-ECO-10060",
    "PT-ECO-10060",
    "AT-ECO-10060",
    "IE-ECO-10060",
    "CZ-ECO-10060",
    "DK-ECO-10060",
    "SE-ECO-10060",
    "FI-ECO-10060",
    "NO-ECO-10060",
    "GR-ECO-10060",
    "US-ECO-10060",
    "CA-ECO-10060",
    "MX-ECO-10060",
    "BR-ECO-10060",
    "AR-ECO-10060",
    "CL-ECO-10060",
    "CO-ECO-10060",
    "CR-ECO-10060",
    "DO-ECO-10060",
    "EC-ECO-10060",
    "GT-ECO-10060",
    "PA-ECO-10060",
    "PE-ECO-10060",
    "UY-ECO-10060",
    "AU-ECO-10060",
    "JP-ECO-10060",
    "KR-ECO-10060",
    "SG-ECO-10060",
    "IN-ECO-10060",
    "ID-ECO-10060",
    "MY-ECO-10060",
    "PH-ECO-10060",
    "TH-ECO-10060",
    "VN-ECO-10060",
    "AE-ECO-10060",
    "SA-ECO-10060",
    "IL-ECO-10060",
    "TR-ECO-10060",
    "MA-ECO-10060",
    "ZA-ECO-10060",
    "apex"
   ],
   "$comment": "The 49 SM-ECO-10060 member jurisdictions + EU bloc + apex, generated from the signed member registry. GB is rejected; UK is the code."
  },
  "signal": {
   "enum": [
    "CPG-000",
    "CPG-200",
    "CPG-300",
    "CPG-403",
    "CPG-404",
    "CPG-451",
    "CPG-500"
   ]
  },
  "state": {
   "enum": [
    "NOT_APPLICABLE",
    "ALLOW",
    "CONDITIONAL",
    "RESTRICT",
    "NOT_FOUND",
    "ESCALATE",
    "SYSTEM_ERROR"
   ]
  },
  "conditions": {
   "type": "array",
   "items": {
    "type": "object",
    "required": [
     "code",
     "ref"
    ],
    "properties": {
     "code": {
      "type": "string",
      "minLength": 1
     },
     "ref": {
      "type": "string",
      "format": "uri"
     }
    },
    "additionalProperties": false
   }
  },
  "resolved_at": {
   "type": "string",
   "format": "date-time"
  },
  "valid_until": {
   "type": "string",
   "format": "date-time"
  },
  "supersedes": {
   "anyOf": [
    {
     "type": "null"
    },
    {
     "type": "string",
     "pattern": "^rco:[a-z0-9-]+:(gtin:[0-9]{14}|host:([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}):([A-Z]{2}-ECO-10060|apex):[1-9][0-9]*$"
    }
   ]
  },
  "eco_ref": {
   "anyOf": [
    {
     "type": "null"
    },
    {
     "type": "object",
     "required": [
      "url",
      "hash"
     ],
     "properties": {
      "url": {
       "type": "string",
       "format": "uri"
      },
      "hash": {
       "type": "string",
       "pattern": "^sha256:[a-f0-9]{64}$"
      }
     },
     "additionalProperties": false
    }
   ]
  },
  "rule_set": {
   "type": "object",
   "required": [
    "id",
    "version",
    "hash",
    "effective_from"
   ],
   "properties": {
    "id": {
     "type": "string"
    },
    "version": {
     "type": "string",
     "pattern": "^20[0-9]{2}\\.(0[1-9]|1[0-2])(\\.[0-9]+)?$"
    },
    "hash": {
     "type": "string",
     "pattern": "^sha256:[a-f0-9]{64}$"
    },
    "effective_from": {
     "type": "string",
     "format": "date-time"
    }
   },
   "additionalProperties": false
  },
  "evidence_refs": {
   "type": "array",
   "items": {
    "type": "object",
    "required": [
     "kind",
     "url",
     "hash"
    ],
    "properties": {
     "kind": {
      "enum": [
       "esg-credential",
       "dpu-proof",
       "eco-object",
       "other"
      ]
     },
     "url": {
      "type": "string",
      "format": "uri"
     },
     "hash": {
      "type": "string",
      "pattern": "^sha256:[a-f0-9]{64}$"
     }
    },
    "additionalProperties": false
   }
  },
  "issuer": {
   "type": "object",
   "required": [
    "id",
    "rail",
    "name"
   ],
   "properties": {
    "id": {
     "type": "string",
     "pattern": "^[a-z0-9-]+$"
    },
    "rail": {
     "enum": [
      "bpc",
      "cpg"
     ]
    },
    "name": {
     "type": "string",
     "minLength": 1
    }
   },
   "additionalProperties": false
  },
  "key_id": {
   "type": "string",
   "minLength": 1
  },
  "verification_url": {
   "type": "string",
   "format": "uri",
   "$comment": "Cross-check only. The verification root is the signed consortium issuer registry: consumers resolve issuer.id there and take the JWKS URL from the registry; mismatch with this field fails verification."
  },
  "signature": {
   "type": "string",
   "pattern": "^[A-Za-z0-9_-]+\\.\\.[A-Za-z0-9_-]+$",
   "description": "Detached JWS Compact Serialization (RFC 7515) with unencoded payload (RFC 7797): BASE64URL(protected header {alg:ES256, b64:false, crit:[b64], kid}) '..' BASE64URL(ES256 raw R||S). Signing input = ASCII(BASE64URL(protected header) '.') || RFC 8785 canonical JSON of the record with this member removed. Test vectors: signature-test-vectors.json."
  },
  "case_study": {
   "type": "boolean",
   "default": false,
   "$comment": "v1.3 (CEO close-out ruling): true marks a labelled case-study record (e.g. the elyssah worked chain); never counted in the real-maker number. Absent = false."
  }
 },
 "allOf": [
  {
   "$comment": "The seven legal signal/state pairs.",
   "oneOf": [
    {
     "properties": {
      "signal": {
       "const": "CPG-000"
      },
      "state": {
       "const": "NOT_APPLICABLE"
      }
     }
    },
    {
     "properties": {
      "signal": {
       "const": "CPG-200"
      },
      "state": {
       "const": "ALLOW"
      }
     }
    },
    {
     "properties": {
      "signal": {
       "const": "CPG-300"
      },
      "state": {
       "const": "CONDITIONAL"
      }
     }
    },
    {
     "properties": {
      "signal": {
       "const": "CPG-403"
      },
      "state": {
       "const": "RESTRICT"
      }
     }
    },
    {
     "properties": {
      "signal": {
       "const": "CPG-404"
      },
      "state": {
       "const": "NOT_FOUND"
      }
     }
    },
    {
     "properties": {
      "signal": {
       "const": "CPG-451"
      },
      "state": {
       "const": "ESCALATE"
      }
     }
    },
    {
     "properties": {
      "signal": {
       "const": "CPG-500"
      },
      "state": {
       "const": "SYSTEM_ERROR"
      }
     }
    }
   ]
  },
  {
   "$comment": "conditions: required non-empty for CPG-300, forbidden otherwise.",
   "if": {
    "properties": {
     "signal": {
      "const": "CPG-300"
     }
    }
   },
   "then": {
    "required": [
     "conditions"
    ],
    "properties": {
     "conditions": {
      "minItems": 1
     }
    }
   },
   "else": {
    "not": {
     "required": [
      "conditions"
     ]
    }
   }
  },
  {
   "$comment": "CPG-404 carries eco_ref null; every other signal carries a non-null eco_ref.",
   "if": {
    "properties": {
     "signal": {
      "const": "CPG-404"
     }
    }
   },
   "then": {
    "properties": {
     "eco_ref": {
      "type": "null"
     }
    }
   },
   "else": {
    "properties": {
     "eco_ref": {
      "type": "object"
     }
    }
   }
  }
 ]
}