{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://opengenealogyai.org/schemas/maxgen/v1/raw-record.schema.json",
  "title": "MaxRecord",
  "description": "MAXGEN v1.12 — Maxwell Genealogy Standard. A single original source document exactly as found, with no interpretation added. Every MaxPerson assertion traces back to at least one MaxRecord. v1.12 adds: extensions{} for source-specific fields (groom_name, battle_unit, cemetery, liber/folio, ark_id, etc.); archive_ref for the dual-emit architecture (queue=transport, E-drive archive=canonical); locations[] array replacing the single location object to support multi-place records (birth_place + death_place + burial_place etc.).",
  "type": "object",
  "required": [
    "record_id", "record_type", "redistribution_license",
    "source_url", "extraction_confidence", "is_living_flag"
  ],
  "properties": {
    "record_id": {
      "type": "string",
      "format": "uuid",
      "description": "Globally unique identifier for this record."
    },
    "schema_version": {
      "type": "string",
      "const": "1.12",
      "description": "MAXGEN version this record conforms to."
    },
    "record_type": {
      "type": "string",
      "enum": [
        "birth_certificate", "death_certificate", "marriage_certificate",
        "census_row", "parish_register", "probate_record", "military_record",
        "immigration_record", "naturalization_record", "land_deed",
        "land_patent", "gravestone", "obituary", "newspaper_article",
        "photograph", "family_bible", "court_record", "tax_record",
        "wikidata_entity", "open_library_work", "dpla_item", "other"
      ],
      "description": "The type of source document."
    },
    "redistribution_license": {
      "type": "string",
      "enum": ["CC0", "CC-BY", "CC-BY-SA", "public-domain", "tier2-private"],
      "description": "Whether this record can be redistributed. tier2-private means never include in open dataset."
    },
    "is_living_flag": {
      "type": "boolean",
      "description": "True if any person in this record may be living. Triggers 404 on all open endpoints."
    },
    "persons_mentioned": {
      "type": "array",
      "description": "All persons referenced in this document, as written in the source.",
      "items": {
        "type": "object",
        "required": ["name_as_written", "role"],
        "properties": {
          "name_as_written": {
            "type": "string",
            "description": "Name exactly as it appears in the source document."
          },
          "role": {
            "type": "string",
            "enum": [
              "subject", "parent", "spouse", "child", "witness",
              "informant", "officiant", "other"
            ],
            "description": "Role this person plays in the document."
          },
          "age_as_written": { "type": "string" },
          "gender_as_written": { "type": "string" }
        }
      }
    },
    "alternate_names": {
      "type": "array",
      "description": "Variant spellings or alternate names for persons mentioned, as they appear across multiple documents.",
      "items": { "type": "string" }
    },
    "record_date": {
      "type": "object",
      "description": "Date range of the event recorded. Never store a single year unless certain.",
      "properties": {
        "year_min": { "type": "integer", "minimum": 1000, "maximum": 2025 },
        "year_max": { "type": "integer", "minimum": 1000, "maximum": 2025 },
        "month": { "type": "integer", "minimum": 1, "maximum": 12 },
        "day": { "type": "integer", "minimum": 1, "maximum": 31 },
        "date_type": {
          "type": "string",
          "enum": ["exact", "estimated", "calculated", "range"],
          "default": "exact"
        }
      }
    },
    "locations": {
      "type": "array",
      "description": "MAXGEN v1.12 — Places associated with this record. Array replaces the single location object to handle records with multiple places (e.g. a marriage record has an event_location; an immigration record has origin + destination; a death certificate may have death_place + burial_place). Use location_type to distinguish. One entry is typical; multiple are allowed and encouraged when the source document names more than one place.",
      "items": {
        "type": "object",
        "properties": {
          "location_type": {
            "type": "string",
            "enum": ["event_location", "birth_place", "death_place", "burial_place", "residence", "origin", "destination", "other"],
            "default": "event_location",
            "description": "What role this place plays in the record. event_location = where the event happened (default for most record types). origin = emigration origin. destination = immigration destination."
          },
          "place_as_written": { "type": "string" },
          "country_code": { "type": "string", "pattern": "^[A-Z]{2}$" },
          "state_province": { "type": "string" },
          "county_district": { "type": "string" },
          "city_town": { "type": "string" },
          "latitude": { "type": "number", "minimum": -90, "maximum": 90 },
          "longitude": { "type": "number", "minimum": -180, "maximum": 180 }
        }
      }
    },
    "transcription": {
      "type": "string",
      "description": "Full text transcription of the document content."
    },
    "language": {
      "type": "string",
      "description": "BCP-47 language code of the document (e.g. en, de, fr, la).",
      "default": "en"
    },
    "image_url": {
      "type": "string",
      "format": "uri",
      "description": "URL to the scanned image of the original document."
    },
    "source_url": {
      "type": "string",
      "format": "uri",
      "description": "Canonical URL of the source (e.g. https://archive.org/details/...)."
    },
    "digital_object_id": {
      "type": "string",
      "description": "Persistent identifier such as ARK, DOI, or Internet Archive identifier."
    },
    "repository": {
      "type": "string",
      "description": "Name of the archive or repository holding the original document."
    },
    "collection": {
      "type": "string",
      "description": "Collection name within the repository."
    },
    "extraction_confidence": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence that the transcription accurately reflects the original document."
    },
    "extracted_by": {
      "type": "string",
      "description": "Agent ID or contributor ID that produced this RawRecord."
    },
    "extracted_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp of extraction."
    },
    "sensitive_data_redacted": {
      "type": "boolean",
      "default": false,
      "description": "True if SSNs, medical data, or other sensitive fields were removed."
    },
    "redaction_notes": {
      "type": "string",
      "description": "Description of what was redacted and why."
    },
    "archive_ref": {
      "type": "string",
      "description": "MAXGEN v1.12 — Local archive path where this record's canonical MaxRecord JSON file is stored (e.g. E:\\OGAI\\BillionGraves\\2026-08\\<id>.json). Used by the dual-emit architecture: the queue is the transport format the embedder reads; the E-drive archive holds the canonical, schema-validated MaxRecord. Populated by producers that use dual-emit. Omit if not using archive-backed storage."
    },
    "extensions": {
      "type": "object",
      "description": "MAXGEN v1.12 — Designated namespace for source-specific fields that don't fit the core schema. Because MaxRecord uses additionalProperties:false (strict validation), every source-specific field needs a legal home — put it here. Examples: groom_name, battle_unit, cemetery, liber, folio, ark_id, vessel_name, ward_number. No schema bump required to add fields inside extensions{}.",
      "additionalProperties": true
    },
    "attribution": {
      "type": "object",
      "description": "v1.8 — Credit for the human who originally created, photographed, transcribed, or donated this record. Distinct from extracted_by (the AI agent that processed it into MAXGEN). Display when redistribution_license is CC-BY or CC-BY-SA — the license legally requires this credit.",
      "properties": {
        "contributor_name": { "type": "string", "description": "Display name of the human contributor, e.g. 'Robert Chen' (Find a Grave volunteer) or 'Jane Smith' (WikiTree curator)." },
        "contributor_url": { "type": "string", "format": "uri", "description": "Profile URL for the contributor, e.g. Find a Grave volunteer profile, WikiTree user page, or archive staff page." },
        "contributor_role": {
          "type": "string",
          "enum": ["photographer", "transcriber", "compiler", "manager", "donor", "submitter", "indexer", "translator", "other"],
          "description": "photographer = took the gravestone/document photo; transcriber = handwriting→text; compiler = assembled from multiple sources; manager = maintains external profile; donor = donated physical original to an archive; submitter = submitted to a database; indexer; translator; other."
        },
        "source_organization": { "type": "string", "description": "Organization the contributor acted under, e.g. 'Find a Grave', 'WikiTree', 'FamilySearch Indexing'." },
        "source_organization_url": { "type": "string", "format": "uri" }
      }
    }
  },
  "additionalProperties": false
}
