merge_writeback.py
Language Python4.1 KB89 lines
#!/usr/bin/env python3"""merge_writeback.py: unified write-back combining Apollo person/company data andweb-search signals for client-enrich. Calls enrich_writeback.py so the vaultcontract holds (writes only under ## Research + frontmatter; never Human Notes).Per stub:- Person = Apollo person lines if matched, else from existing frontmatter.- Company = Apollo company lines if matched, else minimal (name + LinkedIn + TBD firmographics).- Signals = Apollo company_signals (funding/growth) + web-search signals; [TBD] if none.- Sources = web sources + Apollo sources + provenance lines.- Frontmatter = filled from Apollo (empty fields only; enrich_writeback enforces that).Usage:python3 merge_writeback.py --batch no_li_40.json --web web_signals_40.json \--apollo apollo_results.json --stubdir "/path/03-Clients/Check-In" \--script "/path/enrich_writeback.py" [--date YYYY-MM-DD]"""import argparse, json, os, subprocess, sys, datetime, tempfiledef main():ap = argparse.ArgumentParser()ap.add_argument("--batch", required=True)ap.add_argument("--web", required=True)ap.add_argument("--apollo", required=True)ap.add_argument("--stubdir", required=True)ap.add_argument("--script", required=True)ap.add_argument("--date", default=datetime.date.today().isoformat())args = ap.parse_args()batch = {r["file"]: r for r in json.load(open(args.batch, encoding="utf-8"))}web = json.load(open(args.web, encoding="utf-8"))apollo = json.load(open(args.apollo, encoding="utf-8")) if os.path.exists(args.apollo) else {}rows = []for fname, r in batch.items():ap_e = apollo.get(fname, {})matched = bool(ap_e.get("matched"))web_e = web.get(fname, {})if matched and ap_e.get("person"):person = ap_e["person"]else:person = []if r.get("title"): person.append(f"- Title: {r['title']}")if r.get("seniority"): person.append(f"- Seniority: {r['seniority']}")loc = ", ".join([x for x in [r.get("city"), r.get("state")] if x])if loc: person.append(f"- Location: {loc}")person = person or ["[TBD]"]if matched and ap_e.get("company"):company = ap_e["company"]else:company = []if r.get("company"): company.append(f"- {r['company']}")if r.get("company_li"): company.append(f"- LinkedIn: {r['company_li']}")company.append("- [TBD: firmographics not available (Apollo miss or no corporate domain)]")signals = list(ap_e.get("company_signals") or []) + list(web_e.get("signals") or [])if not signals:signals = ["[TBD: no recent signals found via Apollo or web search]"]sources = list(web_e.get("sources") or []) + list(ap_e.get("sources") or [])if web_e.get("signals"):sources.append(f"- Web search, {args.date}")if not matched:sources.append("- Stub frontmatter (prior enrichment)")payload = {"frontmatter": ap_e.get("frontmatter", {}) if matched else {},"person": person, "company": company,"signals": signals, "sources": sources}with tempfile.NamedTemporaryFile("w", suffix=".json", delete=False) as tf:json.dump(payload, tf); pj = tf.nameres = subprocess.run([sys.executable, args.script, "--stub",os.path.join(args.stubdir, fname), "--payload", pj,"--date", args.date], capture_output=True, text=True)os.unlink(pj)rows.append((fname, matched, len([s for s in signals if not s.startswith("[TBD")]),res.returncode == 0, res.stderr.strip()[:120]))okc = sum(1 for _,_,_,k,_ in rows if k)mc = sum(1 for _,m,_,_,_ in rows if m)sc = sum(1 for _,_,n,_,_ in rows if n > 0)print(f"WROTE {okc}/{len(rows)} OK | Apollo-matched: {mc} | with >=1 signal: {sc}")for f, m, n, k, err in rows:print(f" {f[:30]:32} | {'APOLLO' if m else 'frontmtr':8} | {n} sig | {'OK' if k else 'FAIL '+err}")if __name__ == "__main__":main()