"""Continuous accuracy check: re-fetch a sample of the figures we publish straight from the source, compare, and publish the result — matches, source movement, and real misses alike. Every miss opens a public Corrections ticket. This is our own automated re-check, not an independent audit.""" import logging from urllib.parse import quote, urlencode import random from datetime import datetime, timedelta, timezone import httpx from fastapi import APIRouter from deps import db logger = logging.getLogger("accuracy") router = APIRouter(prefix="/api/public") JOB = "accuracy_audit" UA = {"User-Agent": "Mozilla/5.0 (compatible; AlphaCovenantAccuracy/1.0; +https://alphacovenantholdings.com/accuracy)"} RESULTS = {"match": "Our stored figure equals what the source returns right now.", "source_moved": "The source returns a different figure and our copy is inside its refresh window: the agency's data moved after our pull. Visitors see the pull time next to the figure; the copy is refreshed on the next request.", "stale": "The source returns a different figure and our copy is OLDER than its refresh window. Because copies past their window are rebuilt before being shown, no visitor has been served the old value since it expired — but it was still on disk, so we count it against ourselves, force the refresh, and open a public Corrections ticket.", "unavailable": "The source could not be reached (or rate-limited us) for a fresh comparison; nothing is concluded and nothing is counted."} LIMITS = ["This checks that we copied the source faithfully. It cannot check whether the source itself is correct.", "This is not an independent audit. It is our own code re-checking our own copies — the checker is published at /api/public/code/accuracy.py and every daily result is captured by the Internet Archive so anyone can verify the record.", "Samples, not the whole corpus: a handful of figures per source per day, chosen at random from what is currently published.", "No grade is awarded. The page shows plain counts of matched, moved, stale and unreachable checks.", "The refresh that keeps copies current (scorerefresh.py, every 12 h) runs separately from this check, so the check measures the refresh rather than triggering it. A stale result opens a public Corrections ticket; the next scheduled re-pull resolves it publicly with the new value."] def _age_h(iso: str | None) -> float | None: if not iso: return None return round((datetime.now(timezone.utc) - datetime.fromisoformat(iso)).total_seconds() / 3600, 1) def _classify(ours, theirs, age_h, ttl_h) -> str: if theirs is None: return "unavailable" if ours == theirs: return "match" return "stale" if (age_h is not None and age_h > ttl_h) else "source_moved" def _check(source, subject, field, ours, theirs, pulled_at, ttl_h, url, recipe: dict | None = None) -> dict: age = _age_h(pulled_at) return {"source": source, "subject": subject, "field": field, "ours": ours, "source_now": theirs, "our_pull_at": pulled_at, "age_hours": age, "refresh_window_hours": ttl_h, "result": _classify(ours, theirs, age, ttl_h), "source_url": url, "recipe": recipe, "cite": f"/api/cite/{__import__('cite').figure_id(source, subject, field)}?source={quote(source)}&subject={quote(subject)}&field={quote(field)}"} async def _cfpb(client, n=6) -> list[dict]: out = [] docs = await db.covenant_scores.find({"reproduce.steps.0.url": {"$exists": True}}, {"_id": 0, "company": 1, "cached_at": 1, "reproduce": 1}).to_list(200) for d in random.sample(docs, min(n, len(docs))): st = d["reproduce"]["steps"][0] try: r = await client.get(st["url"], timeout=40) theirs = r.json()["hits"]["total"]["value"] if r.status_code == 200 else None except Exception: theirs = None out.append(_check("CFPB Consumer Complaint Database", d["company"], "complaints, last 12 months", st.get("value"), theirs, d.get("cached_at"), 24, st["url"], {"method": "GET", "url": st["url"], "extract": "json_path", "path": "hits.total.value"})) return out async def _fmcsa(n=4) -> list[dict]: import fmcsa_qc if not fmcsa_qc.enabled(): return [{"source": "FMCSA", "subject": "—", "field": "—", "ours": None, "source_now": None, "our_pull_at": None, "age_hours": None, "refresh_window_hours": 168, "result": "unavailable", "source_url": None, "note": "A fresh independent pull needs FMCSA_WEBKEY (QCMobile API); not configured on this deployment."}] out = [] docs = await db.carrier_cache.find({"name": {"$exists": True}}, {"_id": 0, "usdot": 1, "name": 1, "status": 1, "safety_rating": 1, "power_units": 1, "cached_at": 1, "source_url": 1}).to_list(300) for d in random.sample(docs, min(n, len(docs))): try: fresh = await fmcsa_qc.snapshot(d["usdot"]) except Exception: fresh = None for field, ours, theirs, extract in (("USDOT status", d.get("status"), (fresh or {}).get("status"), "fmcsa_status"), ("safety rating", (d.get("safety_rating") or {}).get("rating"), ((fresh or {}).get("safety_rating") or {}).get("rating"), "fmcsa_rating"), ("power units", str(d.get("power_units") or "").replace(",", ""), str((fresh or {}).get("power_units") or "").replace(",", "") if fresh else None, "fmcsa_power_units")): out.append(_check("FMCSA", f"{d['name']} (USDOT {d['usdot']})", field, ours, theirs, d.get("cached_at"), 168, d.get("source_url"), {"method": "GET", "url": f"{fmcsa_qc.QC}/carriers/{d['usdot']}", "query": {"webKey": "$FMCSA_WEBKEY"}, "needs_env": "FMCSA_WEBKEY", "extract": extract, "note": "FMCSA issues free QCMobile WebKeys at https://mobile.fmcsa.dot.gov/QCDevsite/"})) return out async def _registry(n=3) -> list[dict]: import stateregistry out = [] docs = await db.public_record_cache.find({"key": {"$regex": "^stateregistry:"}}, {"_id": 0, "key": 1, "cached_at": 1, "data": 1}).to_list(200) for d in random.sample(docs, min(n, len(docs))): name = d["data"].get("name") for reg in d["data"].get("registries", []): if not reg.get("available"): continue ours = sorted(f"{x['entity_name']} · {x['status']}" for x in reg.get("records", [])) try: fresh = await stateregistry.query_state(reg["state"], name) theirs = sorted(f"{x['entity_name']} · {x['status']}" for x in fresh.get("records", [])) if fresh.get("available") else None except Exception: theirs = None cfg = stateregistry.OPEN_DATA[reg["state"]] out.append({**_check(f"{reg['state']} business registry (open data)", name, "matching rows (name · status)", ours, theirs, d.get("cached_at"), 24, reg.get("source_url"), {"method": "GET", "url": stateregistry.query_url(reg["state"], name), "extract": "registry_rows", "name_field": cfg["f"]["name"], "status_field": cfg["f"]["status"], "implied_status": cfg.get("implied_status")}), "cache_key": d["key"]}) return out async def _dockets(n=2) -> list[dict]: import lawsuits out = [] docs = await db.public_record_cache.find({"key": {"$regex": "^lawsuits:"}}, {"_id": 0, "key": 1, "cached_at": 1, "data": 1}).to_list(200) for d in random.sample(docs, min(n, len(docs))): names = d["data"].get("names") or [] try: fresh = await lawsuits.fetch(names) theirs = None if fresh.get("rate_limited") else fresh.get("total_12mo") except Exception: theirs = None out.append({**_check("CourtListener / RECAP", " / ".join(names), "federal dockets, trailing 12 months", d["data"].get("total_12mo"), theirs, d.get("cached_at"), 24, d["data"].get("search_url"), {"method": "GET", "url": f"{lawsuits.CL}/api/rest/v4/search/?{urlencode(lawsuits.search_params(names))}", "headers": {"Accept": "application/json"}, "extract": "json_path", "path": "count", "note": "CourtListener rate-limits anonymous callers; HTTP 429 is reported as rate_limited, never as a mismatch."}), "cache_key": d["key"]}) return out async def _awards(n=2) -> list[dict]: import recompete out = [] docs = await db.public_record_cache.find({"key": {"$regex": "^federal-awards:"}}, {"_id": 0, "key": 1, "cached_at": 1, "data": 1}).to_list(200) for d in random.sample(docs, min(n, len(docs))): name = d["key"].split(":", 1)[1] try: fresh = await recompete.by_recipient(name.replace("-", " ")) theirs = fresh.get("active_awards") except Exception: theirs = None out.append({**_check("USAspending.gov", name.replace("-", " "), "open prime awards (count)", d["data"].get("active_awards"), theirs, d.get("cached_at"), 24, d["data"].get("source_url"), {"method": "POST", "url": recompete.API, "body": recompete.recipient_payload(name.replace("-", " ")), "extract": "usaspending_active", "paginate": {"field": "page", "max_pages": recompete.MAX_RECIPIENT_PAGES, "stop_when": "a result's 'End Date' is before today, or hasNext is false"}, "note": f"Counts results whose 'End Date' is today or later, paging (sorted by End Date desc) until the first ended award — the platform's method {recompete.COUNT_METHOD}."}), "cache_key": d["key"]}) return out async def run_audit(db_=None, payload: dict | None = None) -> dict: import scheduler as scheduler_mod db_ = db if db_ is None else db_ checks: list[dict] = [] async with httpx.AsyncClient(headers=UA, follow_redirects=True) as client: for fn in (lambda: _cfpb(client), _fmcsa, _registry, _dockets, _awards): try: checks += await fn() except Exception as e: logger.warning(f"accuracy: {getattr(fn, '__name__', 'cfpb')} failed: {e}") by_source: dict = {} for c in checks: s = by_source.setdefault(c["source"], {"checked": 0, "match": 0, "source_moved": 0, "stale": 0, "unavailable": 0}) s["checked"] += 1 s[c["result"]] += 1 run = {"at": datetime.now(timezone.utc).isoformat(), "checks": checks, "by_source": by_source, "totals": {k: sum(v[k] for v in by_source.values()) for k in ("checked", "match", "source_moved", "stale", "unavailable")}} await db_.accuracy_runs.insert_one(dict(run)) for c in [c for c in checks if c["result"] in ("stale", "source_moved") and c.get("cache_key")]: await db_.public_record_cache.delete_one({"key": c["cache_key"]}) for c in [c for c in checks if c["result"] == "stale"]: try: import corrections t = {"ticket_id": __import__("uuid").uuid4().hex[:10].upper(), "page_url": "/accuracy", "figure": f"{c['source']} — {c['subject']} — {c['field']}", "claim": f"Continuous accuracy check: we publish {c['ours']!r}; the source returned {c['source_now']!r}; our copy was {c['age_hours']} h old against a {c['refresh_window_hours']} h refresh window.", "source_url": c.get("source_url") or "", "email": "", "ip": "accuracy-check", "status": "received", "outcome": None, "created_at": run["at"], "resolved_at": None, "resolution": None, "cost_to_requester": 0, "opened_by": "accuracy_audit"} await db_.corrections.insert_one(dict(t)) await corrections._log("correction_requested", t["ticket_id"], {"page_url": "/accuracy", "figure": t["figure"], "source_url": t["source_url"] or None, "cost_to_requester": 0, "opened_by": "accuracy_audit"}) except Exception as e: logger.warning(f"accuracy: could not open ticket: {e}") logger.info(f"accuracy_audit: {run['totals']}") await scheduler_mod.enqueue(db_, JOB, {}, run_at=datetime.now(timezone.utc) + timedelta(hours=24)) return run @router.get("/accuracy") async def accuracy(days: int = 30): latest = await db.accuracy_runs.find_one({}, {"_id": 0}, sort=[("at", -1)]) if latest: import cite as cite_mod for c in latest.get("checks", []): c["cite"] = f"/api/cite/{cite_mod.figure_id(c['source'], c['subject'], c['field'])}?source={quote(c['source'])}&subject={quote(c['subject'])}&field={quote(c['field'])}" since = (datetime.now(timezone.utc) - timedelta(days=min(days, 365))).isoformat() hist = await db.accuracy_runs.find({"at": {"$gte": since}}, {"_id": 0, "checks": 0}).sort("at", 1).to_list(400) agg: dict = {} for r in hist: for src, s in r["by_source"].items(): a = agg.setdefault(src, {"checked": 0, "match": 0, "source_moved": 0, "stale": 0, "unavailable": 0, "runs": 0}) a["runs"] += 1 for k in ("checked", "match", "source_moved", "stale", "unavailable"): a[k] += s.get(k, 0) for a in agg.values(): a["concluded"] = a["checked"] - a["unavailable"] a["faithful_copy_rate_pct"] = round((a["match"] + a["source_moved"]) / a["concluded"] * 100, 1) if a["concluded"] else None return {"method": "Every day a random sample of published figures is re-fetched from its source and compared. Results are published unedited as plain counts, including misses; each miss opens a public Corrections ticket. This is our own automated re-check of our own copies — not an independent audit and not a grade.", "result_definitions": RESULTS, "limits": LIMITS, "latest_run": latest, "history": hist, "aggregate": agg, "window_days": days, "checker_source": "/api/public/code/accuracy.py", "refresh_latest": await db.score_refresh_runs.find_one({}, {"_id": 0}, sort=[("at", -1)]), "refresh_source": "/api/public/code/scorerefresh.py", "dedupe_latest": await db.score_dedupe_runs.find_one({}, {"_id": 0}, sort=[("at", -1)]), "citable_figures": "Every check carries a `cite` permalink: source URL, pull time, hash of our copy and this figure's own check history. /api/cite/{id}", "source_moved_feed": "/api/public/source-moved", "replay": {"script": "/api/public/code/replay.py", "how": "curl -sO https://alphacovenantholdings.com/api/public/code/replay.py && python3 replay.py", "what": "Every check above carries a `recipe` — the exact public request we made and the field we read. The script re-issues each one from your machine and prints the source's answer beside our published figure. Standard library only; no account, no key (FMCSA rows need a free FMCSA WebKey). Reproduces our method from outside; not an independent audit."}}