"""Citable figures: a permalink for any number we publish — source URL, exact pull time, hash of our copy, and that figure's own accuracy-check history. Plus the source-moved feed."""
import hashlib
import json
import re
from urllib.parse import quote
from datetime import datetime, timezone
from html import escape as e
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import HTMLResponse
from deps import db
router = APIRouter()
CSS = "body{font-family:Georgia,serif;max-width:760px;margin:0 auto;padding:28px 18px;color:#1a1a1a;line-height:1.5}h1{font-size:1.4rem;border-bottom:2px solid #1a1a1a;padding-bottom:8px}th{text-align:left;width:32%;vertical-align:top;padding:5px 8px 5px 0}td{padding:5px 0;vertical-align:top}tr{border-bottom:1px solid #e5e5e5}table{border-collapse:collapse;width:100%}code{font-size:.85em;word-break:break-all}.muted{color:#666;font-size:.92em}"
def figure_id(source: str, subject: str, field: str) -> str:
return hashlib.sha256(f"{source}|{subject}|{field}".encode()).hexdigest()[:16]
def value_hash(v) -> str:
return hashlib.sha256(json.dumps(v, sort_keys=True, default=str).encode()).hexdigest()
async def _history(source: str, subject: str, field: str) -> dict:
runs = await db.accuracy_runs.find({"checks": {"$elemMatch": {"source": source, "subject": subject, "field": field}}}, {"_id": 0, "at": 1, "checks.$": 1}).sort("at", -1).to_list(500)
counts = {"match": 0, "source_moved": 0, "stale": 0, "unavailable": 0}
last = None
for r in runs:
c = r["checks"][0]
counts[c["result"]] = counts.get(c["result"], 0) + 1
if last is None:
last = {"at": r["at"], "result": c["result"], "ours": c.get("ours"), "source_now": c.get("source_now")}
tickets = await db.corrections.find({"opened_by": "accuracy_audit", "figure": {"$regex": re.escape(subject)}}, {"_id": 0, "ticket_id": 1, "created_at": 1, "resolved_at": 1, "outcome": 1}).to_list(50)
days = [(datetime.fromisoformat(t["resolved_at"]) - datetime.fromisoformat(t["created_at"])).total_seconds() / 86400 for t in tickets if t.get("resolved_at")]
return {"checks": len(runs), **counts, "last_check": last, "tickets_opened": len(tickets), "tickets_resolved": len(days), "median_days_to_correct": round(sorted(days)[len(days) // 2], 2) if days else None,
"sentence": (f"checked {len(runs)} time{'s' if len(runs) != 1 else ''} against the source · stale {counts['stale']}× · source moved {counts['source_moved']}×" + (f" · corrected in {round(sorted(days)[len(days) // 2], 2)} days (median)" if days else "")) if runs else "not yet sampled by the daily accuracy check"}
async def receipt(source: str, subject: str, field: str, value, source_url: str, pulled_at: str | None, origin: str) -> dict:
fid = figure_id(source, subject, field)
return {"figure_id": fid, "permalink": f"{origin}/api/cite/{fid}?source={quote(source)}&subject={quote(subject)}&field={quote(field)}", "source": source, "subject": subject, "field": field, "value": value, "value_sha256": value_hash(value),
"source_url": source_url, "our_pull_at": pulled_at, "accuracy_history": await _history(source, subject, field), "generated_at": datetime.now(timezone.utc).isoformat(),
"how_to_cite": f"Alpha Covenant Holdings, \"{field}\" for {subject}, from {source}, copy pulled {pulled_at or 'n/a'}, retrieved {datetime.now(timezone.utc).date()}, {origin}/api/cite/{fid}?source={quote(source)}&subject={quote(subject)}&field={quote(field)}"}
async def _lookup(source: str, subject: str, field: str):
"""Find the current published value for a sampled figure. Returns (value, source_url, pulled_at) or None."""
if source == "CFPB Consumer Complaint Database":
d = await db.covenant_scores.find_one({"company": subject, "cached_at": {"$gt": "1971"}}, {"_id": 0, "reproduce": 1, "cached_at": 1}, sort=[("cached_at", -1)])
if d:
st = ((d.get("reproduce") or {}).get("steps") or [{}])[0]
return st.get("value"), st.get("url"), d.get("cached_at")
latest = await db.accuracy_runs.find_one({"checks": {"$elemMatch": {"source": source, "subject": subject, "field": field}}}, {"_id": 0, "checks.$": 1}, sort=[("at", -1)])
if latest:
c = latest["checks"][0]
return c.get("ours"), c.get("source_url"), c.get("our_pull_at")
return None
def _origin(request: Request) -> str:
host = request.headers.get("x-forwarded-host") or request.headers.get("host") or "alphacovenantholdings.com"
return f"https://{host.split(',')[0].strip()}"
@router.get("/api/cite/{fid}")
async def cite(fid: str, request: Request, source: str, subject: str, field: str, format: str = "html"):
if figure_id(source, subject, field) != fid:
raise HTTPException(status_code=404, detail="Figure id does not match source/subject/field.")
found = await _lookup(source, subject, field)
if not found:
raise HTTPException(status_code=404, detail="No published figure found for that source/subject/field.")
value, url, pulled = found
r = await receipt(source, subject, field, value, url, pulled, _origin(request))
if format == "json":
return r
h = r["accuracy_history"]
rows = [("Figure", f"{e(field)} for {e(subject)}"), ("Published value", f"{e(json.dumps(value, default=str))}"), ("Source", f'{e(source)}'),
("Our copy pulled", e(pulled or "not stated")), ("SHA-256 of our copy", f"{r['value_sha256']}"), ("Accuracy-check history", e(h["sentence"])),
("Last check", e(f"{h['last_check']['at'][:16].replace('T', ' ')} UTC → {h['last_check']['result']}") if h["last_check"] else "—"), ("Corrections tickets on this figure", f"{h['tickets_opened']} opened · {h['tickets_resolved']} resolved"),
("How to cite", e(r["how_to_cite"])), ("Machine-readable", f'JSON · all daily checks · checker code')]
body = "".join(f"
{e(fid)}A permanent receipt for one number we publish: where it came from, when we pulled it, the hash of our copy, and how often the daily accuracy check has found it faithful. No script required.
Receipts are generated live; the history grows every day the figure is sampled. This is our own check against the source, not an independent audit.
""") @router.get("/api/public/source-moved") async def source_moved(days: int = 30): """What the government itself revised: checks where the source's current value differs from our copy while our copy was still inside its refresh window.""" since = (datetime.now(timezone.utc) - __import__("datetime").timedelta(days=days)).isoformat() runs = await db.accuracy_runs.find({"at": {"$gte": since}}, {"_id": 0, "at": 1, "checks": 1}).sort("at", -1).to_list(200) items = [] for r in runs: for c in r["checks"]: if c["result"] == "source_moved": items.append({"observed_at": r["at"], "source": c["source"], "subject": c["subject"], "field": c["field"], "was": c.get("ours"), "now": c.get("source_now"), "source_url": c.get("source_url"), "figure_id": figure_id(c["source"], c["subject"], c["field"])}) return {"window_days": days, "count": len(items), "items": items, "meaning": "The agency's published number changed after we copied it, within our refresh window. This is the source moving, not our error; the copy is re-pulled on the next refresh.", "generated_at": datetime.now(timezone.utc).isoformat()}