Files

76 lines
2.8 KiB
Python

#!/usr/bin/env python3
""""Verifier for the arXiv catalog extraction -- exit 0 iff the artifact is correct.
Reads the committed CSV, JSON and MD produced by extract_arxiv.py and checks the
facts that can be checked without re-running the extractor:
* CSV header row is exact
* 15 data rows (matches the Atom feed's entry count)
* every row has non-empty arxiv_id, title, authors, published, updated, category, summary
* arxiv_id matches the ^\d{4}\.\d{4,5}[oha]?v?\d*$ pattern
* JSON parses, 15 entries, keys match the CSV columns
* CSV and JSON agree on arxiv_id set and published dates
Exit code IS the verdict (0 = correct, 1 = wrong).
"""
import csv
import json
import re
import sys
CSV_PATH = "/root/.hermes/wizard-outputs/ledger/arxiv-catalog-2026-10-30.csv"
JSON_PATH = "/root/.hermes/wizard-outputs/ledger/arxiv-catalog-2026-10-30.json"
MD_PATH = "/root/.hermes/wizard-outputs/ledger/arxiv-catalog-2026-10-30.md"
EXPECTED_HEADER = ["arxiv_id", "title", "authors", "published", "updated",
"category", "comment", "summary"]
ID_RE = re.compile(r"^\d{4}\.\d{4,5}[oha]?v?\d*$")
REQUIRED = {"arxiv_id", "title", "authors", "published", "updated", "category", "summary"}
fails = []
def check(name, cond, detail=""):
if cond:
print("ok %s" % name)
else:
print("FAIL %s %s" % (name, detail))
fails.append(name)
def main():
with open(CSV_PATH, newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
check("csv header", reader.fieldnames == EXPECTED_HEADER,
"got %r" % (reader.fieldnames,))
rows = list(reader)
check("csv row count", len(rows) == 15, "got %d" % len(rows))
ids = []
for i, r in enumerate(rows, start=2): # line 1 = header
for col in REQUIRED:
check("row%d.%s non-empty" % (i, col), bool(r.get(col, "").strip()),
"row %d col %s = %r" % (i, col, r.get(col)))
check("row%d.arxiv_id pattern" % i, ID_RE.match(r.get("arxiv_id", "")) is not None,
"got %r" % r.get("arxiv_id"))
ids.append(r.get("arxiv_id", ""))
with open(JSON_PATH, encoding="utf-8") as f:
j = json.load(f)
check("json parses and is a list", isinstance(j, list), type(j).__name__)
check("json row count", len(j) == 15, "got %d" % len(j))
check("json keys match csv columns", set(j[0].keys()) == set(EXPECTED_HEADER),
"got %r" % sorted(j[0].keys()))
check("json ids match csv ids", [x.get("arxiv_id") for x in j] == ids)
with open(MD_PATH, encoding="utf-8") as f:
md = f.read()
check("md mentions 15 rows", "Rows: 15" in md, "not found in %r" % md[:200])
if fails:
print("FAILURES: %d" % len(fails))
sys.exit(1)
print("ALL CHECKS PASSED (%d rows)" % len(rows))
if __name__ == "__main__":
main()