{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://botlandscape.com/policy-dna.schema.json",
  "title": "Bot Landscape Policy DNA projection",
  "description": "Motion fingerprints derived by scripts/policy_dna.py from the recorded episode artefacts. One fingerprint per recorded episode. It is not a suite score, a policy ranking, or a claim about generalization.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "$schema",
    "schema_version",
    "method",
    "inputs_digest",
    "policy_classes",
    "action_families",
    "class_summaries",
    "episodes"
  ],
  "properties": {
    "$schema": {"const": "https://botlandscape.com/policy-dna.schema.json"},
    "schema_version": {"const": 1},
    "method": {
      "type": "object",
      "additionalProperties": false,
      "required": ["version", "strip_columns", "strip_levels", "curve_points", "roughness", "active_share", "t50", "scope"],
      "properties": {
        "version": {"type": "string", "pattern": "^policy-dna/[0-9]+$"},
        "strip_columns": {"type": "integer", "minimum": 1},
        "strip_levels": {"const": 16},
        "curve_points": {"type": "integer", "minimum": 1},
        "roughness": {"type": "string", "minLength": 1},
        "active_share": {"type": "string", "minLength": 1},
        "t50": {"type": "string", "minLength": 1},
        "scope": {"type": "string", "minLength": 1}
      }
    },
    "inputs_digest": {
      "type": "object",
      "additionalProperties": false,
      "required": ["alg", "hex"],
      "properties": {
        "alg": {"const": "sha256"},
        "hex": {"type": "string", "pattern": "^[0-9a-f]{64}$"}
      }
    },
    "policy_classes": {
      "type": "array",
      "minItems": 1,
      "items": {"$ref": "#/$defs/vocabulary"}
    },
    "action_families": {
      "type": "array",
      "minItems": 1,
      "items": {"$ref": "#/$defs/vocabulary"}
    },
    "class_summaries": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "episodes", "with_actions", "successes", "failures", "median_roughness", "median_active_share"],
        "properties": {
          "id": {"$ref": "#/$defs/policyClass"},
          "episodes": {"type": "integer", "minimum": 0},
          "with_actions": {"type": "integer", "minimum": 0},
          "successes": {"type": "integer", "minimum": 0},
          "failures": {"type": "integer", "minimum": 0},
          "median_roughness": {"type": ["number", "null"], "minimum": 0},
          "median_active_share": {"type": ["number", "null"], "minimum": 0}
        }
      }
    },
    "episodes": {
      "type": "array",
      "minItems": 1,
      "items": {"$ref": "#/$defs/episode"}
    }
  },
  "$defs": {
    "slug": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
    "policyClass": {"enum": ["rl", "vla", "human-teleop", "scripted-expert", "planner", "random"]},
    "actionFamily": {"enum": ["joint-absolute", "joint-delta", "ee-delta", "ee-absolute", "whole-body", "base", "none"]},
    "vocabulary": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "label", "description"],
      "properties": {
        "id": {"$ref": "#/$defs/slug"},
        "label": {"type": "string", "minLength": 1},
        "description": {"type": "string", "minLength": 1}
      }
    },
    "episode": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id", "label", "suite", "kind", "origin", "policy_class", "action_family", "success", "dataset_reported_success",
        "steps", "sample_hz", "duration_s", "action", "reward", "events", "strip",
        "manifest_href", "replay_href", "manifest_digest"
      ],
      "properties": {
        "id": {"type": "string", "pattern": "^[a-z0-9]+(?:[-.:_][a-z0-9]+)*$"},
        "label": {"type": "string", "minLength": 1},
        "suite": {"type": "string", "minLength": 1},
        "kind": {"type": "string"},
        "origin": {"type": "string"},
        "policy_class": {"$ref": "#/$defs/policyClass"},
        "action_family": {"$ref": "#/$defs/actionFamily"},
        "success": {"type": ["boolean", "null"]},
        "dataset_reported_success": {"type": ["boolean", "null"]},
        "steps": {"type": "integer", "minimum": 0},
        "sample_hz": {"type": ["number", "null"], "minimum": 0},
        "duration_s": {"type": ["number", "null"], "minimum": 0},
        "action": {
          "type": "object",
          "additionalProperties": false,
          "required": ["channels", "active_channels", "active_share", "roughness", "space"],
          "properties": {
            "channels": {"type": "integer", "minimum": 0},
            "active_channels": {"type": "integer", "minimum": 0},
            "active_share": {"type": ["number", "null"], "minimum": 0},
            "roughness": {"type": ["number", "null"], "minimum": 0},
            "space": {"type": "string"}
          }
        },
        "reward": {
          "type": "object",
          "additionalProperties": false,
          "required": ["recorded", "return_sum", "t50", "curve"],
          "properties": {
            "recorded": {"type": "boolean"},
            "return_sum": {"type": ["number", "null"]},
            "t50": {"type": ["number", "null"], "minimum": 0},
            "curve": {"type": "array", "items": {"type": "number", "minimum": 0}}
          }
        },
        "events": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["at", "kind", "label"],
            "properties": {
              "at": {"type": "number", "minimum": 0},
              "kind": {"type": "string", "minLength": 1},
              "label": {"type": "string"}
            }
          }
        },
        "strip": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["name", "active", "cells"],
            "properties": {
              "name": {"type": "string", "minLength": 1},
              "active": {"type": "boolean"},
              "cells": {"type": "string", "pattern": "^[0-9a-f]*$"}
            }
          }
        },
        "manifest_href": {"type": "string", "pattern": "^/worlds/episodes/[^/]+\\.json$"},
        "replay_href": {"type": "string", "pattern": "^/\\?episode="},
        "manifest_digest": {"type": "string", "pattern": "^([0-9a-f]{64})?$"}
      }
    }
  }
}
