Observed since 20 Oct, 16:53 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
AADR cross-version GeneticID / MasterID join utility for ancient-DNA / population-genetics workflows.
AADR cross-version GeneticID / MasterID join utility for ancient-DNA and population-genetics workflows.
aadr-resolve reads AADR (Allen Ancient DNA Resource) .anno files
across one or more releases and resolves the cross-version sample-ID
join through the Master ID column — the part every ancient-DNA pipeline
currently re-implements with custom awk. It handles AADR's progressive
de-anonymization (I0001 in v44.3 → Loschbour.AG in v66) and the
periodic Master-ID renames (9-18 per consecutive version pair; ~62
cumulative v44.3 → v66.0) automatically.
Designed and bench-verified against AADR releases v44.3, v50.0, v52.2, v54.1, v62.0, and v66.0; six schema classes (A–F) are recognized out-of-the-box via in-package YAML header signatures.
pip install aadr-resolve
Requires Python 3.11+ and pip 23+ with setuptools 61+. If you are on a system Python (Ubuntu 22.04 ships pip 22 / setuptools 59), upgrade first:
python3.11 -m venv .venv && source .venv/bin/activate
pip install --upgrade pip # brings pip to 23+, which upgrades setuptools automatically
pip install aadr-resolve
Installing without upgrading pip on older toolchains causes the package to appear as UNKNOWN 0.0.0, which breaks co-installation with other packages (see #3).
Dependencies: pandas 2.x, click 8.x, PyYAML 6.x.
Resolve a single sample across two AADR releases.
aadr-resolve lookup I0001 \
--anno-files v44.3_1240K_public.anno \
--anno-files v66.0_1240K_public.anno
Output (stdout):
query: I0001
canonical individual_id: Loschbour (matched via individual_id)
v44.3 rows: 1
I0001 Luxembourg_Loschbour 537,182 SNPs
v66.0 rows: 2
Loschbour.AG Luxembourg_Mesolithic.AG 155,036 SNPs pgid=33
Loschbour.DG Luxembourg_Mesolithic.DG 620,881 SNPs pgid=39136
master_id_bridge: v44.3 I0001 → v66.0 Loschbour (via shared GID Loschbour.DG)
status: present_in_2_of_2_versions; multi_row; individual_id_renamed
Recreate a cohort against a newer release.
aadr-resolve cohort patterson_2022_whga.txt \
--anno-files v44.3_1240K_public.anno \
--anno-files v66.0_1240K_public.anno \
--cohort-version v44.3 \
-o whga_v66_manifest.tsv
The manifest is a TSV with one row per (individual × library), with
per-version genetic_id / group_id / snps_hit_1240k columns plus
per-adjacent-pair group_id_change_class_v{old}_to_v{new} columns,
ready to feed into downstream relabeling tools like pgen-samplebind.
Output (stdout summary block):
Loaded 2 .anno file(s):
[v44.3] v44.3_1240K_public.anno: 9,275 rows × 43 cols, class A
[v66.0] v66.0_1240K_public.anno: 23,250 rows × 49 cols, class E
Cross-version bridge:
GID-stable MID-rename detection: 9 events
Manual --mid-bridge entries: 0
Cross-lab MID collision check: no collisions detected
Cohort input: patterson_2022_whga.txt (40 individuals)
Resolved in latest version: 37
Added after earliest: 1
Removed before latest: 2
Group ID changes (v44.3 → v66.0):
convention_restructure_suffix 18
partial 1
substantive_regroup 2
Wrote whga_v66_manifest.tsv (40 rows × 13 cols)
Sample turnover within cohort: 5.0% — PASS
Done in 1.4s.
Add --quiet to suppress the block. Add --report-json summary.json
to also emit a run-level JSON sidecar that loads cheaply via
json.load — see docs/REPORT_JSON_SCHEMA.md.
Structured diff between two releases.
aadr-resolve diff v62.0_1240K_public.anno v66.0_1240K_public.anno \
--tsv > v62_to_v66_changes.tsv
Emits one row per change event: added, removed, genetic_id_renamed,
master_id_renamed, group_changed (with a per-class label —
convention_restructure_suffix etc.).
For large diffs at AADR scale, stream the per-event TSV alongside a small summary JSON instead of buffering the full event list:
aadr-resolve diff v62.0_1240K_public.anno v66.0_1240K_public.anno \
-o changes_summary.json \
--report changes_events.tsv \
--report-json summary.json
--report PATH streams one row per event (constant memory) and
--report-json PATH writes the run-level summary (~few KB, loads
cheaply via json.load). The diff stdout summary block routes to
stderr when stdout is carrying the JSON payload, so pipes stay clean.
| Command | Purpose |
|---|---|
lookup | Resolve a single sample across N versions |
cohort | Emit a cross-version manifest for a user-supplied cohort |
diff | Structured diff between two versions |
join | Wide-format pairwise table over the full intersection |
schema | Diagnostic: report the detected schema class |
aadr-resolve lookupaadr-resolve lookup INDIVIDUAL_OR_GENETIC_ID \
--anno-files PATH [--anno-files PATH ...]
[--json]
Treated as individual_id by default; falls back to genetic_id if no
IID matches. The MID-rename bridge is built automatically from the
supplied versions and reported under master_id_bridge in the output.
aadr-resolve cohortaadr-resolve cohort COHORT_FILE \
--anno-files PATH [--anno-files PATH ...]
[--cohort-version LABEL]
-o OUT.tsv [--json]
[--no-propagate]
[--collapse-to-individual]
[--gid-preference AG,DG,SG,HO,TW,BY,AA,EC,WGC,bare]
[--turnover-warn 0.05] [--turnover-fail 0.30]
[--cohort-coverage-warn 0.50] [--cohort-coverage-fail 0.25]
[--report-json PATH]
COHORT_FILE is a TSV: one column for individual_id, optional second
column for cohort_label. --cohort-version is auto-detected from the
supplied annos when omitted. Default output is row-per-(individual ×
library); --collapse-to-individual reduces to one row per individual
via the --gid-preference suffix priority. --report-json PATH writes
a run-level summary sidecar (~few KB) for CI dashboards.
aadr-resolve diffaadr-resolve diff V_OLD.anno V_NEW.anno
[--json | --tsv]
[-o OUT]
[--include-class CLASS [--include-class CLASS ...]]
[--all-events]
[--turnover-warn 0.05] [--turnover-fail 0.30]
[--substantive-regroup-fail INT]
[--report PATH] [--report-json PATH]
JSON output is summary-first: per-class counts always included;
per-event arrays only for substantive_regroup (always) and any class
named via --include-class, or all classes when --all-events is set.
--tsv switches to streamed one-row-per-event format.
For large diffs, prefer the streamed sidecars: --report PATH writes
per-event TSV with constant memory; --report-json PATH writes the
run-level summary. The summary block routes to stderr when stdout is
the JSON payload, so aadr-resolve diff a.anno b.anno | jq ... works
without breaking the pipe.
aadr-resolve joinaadr-resolve join V_OLD.anno V_NEW.anno
-o OUT.tsv [--json]
[--collapse-to-individual]
[--gid-preference AG,DG,SG,HO,TW,BY,AA,EC,WGC,bare]
Wide-format pairwise table over the full v_old ∪ v_new canonical
individual_id set. Same output schema as cohort; useful when you
don't have a pre-existing cohort list.
aadr-resolve schemaaadr-resolve schema PATH [--json]
Diagnostic: detects which schema class (A–F) the .anno belongs to,
reports the column layout. Useful for debugging "why does this .anno
not load."
These apply to all subcommands:
| Option | Default | Notes |
|---|---|---|
--schema-override CLASS | auto | Force schema class A/B/C/D/E (e.g., renamed .anno) |
--version-label LABEL | auto | Force version label (when filename pattern doesn't match) |
--mid-bridge FILE | none | Manual master_id-rename TSV layered on auto-detected bridge |
--on-mid-collision {error,warn} | error | Cross-lab MID collision policy |
--quiet | false | Suppress the stdout summary block (cohort + diff + join write phase) |
The same functionality is available in-process:
from aadr_resolve import (
AnnoFrame,
resolve_master_ids,
resolve_genetic_ids,
)
# Resolve v44.3 Master IDs to v66.0 GeneticIDs
result = resolve_master_ids(
["I0001", "Bichon", "Mota"],
src_version="v44.3",
dst_version="v66.0",
anno_paths={
"v44.3": "v44.3_1240K_public.anno",
"v66.0": "v66.0_1240K_public.anno",
},
mid_bridge="manual_renames.tsv", # optional override TSV
)
# result = {"I0001": "Loschbour.AG", "Bichon": "Bichon.SG", "Mota": None}
resolve_genetic_ids does the GID → GID inverse:
result = resolve_genetic_ids(
["I0001"],
src_version="v44.3",
dst_version="v66.0",
anno_paths={...},
)
# result = {"I0001": ["Loschbour.AG", "Loschbour.DG"]} # multi-row IID
Both functions also accept anno_frames={label: AnnoFrame, ...} as an
alternative to anno_paths={label: path, ...} — useful when you've
already loaded the frames once and want to reuse them across calls.
Direct AnnoFrame access for lower-level work:
from aadr_resolve import AnnoFrame
af = AnnoFrame.from_path("v66.0_1240K_public.anno", version_label="v66.0")
af.schema_class # SchemaClass.E
af.individual_id # pd.Series of canonical IIDs
af.genetic_id # pd.Series
af.persistent_genetic_id # pd.Series of Int64 nullable for class E; None for A-D
af.date_calbp # pd.Series of Int64 nullable
af.coverage # pd.Series of Float64 nullable
af.path # original Path, useful for re-creating anno_paths dicts
All errors derive from aadr_resolve.AadrResolveError. Sibling tools
catching aadr-resolve errors can except aadr_resolve.<Class>:
| Class | Maps to exit | Trigger |
|---|---|---|
ValidationError | 1 | Turnover gate, coverage gate, substantive-regroup gate |
IOFailure | 2 | File not found, lock held, malformed TSV |
InvariantViolation | 3 | Schema YAML malformed (rare) |
SchemaDetectionError | 3 | Header signature unknown |
MissingNativeFieldError | 3 | Canonical field requested for a class that lacks it |
CollisionDetected | 3 | Cross-lab MID collision under error policy |
UsageError | 4 | Bad CLI args; cohort file has no matching version |
Stable across versions. CI workflows can grep:
0 — success1 — soft-validation failure (any of the gates)2 — I/O failure3 — invariant violation (schema, MID collision)4 — usage error (bad CLI args)"unknown .anno schema signature" — your .anno header doesn't
match any of the 5 known classes. Either the file is from a newer AADR
release (file an issue with the bench-verify diff), or the file has
been edited. Workarounds:
--schema-override A|B|C|D|E|F forces a class without signature check.--version-label vN.N forces a version label when the filename
doesn't match a known pattern. It sets the version-keying label only —
the column layout (for releases that share a class but shift columns,
e.g. v50.0) is detected from the header content, so --version-label
does not force a layout when the headers indicate a different one."cross-lab MID collision" — the GID-stability check found a Master ID that maps to two different individuals in different versions. This indicates either a real data error in AADR or a cross-lab naming collision (rare). Workarounds:
--on-mid-collision warn continues with a stderr warning and marks
affected rows with library_chain_ambiguous status.--mid-bridge FILE lets you specify the correct mapping manually."sample turnover gate (fail)" — removal rate exceeded the
--turnover-fail threshold (default 30%). Indicates either a major
AADR cleanup (the v62→v66 bump removed ~17%) or that the wrong files
are being compared. Override with --turnover-fail 1.0 to disable.
"cohort coverage gate (fail)" — fewer than 25% of cohort entries
resolved in the supplied versions. Usually means the cohort file uses
IDs from a version not in the supplied set. Check --cohort-version.
"substantive_regroup gate (fail)" — only fires on diff when
--substantive-regroup-fail INT is set and the count of
substantive_regroup events exceeds the threshold. Inspect the events
via --report PATH or --include-class substantive_regroup before
adjusting the threshold.
Pandas ParserError on a v52 / v54 .anno — these versions contain
embedded quote characters in some full_date cells. aadr-resolve reads
with csv.QUOTE_NONE to side-step pandas's default quote-handling;
upgrade if you're on an older version.
The manifest TSV is the handoff format to downstream relabeling tools. Typical pipeline pairing aadr-resolve's join output with a PLINK2 sample-rename step:
aadr-resolve cohort patterson_2022.txt \
--anno-files v44.3_1240K_public.anno \
--anno-files v66.0_1240K_public.anno \
-o cohort_manifest.tsv
pgen-samplebind merge \
--relabel-from cohort_manifest.tsv \
--output merged_v66.pgen \
v44.3.pgen v66.0.pgen
Stable column order across versions:
cohort_label, cohort_label_source, individual_id_canonical,
library_tokenv{X}_genetic_id, v{X}_group_id, v{X}_snps_hit_1240kgroup_id_change_class_v_{old}_to_v_{new} (one per consecutive pair;
values: convention_restructure_{suffix,country,order,punct},
partial, substantive_regroup, none, or -- if absent)persistent_genetic_id (only when the latest version is class E and
at least one row has a value)statusMissing-cell sentinel is -- for every column (both string fields and
nullable-Int64 numerics).
MIT.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.4.2 | 12 Jun 2026 | 10 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Observed since 20 Oct, 16:53 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:d20e1722a28ec9a09116181dba085d954f0283eca15933f64883ecae05db1534