{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://omac.io/schemas/v1alpha1/core.schema.json",
  "title": "OMaC Core — v1alpha1",
  "description": "Validates a single OMaC core document (Unit or Relationship). Facet contents are validated separately by each extension's own schema; here `facets` is an open, namespaced map. Cross-reference integrity (parent/from/to resolve to real ids, global id uniqueness) is enforced by a semantic linter, not this schema.",
  "type": "object",
  "required": ["apiVersion", "kind"],
  "properties": {
    "apiVersion": { "const": "omac.io/v1alpha1" },
    "kind": { "enum": ["Unit", "Relationship", "Person", "Customer", "Policy", "Product", "Service", "Position"] },
    "facets": { "$ref": "#/$defs/facets" }
  },
  "oneOf": [
    { "$ref": "#/$defs/unit" },
    { "$ref": "#/$defs/relationship" },
    { "$ref": "#/$defs/person" },
    { "$ref": "#/$defs/customer" },
    { "$ref": "#/$defs/policy" },
    { "$ref": "#/$defs/product" },
    { "$ref": "#/$defs/service" },
    { "$ref": "#/$defs/position" }
  ],

  "$defs": {
    "id": {
      "type": "string",
      "description": "Stable identifier. Unit/Customer ids are kebab slugs; Person ids are the corporate username (may contain dots/underscores, e.g. 'alice.chen').",
      "pattern": "^[a-z0-9][a-z0-9._-]*$"
    },

    "facets": {
      "type": "object",
      "description": "Namespaced extension blocks keyed by a reverse-DNS namespace + version, e.g. 'team-topologies.omac.io/v1alpha1' (official) or 'workday.acme.example/v1' (org-specific). Contents validated by each extension's own schema.",
      "propertyNames": { "pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)+/v[0-9a-z.]+$" },
      "additionalProperties": { "type": "object" }
    },

    "unit": {
      "properties": {
        "kind": { "const": "Unit" },
        "metadata": {
          "type": "object",
          "required": ["id", "name"],
          "additionalProperties": false,
          "properties": {
            "id": { "$ref": "#/$defs/id" },
            "name": { "type": "string" }
          }
        },
        "spec": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "parent": { "$ref": "#/$defs/id" },
            "nature": {
              "description": "Framework-free unit nature — a closed set every matrixed org has. Optional; absent means 'delivery'. 'governance' = decision-making body. TT classification (stream-aligned/platform/enabling) refines delivery-nature units only. There is no 'people' nature: the people axis is expressed as reports-to manager chains (person -> person) plus a governance body of the managers, not as a unit.",
              "enum": ["delivery", "governance"]
            },
            "mission": { "type": "string" },
            "members": {
              "type": "array",
              "description": "Optional Person ids. Broad membership is usually modeled as works-on/reports-to/sits-on edges.",
              "items": { "type": "string" }
            },
            "leadership": {
              "type": "object",
              "description": "Map of role (e.g. pm, lead) to a Person id.",
              "additionalProperties": { "type": "string" }
            }
          }
        },
        "facets": { "$ref": "#/$defs/facets" }
      },
      "required": ["kind", "metadata"]
    },

    "relationship": {
      "properties": {
        "kind": { "const": "Relationship" },
        "spec": {
          "type": "object",
          "required": ["from", "to", "type", "label"],
          "additionalProperties": false,
          "properties": {
            "from": { "$ref": "#/$defs/id" },
            "to": { "$ref": "#/$defs/id" },
            "type": {
              "description": "Core relationship vocabulary: a closed set of framework-free structural planes. 'provides' (value, provider->consumer), 'reports-to' (authority, person->person; points at the MANAGER directly — an org-chart chain; the org apex has none), 'works-on' (assignment, person->delivery-unit), 'sits-on' (governance participation, person->governance-unit), 'owns' (accountability, Unit|Person->Policy; who is answerable), 'governs' (remit, governance-unit->any unit; the deliberative authority a governance body holds over a unit and its subtree, complementing 'sits-on' membership). reports-to targets a Person; the two unit-targeting person-planes (works-on/sits-on) each target one unit nature (delivery/governance); 'governs' is a unit->unit plane whose SOURCE is governance-nature. 'serves'/'depends-on' are RENDER directions of a 'provides' edge, never stored.",
              "enum": ["provides", "reports-to", "works-on", "sits-on", "owns", "governs"]
            },
            "label": { "type": "string" },
            "service": {
              "$ref": "#/$defs/id",
              "description": "Optional: the Service this 'provides' edge concerns. Its provider must be `from` (or within `from`'s subtree)."
            },
            "allocation": {
              "description": "For a 'works-on' edge: the fraction of the person's time invested in this unit, 0..1. OPTIONAL; absent means 1.0 (this is their whole engagement). A person's works-on allocations should sum to <= 1.0 — the sum is their total engaged capacity (a part-timer sums to < 1.0), and the number of edges is how fragmented they are. Ignored on non-'works-on' edges.",
              "type": "number",
              "exclusiveMinimum": 0,
              "maximum": 1
            }
          }
        },
        "facets": { "$ref": "#/$defs/facets" }
      },
      "required": ["kind", "spec"]
    },

    "person": {
      "properties": {
        "kind": { "const": "Person" },
        "metadata": {
          "type": "object",
          "required": ["id", "name"],
          "additionalProperties": false,
          "properties": {
            "id": { "$ref": "#/$defs/id" },
            "name": { "type": "string" }
          }
        },
        "spec": {
          "type": "object",
          "required": ["email"],
          "additionalProperties": false,
          "properties": {
            "email": { "type": "string", "format": "email" },
            "affiliation": {
              "description": "OPTIONAL OVERRIDE. Normally DERIVED from the email domain via org config (contractors now carry 'external' in the domain), so it is omitted. Present only to override a genuine anomaly. Finer classes (contractor, vendor, business-partner) live in an HR facet, not here.",
              "enum": ["internal", "external"]
            },
            "preferredName": { "type": "string" },
            "location": { "type": "string" }
          }
        },
        "facets": { "$ref": "#/$defs/facets" }
      },
      "required": ["kind", "metadata", "spec"]
    },

    "customer": {
      "properties": {
        "kind": { "const": "Customer" },
        "metadata": {
          "type": "object",
          "required": ["id", "name"],
          "additionalProperties": false,
          "properties": {
            "id": { "$ref": "#/$defs/id" },
            "name": { "type": "string" }
          }
        },
        "spec": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "examples": { "type": "array", "items": { "type": "string" } },
            "segment": { "type": "string" }
          }
        },
        "facets": { "$ref": "#/$defs/facets" }
      },
      "required": ["kind", "metadata"]
    },

    "policy": {
      "properties": {
        "kind": { "const": "Policy" },
        "metadata": {
          "type": "object",
          "required": ["id", "name"],
          "additionalProperties": false,
          "properties": {
            "id": { "$ref": "#/$defs/id" },
            "name": { "type": "string" }
          }
        },
        "spec": {
          "type": "object",
          "required": ["statement"],
          "additionalProperties": false,
          "properties": {
            "statement": { "type": "string", "description": "The rule/target/constraint in prose." },
            "target": {
              "type": "object",
              "additionalProperties": true,
              "description": "Optional structured target (shape varies by policy; a policy-type extension may constrain it)."
            },
            "scope": {
              "type": "array",
              "items": { "$ref": "#/$defs/id" },
              "description": "Unit ids this policy applies to (applicability cascades to their subtree). Distinct from ownership."
            },
            "metric": {
              "type": "string",
              "description": "How compliance is measured — points at a DERIVED computation, not a stored value."
            }
          }
        },
        "facets": { "$ref": "#/$defs/facets" }
      },
      "required": ["kind", "metadata", "spec"]
    },

    "product": {
      "properties": {
        "kind": { "const": "Product" },
        "metadata": {
          "type": "object",
          "required": ["id", "name"],
          "additionalProperties": false,
          "properties": {
            "id": { "$ref": "#/$defs/id" },
            "name": { "type": "string" }
          }
        },
        "spec": {
          "type": "object",
          "required": ["customer"],
          "additionalProperties": false,
          "properties": {
            "customer": {
              "$ref": "#/$defs/id",
              "description": "The Customer segment that owns this product (Payments owns Checkout)."
            },
            "availability": {
              "description": "Operational commitment. Makes the '24x7 count' derivable rather than stored.",
              "enum": ["24x7", "business-hours", "best-effort"]
            },
            "description": { "type": "string" }
          }
        },
        "facets": { "$ref": "#/$defs/facets" }
      },
      "required": ["kind", "metadata", "spec"]
    },

    "service": {
      "properties": {
        "kind": { "const": "Service" },
        "metadata": {
          "type": "object",
          "required": ["id", "name"],
          "additionalProperties": false,
          "properties": {
            "id": { "$ref": "#/$defs/id" },
            "name": { "type": "string" }
          }
        },
        "spec": {
          "type": "object",
          "required": ["provider"],
          "additionalProperties": false,
          "properties": {
            "provider": {
              "$ref": "#/$defs/id",
              "description": "The Unit that offers this internal service/capability. A unit's offerings DERIVE from inbound provider refs (there is no stored Unit.provides list)."
            },
            "description": { "type": "string" }
          }
        },
        "facets": { "$ref": "#/$defs/facets" }
      },
      "required": ["kind", "metadata", "spec"]
    },

    "position": {
      "properties": {
        "kind": { "const": "Position" },
        "metadata": {
          "type": "object",
          "required": ["id", "name"],
          "additionalProperties": false,
          "properties": {
            "id": { "$ref": "#/$defs/id" },
            "name": { "type": "string", "description": "The seat's title, e.g. 'Senior SRE'. May repeat across positions — the id disambiguates." }
          }
        },
        "spec": {
          "type": "object",
          "required": ["establishment_fte"],
          "additionalProperties": false,
          "properties": {
            "unit": {
              "$ref": "#/$defs/id",
              "description": "The delivery Unit this position establishes into. OPTIONAL — a generic requisition (e.g. 'Senior SWE') may not yet be assigned to a team."
            },
            "reports_to": {
              "$ref": "#/$defs/id",
              "description": "The Person (manager) the seat reports to — an org-chart line, same grain as a reports-to edge. OPTIONAL."
            },
            "establishment_fte": {
              "description": "Approved establishment for this seat, 0..1 FTE. The quantum of headcount planning; a unit's establishment DERIVES by summing its positions.",
              "type": "number",
              "exclusiveMinimum": 0,
              "maximum": 1
            },
            "heldBy": {
              "$ref": "#/$defs/id",
              "description": "The Person currently filling the seat. OPTIONAL — ABSENT means the position is OPEN. Vacancy DERIVES (a position with no incumbent); no stored fill-status."
            }
          }
        },
        "facets": { "$ref": "#/$defs/facets" }
      },
      "required": ["kind", "metadata", "spec"]
    }
  }
}
