{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://research.opensourcemed.info/data/pais-cohort.schema.json",
  "title": "PAIS Cohort (v2, heterogeneous / Observation model)",
  "description": "v2 replaces Finding + SymptomFinding with one polymorphic Observation record whose value is a discriminated union keyed to the Measure registry. Layer 1 Core is strict; Layer 2 Observations carry every reported result; Layer 3 extensions are namespaced. Missingness is a typed sentinel, never null. See pais-cohort-db-v2-heterogeneous-schema.md.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema_version", "harmonisation_ruleset", "id", "name", "pathogen_id", "pathogen_class",
    "exposure_ascertainment", "design", "denominator_defined", "recruitment_source",
    "time_zero_definition", "time_zero_precision", "control_group", "case_definition",
    "pem_assessed", "specimens_collected", "acute_phase_specimens", "biobank_status",
    "symptom_inventory_scope", "last_verified", "verified_by", "publications", "observations"
  ],
  "$defs": {
    "missing": {
      "type": "object",
      "additionalProperties": false,
      "required": ["status"],
      "properties": {
        "status": { "enum": ["not_measured", "measured_not_reported", "reported_as_zero", "not_applicable", "unknown"] }
      }
    },
    "num_or_missing": {
      "anyOf": [{ "type": "number" }, { "$ref": "#/$defs/missing" }]
    },
    "int_or_missing": {
      "anyOf": [{ "type": "integer" }, { "$ref": "#/$defs/missing" }]
    },
    "ci": {
      "anyOf": [
        { "type": "null" },
        { "type": "array", "items": { "type": "number" }, "minItems": 2, "maxItems": 2 },
        { "$ref": "#/$defs/missing" }
      ]
    },
    "precision": { "enum": ["exact", "approximate", "derived", "digitised_from_figure"] },
    "value": {
      "type": "object",
      "required": ["type"],
      "oneOf": [
        { "additionalProperties": false, "required": ["type", "percent", "precision"],
          "properties": { "type": { "const": "proportion" },
            "numerator": { "$ref": "#/$defs/int_or_missing" }, "denominator": { "$ref": "#/$defs/int_or_missing" },
            "percent": { "$ref": "#/$defs/num_or_missing" }, "ci": { "$ref": "#/$defs/ci" }, "precision": { "$ref": "#/$defs/precision" } } },
        { "additionalProperties": false, "required": ["type", "n", "precision"],
          "properties": { "type": { "const": "count" },
            "n": { "$ref": "#/$defs/int_or_missing" }, "denominator": { "$ref": "#/$defs/int_or_missing" }, "precision": { "$ref": "#/$defs/precision" } } },
        { "additionalProperties": false, "required": ["type", "rate", "person_time_unit"],
          "properties": { "type": { "const": "rate" },
            "events": { "$ref": "#/$defs/int_or_missing" }, "person_time": { "$ref": "#/$defs/num_or_missing" },
            "person_time_unit": { "type": "string" }, "rate": { "$ref": "#/$defs/num_or_missing" }, "ci": { "$ref": "#/$defs/ci" } } },
        { "additionalProperties": false, "required": ["type", "mean", "n"],
          "properties": { "type": { "const": "mean_sd" },
            "mean": { "$ref": "#/$defs/num_or_missing" }, "sd": { "$ref": "#/$defs/num_or_missing" },
            "n": { "$ref": "#/$defs/int_or_missing" }, "unit": { "type": ["string", "null"] }, "ci": { "$ref": "#/$defs/ci" } } },
        { "additionalProperties": false, "required": ["type", "median", "n"],
          "properties": { "type": { "const": "median_iqr" },
            "median": { "$ref": "#/$defs/num_or_missing" }, "q1": { "$ref": "#/$defs/num_or_missing" }, "q3": { "$ref": "#/$defs/num_or_missing" },
            "n": { "$ref": "#/$defs/int_or_missing" }, "range": { "type": ["array", "null"], "items": { "type": "number" } } } },
        { "additionalProperties": false, "required": ["type", "gm", "n"],
          "properties": { "type": { "const": "geometric_mean" },
            "gm": { "$ref": "#/$defs/num_or_missing" }, "gsd": { "$ref": "#/$defs/num_or_missing" }, "n": { "$ref": "#/$defs/int_or_missing" } } },
        { "additionalProperties": false, "required": ["type", "categories"],
          "properties": { "type": { "const": "categorical_distribution" },
            "categories": { "type": "array", "items": { "type": "object", "additionalProperties": false,
              "required": ["label"], "properties": { "label": { "type": "string" },
                "n": { "$ref": "#/$defs/int_or_missing" }, "percent": { "$ref": "#/$defs/num_or_missing" } } } } } },
        { "additionalProperties": false, "required": ["type", "unit"],
          "properties": { "type": { "const": "time_to_event" },
            "median_time": { "$ref": "#/$defs/num_or_missing" }, "unit": { "type": "string" },
            "n_events": { "$ref": "#/$defs/int_or_missing" }, "n_at_risk": { "$ref": "#/$defs/int_or_missing" }, "ci": { "$ref": "#/$defs/ci" } } },
        { "additionalProperties": false, "required": ["type", "estimate", "effect_type"],
          "properties": { "type": { "const": "effect_only" },
            "estimate": { "$ref": "#/$defs/num_or_missing" },
            "effect_type": { "enum": ["rr", "or", "hr", "pr", "rd", "smd", "beta", "none"] },
            "ci": { "$ref": "#/$defs/ci" }, "p_value": { "type": ["number", "null"] },
            "adjusted_for": { "type": "array", "items": { "type": "string" } } } },
        { "additionalProperties": false, "required": ["type", "n_pairs"],
          "properties": { "type": { "const": "paired_change" },
            "baseline": { "$ref": "#/$defs/num_or_missing" }, "followup": { "$ref": "#/$defs/num_or_missing" },
            "delta": { "$ref": "#/$defs/num_or_missing" }, "sd_delta": { "$ref": "#/$defs/num_or_missing" },
            "n_pairs": { "$ref": "#/$defs/int_or_missing" }, "p_value": { "type": ["number", "null"] } } },
        { "additionalProperties": false, "required": ["type", "boolean"],
          "properties": { "type": { "const": "presence" },
            "boolean": { "type": "boolean" }, "basis": { "type": ["string", "null"] } } },
        { "additionalProperties": false, "required": ["type", "text"],
          "properties": { "type": { "const": "qualitative" },
            "text": { "type": "string" }, "n_supporting": { "$ref": "#/$defs/int_or_missing" } } }
      ]
    },
    "observation": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "cohort_id", "publication_id", "schema_version", "measure_id",
                   "population", "timing", "method", "value", "comparator", "provenance"],
      "properties": {
        "id": { "type": "string", "pattern": "^[a-z0-9-]+$" },
        "cohort_id": { "type": "string" },
        "publication_id": { "type": "string" },
        "schema_version": { "const": "2.0.0" },
        "measure_id": { "type": "string", "pattern": "^[a-z-]+:[a-z0-9-]+$" },
        "measure_verbatim": { "type": ["string", "null"] },
        "population": {
          "type": "object", "additionalProperties": false,
          "required": ["scope", "denominator_basis", "n_assessed"],
          "properties": {
            "scope": { "enum": ["whole_cohort", "subgroup", "stratum"] },
            "stratum": {
              "anyOf": [{ "type": "null" }, { "type": "object", "additionalProperties": false,
                "required": ["variable", "level"], "properties": { "variable": { "type": "string" }, "level": { "type": "string" } } }] },
            "denominator_basis": { "enum": ["enrolled", "assessed_at_timepoint", "symptomatic_subset", "responders", "person_time", "unclear", "not_applicable"] },
            "n_assessed": { "$ref": "#/$defs/int_or_missing" }
          }
        },
        "timing": {
          "type": "object", "additionalProperties": false,
          "required": ["timepoint_months", "timepoint_band", "reference_period", "is_cumulative"],
          "properties": {
            "timepoint_months": { "type": ["number", "null"] },
            "timepoint_band": { "enum": ["acute", "0-3mo", "3-6mo", "6-12mo", "12-24mo", "24mo+", "unspecified"] },
            "reference_period": { "enum": ["current", "past_7d", "past_30d", "past_3mo", "since_infection", "ever_since_onset", "not_reported", "not_applicable"] },
            "is_cumulative": { "type": "boolean" }
          }
        },
        "method": {
          "type": "object", "additionalProperties": false,
          "required": ["ascertainment"],
          "properties": {
            "ascertainment": { "enum": ["validated_instrument_threshold", "structured_checklist", "open_ended_report", "clinician_assessed", "medical_record_code", "physical_exam", "lab_assay", "physiologic_test", "registry_linkage", "unclear"] },
            "instrument_id": { "type": ["string", "null"] },
            "severity_threshold": { "type": ["string", "null"] },
            "blinded_assessment": { "enum": ["yes", "no", "not_reported", "not_applicable"] }
          }
        },
        "value": { "$ref": "#/$defs/value" },
        "comparator": {
          "type": "object", "additionalProperties": false,
          "required": ["group", "value"],
          "properties": {
            "group": { "enum": ["none", "unexposed_matched", "unexposed_unmatched", "seronegative_contacts", "household_contacts", "other_disease", "self_control", "healthy_convenience", "population_norm", "not_reported"] },
            "value": { "anyOf": [{ "$ref": "#/$defs/value" }, { "$ref": "#/$defs/missing" }] },
            "effect": {
              "anyOf": [{ "type": "null" }, { "type": "object", "additionalProperties": false,
                "required": ["estimate", "effect_type"],
                "properties": { "estimate": { "$ref": "#/$defs/num_or_missing" },
                  "effect_type": { "enum": ["rr", "or", "hr", "pr", "rd", "smd", "beta", "none"] },
                  "ci": { "$ref": "#/$defs/ci" }, "p_value": { "type": ["number", "null"] },
                  "adjusted_for": { "type": "array", "items": { "type": "string" } } } }]
            }
          }
        },
        "harmonised": {
          "anyOf": [{ "type": "null" }, { "type": "object", "additionalProperties": false,
            "required": ["ruleset", "measure_id", "value", "transformations", "confidence"],
            "properties": { "ruleset": { "type": "string" }, "measure_id": { "type": "string" },
              "value": { "$ref": "#/$defs/value" },
              "transformations": { "type": "array", "items": { "type": "string" } },
              "confidence": { "enum": ["exact", "close", "broad", "uncertain"] } } }]
        },
        "extensions": { "type": "object" },
        "provenance": {
          "type": "object", "additionalProperties": false,
          "required": ["source_locator", "extraction_method"],
          "properties": {
            "source_locator": { "type": "string", "minLength": 1 },
            "extracted_by": { "type": ["string", "null"] },
            "extracted_on": { "type": ["string", "null"], "pattern": "^\\d{4}-\\d{2}-\\d{2}$" },
            "verified_by": { "type": ["string", "null"] },
            "verified_on": { "anyOf": [{ "type": "null" }, { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }] },
            "extraction_method": { "enum": ["manual", "assisted_verified"] }
          }
        }
      }
    }
  },
  "properties": {
    "schema_version": { "const": "2.0.0" },
    "harmonisation_ruleset": { "type": "string", "minLength": 1 },
    "id": { "type": "string", "pattern": "^[a-z0-9-]+$" },
    "name": { "type": "string" },
    "aliases": { "type": "array", "items": { "type": "string" }, "default": [] },
    "outbreak_event": { "type": ["string", "null"] },

    "pathogen_id": { "type": "string", "pattern": "^[a-z0-9-]+$" },
    "pathogen_class": { "enum": ["virus", "bacterium", "protozoan", "vaccine", "mixed", "unknown"] },
    "exposure_ascertainment": { "enum": ["pcr", "serology", "culture", "clinical_diagnosis", "registry_code", "self_report", "mixed", "not_reported"] },

    "design": { "enum": ["prospective_inception", "prospective_non_inception", "retrospective_cohort", "cross_sectional", "case_control", "registry_linkage", "self_controlled", "survey"] },
    "denominator_defined": { "enum": ["yes", "partial", "no", "unclear"] },
    "denominator_method": { "type": ["string", "null"] },
    "recruitment_source": { "enum": ["community", "population_registry", "hospital", "outpatient_clinic", "occupational", "household_contacts", "self_referral", "patient_organisation", "mixed"] },
    "time_zero_definition": { "type": "string" },
    "time_zero_precision": { "enum": ["exact_date", "week", "month", "quarter", "year", "undefined"] },
    "control_group": { "enum": ["none", "unexposed_matched", "unexposed_unmatched", "seronegative_contacts", "household_contacts", "other_disease", "self_control", "healthy_convenience"] },
    "control_matching_variables": { "type": "array", "items": { "type": "string" }, "default": [] },

    "n_source_population": { "type": ["integer", "null"] },
    "n_enrolled": { "type": ["integer", "null"] },
    "n_analysed": { "type": ["integer", "null"] },
    "followups": {
      "type": "array",
      "items": { "type": "object", "additionalProperties": false, "required": ["months"],
        "properties": { "months": { "type": "number" }, "n_assessed": { "type": ["integer", "null"] }, "n_lost": { "type": ["integer", "null"] } } },
      "default": []
    },
    "max_followup_months": { "type": ["number", "null"] },

    "instruments": { "type": "array", "items": { "type": "string" }, "default": [] },
    "case_definition": { "enum": ["fukuda_1994", "canadian_consensus", "iom_nam_2015", "who_pcc_2021", "nice_ng188", "chalder_threshold", "author_defined", "none", "not_reported", "not_applicable"] },
    "pem_assessed": { "enum": ["yes_validated_instrument", "yes_single_item", "no", "unclear"] },
    "objective_measures": { "type": "array", "items": { "enum": ["cpet_single_day", "cpet_two_day", "tilt_table", "nasa_lean", "nirs", "muscle_biopsy", "other_biopsy", "imaging", "actigraphy", "polysomnography", "lab_panel", "none"] }, "default": [] },

    "specimens_collected": { "type": "boolean" },
    "specimen_types": { "type": "array", "items": { "enum": ["serum", "plasma", "pbmc", "whole_blood", "stool", "saliva", "urine", "csf", "muscle_tissue", "synovial", "other"] }, "default": [] },
    "acute_phase_specimens": { "enum": ["yes", "no", "unclear", "not_applicable"] },
    "storage": { "type": ["string", "null"] },
    "biobank_status": { "enum": ["active", "archived", "destroyed", "unknown", "not_applicable"] },
    "consent_future_use": { "enum": ["broad", "disease_specific", "none", "unknown", "not_applicable"] },
    "external_access": { "enum": ["open_application", "collaboration_only", "closed", "unknown", "not_applicable"] },
    "contact": { "type": ["string", "null"] },

    "registration_id": { "type": ["string", "null"] },
    "funders": { "type": "array", "items": { "type": "string" }, "default": [] },
    "conflicts": { "type": ["string", "null"] },
    "data_availability": { "type": ["string", "null"] },
    "notes": { "type": ["string", "null"] },

    "symptom_inventory_scope": { "enum": ["comprehensive_inventory", "targeted_panel", "single_domain", "incidental", "none"] },
    "n_symptoms_queried": { "type": ["integer", "null"] },
    "symptom_instrument_note": { "type": ["string", "null"] },

    "related_cohorts": {
      "type": "array",
      "items": { "type": "object", "additionalProperties": false, "required": ["id", "relation"],
        "properties": { "id": { "type": "string" }, "relation": { "enum": ["parent", "child", "overlapping_population", "sibling_analysis"] } } },
      "default": []
    },

    "last_verified": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" },
    "verified_by": { "type": "string", "minLength": 1 },

    "flags": {
      "type": "array",
      "description": "Prominent, honest caveats about the cohort's evidentiary standing, rendered as badges on the table and detail page.",
      "items": { "enum": ["preprint", "grey_literature", "patient_reported", "not_peer_reviewed", "self_selected", "small_sample", "author_conflict", "unverified_source", "single_timepoint", "no_control"] },
      "default": []
    },

    "extensions": { "type": "object" },

    "publications": {
      "type": "array", "minItems": 1,
      "items": {
        "type": "object", "additionalProperties": false,
        "required": ["id", "title", "year", "is_primary_cohort_paper"],
        "anyOf": [
          { "required": ["doi"] },
          { "required": ["pmid"] },
          { "allOf": [ { "required": ["url", "type"] },
                       { "properties": { "type": { "enum": ["grey_literature", "report", "dataset"] } } } ] }
        ],
        "properties": {
          "id": { "type": "string", "pattern": "^[a-z0-9-]+$" },
          "title": { "type": "string" }, "authors": { "type": ["string", "null"] },
          "year": { "type": "integer", "minimum": 1900, "maximum": 2100 },
          "journal": { "type": ["string", "null"] },
          "type": { "enum": ["journal", "preprint", "grey_literature", "registry", "dataset", "report"] },
          "doi": { "type": "string", "pattern": "^10\\.\\d{4,9}/[-._;()/:A-Za-z0-9]+$" },
          "pmid": { "type": "string", "pattern": "^[0-9]{1,9}$" },
          "url": { "type": ["string", "null"] },
          "open_access": { "type": "boolean", "default": false },
          "is_primary_cohort_paper": { "type": "boolean" }
        }
      }
    },

    "observations": { "type": "array", "items": { "$ref": "#/$defs/observation" }, "default": [] }
  }
}
