{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openworkplacehealth.org/schemas/v0.1/AbsenceEpisode.json",
  "title": "OWHS AbsenceEpisode v0.1",
  "description": "One episode of sickness absence, ONS-comparable. No direct identifiers.",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "episodeId": {
      "type": "string",
      "minLength": 1
    },
    "pseudonymId": {
      "type": "string",
      "pattern": "^owhs:pseudo:[0-9a-f]{16,64}$",
      "description": "Per-org opaque pseudonym; never a direct identifier"
    },
    "reasonCode": {
      "type": "string",
      "enum": [
        "minor-illness",
        "musculoskeletal",
        "mental-health",
        "respiratory",
        "gastrointestinal",
        "other"
      ],
      "$comment": "codelist:absence-reason@0.1.0 — ONS reason taxonomy"
    },
    "startDate": {
      "type": "string",
      "format": "date"
    },
    "endDate": {
      "type": "string",
      "format": "date"
    },
    "workingDaysLost": {
      "type": "number",
      "minimum": 0,
      "$comment": "ONS 7.5-hour working-day unit"
    },
    "workingHoursLost": {
      "type": "number",
      "minimum": 0
    },
    "fitNoteFlag": {
      "type": "boolean"
    },
    "workRelatedFlag": {
      "type": "boolean"
    },
    "clinicalCauseCode": {
      "type": "string",
      "pattern": "^[0-9]{6,18}$",
      "$comment": "OPTIONAL SNOMED CT; affiliate-licence caveat; never conformance-required"
    },
    "sourceProvenance": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "sourceType"
      ],
      "properties": {
        "sourceType": {
          "type": "string",
          "enum": [
            "hris",
            "manual",
            "broker",
            "oh-provider"
          ],
          "$comment": "codelist:source-type@0.1.0 — OWHS record provenance"
        },
        "sourceProvider": {
          "type": "string"
        },
        "sourceId": {
          "type": "string"
        }
      }
    }
  },
  "required": [
    "episodeId",
    "pseudonymId",
    "reasonCode",
    "startDate",
    "sourceProvenance"
  ],
  "allOf": [
    {
      "$comment": "P1 (no direct identifiers) is enforced structurally by \"additionalProperties\": false on this object and on every nested object, which rejects any property not declared here, including name, nino, email, dateOfBirth and address. A key-based rule cannot reach an identifier written into the value of a permitted string field; that part of P1 is a producer obligation, stated in the privacy profile. The previous allOf member duplicated additionalProperties and claimed to forbid identifiers \"anywhere\", which was not true of values."
    },
    {
      "$comment": "Chronology (endDate not before startDate) is not expressible in JSON Schema, which compares an instance against a schema and never one field against another. It is the named Level 1 cross-field rule C1, listed in the specification and implemented in tools/validate.py. The previous allOf member re-asserted the type and format of endDate and enforced no ordering."
    }
  ]
}
