{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://neon-sprawl.local/schemas/mastery-catalog.schema.json",
  "title": "MasteryCatalog",
  "description": "Mastery tracks and perk definitions for content/mastery/*_mastery.json. Perk and branch ids are stable forever—rename displayName only. See docs/decomposition/modules/E2_M3_MasteryAndPerkUnlocks.md.",
  "type": "object",
  "additionalProperties": false,
  "required": ["schemaVersion", "perks", "tracks"],
  "properties": {
    "schemaVersion": {
      "type": "integer",
      "const": 1
    },
    "perks": {
      "type": "object",
      "description": "Map of perkId to PerkDef. Keys must match each PerkDef.id.",
      "additionalProperties": {
        "$ref": "#/$defs/PerkDef"
      }
    },
    "tracks": {
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/MasteryTrack"
      }
    }
  },
  "$defs": {
    "stableId": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9_]*$"
    },
    "PerkDef": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "displayName"],
      "properties": {
        "id": {
          "$ref": "#/$defs/stableId",
          "description": "Immutable perk key for unlock state and telemetry."
        },
        "displayName": {
          "type": "string",
          "minLength": 1,
          "description": "Player-facing label; safe to change without migrating unlock data."
        },
        "effectKind": {
          "type": "string",
          "minLength": 1,
          "description": "Optional stub for future gameplay hooks (E3+). No apply in E2.M3 core."
        }
      }
    },
    "MasteryBranch": {
      "type": "object",
      "additionalProperties": false,
      "required": ["branchId", "perkIds"],
      "properties": {
        "branchId": {
          "$ref": "#/$defs/stableId",
          "description": "Immutable branch key; mutually exclusive pick per tier."
        },
        "displayName": {
          "type": "string",
          "minLength": 1
        },
        "perkIds": {
          "type": "array",
          "uniqueItems": true,
          "items": {
            "$ref": "#/$defs/stableId"
          },
          "description": "Perks unlocked when this branch is chosen at this tier (may be empty at tier 1)."
        }
      }
    },
    "MasteryTier": {
      "type": "object",
      "additionalProperties": false,
      "required": ["tierIndex", "requiredLevel", "branches"],
      "properties": {
        "tierIndex": {
          "type": "integer",
          "minimum": 1,
          "description": "1-based tier index; stable key for PerkState branch picks (NEO-47+)."
        },
        "requiredLevel": {
          "type": "integer",
          "minimum": 1,
          "description": "Skill level from E2.M2 required before this tier's branches are eligible."
        },
        "branches": {
          "type": "array",
          "minItems": 2,
          "items": {
            "$ref": "#/$defs/MasteryBranch"
          }
        }
      }
    },
    "MasteryTrack": {
      "type": "object",
      "additionalProperties": false,
      "required": ["skillId", "tiers"],
      "properties": {
        "skillId": {
          "$ref": "#/$defs/stableId",
          "description": "Must exist in E2.M1 SkillDef catalog."
        },
        "tiers": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/MasteryTier"
          }
        }
      }
    }
  }
}
