{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "@context": {
      "description": "JSON-LD context. Production deployments use the published register vocabulary contexts at vocabulary.uncefact.org so that register.json is processable as Linked Data.",
      "oneOf": [
        { "type": "string", "format": "uri" },
        { "type": "array" },
        { "type": "object" }
      ]
    },
    "@type": {
      "oneOf": [
        { "type": "string" },
        { "type": "array", "items": { "type": "string" } }
      ]
    },
    "id": {
      "type": "string",
      "format": "uri",
      "description": "Globally unique identifier for this register."
    },
    "name": {
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "lastUpdated": {
      "type": "string",
      "format": "date"
    },
    "registrar": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "format": "uri"
        },
        "name": {
          "type": "string"
        },
        "agent": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "id": {
              "type": "string",
              "format": "uri",
              "description": "DID of the autonomous registrar agent that fetches each extension's registration VC, fetches and hashes the referenced schema/context/vocabulary documents, runs extension-conformance checks, optionally validates sample instances, and records signed observations against this register."
            },
            "name": { "type": "string" },
            "description": { "type": "string" }
          },
          "required": ["id"]
        }
      },
      "required": ["id", "name"]
    },
    "entries": {
      "type": "array",
      "items": { "$ref": "#/$defs/ExtensionEntry" }
    }
  },
  "required": ["id", "name", "lastUpdated", "registrar", "entries"],
  "description": "A register of community extensions to the UN Transparency Protocol (UNTP). Extensions are owned by member organisations (industry associations, standards bodies, intergovernmental bodies, consortia) that represent the shared interests of many constituent organisations. Each register entry is sourced from a Verifiable Credential issued by the extension owner: the registrar agent fetches that VC, verifies its signature, hashes the referenced schema/context/vocabulary documents, runs UNTP extension-conformance checks (UNTP context required, all terms defined, no UNTP redefinitions, scoped @vocab catch-all, sample validation), and appends signed observations.",
  "$defs": {
    "ExtensionEntry": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "@type": {
          "oneOf": [
            { "type": "string" },
            { "type": "array", "items": { "type": "string" } }
          ]
        },
        "id": {
          "type": "string",
          "format": "uri",
          "description": "Globally unique identifier for this entry within the register."
        },
        "name": {
          "type": "string",
          "description": "Full name of the extension (e.g. 'Global Battery Alliance Transparency Protocol')."
        },
        "shortName": {
          "type": "string",
          "description": "Acronym or short identifier (e.g. 'GBA-TP', 'AATP', 'RBTP')."
        },
        "owner": {
          "$ref": "#/$defs/ExtensionOwner",
          "description": "Primary extension owner. The `owner.id` (DID) MUST be the issuer of the registration VC; signature verification by the registrar agent uses this DID."
        },
        "coOwners": {
          "type": "array",
          "items": { "$ref": "#/$defs/ExtensionOwner" },
          "description": "Optional. Additional owners that participate in extension governance but are not the primary signer of the registration VC."
        },
        "statement": {
          "type": "string",
          "description": "Owner-authored overview describing the extension's purpose and scope."
        },
        "extensionWebsite": {
          "type": "string",
          "format": "uri",
          "description": "Public landing page for the extension specification."
        },
        "commitmentDate": {
          "type": "string",
          "format": "date",
          "description": "Date the owner committed to maintaining a registered UNTP extension."
        },
        "industrySector": {
          "$ref": "#/$defs/IndustrySector"
        },
        "geographicScope": {
          "$ref": "#/$defs/GeographicScope"
        },
        "status": {
          "type": "string",
          "enum": ["proposed", "development", "pilot", "active", "dormant", "withdrawn"],
          "description": "Lifecycle status. `proposed` (committed but no schema yet), `development` (schema in progress), `pilot` (schema published, real-world piloting), `active` (in production use), `dormant` (no recent updates or pilot activity), `withdrawn` (owner exited)."
        },
        "registrationVc": {
          "$ref": "#/$defs/RegistrationVcReference",
          "description": "The Verifiable Credential issued by the extension owner whose `credentialSubject` is this entry. The registrar agent verifies its signature against `owner.id` on each refresh."
        },
        "credentials": {
          "type": "array",
          "items": { "$ref": "#/$defs/ExtensionCredential" },
          "description": "The credential types this extension defines. Each must extend a base UN/CEFACT credential class (typically one of the 5 core UNTP credential types — DPP, DCC, DTE, DFR, DIA — or the equivalents in other UN/CEFACT specs) and ship its own schema, context, and vocabulary. Extensions that contribute conformity vocabulary catalogues (rather than credential types) belong in the CVC register, not here."
        },
        "observedStatus": {
          "$ref": "#/$defs/ObservedStatus"
        }
      },
      "required": ["id", "name", "owner", "status", "credentials"]
    },
    "ExtensionOwner": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "format": "uri",
          "description": "DID of the owner organisation. MUST resolve to a DID Document with at least one verification method usable to verify the registration VC signature."
        },
        "name": { "type": "string" },
        "website": { "type": "string", "format": "uri" },
        "logo": { "type": "string", "format": "uri" },
        "memberOrganisationType": {
          "type": "string",
          "enum": ["industry-association", "standards-body", "intergovernmental", "consortium", "research-centre", "other"],
          "description": "Type of member organisation. Extension ownership is restricted to organisations that represent the shared interests of multiple constituent organisations — single companies are not eligible owners."
        },
        "memberCount": {
          "type": "integer",
          "minimum": 0,
          "description": "Approximate count of member organisations this owner represents."
        }
      },
      "required": ["id", "name"]
    },
    "RegistrationVcReference": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "format": "uri",
          "description": "URI from which the registration VC can be fetched."
        },
        "issuer": {
          "type": "string",
          "format": "uri",
          "description": "Issuer DID of the registration VC. MUST equal `owner.id`."
        },
        "issuedAt": {
          "type": "string",
          "format": "date-time"
        },
        "hashAlgorithm": { "type": "string", "examples": ["sha-256", "sha-384"] },
        "hashValue": {
          "type": "string",
          "description": "Hash of the canonicalised registration VC at the time of last successful fetch by the registrar agent."
        }
      },
      "required": ["id", "issuer"]
    },
    "ExtensionCredential": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "credentialType": {
          "type": "string",
          "description": "The type the extension defines, as it appears alongside the base UNTP type in a credential's `type` array (e.g. `DigitalBatteryPassport`, `LivestockDigitalProductPassport`)."
        },
        "shortName": {
          "type": "string",
          "description": "Acronym used by the owner (e.g. `DBP`, `RMIC`)."
        },
        "extends": {
          "type": "string",
          "format": "uri",
          "pattern": "^https://(vocabulary\\.uncefact\\.org/(untp|unvtd)/|registers\\.uncefact\\.org/.+/ext/.+/credentials/).+",
          "description": "URI of the base credential type this extension extends. Typically a UN/CEFACT credential class (e.g. `https://vocabulary.uncefact.org/untp/DigitalProductPassport`); may also be another registered ExtensionCredential URI under `registers.uncefact.org/.../ext/.../credentials/...` to model extension-of-extension. The registry vocabulary declares `reg:extendsBaseType` as `rdfs:subPropertyOf rdfs:subClassOf` so OWL/RDFS reasoners derive transitive type inheritance automatically; verifiers encountering a credential whose `type` array carries an extension type can therefore conclude it is also an instance of the extended base class."
        },
        "purpose": {
          "type": "string"
        },
        "typicalFlow": {
          "type": "string",
          "description": "Brief description of the typical credential flow (e.g. 'Auditor → Facility → Brand verifies')."
        },
        "versions": {
          "type": "array",
          "items": { "$ref": "#/$defs/ExtensionCredentialVersion" },
          "description": "Released versions of the extension credential. Each version is the unit at which schema/context/vocabulary hashes and conformance observations are recorded."
        }
      },
      "required": ["credentialType", "extends"]
    },
    "ExtensionCredentialVersion": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "versionLabel": {
          "type": "string",
          "description": "Human-readable extension version label (e.g. `0.1.0`, `1.0`, `2026.04`)."
        },
        "extendsUntpVersion": {
          "type": "string",
          "description": "The UNTP core specification version this extension version extends (e.g. `0.6.1`). The extension's JSON-LD context MUST import the UNTP context at exactly this version. The registrar agent verifies this on each observation cycle."
        },
        "releasedDate": {
          "type": "string",
          "format": "date"
        },
        "schema": {
          "$ref": "#/$defs/HashedReference",
          "description": "The JSON Schema that defines the extension credential's structure. Required for `pilot`/`active` versions; may be absent during `proposed`/`development`. The registrar agent fetches and hashes this document to detect drift from the registered hash."
        },
        "context": {
          "$ref": "#/$defs/HashedReference",
          "description": "The JSON-LD context for the extension. MUST import the UNTP context at `extendsUntpVersion`. MUST define every term used by the extension schema. MUST NOT redefine any term defined in the UNTP context."
        },
        "vocabulary": {
          "$ref": "#/$defs/HashedReference",
          "description": "The vocabulary (typically RDF or SKOS) that defines the extension's terms. Every term in the extension schema MUST resolve to a definition in this vocabulary or in a UNTP core vocabulary. An `@vocab` catch-all in the context is permitted only for implementer-supplied terms not defined by either the extension or UNTP."
        },
        "samples": {
          "type": "array",
          "items": { "$ref": "#/$defs/SampleInstance" },
          "description": "At least one sample instance per credential type is required for `pilot` status (per UNTP extension methodology); two are recommended."
        },
        "observations": {
          "type": "array",
          "items": { "$ref": "#/$defs/ConformanceObservation" },
          "description": "Conformance observations recorded by the registrar agent. Append-only."
        }
      },
      "required": ["versionLabel", "extendsUntpVersion"]
    },
    "HashedReference": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "uri": {
          "type": "string",
          "format": "uri",
          "description": "URI from which the document can be fetched."
        },
        "hashAlgorithm": {
          "type": "string",
          "examples": ["sha-256", "sha-384"]
        },
        "hashValue": {
          "type": "string",
          "description": "Hex-encoded hash of the document content as fetched. Verifiers re-hash on fetch and reject the document if the hash differs from the registered value."
        },
        "registeredAt": {
          "type": "string",
          "format": "date-time",
          "description": "When the registrar agent last fetched and hashed this document."
        }
      },
      "required": ["uri"]
    },
    "SampleInstance": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "uri": {
          "type": "string",
          "format": "uri",
          "description": "URI from which the sample VC can be fetched. Plain URI — hashlinks not required, since samples are illustrative rather than normative."
        },
        "description": {
          "type": "string"
        },
        "scenario": {
          "type": "string",
          "description": "What real-world situation or actor flow this sample represents."
        },
        "isExpectedPass": {
          "type": "boolean",
          "description": "Whether this sample is intended to validate successfully against the extension schema (true) or is a deliberate failure-mode sample for negative testing (false). Defaults to true.",
          "default": true
        }
      },
      "required": ["uri", "description"]
    },
    "ConformanceObservation": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "observedAt": { "type": "string", "format": "date-time" },
        "observedVersionLabel": {
          "type": "string",
          "description": "The `versionLabel` of the extension version observed."
        },
        "checks": {
          "type": "object",
          "additionalProperties": false,
          "description": "Pass/fail flags for each UNTP extension-conformance rule.",
          "properties": {
            "registrationVcSignatureValid": { "type": "boolean" },
            "schemaHashMatch": { "type": "boolean", "description": "Fetched schema document hash matches the registered hash." },
            "contextHashMatch": { "type": "boolean" },
            "vocabularyHashMatch": { "type": "boolean" },
            "untpContextRequired": { "type": "boolean", "description": "Extension context imports the UNTP context at the declared `extendsUntpVersion`." },
            "extensionContextDefined": { "type": "boolean", "description": "Extension publishes its own context document." },
            "allTermsResolved": { "type": "boolean", "description": "Every term in the extension schema resolves either to the extension context/vocabulary or to a UNTP core context/vocabulary term." },
            "noUntpRedefinitions": { "type": "boolean", "description": "Extension context does not redefine any term defined by the UNTP context." },
            "vocabCatchAllScope": { "type": "boolean", "description": "Any `@vocab` catch-all is scoped to terms outside both the extension and UNTP vocabularies (i.e. only for implementer-supplied terms)." },
            "samplesValidate": { "type": "boolean", "description": "All `isExpectedPass: true` samples validate against the schema; `isExpectedPass: false` samples fail as expected." }
          }
        },
        "overallResult": {
          "type": "string",
          "enum": ["pass", "fail", "partial"]
        },
        "failures": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "check": { "type": "string", "description": "Name of the failing check (matches a property in `checks`)." },
              "detail": { "type": "string" }
            },
            "required": ["check", "detail"]
          }
        },
        "registrarAttestation": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "id": { "type": "string", "format": "uri" },
            "issuer": { "type": "string", "format": "uri" },
            "issuedAt": { "type": "string", "format": "date-time" }
          },
          "required": ["id", "issuer"]
        }
      },
      "required": ["observedAt", "observedVersionLabel", "checks", "overallResult"]
    },
    "ObservedStatus": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "lastObservedAt": { "type": "string", "format": "date-time" },
        "currentAssessment": {
          "type": "string",
          "enum": ["conformant", "non-conformant", "partially-conformant", "insufficient-data"]
        },
        "conformantVersions": {
          "type": "integer",
          "minimum": 0
        },
        "nonConformantVersions": {
          "type": "integer",
          "minimum": 0
        }
      },
      "required": ["currentAssessment"]
    },
    "IndustrySector": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "label": {
          "type": "string",
          "description": "Free-text industry label as used by the extension owner (e.g. 'Battery manufacturing and value chains')."
        },
        "isicCodes": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Optional. ISIC Rev.4 codes covered by this extension (e.g. `B.7`, `C.24`, `C.2720`)."
        }
      },
      "required": ["label"]
    },
    "GeographicScope": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "label": {
          "type": "string",
          "description": "Free-text geographic label (e.g. 'Global', 'Australia', 'EU + UK')."
        },
        "countries": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Optional. ISO 3166-1 alpha-2 country codes when the scope is enumerable."
        },
        "isGlobal": {
          "type": "boolean",
          "description": "Convenience flag for unrestricted geographic scope."
        }
      },
      "required": ["label"]
    }
  }
}
