{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://neuroglyph.org/schemas/v0.3/message.json",
  "title": "NeuroGlyph Message v0.3",
  "description": "Семантический протокол: NSM-примы + PropBank-роли + диакритики + прагматика + культурные глоссы. Фиксы D1-D8 из стресс-теста (Dialog 5) + D13: root XOR discourse (tracer-прототип, 2026-08-11).",
  "type": "object",
  "required": ["v", "act"],
  "properties": {
    "v": { "type": "string", "const": "0.3" },
    "act": { "$ref": "#/$defs/Intent" },
    "mode": { "$ref": "#/$defs/Mode" },
    "root": { "$ref": "#/$defs/GlyphInstance", "description": "Единый корневой глиф. Для многоклаузных сообщений используй discourse вместо root [D13]" },
    "discourse": { "$ref": "#/$defs/Discourse" },
    "envelope": { "$ref": "#/$defs/Envelope" },
    "provenance": { "$ref": "#/$defs/Provenance" },
    "fallback": { "type": "string", "description": "Человекочитаемый fallback в исходном языке" },
    "lang_hint": { "type": "string", "pattern": "^[a-z]{2}(-[A-Z]{2})?$" }
  },
  "oneOf": [
    { "required": ["root"] },
    { "required": ["discourse"] }
  ],

  "$defs": {

    "GlyphInstance": {
      "type": "object",
      "description": "Употребление глифа. Либо 'g' (вложенный), либо 'ref' (ссылка на node_id). [D3]",
      "required": ["g"],
      "properties": {
        "node_id": {
          "type": "string",
          "description": "Идентификатор узла для кореференции/ре-ентерабельности [D3]"
        },
        "g": { "$ref": "#/$defs/GlyphID" },
        "f": { "$ref": "#/$defs/FeatureMask", "description": "По умолчанию 0 = unspecified-neutral [D6]" },
        "a": {
          "type": "array",
          "description": "Аргументы как МАССИВ пар {role, target} — допускает дубли ролей (два ArgM-LOC). [D1]",
          "items": { "$ref": "#/$defs/Arg" }
        },
        "decomposition": {
          "type": "array",
          "description": "Обязателен для макро (g >= 0x80) — обратная совместимость [D11]",
          "items": { "$ref": "#/$defs/GlyphInstance" }
        }
      },
      "allOf": [
        {
          "if": { "properties": { "g": { "pattern": "^0x(8[0-9a-fA-F]|9[0-9a-fA-F]|[a-fA-F][0-9a-fA-F])$" } } },
          "then": { "required": ["decomposition"] }
        }
      ]
    },

    "GlyphID": {
      "type": "string",
      "pattern": "^0x[0-9a-fA-F]{2,4}$",
      "description": "0x00-0x0F структуры, 0x10-0x1F действия, 0x20-0x60 NSM-примы, 0x61-0x7F резерв, 0x80-0xBF макро, 0xC0-0xFF культурные"
    },

    "FeatureMask": {
      "type": "integer",
      "minimum": 0,
      "maximum": 4294967295,
      "description": "uint32 (v0.3, было 16 бит [D4]). Биты 0-1 INTENSITY, 2-3 VALENCE, 4-5 TIME, 6-7 ASPECT, 8-9 EPISTEMIC, 10-11 EVIDENTIAL, 12-13 POWER, 14-15 AGENCY, 16-17 SOCIAL, 18 REALIS, 19 INFO_STRUCTURE, 20-21 резерв, 30 EXTENDED, 31 CULTURAL"
    },

    "Arg": {
      "type": "object",
      "description": "Пара роль → глиф/литерал. Массив вместо объекта: допускает дубли ролей [D1]",
      "required": ["role", "target"],
      "properties": {
        "role": { "$ref": "#/$defs/Role" },
        "target": {
          "oneOf": [
            { "$ref": "#/$defs/GlyphInstance" },
            { "$ref": "#/$defs/Literal" },
            { "type": "string", "description": "ref на node_id (кореференция) [D3]" }
          ]
        }
      }
    },

    "Literal": {
      "type": "object",
      "required": ["type", "value"],
      "properties": {
        "type": { "enum": ["number", "time", "text", "boolean", "uri"] },
        "value": {}
      },
      "allOf": [
        { "if": { "properties": { "type": { "const": "number" } } }, "then": { "properties": { "value": { "type": "number" } } } },
        { "if": { "properties": { "type": { "const": "boolean" } } }, "then": { "properties": { "value": { "type": "boolean" } } } },
        { "if": { "properties": { "type": { "const": "text" } } }, "then": { "properties": { "value": { "type": "string" } } } },
        { "if": { "properties": { "type": { "const": "uri" } } }, "then": { "properties": { "value": { "type": "string", "format": "uri" } } } }
      ]
    },

    "Discourse": {
      "type": "object",
      "description": "Многоклаузный контейнер [D7, D8]",
      "properties": {
        "units": {
          "type": "array",
          "items": { "$ref": "#/$defs/MessageUnit" }
        },
        "relations": {
          "type": "array",
          "description": "Дискурсивные связи между units [D8]",
          "items": { "$ref": "#/$defs/DiscourseRelation" }
        }
      }
    },

    "MessageUnit": {
      "type": "object",
      "required": ["root"],
      "properties": {
        "unit_id": { "type": "string" },
        "root": { "$ref": "#/$defs/GlyphInstance" },
        "act": { "$ref": "#/$defs/Intent" }
      }
    },

    "DiscourseRelation": {
      "type": "object",
      "required": ["rel", "from", "to"],
      "properties": {
        "rel": { "$ref": "#/$defs/DiscourseRel" },
        "from": { "type": "string", "description": "unit_id" },
        "to": { "type": "string", "description": "unit_id" }
      }
    },

    "DiscourseRel": {
      "type": "string",
      "enum": ["BECAUSE", "IF", "BEFORE", "AFTER", "WHILE", "CONTRAST", "CONCESSION", "PURPOSE", "SEQUENCE", "ELABORATION"]
    },

    "Role": {
      "type": "string",
      "enum": [
        "Arg0", "Arg1", "Arg2", "Arg3", "Arg4", "Arg5",
        "ArgM-LOC", "ArgM-TMP", "ArgM-MNR", "ArgM-CAU", "ArgM-PRP", "ArgM-ADV",
        "ArgM-COM", "ArgM-BEN", "ArgM-DIR", "ArgM-GOL", "ArgM-SRC", "ArgM-TOP",
        "ArgM-NEG", "ArgM-DIS", "ArgM-MOD", "ArgM-EXT", "ArgM-LVB"
      ]
    },

    "Intent": {
      "type": "string",
      "enum": ["ASSERT", "QUERY", "REQUEST", "COMMAND", "EMOTE", "NEGATE", "OFFER", "REFUSE", "CONFIRM", "ALERT", "INITIATE", "PROCEED", "REPAIR", "NIL"]
    },

    "Mode": {
      "type": "string",
      "enum": ["GENERIC", "INVITE", "START", "PROCEED", "ENCOURAGE", "ACCEPT", "CHALLENGE", "SOFTEN", "DECLARATIVE", "INTERROGATIVE", "IMPERATIVE", "EXPRESSIVE", "NIL"]
    },

    "Envelope": {
      "type": "object",
      "properties": {
        "tone": { "$ref": "#/$defs/Tone" },
        "register": { "enum": ["formal", "neutral", "informal", "intimate", "slang"] },
        "urgency": { "enum": ["low", "normal", "high", "critical"] },
        "politeness": { "enum": ["blunt", "neutral", "polite", "deferential"] },
        "confidence": { "type": "number", "minimum": 0, "maximum": 1 }
      }
    },

    "Tone": {
      "type": "string",
      "enum": ["neutral", "warm", "cold", "playful", "ironic", "sarcastic", "serious", "urgent", "calm", "excited", "sad", "angry", "encouraging", "reluctant", "aggressive", "gentle", "NIL"]
    },

    "Provenance": {
      "type": "object",
      "properties": {
        "source_hash": { "type": "string" },
        "span": { "type": "string" },
        "annotator": { "enum": ["human", "ai", "hybrid"] },
        "model_id": { "type": "string" },
        "confidence": { "type": "number", "minimum": 0, "maximum": 1 },
        "version": { "type": "integer" },
        "cultural_glosses": { "type": "array", "items": { "$ref": "#/$defs/CulturalGloss" } },
        "decomposition": { "type": "array", "items": { "$ref": "#/$defs/GlyphInstance" } }
      }
    },

    "CulturalGloss": {
      "type": "object",
      "required": ["tag"],
      "properties": {
        "tag": { "type": "string" },
        "explanation": { "type": "string" },
        "source_lang": { "type": "string", "pattern": "^[a-z]{2}$" },
        "equivalent_approx": { "type": "string" }
      }
    }
  }
}
