# Reproducibility runbook — WP44 Everything below was executed on M3U96b (Mac Studio M3 Ultra, 28 cores, 96 GB, macOS 27.0) in `~/wp44_uqo` with the locked environment `reproducibility/environment_M3U96b.txt` (Python 3.12.15 via uv). Raw sources are public; the exact inputs are pinned by manifests and hashes (`data/raw/README.md`, ledgers). Nothing requires credentials except the two LLM raters of the taxonomy validation (Anthropic API key, never stored in the repository). | Step | Command | Inputs | Outputs | Wall time (measured) | |---|---|---|---|---| | 1 OpenAlex works snapshot (pass 1, CS filter + slim table) | `python ingestion/openalex_snapshot.py --out data/raw/openalex/works --manifest data/raw/openalex/works_manifest_2026-10-14.json --workers 8` | S3 public bucket, release 2026-10-14 | `works/cs/*.jsonl.zst` (15,490,159), `works/slim/*.parquet` (464,765,485), `ledger.sqlite` | 1 h 46 min at ≈ 108 MB/s | | 2 OpenAlex entities | `python ingestion/openalex_entities.py --out data/raw/openalex` | S3 | `topics/ … institutions/`, `entities_ledger.json` | 5 min | | 3 DBLP | `python ingestion/dblp_parse.py --xml data/raw/dblp/dblp.xml.gz --out data/raw/dblp` | dump 2026-11-02 (MD5 verified) | `dblp_publications.parquet` (8,840,866), report | 4 min 45 s | | 4 arXiv OAI-PMH | `python ingestion/arxiv_oai.py --out data/raw/arxiv --from 2018-01-01 --until 2026-11-02` | OAI feed, set `cs` | raw XML pages (758), `arxiv_cs.parquet` (915,115) | ≈ 1 h | | 5 ACL Anthology | `python ingestion/acl_parse.py --bib data/raw/acl/anthology+abstracts.bib.gz --out data/raw/acl` | bib export | `acl_anthology.parquet` (138,796) | 10 s | | 6 Normalise | `python ingestion/build_corpus.py --cs-dir data/raw/openalex/works/cs --out data/processed --workers 12` | step 1 | `tables//*.parquet` | 2 min 10 s | | 7 Compact | `ulimit -n 65536; python ingestion/compact_tables.py ~/wp44_uqo` | step 6 | `compact/
.parquet` | 30 s | | 8 Link | `python ingestion/link_sources.py --root ~/wp44_uqo` | steps 3–7 | DuckDB `wp44.duckdb`, `link_*`, `data/metadata/linkage_report.json`, `needed_oa_ids.csv` | 10 s | | 9 Second pass (DBLP/arXiv-linked works outside the CS-topic filter) | `python ingestion/openalex_snapshot.py --out data/raw/openalex/works_pass2 --manifest … --workers 8 --id-list data/metadata/needed_oa_ids.csv` then `ingestion/run_pass2_chain.sh` (steps 6–8 with suffix `_p2`, then 10–11) | S3 | `works_pass2/cs/*.jsonl.zst`, `compact/
_p2.parquet` | ≈ 1 h 50 min | | 10 Corpus definition | `python systematic_review/define_corpus.py --root ~/wp44_uqo` | step 8 | `corpus_works`, `data/metadata/prisma_counts.json` | 2 min | | 11 Volume, collaboration, citations, graph | `python bibliometrics/01_volume_series.py …`, `02_collaboration.py`, `03_citation_impact.py`, `knowledge_graph/01_citation_graph.py` | step 10 | `results/bibliometrics/*.csv`, `results/graph/*`, `data/processed/graph/*` | minutes | | 12 Classification | `python taxonomy/classify.py --root ~/wp44_uqo --ontology taxonomy/ontology.yaml --prepare --run` | steps 8, 10, `taxonomy/ontology.yaml` | `data/processed/classification/{cats,primary}/*.parquet`, report | (to be measured) | | 13 Validation sample + raters | `python taxonomy/validate_sample.py --root … --draw`; `--rate --model claude-haiku-5-5`; `--rate --model claude-sonnet-5-5`; `--metrics` | step 12 | `taxonomy/validation/*` | (to be measured) | | 14 Embeddings | `python embeddings/embed_corpus.py --root … --prepare`; `--run --model allenai/specter2_base` (sharded over nodes) | step 10 | `data/processed/embeddings//shard_*.npy` | ≈ 300 texts/s per M3 Ultra | | 15 Structural change, emerging detection, figures, tables | `econometrics/run_structural_change.py`, `experiments/emerging_detection.py`, `figures/make_figures.py`, `tables/make_numbers.py` | 11–14 | `results/econometrics`, `results/emerging`, `figures/`, `manuscript/tables/numbers.tex` | minutes | | 16 Manuscript | `cd manuscript && make` | all | `manuscript/main.pdf` | — | Tests: `python -m pytest -q tests/` (structural-change toolkit, classification scoring, corpus rules).