Skip to content

test(citations): 49 tests pin auditor regex + stopword behaviour #3

test(citations): 49 tests pin auditor regex + stopword behaviour

test(citations): 49 tests pin auditor regex + stopword behaviour #3

name: Citation Audit
# Enforces CLAUDE.md §10 "zero-hallucination" red line. Two gates:
#
# 1. tools/audit_citations.py — every arXiv / NBER / DOI reference in
# src/ and docs/ must match primary-source metadata (authors / year /
# title). Fails on MISMATCH or UNRESOLVED under --strict.
#
# 2. tools/audit_bib_duplicates.py — paper.bib must have no duplicate
# bib keys (biblatex error), no duplicate DOIs, no duplicate arXiv
# ids (same paper under two keys = citation drift). Fails on any
# duplicate under --strict.
#
# Both audit reports are uploaded as artifacts so reviewers can see the
# full verdict.
#
# Security: no untrusted PR inputs flow into `run:` commands — only the
# repo's own scripts under tools/ are executed.
on:
pull_request:
branches: [ main ]
paths:
- 'src/**'
- 'docs/**'
- 'paper.bib'
- 'paper.md'
- 'tools/audit_citations.py'
- 'tools/audit_bib_duplicates.py'
- 'tests/test_audit_citations.py'
- 'tests/test_audit_bib_duplicates.py'
- '.github/workflows/citation-audit.yml'
push:
branches: [ main ]
paths:
- 'src/**'
- 'docs/**'
- 'paper.bib'
- 'paper.md'
- 'tools/audit_citations.py'
- 'tools/audit_bib_duplicates.py'
- 'tests/test_audit_citations.py'
- 'tests/test_audit_bib_duplicates.py'
- '.github/workflows/citation-audit.yml'
workflow_dispatch:
concurrency:
group: citation-audit-${{ github.ref }}
cancel-in-progress: true
jobs:
audit:
name: Audit arXiv / NBER / DOI citations
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Install certifi + pytest
# certifi for the citation auditor's HTTPS calls; pytest to run
# the auditor test suite that pins the §10 regex regressions.
run: python -m pip install --quiet certifi pytest
- name: Run auditor test suite
# Fast (<1s) stdlib-only tests guarding DOI regex / Q-network
# stopword / parse_bib brace-balance regressions. Runs BEFORE
# the live auditors so a broken auditor can't silently pass.
run: python -m pytest tests/test_audit_citations.py tests/test_audit_bib_duplicates.py --no-cov -q
- name: Run paper.bib duplicate auditor (strict)
id: bib_audit
# Gate 1: runs first because it's cheap (stdlib only, no network)
# and a broken bibliography invalidates downstream citation checks.
run: python tools/audit_bib_duplicates.py --strict
- name: Run citation auditor (strict)
id: citation_audit
# Gate 2: live verification against arXiv / NBER / Crossref.
# --strict: unresolved IDs fail alongside mismatches, so a typo
# that breaks primary-source lookup is caught early.
run: python tools/audit_citations.py --strict --out audit_report.md
- name: Upload citation audit report
if: always()
uses: actions/upload-artifact@v4
with:
name: citation-audit-report
path: audit_report.md
retention-days: 30
- name: Summarise to GitHub step summary
if: always()
run: |
{
echo "### Citation Audit"
echo ""
if [ -f audit_report.md ]; then
sed -n '3p' audit_report.md
fi
echo ""
echo "Full citation report is attached as the \`citation-audit-report\` artifact."
} >> "$GITHUB_STEP_SUMMARY"