{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://devicegrading.com/schema/v1.0/record.json",
  "title": "UGP record",
  "description": "One device (or a declared lot) described under the Universal Grading Protocol v1.0 (Annex B). The grade, status and core code in `result` are derived values and shall match the derivation in §11–12. Objects accept extra fields only with an `x_` prefix.",
  "type": "object",
  "required": ["ugp_version", "profile", "profile_status", "record_scope", "identity", "axes", "audit"],
  "properties": {
    "ugp_version": {
      "description": "The UGP version the record was graded under (MAJOR.MINOR, §18.2).",
      "type": "string",
      "pattern": "^[1-9][0-9]*\\.[0-9]+$"
    },
    "profile": { "$ref": "#/$defs/deviceClass" },
    "profile_status": {
      "description": "`provisional` for a device class whose profile pack is not yet published (§1.2).",
      "enum": ["complete", "provisional"]
    },
    "record_scope": { "enum": ["unit", "lot"] },
    "disposition": {
      "description": "`parts`: a device with a failed key function sent for parts (§11.1).",
      "enum": ["parts", null]
    },
    "identity": { "$ref": "#/$defs/identity" },
    "axes": {
      "type": "object",
      "required": ["cosmetic", "functional", "battery", "locks", "operator", "data", "parts", "kit"],
      "properties": {
        "cosmetic": { "$ref": "#/$defs/cosmetic" },
        "functional": { "$ref": "#/$defs/functional" },
        "battery": { "$ref": "#/$defs/battery" },
        "locks": { "$ref": "#/$defs/locks" },
        "operator": { "$ref": "#/$defs/operator" },
        "data": { "$ref": "#/$defs/data" },
        "parts": { "$ref": "#/$defs/parts" },
        "kit": { "$ref": "#/$defs/kit" }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "result": { "$ref": "#/$defs/result" },
    "audit": { "$ref": "#/$defs/audit" }
  },
  "patternProperties": { "^x_": true },
  "additionalProperties": false,
  "$defs": {
    "deviceClass": {
      "description": "Device class (§12.1). PHN and TAB are complete in v1.0; the others are profile packs to come.",
      "enum": ["PHN", "TAB", "WCH", "BUD", "LAP", "DSK", "CON", "CNH", "CNX", "CTL", "VRH", "GLS", "TRK"]
    },
    "basis": {
      "description": "How a value was obtained (§3).",
      "enum": ["measured", "evidenced", "declared", "unknown"]
    },
    "nullableString": { "type": ["string", "null"] },
    "identity": {
      "type": "object",
      "required": ["make", "model", "blacklist"],
      "properties": {
        "make": { "type": "string", "minLength": 1 },
        "model": { "type": "string", "minLength": 1 },
        "model_number": { "$ref": "#/$defs/nullableString" },
        "storage": { "$ref": "#/$defs/nullableString" },
        "colour": { "$ref": "#/$defs/nullableString" },
        "region": { "$ref": "#/$defs/nullableString" },
        "imei": { "type": ["string", "null"], "pattern": "^[0-9]{14,16}$" },
        "serial": { "$ref": "#/$defs/nullableString" },
        "blacklist": {
          "description": "The lost/stolen check (§9.3), with its source and date, or `unchecked`. A grade needs `clear`, reached by a check (basis measured / evidenced) or by a declaration (basis declared); `unchecked` is NOT GRADED.",
          "type": "object",
          "required": ["status"],
          "properties": {
            "status": { "enum": ["clear", "reported", "unchecked"] },
            "basis": {
              "description": "How `clear` was reached: a database check (measured / evidenced, with its source) or the grader's / seller's declaration that the device is not reported lost or stolen (declared). Unset means a check.",
              "enum": ["measured", "evidenced", "declared", null]
            },
            "source": { "$ref": "#/$defs/nullableString" },
            "checked_at": { "type": ["string", "null"], "format": "date-time" }
          },
          "patternProperties": { "^x_": true },
          "additionalProperties": false
        },
        "counterfeit": { "type": "boolean" },
        "recalled_unsafe": { "type": "boolean" },
        "imei_mismatch": {
          "description": "Software and hardware IMEIs differ, or signs of tampering (IDN-02).",
          "type": "boolean"
        }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "defect": {
      "type": "object",
      "required": ["type"],
      "properties": {
        "type": {
          "description": "Defect type and level (§5.1–5.2).",
          "enum": ["S1", "S2", "S3", "S4", "DN1", "DN2", "DN3", "CH1", "CH2", "K", "X", "M"]
        },
        "extent": { "description": "For X (discolouration / wear-through).", "enum": ["minor", "major", null] },
        "length_mm": { "type": ["number", "null"], "minimum": 0 },
        "width_mm": { "type": ["number", "null"], "minimum": 0 },
        "note": { "$ref": "#/$defs/nullableString" }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "defectList": { "type": "array", "items": { "$ref": "#/$defs/defect" } },
    "cosmetic": {
      "type": "object",
      "required": ["value"],
      "properties": {
        "value": {
          "description": "§5.3. A–D take a trailing 0 when zone AA has zero defects.",
          "enum": ["S", "O", "A", "A0", "B", "B0", "C", "C0", "D", "D0", "K", "E", "N"]
        },
        "basis": { "$ref": "#/$defs/basis" },
        "mapped_from": {
          "description": "Set when the value was transcribed from a supplier's own grading scale through a crosswalk rather than inspected (basis declared). The grade is unchanged; the core code carries `~src:supplier`.",
          "type": ["object", "null"],
          "required": ["scale", "value"],
          "properties": {
            "scale": { "description": "The supplier's scale, e.g. \"MobileSentrix\".", "type": "string", "minLength": 1 },
            "value": { "description": "The supplier's own grade, e.g. \"Grade B\".", "type": "string", "minLength": 1 },
            "crosswalk": { "description": "The crosswalk used, e.g. \"ugp-1.0/mobilesentrix\".", "type": ["string", "null"] }
          },
          "patternProperties": { "^x_": true },
          "additionalProperties": false
        },
        "zones": {
          "description": "Raw defects per surface zone (§3, §4.3).",
          "type": "object",
          "properties": {
            "AA": { "$ref": "#/$defs/defectList" },
            "A": { "$ref": "#/$defs/defectList" },
            "B": { "$ref": "#/$defs/defectList" },
            "C": { "$ref": "#/$defs/defectList" },
            "L": { "$ref": "#/$defs/defectList" },
            "V": { "$ref": "#/$defs/defectList" }
          },
          "patternProperties": { "^x_": true },
          "additionalProperties": false
        },
        "ldi_triggered": { "type": ["boolean", "null"] }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "functional": {
      "type": "object",
      "required": ["status", "faults"],
      "properties": {
        "status": { "enum": ["FF", "FM", "FJ", "FK", "FX"] },
        "faults": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["code"],
            "properties": {
              "code": {
                "description": "A functional fault code (Annex A). Lock, identity, data and battery codes belong on their own axes.",
                "type": "string",
                "pattern": "^[A-Z]{3}-[0-9]{2}$",
                "not": { "enum": ["BAT-02", "LCK-01", "LCK-02", "LCK-03", "LCK-04", "LCK-05", "LCK-06", "IDN-01", "IDN-02", "DAT-01"] }
              },
              "severity": { "enum": ["minor", "major", "key", null] },
              "note": { "$ref": "#/$defs/nullableString" }
            },
            "patternProperties": { "^x_": true },
            "additionalProperties": false
          }
        }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "battery": {
      "type": "object",
      "required": ["health_pct", "basis"],
      "properties": {
        "applicable": { "description": "false: the device has no battery.", "type": "boolean" },
        "health_pct": {
          "description": "Health of the governing cell, % of original capacity.",
          "type": ["integer", "null"],
          "minimum": 0,
          "maximum": 100
        },
        "basis": { "$ref": "#/$defs/basis" },
        "charge_hold": { "description": "§8.4.", "enum": ["pass", "fail", null] },
        "cells": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["cell", "health_pct", "basis"],
            "properties": {
              "cell": { "type": "string", "minLength": 1 },
              "health_pct": { "type": ["integer", "null"], "minimum": 0, "maximum": 100 },
              "basis": { "$ref": "#/$defs/basis" }
            },
            "patternProperties": { "^x_": true },
            "additionalProperties": false
          }
        },
        "replaced": { "enum": ["genuine", "non-genuine", "unknown", null] }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "locks": {
      "type": "object",
      "required": ["value", "types"],
      "properties": {
        "value": { "description": "§9.1. A grade requires C.", "enum": ["C", "E", "U", "N"] },
        "types": {
          "type": "array",
          "items": { "enum": ["LCK-01", "LCK-02", "LCK-03", "LCK-04", "LCK-06"] }
        }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "operator": {
      "type": "object",
      "required": ["value"],
      "properties": {
        "value": { "description": "§9.2. L is disclosed in every view of the grade.", "enum": ["U", "L", "V", "N"] },
        "carrier": { "$ref": "#/$defs/nullableString" }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "data": {
      "type": "object",
      "required": ["value"],
      "properties": {
        "value": { "description": "§10.1. A grade requires V or W.", "enum": ["V", "W", "X", "U", "N"] },
        "method": { "enum": ["clear", "purge", "destroy", null] },
        "technique": { "$ref": "#/$defs/nullableString" },
        "tool": { "$ref": "#/$defs/nullableString" },
        "certificate_id": { "$ref": "#/$defs/nullableString" },
        "standard_rev": {
          "description": "The revision of NIST SP 800-88 used, e.g. \"NIST SP 800-88 Rev. 2\".",
          "$ref": "#/$defs/nullableString"
        }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "parts": {
      "type": "object",
      "required": ["value", "manifest"],
      "properties": {
        "value": { "description": "§10.2.2.", "enum": ["G", "D", "M", "U", "N"] },
        "manifest": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["part", "state"],
            "properties": {
              "part": { "type": "string", "minLength": 1 },
              "state": { "enum": ["genuine", "non-genuine", "used-genuine", "unknown", "not-checkable"] },
              "basis": { "$ref": "#/$defs/basis" }
            },
            "patternProperties": { "^x_": true },
            "additionalProperties": false
          }
        }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "kit": {
      "type": "object",
      "required": ["value", "components"],
      "properties": {
        "value": { "description": "§10.4. Disclosed; never changes the grade.", "enum": ["F", "P", "H"] },
        "components": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["item", "present"],
            "properties": {
              "item": { "type": "string", "minLength": 1 },
              "present": { "type": "boolean" },
              "oem": { "type": ["boolean", "null"] },
              "condition": { "$ref": "#/$defs/nullableString" },
              "quantity": { "type": ["integer", "null"], "minimum": 0 }
            },
            "patternProperties": { "^x_": true },
            "additionalProperties": false
          }
        }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "result": {
      "description": "Derived values (§11–12). Never entered by hand.",
      "type": "object",
      "required": ["status", "reasons", "grade", "premium", "core_code", "disclosures"],
      "properties": {
        "status": { "enum": ["READY", "REPAIR", "PARTS", "ENCUMBERED", "UNSANITIZED", "PROHIBITED", "NOT_GRADED"] },
        "reasons": { "type": "array", "items": { "type": "string", "minLength": 1 } },
        "grade": { "enum": ["NS", "OB", "A", "B", "C", "D", null] },
        "premium": { "type": "boolean" },
        "core_code": {
          "type": "string",
          "pattern": "^U[0-9]+-(PHN|TAB|WCH|BUD|LAP|DSK|CON|CNH|CNX|CTL|VRH|GLS|TRK)-C(S|O|[ABCD]0?|K|E|N)-F[FMJKX]-B(([0-9]{2}|100)[MD]|NA|UN|CP|CF)-L[CEUN]-R[ULVN]-D[VWXUN]-P[GDMUN]-K[FPH](~[a-z][a-z0-9_.-]*:[A-Za-z0-9_.+%/-]+(,[a-z][a-z0-9_.-]*:[A-Za-z0-9_.+%/-]+)*)?$"
        },
        "disclosures": {
          "description": "What every view of the grade shows besides its name (§11.4(b), §8.3, §10.2.3): carrier lock, non-genuine parts, kit, a declared battery or lost/stolen status, a supplier-mapped grade. Derived; READY records only, [] otherwise.",
          "type": "array",
          "items": { "$ref": "#/$defs/disclosure" }
        },
        "ctia_derived": {
          "description": "A CTIA vector derived from this record, labelled \"derived from UGP v1.0\" wherever it is shown (§15).",
          "type": "string"
        }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "disclosure": {
      "type": "object",
      "required": ["kind"],
      "properties": {
        "kind": {
          "enum": [
            "operator_locked",
            "operator_unknown",
            "non_genuine_parts",
            "parts_not_verified",
            "kit_partial",
            "kit_unit_only",
            "battery_declared",
            "lost_stolen_declared",
            "supplier_mapped"
          ]
        },
        "carrier": { "description": "operator_locked: the carrier, when recorded.", "type": ["string", "null"] },
        "parts": { "description": "non_genuine_parts: the parts named.", "type": "array", "items": { "type": "string" } },
        "missing": { "description": "kit_partial: the missing items.", "type": "array", "items": { "type": "string" } },
        "pct": { "description": "battery_declared: the declared health, %.", "type": "integer", "minimum": 0, "maximum": 100 }
      },
      "additionalProperties": false
    },
    "audit": {
      "type": "object",
      "required": ["grader_id", "graded_at", "method", "verification_tier", "conformance", "tolerance_table"],
      "properties": {
        "grader_id": { "description": "Pseudonymous (§14.4).", "type": "string", "minLength": 1 },
        "graded_at": { "type": "string", "format": "date-time" },
        "method": { "enum": ["human", "cv", "hybrid"] },
        "verification_tier": { "enum": ["V0", "V1", "V2"] },
        "conformance": { "enum": ["UGP-Full", "UGP-Cosmetic", "UGP-Functional"] },
        "tolerance_table": {
          "description": "The tolerance table applied, e.g. \"phone-1.0-provisional\" (§5.5).",
          "type": "string",
          "pattern": "^[a-z]+-[0-9]+\\.[0-9]+(-provisional)?$"
        }
      },
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    }
  }
}
