{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://inverencebbs.github.io/modelos-catalogo/alta-0.1.schema.json",
  "title": "Anexo de alta de una ficha 0.10 — contrato v0.1",
  "description": "Lo que la plataforma necesita para servir un modelo y la ficha del emisor no trae. Es un artefacto APARTE: la ficha no se toca jamás. Se ata por el sha256 de cada ficha que anota, y es una propuesta: se acepta al importar (import-ficha, con operador y acta). Si la ficha trae un campo que el anexo también pone y no coinciden, la importación se detiene.",
  "type": "object",
  "additionalProperties": false,
  "required": ["alta_version", "bound_fichas", "domain", "tenant", "outputs", "leaves", "default_band_level"],
  "properties": {
    "alta_version": {"const": "0.1"},
    "bound_fichas": {
      "description": "Las fichas que este anexo anota, una por nodo, por el sha256 de sus bytes tal como llegaron. Un anexo no se aplica a otra emisión.",
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["node", "sha256"],
        "properties": {
          "node": {"type": "string", "pattern": "^(_raiz|[A-Za-z0-9._-]+)$"},
          "sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"},
          "catalogue_key": {"type": "string", "minLength": 1}
        }
      }
    },
    "domain": {
      "description": "El dominio de plataforma que servirá el modelo.",
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9_-]*$"
    },
    "tenant": {
      "description": "El tenant al que pertenece el dominio.",
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9_-]*$"
    },
    "outputs": {
      "description": "Por cada salida modelada: cómo se nombra y en qué unidad se sirve, y de qué KPI y fuente sale.",
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["node", "output", "label", "unit", "scale_factor", "kpi", "source", "aggregation"],
        "properties": {
          "node": {"type": "string", "pattern": "^(_raiz|[A-Za-z0-9._-]+)$"},
          "output": {"type": "string", "minLength": 1},
          "label": {"type": "string", "minLength": 1},
          "unit": {"type": "string", "minLength": 1},
          "scale_factor": {"type": "number", "exclusiveMinimum": 0},
          "kpi": {"type": "string", "minLength": 1},
          "source": {"type": "string", "minLength": 1},
          "aggregation": {"enum": ["sum", "mean", "count", "count_distinct", "last"]}
        }
      }
    },
    "leaves": {
      "description": "Por cada hoja de un árbol: la dimensión y el miembro que representa.",
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["node", "dimension", "member"],
        "properties": {
          "node": {"type": "string", "pattern": "^[A-Za-z0-9._-]+$"},
          "dimension": {"type": "string", "minLength": 1},
          "member": {"type": "string", "minLength": 1}
        }
      }
    },
    "default_band_level": {
      "description": "Nivel de la banda con el que se sirve la previsión cuando no se pide otro, en porcentaje.",
      "type": "number",
      "minimum": 50,
      "maximum": 99
    }
  }
}
