{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://yarramate.org/schema/document/v1",
  "title": "YarraMate native document",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "format",
    "id",
    "profile",
    "concepts",
    "relationships"
  ],
  "properties": {
    "format": {
      "const": "yarramate/v1"
    },
    "id": {
      "$ref": "#/$defs/id"
    },
    "profile": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9-]*(?:/[a-z][a-z0-9-]*)+@[0-9]+\\.[0-9]+$"
    },
    "states": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/architectureState"
      }
    },
    "concepts": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/concept"
      }
    },
    "relationships": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/relationship"
      }
    }
  },
  "$defs": {
    "id": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$"
    },
    "nonEmptyText": {
      "type": "string",
      "pattern": "\\S"
    },
    "reference": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*(?:#[a-z][a-z0-9]*(?:-[a-z0-9]+)*)?$"
    },
    "architectureState": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "kind",
        "name"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/id"
        },
        "kind": {
          "enum": [
            "baseline",
            "transition",
            "target"
          ]
        },
        "name": {
          "$ref": "#/$defs/nonEmptyText"
        },
        "description": {
          "$ref": "#/$defs/nonEmptyText"
        },
        "after": {
          "$ref": "#/$defs/reference"
        }
      }
    },
    "concept": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "kind",
        "name"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/id"
        },
        "kind": {
          "type": "string",
          "minLength": 1
        },
        "name": {
          "$ref": "#/$defs/nonEmptyText"
        },
        "description": {
          "$ref": "#/$defs/nonEmptyText"
        },
        "aka": {
          "$ref": "#/$defs/alternativeLabels"
        },
        "status": {
          "$ref": "#/$defs/lifecycleStatus"
        },
        "owner": {
          "$ref": "#/$defs/reference"
        },
        "folder": {
          "type": "string",
          "description": "The folder this files itself under in an editor's tree. A LABEL the author declares, never a directory: nest with '/' separators, and the filesystem is never consulted (ADR 0104).",
          "pattern": "^[^/]+(?:/[^/]+)*$",
          "minLength": 1
        },
        "distinctFrom": {
          "$ref": "#/$defs/subjectReferences"
        },
        "supersedes": {
          "$ref": "#/$defs/successionReferences"
        },
        "forbids": {
          "description": "Relationship shapes this subject rules out, checked against the graph. A constraint nothing tests is a comment. Deliberately narrow: forbid a relationship kind between named endpoints, with exceptions, which covers \"everything goes through X\" and needs no traversal.",
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["relationship"],
            "anyOf": [{ "required": ["from"] }, { "required": ["to"] }],
            "properties": {
              "relationship": { "type": "string", "minLength": 1 },
              "from": { "type": "string", "minLength": 1 },
              "to": { "type": "string", "minLength": 1 },
              "exceptFrom": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
              "exceptTo": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } }
            }
          }
        },
        "constraints": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/constraint"
          }
        },
        "parts": {
          "description": "The subjects that fill this instance's pattern slots, by slot name (ADR 0123). Valid only on a kind that has a pattern; the compiler mints the pattern's wiring between the instance and what these name, and refuses any authored relationship that contradicts it. Binding, not generation: a part keeps its own name, owner, evidence and outside edges.",
          "type": "object",
          "minProperties": 1,
          "additionalProperties": false,
          "propertyNames": {
            "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$"
          },
          "patternProperties": {
            "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$": {
              "$ref": "#/$defs/reference"
            }
          }
        },
        "references": {
          "$ref": "#/$defs/identifiedReferences"
        },
        "presentIn": {
          "$ref": "#/$defs/stateReferences"
        },
        "attestations": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/attestation"
          }
        }
      }
    },
    "constraint": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "ref"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/id"
        },
        "ref": {
          "$ref": "#/$defs/reference"
        },
        "expects": {
          "$ref": "#/$defs/expectedObservation"
        }
      }
    },
    "expectedObservation": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "provider",
        "key",
        "value"
      ],
      "properties": {
        "provider": {
          "$ref": "#/$defs/id"
        },
        "key": {
          "$ref": "#/$defs/observationKey"
        },
        "value": {
          "$ref": "#/$defs/nonEmptyText"
        }
      }
    },
    "observationKey": {
      "type": "string",
      "pattern": "^[A-Za-z0-9][A-Za-z0-9._/-]*$"
    },
    "identifiedReference": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "ref"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/id"
        },
        "ref": {
          "$ref": "#/$defs/reference"
        }
      }
    },
    "identifiedReferences": {
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/identifiedReference"
      }
    },
    "alternativeLabels": {
      "description": "Other names this subject is known by: abbreviations, legacy names, team jargon. The preferred label stays in name; renderers show only that.",
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "$ref": "#/$defs/nonEmptyText"
      }
    },
    "subjectReferences": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "$ref": "#/$defs/reference"
      }
    },
    "successionReferences": {
      "description": "Subjects whose responsibility this one took over. One entry is a rename, several are a merge, and one predecessor named by several successors is a split. A predecessor need not be retired: the transition period is real.",
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "oneOf": [
          { "$ref": "#/$defs/reference" },
          {
            "type": "object",
            "additionalProperties": false,
            "required": ["subject", "inRespectOf"],
            "properties": {
              "subject": { "$ref": "#/$defs/reference" },
              "inRespectOf": { "$ref": "#/$defs/nonEmptyText" }
            }
          }
        ]
      }
    },
    "relationship": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "kind",
        "from",
        "to"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/id"
        },
        "kind": {
          "type": "string",
          "minLength": 1
        },
        "from": {
          "$ref": "#/$defs/reference"
        },
        "to": {
          "$ref": "#/$defs/reference"
        },
        "name": {
          "$ref": "#/$defs/nonEmptyText"
        },
        "description": {
          "$ref": "#/$defs/nonEmptyText"
        },
        "mode": {
          "enum": [
            "read",
            "write",
            "read-write",
            "unspecified"
          ]
        },
        "content": {
          "$ref": "#/$defs/nonEmptyText"
        },
        "status": {
          "$ref": "#/$defs/lifecycleStatus"
        },
        "references": {
          "$ref": "#/$defs/identifiedReferences"
        },
        "presentIn": {
          "$ref": "#/$defs/stateReferences"
        }
      }
    },
    "stateReferences": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "$ref": "#/$defs/reference"
      }
    },
    "lifecycleStatus": {
      "enum": [
        "planned",
        "current",
        "retired"
      ]
    },
    "attestation": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "topic",
        "by",
        "on"
      ],
      "properties": {
        "topic": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9-]*$"
        },
        "by": {
          "description": "The authority whose judgment this records, as a subject reference. A sign-off names someone the model already knows, on the same rule as ownership: an authority absent from the model cannot be held to the judgment.",
          "$ref": "#/$defs/reference"
        },
        "recordedBy": {
          "description": "Who wrote this record, when that is not the attesting authority's own hand. An agent recording a judgment on someone's behalf names itself here, so a sign-off and a transcription of one are never the same bytes.",
          "$ref": "#/$defs/nonEmptyText"
        },
        "on": {
          "type": "string",
          "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
        }
      }
    }
  }
}
