Correctness + maintainability patch from a "wrap plink2, don't reimplement" audit.
Fix: chrX Hardy-Weinberg equilibrium
plink_hardy previously computed chrX HWE from a female-only stratum (males were dropped), giving p-values that deviate from plink2. It now wraps plink2's own HweXchrLnP, including male allele counts — matching plink2 --hardy / --hardy midp exactly. Autosomal HWE and all plink_glm p-values are unchanged.
Under the hood: wrap, don't reimplement
- Un-excluded
plink2_stats.ccfrom the build and replaced two hand-rolled statistics reimplementations with direct calls to plink2: HWE exact test (HweLnP/HweXchrLnP) and GWAS p-value math (TstatToP2/ChisqToP). - Documented the remaining vendored plink2 extracts with explicit upstream pins, plus a drift canary (
scripts/check_vendored_drift.sh) that flags when a plink-ng bump changes the vendored code. - No behavior change beyond the chrX HWE fix.
See docs/planning/plink2-wrapping-audit.md for the full audit.