Releases · current v1.13
Versions and the stability promise
How versions work
One number for all seven schemas. When any schema changes, the whole standard moves to the next number and every file is stamped with it, even the ones that did not change. You adopt "MAXGEN v1.13" as a set. This is how HL7 FHIR (the healthcare data standard) and GEDCOM release, and it makes it impossible for two files to disagree about which version they belong to.
Semantic versioning. The number has the industry-standard meaning:
| Change | Bump | Example |
|---|---|---|
| Wording, descriptions, a regex fix. No field changes. | patch: 1.13.0 → 1.13.1 | Clarifying that output_text may hold a JSON string |
| Additive: a new optional field, a new enum value, a loosened constraint | minor: 1.13 → 1.14 | Adding parent_source_id to MaxSource |
| Anything that could make an existing valid record invalid | major: v1 → v2 | Making a field required, renaming or removing a field |
The stability promise
Within a major version, fields are never renamed or removed. A field can be marked deprecated with a note, but it stays valid. Every record that validated against v1.3 validates against every later v1.x.
A major version gets a new address space (/schemas/maxgen/v2/), a written migration guide, and the full review process including the longer comment period. There is no forced migration: a tool that understands v2 must still read v1 records without failing silently.
Permanent addresses
/schemas/maxgen/v1/<name>.schema.jsonalways points at the latest v1.x. This is the$idinside every schema file./schemas/maxgen/v1.NN/<name>.schema.jsonis a frozen copy of that release and never changes./schemas/maxgen/index.jsonlists every version for machines.
| Version | Schemas | Files (permanent links) |
|---|---|---|
| v1.13 current | 7 | raw-record · person · task-queue · dna · source · recognition · name |
| v1.12 | 7 | raw-record · person · task-queue · dna · source · recognition · name |
| v1.11 | 7 | raw-record · person · task-queue · dna · source · recognition · name |
| v1.10 | 6 | raw-record · person · task-queue · dna · source · recognition |
| v1.9 | 6 | raw-record · person · task-queue · dna · source · recognition |
| v1.8 | 5 | raw-record · person · task-queue · dna · source |
| v1.7 | 5 | raw-record · person · task-queue · dna · source |
| v1.6 | 4 | raw-record · person · task-queue · dna |
| v1.5 | 4 | raw-record · person · task-queue · dna |
| v1.4 | 4 | raw-record · person · task-queue · dna |
| v1.3 | 4 | raw-record · person · task-queue · dna |
Release ritual
Every release, in this order: bump the schema_version constant in all seven files, re-run every fixture through the validators, write the changelog entry, tag the release in git, copy the files to /v1/ and /v1.NN/ on this site, update the version badge, and regenerate any podcast episode whose schema changed.
Changelog
Version history for the seven MAXGEN schemas: MaxRecord, MaxPerson, MaxSource, MaxName, MaxDNA, MaxRecognition, MaxTask.
Versioning policy — LOCKSTEP (as of v1.3)
All seven schemas share one MAXGEN version number. When any schema changes,
the whole standard's version increments and every schema's schema_version
const is stamped with the new number — even schemas that did not change in that
release.
This is the model used by HL7 FHIR releases and GEDCOM versions: you adopt "MAXGEN v1.3" as a set, not schema-by-schema. It makes compatibility trivial to reason about and makes version skew (different schemas reporting different versions) impossible by construction.
- Major version (
v1→v2): breaking changes. New$idURL namespace (/schemas/maxgen/v2/). Requires Human Gate HG-6. - Minor version (
v1.2→v1.3): additive, backward-compatible. Same$idURL;schema_versionconst bumped across all schemas; all fixtures re-stamped and re-validated.
Before v1.3, schemas versioned independently, which produced confusing skew (MaxTask sat at 0.1 while MaxPerson reached 1.2). v1.3 ended that by adopting lockstep and bringing every schema to the same number.
v1.13 — 2026-08-14
Driver: the OGAI MaxName session hit a structural wall during its Tier-A
calibration batch. It could not record a single cognate, because MaxName required
related_name_id — a UUID for a record that does not exist yet. Cognate
relationships are discovered during the research on the first name and would
have to be thrown away and re-derived later. This release fixes that, and clears
the version-stamp drift found while auditing.
MaxName (name.schema.json) — cognates become two-pass
cognates[].related_name_id is no longer required. The item-level constraint
is now:
"required": ["cognate_id", "relationship_type", "direction"],
"anyOf": [
{ "required": ["related_name_id"] },
{ "required": ["related_canonical_form"] }
]
At least one identifier must still be present — a cognate pointing at nothing is still invalid. The two legal states are:
| State | Carries | Meaning |
|---|---|---|
| Unresolved | related_canonical_form only |
Recorded during first-pass research. Correct and publishable, but not yet joinable. |
| Resolved | related_name_id (+ optionally the readable form) |
A linking pass has matched it to a real MaxName record. |
related_canonical_form changes role: it was a denormalized convenience copy
alongside a mandatory UUID; it is now the field that makes first-pass capture
possible at all.
Backward compatible. Every v1.12 cognate carried related_name_id, so all
existing records remain valid — this release only removes a constraint. Readers
must now handle a cognate whose related_name_id is absent; treat it as an
unresolved link rather than an error.
New fixture: test/fixtures/name/valid-v113-unresolved-cognate.json (Seán) covers
all three cases — two unresolved cognates, one resolved.
Housekeeping — version-stamp drift corrected
Auditing for this release surfaced metadata that the v1.12 bump missed. None of it affected validation, but all of it misreported the standard's version:
$idnormalized across all seven schemas tohttps://opengenealogyai.org/schemas/maxgen/v1/<name>.schema.json.name.schema.jsonwas pinned at/schemas/name/1.11andrecognition.schema.jsonat/schemas/recognition/1.10— both stale, and both would drift again at every bump. The version belongs in theschema_versionconst and inschemas/archive/, not in the$id.descriptionversion stamps corrected.dnasaid v1.4,namesaid v1.11,task-queuesaid v1.5, andrecognitionhad no stamp at all. All seven now readMAXGEN v1.13 —.- Changelog header said "the four MAXGEN schemas"; there are seven.
Unchanged in v1.13
MaxRecord, MaxPerson, MaxSource, MaxDNA, MaxRecognition, and MaxTask have no
structural changes — only the lockstep schema_version const and the description
stamp. Records valid under v1.12 remain valid; re-stamp schema_version to
"1.13".
Verification
- 75/75 fixtures pass (74 re-stamped + 1 new)
- All seven schemas validate against the draft-07 metaschema
- Cognate behavior tested in all five cases: canonical-form-only ✓ valid,
UUID-only ✓ valid, both ✓ valid, neither ✓ rejected, missing
direction✓ rejected - Canonical,
schemas/archive/v1.13/, andE:\OGAI\_hub\schemas\verified byte-identical by SHA-256
v1.12 — 2026-08-14
MaxPerson — expanded relationship vocabulary + time-bounded gender records
Typed parent relationships. parent_assertions[].relationship_type and
child_assertions[].relationship_type expand from 5 values to 10, with renamed tokens that
are more precise and self-documenting:
| Old (v1.11) | New (v1.12) | Notes |
|---|---|---|
biological |
birth_parent |
Clearer: the relationship is "birth parent", not just "biological" |
adoptive |
adoptive_parent |
Noun-phrase form, parallel to the others |
step |
step_parent |
Same |
foster |
foster_parent |
Same |
unknown |
unknown |
Unchanged |
| — | donor_parent |
Sperm or egg donor — genetic link, no social/legal relationship |
| — | gestational_carrier |
Surrogate with no genetic contribution |
| — | guardian |
Legal guardianship without formal adoption |
| — | social_parent |
Raised the child without legal mechanism (common historically) |
| — | ecclesiastical |
LDS sealing or godparent in traditions where kinship is recognized |
Multiple simultaneous types per parent entry are allowed and expected: e.g. a person who was
both a birth_parent (DNA evidence, confidence 0.97) AND an adoptive_parent (court records,
confidence 1.0) can have both assertions without either overwriting the other.
All existing fixtures bumped: biological → birth_parent, adoptive → adoptive_parent,
step → step_parent, foster → foster_parent.
Time-bounded gender records. gender_assertions[] items gain three new optional fields:
evidence_typeenum:assigned_at_birth|lived_as|self_identified|legal|documentary— distinguishes what KIND of gender claim is being made (a birth record's assigned sex is different from a census record's lived gender)date_start(ISO 8601 string) — from when this gender assertion appliesdate_end(ISO 8601 string) — through when this assertion applies
Handles: the Billy Tipton problem (person lived as male, assigned female at birth), transgender
history, intersex conditions, two-spirit / indigenous gender traditions, and any case where a
person's documented gender changed over time. Living trans persons are protected by the existing
is_living=TRUE + tier2-private gate.
MaxSource — sub-collection linking + record count as core field
parent_source_id (UUID, optional, root-level): links a sub-collection entry to its parent
institution. Without this field, 173 individual query-pattern entries for one Swiss cantonal
archive each embed independently, flooding vector search results with near-duplicate embeddings.
With it, sub-collections can be grouped by parent for display and rolled up for ranking.
coverage.record_count_estimate (integer, optional): moved from extensions{} to the core
coverage object. This is the primary ranking signal for the vector-DB router ("go to
FamilySearch with 14B records before a county society with 2K"). Having it in extensions{}
caused inconsistent key names across collectors; core placement gives it schema validation and
a stable canonical path.
Description fixed: the description field previously said "MAXGEN v1.7" (stale); now reads
"MAXGEN v1.12".
MaxRecord — extensions{}, archive_ref, locations[] array
Three additions requested by the MaxSource (data collection) session after encountering the
additionalProperties: false wall with no escape hatch:
extensions{} — open-schema namespace for source-specific fields. Same pattern as
MaxPerson, MaxTask, MaxSource. Gives all 197 producers a legal home for groom_name,
battle_unit, cemetery, liber, folio, ark_id, and any other source-specific fields
without requiring a schema bump. Omit it, the record still validates; add whatever keys you
need inside it.
archive_ref (string, optional) — local file path to the canonical MaxRecord JSON on the
E: drive. Supports 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 using dual-emit; omit otherwise.
locations[] (array, optional) — replaces the single location object. Each item adds a
location_type field (event_location | birth_place | death_place | burial_place |
residence | origin | destination | other) plus latitude/longitude. Multi-place
records (immigration: origin + destination; death cert: death_place + burial_place) now have a
clean model. All 19 existing fixtures migrated: location: {...} → locations: [{location_type:
"event_location", ...}].
All schemas
All 7 schemas at "const": "1.12". All 74 test fixtures re-stamped and validated.
Archived at schemas/archive/v1.12/.
v1.11 — 2026-07-26
MaxName — new schema (schemas/name.schema.json)
Seventh MAXGEN schema. A structured open standard for historical name variants — the first machine-readable format that captures typed, directed, provenance-bearing name relationships across languages, scripts, locales, and time periods.
Why this schema exists. Every genealogy search engine fails on name matching because names are not stable strings — they are living things that drift across centuries, clerks, borders, and languages. "Maxwell" and "Makeswell" and "Maccuswell" and "M'Axwell" are the same family. "Müller" and "Mueller" and "Miller" are the same occupation-surname in three forms. "John" and "Ivan" and "Giovanni" and "Seán" are the same baptismal name in four languages. Without a structured record that says so — with provenance, time scope, and confidence — no machine knows this. MaxName is that record.
Council provenance. Three-brain review 2026-07-26 (Grok-3 as Engineer, qwen3:14b as Contrarian). 10 specific improvements incorporated:
- URI-extensible
variant_type(Grok-3) — changed from a closed enum to a free string with documented standard values. New variant types (forced_substitution, administrative_reassignment, etc.) don't require a schema bump. variant_idUUID on each variant (qwen3) — every variant entry is independently addressable, citable, and retractable without touching the parent record.disputed_by[]per variant (Grok-3) — scholarly disputes are preserved, not silently resolved. A variant with disputes is retained and flagged; both views coexist.cognate.direction(qwen3) —this_derives_from | this_is_source_of | parallel_cognatemakes the directional relationship explicit. Solves the "which way does the arrow point?" ambiguity in cross-language cognate links.cognate.attestation_source(Grok-3) — the cognate relationship is itself a scholarly claim. It needs provenance, not just assertion.phonetic_key.algorithm_version(qwen3) — prevents silent mismatches when algorithm implementations change. A Soundex code computed in 2026 may differ from one computed in 2040.transliteration_standardper variant (qwen3) — captures the standard used when transliterating from non-Latin scripts (ALA-LC, BGN/PCGN, Pinyin, ISO 233). Enables reverse-transliteration and cross-standard comparison.regional_canonical[]array (stress test) — non-English preferred forms are first-class. Seán, Eoin, Ioan, Johann are not "variants of John" — they are the preferred canonical forms in their own language communities.legal_substitutionvariant type (stress test) — captures name changes imposed by law or immigration administration (e.g. forced anglicization of immigrant names at Ellis Island).canonical_scriptfield (stress test) — drives rendering decisions for bi-directional text, font selection, and search index configuration.
Research gap confirmed. No existing open, structured, machine-readable standard captures typed, directed, provenance-bearing historical name variant relationships. Reviewed: GEDCOM X (no typed variants, no time/place scope), WeRelate (wiki only, no schema), Behind the Name API (read-only, proprietary, no cognate provenance), JRC-Names (NLP tool, not genealogical), LCNAF (authority control, not variant-network standard), VIAF (aggregator, not a schema), schema.org (no historical scope), HistNorm (NLP research, not standards-track), Popolo (political entities only). MaxName fills a genuine gap.
Schema fields:
- Required: name_id (UUID), schema_version (const "1.11"), canonical_form, name_type
- Optional top-level: canonical_script, regional_canonical[], gender, language_of_origin
(ISO 639-3), etymology, see_also_urls[], redistribution_license, contributor{}, extensions{}
- variants[]: each with variant_id (UUID), variant_text, variant_type (URI-extensible),
locale, language, script, transliteration_standard, period_start, period_end,
frequency (rare|occasional|common|dominant), attestation_source, notes, confidence,
contributor{}, disputed_by[]
- phonetic_keys{}: soundex, nysiis, metaphone, double_metaphone, daitch_mokotoff, beider_morse
— each with value/values + algorithm_version
- cognates[]: each with cognate_id, related_name_id, related_canonical_form,
relationship_type (etymological_root|cross_language_cognate|derivative|contracted_form),
direction (this_derives_from|this_is_source_of|parallel_cognate), attestation_source,
notes, contributor{}
Fixtures added (4):
- test/fixtures/name/valid-v111-maxwell-surname.json — Maxwell surname with 4 variants
(Maccuswell, Makeswell, M'Axwell, McAxwell) including a disputed variant classification,
full phonetic keys, and an etymological_root cognate link to Maccus.
- test/fixtures/name/valid-v111-john-given.json — John given name with regional_canonical[]
for Seán, Eoin, Ioan, Johann; 4 variants (Jon, Joannes, Johnny, Jack); 3 cognate links
(Johann, Giovanni, Ivan) all parallel_cognate direction.
- test/fixtures/name/valid-v111-ai-contributed.json — Müller surname showing AI-contributed
records (contributor_type: "ai"), umlaut variant handling, emigration_adaptation Miller, and
extensions{} with corpus frequency data.
- test/fixtures/name/valid-v111-disputed-variant.json — O'Brien/Ó Briain showing the
disputed_by[] mechanism with two competing scholarly sources disputing the etymology of Brian
(strength vs. hill vs. Brythonic root). Neither dispute is resolved — both are preserved.
All other schemas (const bump only)
MaxRecord, MaxPerson, MaxTask, MaxDNA, MaxSource, MaxRecognition: schema_version const
1.10 → 1.11. No field changes.
Archive
schemas/archive/v1.11/ — all 7 schemas snapshotted at v1.11.
v1.10 — 2026-07-01
MaxRecognition — probabilistic transcription fields
Three new optional fields on schemas/recognition.schema.json. Three-brain panel
(Grok-3 Engineer + qwen3:14b Contrarian) returned PROCEED unanimously.
word_confidences[].reading_type (enum, optional)
Captures how each word was produced:
- observed — directly read from the image (default when omitted)
- inferred_context — logically filled in from surrounding entries
- inferred_pattern — filled in from known naming/place conventions
- partial_read — some characters legible, remainder inferred
word_confidences[].inference_notes (string, optional)
Free-text audit trail required whenever reading_type is not observed.
Explains the basis for the inference so future AI or human reviewers can
judge whether it was sound. Example: "5 of 6 surrounding entries read
Maxwell; characters 4-7 are water-damaged and unreadable."
searchable_variants[] (string array, top-level, optional)
All possible full-text spellings this record should be findable under —
including uncertain readings, alternative spellings, and normalized forms.
Populated by the contributor at submission time or by a post-processing
normalizer. If omitted, search engines fall back to output_text only.
Enables a record to be found under "Maxwell" AND "Maxweil" without
duplicating the record.
Design philosophy captured: Traditional genealogy treats a partial read as a dead end. MAXGEN treats uncertainty as a first-class value: record everything observed and inferred, label which is which, rate confidence, and let future AI runs re-examine the same image to either confirm or correct the inference. Ten years of AI passes over the same document will converge on the correct reading — and the audit trail will show exactly how.
All other schemas (const bump only)
MaxRecord, MaxPerson, MaxTask, MaxDNA, MaxSource: schema_version const 1.9 → 1.10.
No field changes.
v1.9 — 2026-07-01
New schema: MaxRecognition (schemas/recognition.schema.json)
Sixth MAXGEN schema. Provenance record for an OCR or HTR transcription of a genealogical document image. Design principles:
- One schema, not two.
recognition_type: "ocr" | "htr"is the discriminator. Modern AI models (and many humans) do both; splitting would duplicate 90% of fields. - Unified contributor object. Human transcribers and AI models share the same
contributor{}shape with acontributor_type: "human" | "ai"discriminator. Human-specific fields: credentials[], specialty_scripts[], specialty_languages[], specialty_regions[], records_transcribed (reputation signal), training_notes. AI-specific fields: model_name, model_provider, model_type, prompt{}, fine_tuning{}. - Self-reported confidence with alternatives.
word_confidences[]allows contributors to flag uncertain words and provide alternative readings with relative probabilities. AI models derive these from token log-probabilities; humans estimate from legibility. - Cross-run consensus via group ID.
consensus_group_idlinks multiple independent transcriptions of the same image.is_independent: trueprevents double-counting correlated runs. Consensus calculation belongs in the matching engine, not the schema — the schema only stores the evidence. - HTR-specific:
script_typeenum (kurrent, gothic_fraktur, secretary_hand, arabic, etc.),approx_centuryfor routing to the right model. - OCR-specific:
font_type,scan_dpi. - Standard redistribution_license enum reused from MaxRecord.
All other schemas (const bump only)
MaxRecord, MaxPerson, MaxTask, MaxDNA, MaxSource: schema_version const 1.8 → 1.9.
No field changes.
Fixtures added
test/fixtures/recognition/valid-v19-ai-htr-kurrent.json— Claude Sonnet HTR of a 19th-century Württemberg Kirchenbuch entry, with word-level confidence and alternatives on the uncertain surname spelling.test/fixtures/recognition/valid-v19-human-htr-kurrent.json— Certified genealogist (14,720 records transcribed) transcribing the same image, linked viaconsensus_group_id. The two runs disagree on "Mäier" vs "Maier" — the matching engine will surface this for review.
v1.8 — 2026-06-25
Theme: Attribution — structured human-contributor credit for CC-BY/CC-BY-SA compliance.
Additive / backward-compatible. All five schemas stamped 1.8; 68/68 fixtures pass.
Council: Opus operator PROCEED (unanimous — no caution required; zero blast radius,
all fields optional, legally-motivated).
attribution{} object — added in three places
One reusable object shape, placed wherever a human created or manages the original material:
"attribution": {
"contributor_name": "Robert Chen",
"contributor_url": "https://www.findagrave.com/user/profile/12345",
"contributor_role": "photographer",
"source_organization": "Find a Grave",
"source_organization_url": "https://www.findagrave.com"
}
contributor_role enum: photographer | transcriber | compiler | manager |
donor | submitter | indexer | translator | other.
Where it appears:
- MaxRecord (top-level) — credit the human who photographed, transcribed, or donated
the original document. Distinct from extracted_by (the AI agent that processed it).
- MaxPerson photo_assertions[] — replaces the bare photographer: string field with
the structured object. Existing bare-string data remains valid in extensions{} until
migrated.
- MaxPerson external_id_assertions[] — credit the WikiTree volunteer who manages a
linked profile, or the Find a Grave contributor who created a memorial.
Why now: CC-BY and CC-BY-SA licenses legally require a credit link. Without a structured
contributor_url field there is nowhere to store the legally-required hyperlink when
ingesting Find a Grave photos (CC-BY) or WikiTree / FS Research Wiki content (CC-BY-SA)
at scale. The previous bare photographer: string was legally insufficient for redistribution.
New fixture: test/fixtures/raw-record/valid-v18-gravestone-with-attribution.json —
Find a Grave gravestone photo (CC-BY) credited to volunteer Robert Chen.
v1.7 — 2026-06-25
Theme: Source discovery — a neutral way to describe WHERE genealogy data lives,
so an AI/harvester can answer "where do I find records for X?" and route to the right
site. Additive / backward-compatible (all five schemas now stamped 1.7; 67/67
fixtures pass). Reviewed by three-brain council (engineer + strategist + Opus operator):
GPT + Opus PROCEED WITH CAUTION; Gemini raised two objections — both addressed below.
MaxSource — new schema (the 5th MAXGEN schema)
A SOURCE-DISCOVERY entry: a catalogued pointer to a data source, never genealogical
facts about persons. Fields: source_type (directory_index | research_wiki |
record_catalog | record_database | archive | dna_database | library | newspaper_archive
| forum | blog | society | other); coverage{places[] (mirrors MaxRecord location),
record_types[], time_period, languages[], ethnic_or_religious_groups[]};
access{access_method (free_web | paid_subscription | api | bulk_download | scrape_only
| onsite_only), requires_auth, api_base_url, robots_allowed, tos_url, crawl_notes};
embedding_text (denormalized text embedded into the vector DB — the semantic routing
brain); provenance{discovered_via, external_ref, status (active | dead_link | superseded
| unverified), asserted_by/at, last_verified_at}; extensions{}.
Council fixes applied (Gemini's design objection)
- Neutrality: dropped a bespoke
visibilityenum in favor of the standard MAXGENredistribution_licenseenum (CC0 | CC-BY | CC-BY-SA | public-domain | tier2-private), consistent with MaxRecord.tier2-private= a privately-held routing entry that MUST NEVER appear in any open dataset, public share, export, public embedding, API response, or commit. - Product infra out of core: harvester routing (
harvester_adapter,query_pattern) moved toextensions{}so the standard stays implementation-neutral.
Note on Cyndi's List (recorded, not resolved by the standard)
Gemini flagged that bulk-ingesting a third party's curated directory (e.g. Cyndi's List)
is a copyright/ToS exposure even for private use; this is an operator/owner decision, NOT
something the schema sanctions. The standard only provides redistribution_license:
tier2-private so any such entry, if held, is never republished.
v1.6 — 2026-06-02
Theme: Cross-database identity — merge the same person across FamilySearch,
WikiTree, Ancestry, Wikidata, Find a Grave, etc. Additive / backward-compatible
(all four schemas stamped 1.6; 65/65 fixtures pass). Reviewed by three-brain
council (engineer + strategist + Opus operator + jury): unanimous PROCEED WITH
CAUTION — design endorsed, with one required privacy guardrail (below).
MaxPerson — external_id_assertions[] (new)
Scored, sourced, reversible links from this conclusion-person to the same
individual as represented in an external database (a persona). Implements the
GEDCOM X persona/conclusion model and mirrors Wikidata sameAs practice, but with
genealogy-grade confidence + provenance. Each entry: system (open string — ANY
database works), external_id, url, confidence (0–1), match_method
(exact_id_from_source | probabilistic_match | dna_confirmed | hub_crosswalk
| manual), match_signals{}, status (active | disputed | retracted),
asserted_by/asserted_at, retracted_at.
Key properties:
- Multiple entries per system are allowed — external DBs (esp. FamilySearch)
hold duplicate profiles for one person.
- Wrong links are retracted (status), never deleted — auditable, reversible.
- Never forces one "truth" — a link is a scored claim, not a fiat merge; this is
the substrate an AI scorer reads/writes when reconciling across databases.
- Real-world notes baked into the field docs: Ancestry IDs are tree-scoped
(tree_id:person_id); FamilySearch PIDs can become redirects; Wikidata QID is the
best join hub (P6577 FamilySearch, P2949 WikiTree, P535 Find a Grave → hub_crosswalk).
external_ids (existing) → now a denormalized mirror
The flat {system → id} map is retained as a top-confidence-per-system convenience
mirror of external_id_assertions[]. The merge model (merge_history with
merge_method: exact_external_id, reversible) is unchanged.
PRIVACY GUARDRAIL (normative — required by council before publish)
For any record where is_living = TRUE (tier2-private), external_id_assertions
MUST NOT appear in any public share, export, embedding, API response, or commit.
A cross-system identity crosswalk is a powerful de-anonymization vector — strip these
for living subjects like every other tier2-private field. This contract is written
into the field's own schema description so it travels with the standard. (Living
fixture valid-living-person-tier2.json carries no external_id_assertions,
demonstrating the gate.)
Lockstep + fixtures
MaxRecord, MaxTask, MaxDNA stamped schema_version: "1.6". +1 fixture
(valid-v16-cross-db-identity — multiple FamilySearch IDs incl. a duplicate, a
WikiTree + Wikidata hub crosswalk, and one disputed Ancestry link). 65/65 validate.
v1.5 — 2026-06-02
Theme: MaxTask becomes a real distributed-work unit — structured results, a
color-coded verdict vocabulary, and the neutral half of a contributor model
(quality + privacy). Additive / backward-compatible — all new fields are
optional; pre-1.5 tasks validate unchanged. Lockstep: all four schemas stamped
1.5. 64/64 fixtures pass. Reviewed by three-brain council (verdict: PROCEED
WITH CAUTION — split economics out of the standard; see below).
MaxTask — structured result (replaces the free-form blob)
A client-readable result object: description, hypothesis_tested,
why_this_matters, what_we_did_and_result, how_results_affect_goal,
what_we_did_with_results, next_step, confidence,
next_directions_suggested[], and steps[] — one entry per search performed
(action, source, source_url, query, found, verdict, confidence).
additionalProperties stays true for extensibility.
MaxTask — verdict enum + UI colors (new $defs/verdict)
key_finding (GREEN, confirmed/found), usable (BLUE, usable lead),
inconclusive (AMBER, mixed), ruled_out (RED — a disproof: definitively
NOT the right person/record), dead_end (GREY — searched, found nothing),
infra (GREY — support task). ruled_out is deliberately distinct from
dead_end: a disproof is information; an empty search is not.
MaxTask — neutral contributor / quality fields (IN the standard)
parent_task_id, acceptance_criteria[] (objective conditions defining a
complete result), min_confidence, evidence_required[] (proof a worker must
return — anti-low-effort/anti-fabrication), contributor{contributor_id,
contributor_type ∈ first_party_ai|third_party_ai|human|organization,
display_name, claimed_at}, deadline, and an independent review{reviewed_by
(MUST differ from contributor — enforced at app layer), review_verdict ∈
accepted|rework|rejected, quality_score, rejection_reason (incl.
fabricated_or_hallucinated, privacy_violation), review_notes, reviewed_at}.
These describe work and quality, which is neutral, so they belong in the open
standard.
MaxTask — contributor_eligibility PRIVACY GATE (IN the standard)
Enum first_party_only | any_contributor, default first_party_only
(fail-closed). MUST be first_party_only whenever a task concerns a living
person (tier2-private): living-subject tasks are never dispatched to
third-party/human/organization contributors, and any externally dispatched
result must be scrubbed of tier2-private PII.
Payment/economics are DELIBERATELY NOT in the standard
Per three-brain council (strategist + operator): an open standard must stay
neutral — a common work/quality language, not a business model. Hard-coding
payout, list_price_usd, or a revenue split into the public standard would
(a) fragment adoption (forces everyone into one business model), (b) publish a
portable fraud/sybil blueprint, and (c) push legal/tax burden (worker
classification, KYC/AML, 1099) onto every adopter. So payment lives in the
implementer's product layer (The Probable Pedigree) under the open
extensions{} namespace — never in core. MaxTask gains an extensions object
(additionalProperties: true) documenting this. This matches the locked
two-brand architecture (OpenGenealogyAI = standard; The Probable Pedigree =
product). Collusion-resistance, KYC, and worker-classification are the
implementer's responsibility.
Lockstep version bump (no content change)
MaxRecord, MaxPerson, MaxDNA stamped schema_version: "1.5" per lockstep policy.
Fixtures
+2 task-queue fixtures (valid-v15-ruled-out, valid-v15-marketplace-paid —
the latter shows payout living under extensions). 64/64 validate.
v1.4 addendum — 2026-06-02 (NO schema version bump)
Theme: Migration / life-event storage clarified, and a biography convention.
This is a documentation + infrastructure release. The JSON Schema files did
not change — everything here uses fields that already exist. No schema_version
bump; no Human Gate. Approved by three-brain council (operator: PROCEED WITH
CAUTION — gate the public commit by diff-inspection).
Migration & life events live in event_assertions[] — do NOT add a vital_events table
A contributor session proposed a new flat vital_events table for
migration/residence data. Rejected — it would fork the standard. The canonical
home already exists: MaxPerson.event_assertions[] (since v1.3), whose event_type
enum already covers immigration, emigration, naturalization, residence,
census_enumeration, land_grant, military_service, will, probate, burial,
etc. A person's migration story = an ordered set of these assertions, each with its
own year_min/max, place_as_written, description (the narrative), confidence,
and source_record_id.
Places whose name/jurisdiction changed over time (e.g. "Kentucky County, Virginia"
→ "Bourbon County, KY" after 1786) are represented in place_registry[] via
historical_polity + valid_from_year/valid_to_year + lat/long — something a
flat events table cannot express. The enum maps 1:1 to GEDCOM tags
(RESI/EMIG/IMMI/CENS/NATU/PROB/WILL/MILI), preserving round-trip.
Mapping for anyone migrating a vital_events-style table:
event_type→event_type · event_date/event_year/±tol→year_min+year_max+month+day+date_type · event_place→place_as_written · source_*→source_record_id · confidence→confidence · notes→description.
bio_summary — a per-person hover biography (via extensions, not a core field)
A short prose biography shown on profile/hover. Stored as extensions.bio_summary
(string) plus extensions.bio_summary_ai_generated (boolean — a biography is
narrative, not a sourced assertion, so we mark machine-written ones). Uses the
extensions{} open namespace (added v1.3) by design: no schema bump, no Human Gate.
Promote to a first-class biography_assertions[] in a future version if it proves out.
Postgres / portal mirror — migration 002_events_places.sql
Added additive mirror tables backing the two JSON fields above:
- person_events — mirror of event_assertions[] (FK → persons, ON DELETE CASCADE).
- place_registry — mirror of place_registry[] (historical polity + valid years + lat/long).
- Portal SQLite persons gains bio_summary + bio_summary_ai_generated columns.
JSON MaxPerson remains the source of truth; mirrors exist for JOINs, sorting, and the
portal Life-Story / Migration views.
Privacy / repo invariant (reaffirmed)
Family-tree data rows are never committed to the public GitHub repo — only schemas,
docs, and migration scripts. Living people (is_living = TRUE ⇔ tier2-private) never
appear in public commits, indexes, or embeddings.
v1.4 — 2026-05-17
Theme: Photos as a first-class field. A face transforms genealogy from data to story; previous versions had no model for portraits and that was a real gap for end-user engagement. Garlon-requested.
MaxPerson
photo_assertions[]— portraits and snapshots OF this person (NOT gravestones or documents — those stay on MaxRecord). Each photo carries:photo_id,url,thumbnail_url,storage_tier(internet_archive / local_private / contributor_upload / external)caption,year_min/max,place_as_written,photographer,licenseis_primary— designate ONE photo as the profile image (ties broken by confidence then most-recentasserted_at)confidence— is this actually this person? (same scale as other assertions; see CONFIDENCE_CALIBRATION.md)subject_roleenum (solo / group / wedding / family / military / occupational / unknown) so UI knows whether to auto-cropface_bounding_box(normalized 0–1 coords) — optional, for auto-cropping group photos to the subject's face in cards and pedigree nodesalt_text— accessibility (screen-reader description)ia_id— Internet Archive identifier when stored theresource_record_id— optional link back to a MaxRecord (e.g. obituary with a portrait)- Living-subject photos inherit
tier2-privateregardless of declaredlicense, per the existing privacy gate. - Photography min year set to 1839 (invention of the technology).
Lockstep version bump (no content change)
- MaxRecord, MaxTask, MaxDNA all bumped to
schema_version: "1.4"per the lockstep policy. Their descriptions now note "schema content stable since vX.X; version stamp follows lockstep MAXGEN release versioning."
Fixtures
- 58 fixtures re-stamped to v1.4; 62/62 validate against new schemas.
v1.3 — 2026-05-17
Theme: Scale-readiness for the 1.5B-person dedup roadmap, plus lockstep versioning. All additive — no breaking changes. Approved via six-brain review 2026-05-17 (option A: additive batch).
MaxPerson
- Merge/dedup provenance model (the headline change):
merge_history[]— entities absorbed INTO this one, each withmerge_confidence,merge_method(exact_external_id / probabilistic_match / manual / dna_confirmed),match_signals,merged_by,merged_at,reverted_at. A merge is a reversible assertion, never a deletion.duplicate_of— when this entity was absorbed, points to the survivor.merge_status— active / merged_away / split_pending.- Design principle: nothing is destroyed on merge. The absorbed entity
persists with
merge_status='merged_away', preserving append-only history and full reversibility. event_assertions[]— long-tail life events (baptism, immigration, naturalization, residence, census, burial, military_service, will, probate, etc.) with anevent_typeenum. First-class birth/death/marriage stay separate (most-queried). Adding a new event kind no longer needs a schema bump.place_registry[]— gazetteer normalization. Resolves free-textplace_as_writtenstrings to GeoNames / Wikidata QID / lat-long without modifying every assertion (avoids a mass backfill). Handles historical polities ("Austria-Hungary 1880") viahistorical_polity+ valid-year range.extensionsobject — designatedadditionalProperties:truenamespace for experimental fields, so new ideas don't require a schema bump while the rest of the schema stays strict.- Fix: birth/death/occupation
year_max2025 → 2100.
MaxRecord, MaxTask, MaxDNA
schema_versionconst bumped to1.3(lockstep; content unchanged this release except the version stamp).- MaxTask jumped 0.1 → 1.3 (was the worst skew offender).
Tooling
- All 62 fixtures re-stamped to
1.3and re-validated (62 PASS / 0 FAIL).
Companion docs
- ✅
CONFIDENCE_CALIBRATION.md— defines the anchored confidence scale, per-assertion scoring procedure, noisy-OR corroboration (+ independence rule), conflict handling, thecomposite_confidenceformula, and cross-agent calibration via a gold set. (Completed 2026-05-17.)
Deferred to later work (not in v1.3)
- Atomicity enforcement for bidirectional-sync — an implementation task in the
Postgres
persons-mirror transaction layer, not a schema change. - Gazetteer integration — populating
place_registryfrom GeoNames / Wikidata (the field exists now; population happens after the embedding run stabilizes).
v1.2 — 2026-05-15
Theme: DNA layer + Max* naming + symmetric-relationship discipline.
Naming
- Renamed
MXRecord→ MaxRecord,MXPerson→ MaxPerson,TaskQueue→ MaxTask (Garlon preference: "Max" not "MX"). - MaxTask moved into the
maxgen/v1$idnamespace (was legacyv0.1).
MaxDNA (new schema)
- Created
dna.schema.json— DNA test metadata + match assertions linked to a MaxPerson. Purpose: strengthen ancestor confidence, not living-cousin discovery. - Hard-locked safety constants:
redistribution_license=tier2-private,raw_genotype_stored=false,kit_id_hash/external_ids= HMAC-SHA-256 (64-hex regex). - Six-brain review 2026-05-15 added 9 amendments:
shared_cmmax → 7000,longest_segment_cmmax → 285,cm_map_version,phasing_status,common_ancestor_candidates[](replacing the singular field), HMAC (not plain SHA-256),is_living_flagdefault policy.
MaxPerson
- Added
dna_evidence[]— DNA chains touching this person as candidate MRCA; feeds noisy-OR confidence boosting. spouse_assertionsexpanded: explicit bidirectional-sync requirement, plusend_year_min/max,end_reason(divorce / annulment / death_of_spouse / separation),marriage_place_as_written,relationship_type(marriage / civil_union / domestic_partnership / common_law),conflict_flag.parent_assertions— bidirectional-sync warning added (was only documented on thechild_assertionsside).
v1.1 — (pre-2026-05-15)
Theme: Richer person assertions + more record types.
MaxPerson
- Added
child_assertions[](bidirectional withparent_assertions). - Added
occupation_assertions[](for disambiguation when name + date aren't enough). - Added
external_idsmap (cross-source dedup: wikidata_qid, familysearch_pid, findagrave_id, ia_id, ssdi_id).
MaxRecord
- Added record types:
land_patent,wikidata_entity,open_library_work,dpla_item.
v1.0 — initial release
- Three schemas: MaxRecord (source documents), MaxPerson (probabilistic identities), MaxTask (distributed work queue).
- Core design: uncertainty-as-data. Every claim is an assertion with confidence
- source + timestamp. Nothing is ever overwritten. Multiple possible parents coexist.
- Evidence/interpretation split: MaxRecord = what the document says, MaxPerson =
what we think it means, linked by
source_record_id. - Privacy by design: living-person 404 gate, most-restrictive-license propagation.
Schema $id URLs (permanent)
These never change within a major version:
https://opengenealogyai.org/schemas/maxgen/v1/raw-record.schema.jsonhttps://opengenealogyai.org/schemas/maxgen/v1/person.schema.jsonhttps://opengenealogyai.org/schemas/maxgen/v1/task-queue.schema.jsonhttps://opengenealogyai.org/schemas/maxgen/v1/dna.schema.json
A breaking change creates /schemas/maxgen/v2/ and requires Human Gate HG-6.