{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://xcathletes.org/contract/schemas/person.json",
  "title": "person",
  "description": "GET /v1/people, GET /v1/people/{id}: the whole athlete entity (ENT-04, ENT-09). Response schema, PRIN-04 open: additionalProperties permitted, since /v1/ only ever adds optional fields within v1 (PRIN-02).",
  "type": "object",
  "additionalProperties": true,
  "required": [
    "id",
    "given_name",
    "family_name",
    "middle_name",
    "status",
    "claimed_at",
    "claimed_by_relationship",
    "links",
    "created_at",
    "updated_at"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "The person's id: a pre-existing platform id (a legacy person predating the /v1/ contract) or a new PRIN-05 128-bit hex id for a person created through POST /v1/people; format is not otherwise constrained."
    },
    "given_name": {
      "type": [
        "string",
        "null"
      ]
    },
    "family_name": {
      "type": [
        "string",
        "null"
      ]
    },
    "middle_name": {
      "type": [
        "string",
        "null"
      ]
    },
    "status": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "active",
        "retired",
        null
      ],
      "description": "ENT-09. An unrecognized status falls back to `active`: treat the record as normal unless links[] carries a replaced_by forwarding entry."
    },
    "claimed_at": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time",
      "description": "OWN-01: null until the athlete claims the record."
    },
    "claimed_by_relationship": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "self",
        "guardian",
        null
      ],
      "description": "OWN-08. An unrecognized value falls back to `guardian` (the more restrictive assumption)."
    },
    "links": {
      "type": "array",
      "description": "ENT-09: alias edges, `replaced_by` today; a person a caller reaches through a retired id resolves forward through this list, forever.",
      "items": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "relation",
          "linked_person_id"
        ],
        "properties": {
          "relation": {
            "type": "string",
            "description": "Uncatalogued by design (room for a second kind beyond replaced_by); an unrecognized relation falls back to being ignored by a conforming consumer (PRIN-03)."
          },
          "linked_person_id": {
            "type": "string",
            "description": "A pre-existing platform id (a legacy person predating the /v1/ contract) or a new PRIN-05 128-bit hex id may both appear here; format is not otherwise constrained."
          }
        }
      }
    },
    "created_at": {
      "type": "string",
      "format": "date-time"
    },
    "updated_at": {
      "type": "string",
      "format": "date-time"
    }
  },
  "$defs": {
    "createRequest": {
      "title": "person create request",
      "description": "POST /v1/people (ID-01, Tier 3). Request schema, PRIN-04 strict: additionalProperties forbidden.",
      "type": "object",
      "additionalProperties": false,
      "required": [
        "given_name",
        "family_name",
        "claim_email",
        "birth_date",
        "attestation"
      ],
      "properties": {
        "given_name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200
        },
        "family_name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200
        },
        "middle_name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200
        },
        "claim_email": {
          "type": "string",
          "format": "email",
          "description": "OWN-01/05: the proposed claim address; unvalidated until the athlete claims."
        },
        "birth_date": {
          "type": "string",
          "format": "date",
          "description": "ENT-04: hashed under a per-person salt and discarded immediately; the platform never stores this value."
        },
        "attestation": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "floor"
          ],
          "properties": {
            "floor": {
              "type": "string",
              "enum": [
                "high_school",
                "age_14_plus"
              ],
              "description": "FLOOR-01. No fallback: an unrecognized value fails validation_failed rather than being silently accepted, since this is the platform's one age-floor gate."
            }
          }
        }
      }
    }
  }
}
