1"""Write reports/extraction_audit.md from the extraction JSONs, the validation comparison and the effects table."""2import json3from pathlib import Path4import pandas as pd56ROOT = Path(__file__).resolve().parents[2]; FINAL = ROOT / "data" / "final"789def main():10 S = pd.read_csv(FINAL / "studies.csv"); E = pd.read_csv(FINAL / "effects_all.csv"); U = pd.read_csv(FINAL / "effects.csv")11 val = json.load(open(ROOT / "data" / "validated" / "validation_summary.json")) if (ROOT / "data" / "validated" / "validation_summary.json").exists() else {}12 conf = E.confidence.value_counts().to_dict(); flags = E.harm_flags.fillna("none").value_counts().head(10).to_dict(); se_src = E.se_source.fillna("none").value_counts().to_dict()13 excl = S[S.eligible == False].exclusion_reason.fillna("").str.slice(0, 80).value_counts().head(15)14 lines = ["# WP21 — Extraction audit (generated)", "", f"Studies extracted: {len(S)}; eligible: {int(S.eligible.sum())}; ineligible at full text: {int((S.eligible == False).sum())}.",15 f"Coefficient rows: {len(E)}; usable in the pooled synthesis: {len(U)} from {U.study_id.nunique()} studies.", "",16 "## Confidence of extracted rows", "", "| confidence | rows |", "|---|---|"] + [f"| {k} | {v} |" for k, v in conf.items()]17 lines += ["", "## Source of the standard error", "", "| source | rows |", "|---|---|"] + [f"| {k} | {v} |" for k, v in se_src.items()]18 lines += ["", "## Harmonisation flags (rows excluded from pooling)", "", "| flag | rows |", "|---|---|"] + [f"| {k} | {v} |" for k, v in flags.items()]19 lines += ["", "## Full-text exclusion reasons (first 80 characters)", "", "| reason | studies |", "|---|---|"] + [f"| {k} | {v} |" for k, v in excl.items()]20 lines += ["", "## Independent double-extraction validation", "", "```json", json.dumps(val, indent=2, default=float), "```", "",21 "Interpretation: numerical agreement on matched coefficients is the relevant accuracy measure; recall/precision below one reflect",22 "differences in which auxiliary variables (composite indices, planning dummies, local-regression summaries) each extractor recorded.",23 "Eligibility disagreements are listed in data/validated/validation_results.csv and were resolved by the protocol rule (duplicate-of-prior-publication → excluded)."]24 (ROOT / "reports" / "extraction_audit.md").write_text("\n".join(lines)); print("extraction audit written")252627if __name__ == "__main__":28 main()29