SPB Git

spb/wp44_uqo

Public
30.3 KB · 316 lines latex
1% ============================================================================2% Appendix H — Reproducibility3% Written by Agent L (appendices A/E/H instance), 2026-11-03. Sources of truth: reproducibility/RUNBOOK.md,4% reproducibility/environment_M3U96b.txt, data/raw/README.md, reports/INCIDENTS.md, protocol/amendments.csv,5% protocol/PROTOCOL.md §P8, README.md, .gitignore, ingestion/*.py (ledger schemas). Every number here is a6% provenance fact (file counts, sizes, wall times, versions) taken from those files; no corpus result appears.7% ============================================================================89\section{Reproducibility}10\label{app:repro}1112The mandate requires that the corpus be reproducible from immutable raw snapshots and that every quantitative13claim trace to a script, an input artefact and a result file. This appendix records what a reader needs to14re-run the pipeline: the computing environment and the locked package versions, the ordered steps with their15commands, inputs, outputs and measured wall times, the mechanisms by which provenance is kept (manifests,16hash ledgers, verbatim raw pages, API ledgers), the incidents that occurred during the first run and what17they imply for a second one, the protocol amendments, and the licence of each source together with what is18and is not redistributed. The runbook (\texttt{reproducibility/\allowbreak RUNBOOK.\allowbreak md}) is the operational version of19this appendix and is updated whenever a step changes; where the two differ, the runbook is more recent.2021\subsection{Environment}22\label{app:repro-env}2324Everything described in the runbook was executed on one node of the MacLustr cluster, M3U96b (Mac Studio,25Apple M3~Ultra, 28~cores, 96~GB of unified memory, 103{,}079{,}215{,}104 bytes as recorded by the environment26capture), in the working directory \texttt{\textasciitilde/\allowbreak wp44\_\allowbreak uqo}, under Python 3.12.15 in a virtual27environment created with \texttt{uv} from \texttt{requirements.\allowbreak txt} and then frozen to28\texttt{reproducibility/\allowbreak environment\_\allowbreak M3U96b.\allowbreak txt} (92 lines: 88 pinned packages, the interpreter version, the29operating-system version string, the processor and the memory size). The operating-system version string30captured in that file is 26.4, whereas the runbook header states macOS~27.0; the discrepancy is recorded here31rather than resolved, since the node was updated between captures and neither value affects the computation.32Two further nodes were used after the incidents of Section~\ref{app:repro-incidents}: M5M36 for the second33snapshot pass and M4M64c and M3U96a for embedding shards; they run the same locked environment.34Table~\ref{tab:appH-packages} lists the packages on which results depend; the complete list is the lock file.35No step requires credentials except the two LLM raters of the taxonomy validation and the knowledge-graph36extraction (an Anthropic API key read from a file outside the repository, never stored in it).3738\begin{table}[htbp]39\begin{singlespace}40\centering41\caption{Key packages of the locked environment (\texttt{reproducibility/\allowbreak environment\_\allowbreak M3U96b.\allowbreak txt}, Python 3.12.15).}42\label{tab:appH-packages}43\small44\begin{tabularx}{\textwidth}{l X l}45\toprule46Role & Package & Version \\47\midrule48Analytical database & \texttt{duckdb} \citep{raasveldt2019duckdb} & 2.0.0 \\49Columnar I/O & \texttt{pyarrow} & 26.0.0 \\50Data frames & \texttt{polars} / \texttt{pandas} & 2.1.0 / 3.1.0 \\51Numerics & \texttt{numpy} / \texttt{scipy} & 2.5.4 / 1.18.1 \\52Statistics, time series & \texttt{statsmodels} / \texttt{formulaic} & 0.15.0 / 1.2.2 \\53Change-point detection & \texttt{ruptures} \citep{truong2020ruptures} & 1.1.10 \\54Machine learning & \texttt{scikit-learn} & 1.9.1 \\55Embeddings & \texttt{torch} / \texttt{transformers} / \texttt{sentence-transformers} \citep{reimers2019sbert} & 2.15.0 / 5.22.1 / 6.2.0 \\56Model hub client & \texttt{huggingface-hub} & 2.4.0 \\57Dimensionality reduction, clustering & \texttt{umap-learn} / \texttt{hdbscan} / \texttt{pynndescent} & 0.5.12 / 0.8.44 / 0.7.0 \\58Networks & \texttt{networkx} / \texttt{igraph} & 3.7 / 1.0.0 \\59Parsing & \texttt{lxml} / \texttt{orjson} / \texttt{zstandard} / \texttt{regex} & 6.1.3 / 3.13.0 / 0.25.0 / 2026.9.29 \\60Ontology file & \texttt{pyyaml} & 6.0.3 \\61HTTP & \texttt{requests} / \texttt{httpx2} & 2.34.2 / 2.16.0 \\62LLM raters, extraction & \texttt{anthropic} & 2.4.0 \\63Figures & \texttt{matplotlib} & 3.11.2 \\64Tests & \texttt{pytest} & 9.2.0 \\65\bottomrule66\end{tabularx}67\end{singlespace}68\end{table}6970\subsection{Steps, commands and measured times}71\label{app:repro-steps}7273Table~\ref{tab:appH-steps} reproduces the runbook's step table. Commands are given relative to the repository74root with the virtual environment active; \texttt{\ldots} abbreviates arguments that are spelled out in the75runbook. Wall times are those measured during the first run and are reported as orientation, not as76guarantees: the snapshot download depends on network throughput (about 108~MB/s was sustained from the node77with eight parallel streams), and the steps marked ``to be measured'' had not completed at the time the78runbook was last updated because of the node freezes described below. Steps~1--5 are pure acquisition and79can be run independently and in any order; steps 6--10 are sequential; step~9 is a second acquisition pass80whose need is discovered at step~8 and which then repeats steps 6--8 and 10--11 with the suffix \texttt{\_\allowbreak p2}81(\texttt{ingestion/\allowbreak run\_\allowbreak pass2\_\allowbreak chain.\allowbreak sh}, which waits for a flag file written when the pass-2 outputs have82been copied back to the node). The API increment of Table~\ref{tab:appH-raw} (works published after the83snapshot cut-off) is converted to the snapshot's part format by \texttt{ingestion/\allowbreak ingest\_\allowbreak api\_\allowbreak increment.\allowbreak py}84and normalised by the same step~6; it is not yet a numbered step of the runbook.8586\begin{singlespace}87\begin{footnotesize}88\begin{longtable}{@{}p{0.5cm} p{5.6cm} p{2.3cm} p{4.6cm} p{2.3cm}@{}}89\caption{Pipeline steps (\texttt{reproducibility/\allowbreak RUNBOOK.\allowbreak md}), with the command, the inputs, the outputs and the wall time measured on M3U96b.}90\label{tab:appH-steps}\\91\toprule92\# & Step and command & Inputs & Outputs & Wall time \\93\midrule94\endfirsthead95\caption[]{Pipeline steps (continued).}\\96\toprule97\# & Step and command & Inputs & Outputs & Wall time \\98\midrule99\endhead100\midrule101\multicolumn{5}{r}{continued on next page}\\102\endfoot103\bottomrule104\endlastfoot1051 & OpenAlex works snapshot, pass~1 (CS filter + slim table): \texttt{python ingestion/\allowbreak openalex\_\allowbreak snapshot.\allowbreak py --out data/\allowbreak raw/\allowbreak openalex/\allowbreak works --manifest data/\allowbreak raw/\allowbreak openalex/\allowbreak works\_\allowbreak manifest\_\allowbreak 2026-10-14.\allowbreak json --workers 8} & public S3 bucket, release 2026-10-14 & \texttt{works/\allowbreak cs/\allowbreak *.\allowbreak jsonl.\allowbreak zst} (15{,}490{,}159 records), \texttt{works/\allowbreak slim/\allowbreak *.\allowbreak parquet} (464{,}765{,}485 rows), \texttt{ledger.\allowbreak sqlite} & 1~h 46~min at $\approx$108~MB/s \\1062 & OpenAlex entities: \texttt{python ingestion/\allowbreak openalex\_\allowbreak entities.\allowbreak py --out data/\allowbreak raw/\allowbreak openalex} & S3 & \texttt{topics/\allowbreak }, \ldots, \texttt{institutions/\allowbreak }; \texttt{entities\_\allowbreak ledger.\allowbreak json} & 5~min \\1073 & DBLP: \texttt{python ingestion/\allowbreak dblp\_\allowbreak parse.\allowbreak py --xml data/\allowbreak raw/\allowbreak dblp/\allowbreak dblp.\allowbreak xml.\allowbreak gz --out data/\allowbreak raw/\allowbreak dblp} & dump of 2026-11-02, MD5 verified & \texttt{dblp\_\allowbreak publications.\allowbreak parquet} (8{,}840{,}866 records), parse report & 4~min 45~s \\1084 & arXiv OAI-PMH: \texttt{python ingestion/\allowbreak arxiv\_\allowbreak oai.\allowbreak py --out data/\allowbreak raw/\allowbreak arxiv --from 2018-01-01 --until 2026-11-02} & OAI feed, set \texttt{cs} & raw XML pages (758), \texttt{arxiv\_\allowbreak cs.\allowbreak parquet} (915{,}115 records) & $\approx$1~h \\1095 & ACL Anthology: \texttt{python ingestion/\allowbreak acl\_\allowbreak parse.\allowbreak py --bib data/\allowbreak raw/\allowbreak acl/\allowbreak anthology+abstracts.\allowbreak bib.\allowbreak gz --out data/\allowbreak raw/\allowbreak acl} & BibTeX export & \texttt{acl\_\allowbreak anthology.\allowbreak parquet} (138{,}796 entries) & 10~s \\1106 & Normalise: \texttt{python ingestion/\allowbreak build\_\allowbreak corpus.\allowbreak py --cs-dir data/\allowbreak raw/\allowbreak openalex/\allowbreak works/\allowbreak cs --out data/\allowbreak processed --workers 12} & step 1 & \texttt{tables/\allowbreak <table>/\allowbreak *.\allowbreak parquet} & 2~min 10~s \\1117 & Compact: \texttt{ulimit -n 65536; python ingestion/\allowbreak compact\_\allowbreak tables.\allowbreak py \textasciitilde/\allowbreak wp44\_\allowbreak uqo} & step 6 & \texttt{compact/\allowbreak <table>.\allowbreak parquet} & 30~s \\1128 & Link: \texttt{python ingestion/\allowbreak link\_\allowbreak sources.\allowbreak py --root \textasciitilde/\allowbreak wp44\_\allowbreak uqo} & steps 3--7 & \texttt{wp44.\allowbreak duckdb} with \texttt{link\_\allowbreak *}; \texttt{data/\allowbreak metadata/\allowbreak linkage\_\allowbreak report.\allowbreak json}; \texttt{needed\_\allowbreak oa\_\allowbreak ids.\allowbreak csv} & 10~s \\1139 & Second pass (DBLP- and arXiv-linked works outside the CS-topic filter): \texttt{python ingestion/\allowbreak openalex\_\allowbreak snapshot.\allowbreak py --out data/\allowbreak raw/\allowbreak openalex/\allowbreak works\_\allowbreak pass2 --manifest \ldots --workers 8 --id-list data/\allowbreak metadata/\allowbreak needed\_\allowbreak oa\_\allowbreak ids.\allowbreak csv}, then \texttt{ingestion/\allowbreak run\_\allowbreak pass2\_\allowbreak chain.\allowbreak sh} (steps 6--8 with suffix \texttt{\_\allowbreak p2}, then 10--11) & S3, step 8 & \texttt{works\_\allowbreak pass2/\allowbreak cs/\allowbreak *.\allowbreak jsonl.\allowbreak zst}, \texttt{compact/\allowbreak <table>\_\allowbreak p2.\allowbreak parquet} & $\approx$1~h 50~min \\11410 & Corpus definition: \texttt{python systematic\_\allowbreak review/\allowbreak define\_\allowbreak corpus.\allowbreak py --root \textasciitilde/\allowbreak wp44\_\allowbreak uqo} & step 8 & \texttt{corpus\_\allowbreak works}, \texttt{data/\allowbreak metadata/\allowbreak prisma\_\allowbreak counts.\allowbreak json} & 2~min \\11511 & Volume, collaboration, citations, graph: \texttt{bibliometrics/\allowbreak 01\_\allowbreak volume\_\allowbreak series.\allowbreak py}, \texttt{02\_\allowbreak collaboration.\allowbreak py}, \texttt{03\_\allowbreak citation\_\allowbreak impact.\allowbreak py}, \texttt{knowledge\_\allowbreak graph/\allowbreak 01\_\allowbreak citation\_\allowbreak graph.\allowbreak py} & step 10 & \texttt{results/\allowbreak bibliometrics/\allowbreak *.\allowbreak csv}, \texttt{results/\allowbreak graph/\allowbreak *}, \texttt{data/\allowbreak processed/\allowbreak graph/\allowbreak *} & minutes \\11612 & Classification: \texttt{python taxonomy/\allowbreak classify.\allowbreak py --root \ldots --ontology taxonomy/\allowbreak ontology.\allowbreak yaml --prepare --run} (in practice \texttt{taxonomy/\allowbreak run\_\allowbreak classify\_\allowbreak shards.\allowbreak sh}, see incident I-3) & steps 8, 10; \texttt{ontology.\allowbreak yaml} & \texttt{classification/\allowbreak cats/\allowbreak *.\allowbreak parquet}, \texttt{classification/\allowbreak primary/\allowbreak *.\allowbreak parquet}, report & to be measured \\11713 & Validation sample and raters: \texttt{python taxonomy/\allowbreak validate\_\allowbreak sample.\allowbreak py --root \ldots --draw}; \texttt{--rate --model claude-haiku-5-5}; \texttt{--rate --model claude-sonnet-5-5}; \texttt{--metrics} & step 12 & \texttt{taxonomy/\allowbreak validation/\allowbreak *} & to be measured \\11814 & Embeddings: \texttt{python embeddings/\allowbreak embed\_\allowbreak corpus.\allowbreak py --root \ldots --prepare}; \texttt{--run --model allenai/\allowbreak specter2\_\allowbreak base} (sharded over nodes) & step 10 & \texttt{embeddings/\allowbreak <model>/\allowbreak shard\_\allowbreak *.\allowbreak npy} & $\approx$300 texts/s per M3~Ultra \\11915 & Structural change, emerging detection, figures, tables: \texttt{econometrics/\allowbreak run\_\allowbreak structural\_\allowbreak change.\allowbreak py}, \texttt{experiments/\allowbreak emerging\_\allowbreak detection.\allowbreak py}, \texttt{figures/\allowbreak make\_\allowbreak figures.\allowbreak py}, \texttt{tables/\allowbreak make\_\allowbreak numbers.\allowbreak py} & steps 11--14 & \texttt{results/\allowbreak econometrics}, \texttt{results/\allowbreak emerging}, \texttt{figures/\allowbreak }, \texttt{manuscript/\allowbreak tables/\allowbreak numbers.\allowbreak tex} & minutes \\12016 & Manuscript: \texttt{cd manuscript \&\& make} (\texttt{latexmk}) & all & \texttt{manuscript/\allowbreak main.\allowbreak pdf} & --- \\121\end{longtable}122\end{footnotesize}123\end{singlespace}124125The test suite (\texttt{python -m pytest -q tests/\allowbreak }) covers the structural-change toolkit and the126classification scoring rule (\texttt{tests/\allowbreak test\_\allowbreak structural\_\allowbreak change.\allowbreak py}, \texttt{tests/\allowbreak test\_\allowbreak classify\_\allowbreak rules.\allowbreak py});127the second fixes the implemented aggregation of equation~\eqref{eq:score} against the toy ontology it128declares, so that a change in \texttt{classify.\allowbreak py} that altered the rule would fail before any corpus were129classified.130131\subsection{Provenance mechanisms}132\label{app:repro-provenance}133134Provenance is kept at the level of files and jobs, not of individual records, by six mechanisms.135136\paragraph{Manifests and hash ledgers for the OpenAlex snapshot.} The snapshot's own manifest137(\texttt{works\_\allowbreak manifest\_\allowbreak 2026-10-14.\allowbreak json}) lists every part file with its content length and record count.138The ingestion script keeps a SQLite ledger (\texttt{works/\allowbreak ledger.\allowbreak sqlite}) with a \texttt{files} table (one139row per part: URL, local name, expected length, manifest record count, status, SHA-256 of the gzip bytes,140records parsed, records retained by the filter, lines that failed to parse, download and total time, number141of attempts, start and end timestamps, error text) and a \texttt{runs} table (start time, manifest date,142manifest record and byte totals, number of workers, host name and command line of every invocation). A143part is downloaded with resume and retries until its size equals the manifest's, hashed, parsed, and only144then marked done; outputs are written to a temporary name and renamed atomically, so an interrupted run145leaves no partial output that a resumed run would mistake for a complete one. The raw gzip files are deleted146after a successful parse unless \texttt{--keep-raw} is given: the snapshot is a public, versioned release, and147the manifest together with the per-file hashes allows any later copy to be verified against what was148ingested. For the first pass the ledger records 1{,}898 of 1{,}898 files done, 0 parse errors, and a sum of149per-file record counts equal to the manifest total.150151\paragraph{Entity ledger.} The small entity snapshots (topics, subfields, fields, domains, sources,152institutions, publishers, funders, concepts) are listed in \texttt{entities\_\allowbreak ledger.\allowbreak json} with, per file, the153entity, the local path, the byte count, the SHA-256 and the status.154155\paragraph{DBLP checksum.} The DBLP dump is distributed with an \texttt{.md5} file; the downloaded156\texttt{dblp.\allowbreak xml.\allowbreak gz} was verified against it (\texttt{ff1c424c3b4cef36582f647c36df27c0}). The parse report157(\texttt{dblp\_\allowbreak parse\_\allowbreak report.\allowbreak json}) additionally records the input path, its size in bytes, an MD5 of its158first GiB (the file is 1.12~GB, so this digest is not the published one and is a convenience for detecting a159changed input), the parse timestamp, per-type and per-year record counts, and timings.160161\paragraph{Verbatim OAI-PMH pages.} The arXiv harvest stores every XML response page as received under162\texttt{data/\allowbreak raw/\allowbreak arxiv/\allowbreak raw/\allowbreak <window>/\allowbreak page\_\allowbreak NNNN.\allowbreak xml} (758 pages for the monthly windows from 2018-01 to1632026-11), together with a harvest state file that allows resumption by window and a parse report; the164Parquet table can be rebuilt from the pages alone with \texttt{--parse-only}. Because OAI selects by record165\emph{datestamp}, a record updated in several windows appears in several pages; the parser keeps the latest.166167\paragraph{API ledger.} The OpenAlex API increment (works with a CS topic published between 2026-10-01 and1682026-11-02, fetched after the snapshot) stores every JSON page verbatim under \texttt{api\_\allowbreak increment/\allowbreak pages/\allowbreak }169and a ledger (\texttt{api\_\allowbreak increment/\allowbreak ledger.\allowbreak json}) with the slices requested (day $\times$ CS-primary or not),170the number of calls and the cost charged against the public budget; without an API key the harvest is paged171by day with at most 10{,}000 results per slice and spread over several days.172173\paragraph{Step reports and generated numbers.} Each processing step writes a machine-readable report:174\texttt{linkage\_\allowbreak report.\allowbreak json} (counts of keys, links by method, unlinked records by type, identifiers needed175for the second pass), \texttt{prisma\_\allowbreak counts.\allowbreak json} (every PRISMA stage, with an identity check that the176records loaded equal the sum of sequential exclusions and the remainder), \texttt{classification\_\allowbreak report.\allowbreak json}177(ontology version, works scored, works classified, timestamp), one embedding manifest per host (model,178maximum sequence length, device, and per shard the number of texts, the seconds taken and the timestamp),179and the validation metrics. The macros of \texttt{manuscript/\allowbreak tables/\allowbreak numbers.\allowbreak tex} are generated from these180files by \texttt{tables/\allowbreak make\_\allowbreak numbers.\allowbreak py}; a number whose source file is missing yields an undefined macro181and therefore a compilation error, which is intended: the prose cannot cite a number that no result file182contains.183184\subsection{Incident log and its implications}185\label{app:repro-incidents}186187Six incidents were recorded during the first run (\texttt{reports/\allowbreak INCIDENTS.\allowbreak md}); none caused data loss,188because every step is resumable from its ledger or its shard files, but three of them changed how the189pipeline must be run and are therefore part of the reproduction instructions.190191\begin{table}[htbp]192\begin{singlespace}193\centering194\caption{Incident log of the first run (\texttt{reports/\allowbreak INCIDENTS.\allowbreak md}; times in Eastern Time, 2026-11-03).}195\label{tab:appH-incidents}196\footnotesize197\begin{tabularx}{\textwidth}{l l X X}198\toprule199\# & When & What happened & Impact and recovery \\200\midrule201I-1 & $\approx$15:45 & Second snapshot pass with \texttt{--id-list}: worker processes had an empty identifier set, because the macOS \texttt{spawn} start method does not inherit module globals & 68 part files marked in error, no data loss; a pool initialiser now loads the identifier set in each worker; ledger reset and rerun \\202I-2 & $\approx$15:50 & DuckDB ``too many open files'' when reading 1{,}898 Parquet files per table & Linkage step failed; \texttt{compact\_\allowbreak tables.\allowbreak py} (one file per table) and \texttt{ulimit -n 65536} \\203I-3 & $\approx$16:30 & \texttt{multiprocessing.\allowbreak Pool} with pyarrow in spawned workers hung (0\,\% CPU) in the classifier & Test stalled 10~min; shard mode: independent processes started by \texttt{run\_\allowbreak classify\_\allowbreak shards.\allowbreak sh} \\204I-4 & $\approx$16:58 & M3U96b froze (no ping, SSH ``host is down'') while running the second pass (8 download-and-parse workers), the SPECTER2 embedding job on the GPU and earlier DuckDB jobs concurrently & Second pass ($\approx$1{,}400 of 1{,}898 files done), the chained corpus v2 and classification, and the node's embedding share interrupted; other embedding nodes unaffected; all jobs resumable; rule adopted: never run ingestion, embeddings and classification concurrently on one node \\205I-5 & 17:16 & M3U96b froze again two minutes after the second pass was restarted alone on the rebooted node & Pass~2 moved to the idle node M5M36 (10 workers, ledger copied); M3U96b reserved for DuckDB and classification; the chain now waits for a flag raised when the pass-2 outputs are copied back; Apple diagnostics show performance auto-bug-capture reports, no kernel panic found \\206I-6 & 17:17 & M4M64a froze a second time within two minutes of restarting its embedding share (batch 32); M3U96b rebooted in the same minute while running pass~2 alone & M4M64a embedding share lost again; M4M64a and M3U96b withdrawn from GPU and bulk-download work; shard ranges reassigned to M4M64c and M3U96a; pass~2 on M5M36 \\207\bottomrule208\end{tabularx}209\end{singlespace}210\end{table}211212Three implications follow for anyone reproducing the work. First, the parallelism in the scripts assumes213the \texttt{spawn} start method of macOS: worker state must be built in initialisers, and the classifier214should be run as independent shard processes rather than through a pool (\texttt{classify.\allowbreak py --shard i/\allowbreak N});215on Linux, where \texttt{fork} is the default, the pool mode may work but has not been exercised. Second, the216per-part Parquet layout exceeds default file-descriptor limits; the compaction step is mandatory, not an217optimisation. Third, the two freezes of the primary node occurred under concurrent download, parse, GPU218and database load, and their cause was not established from the system logs; the operational rule adopted219afterwards (one heavy job per node at a time) costs wall time but is the configuration under which the220reported outputs were produced, and the measured times of Table~\ref{tab:appH-steps} assume it. Because221every job writes its outputs atomically and records what it has completed, the state of the pipeline after222an interruption is recoverable from the ledgers alone, and the outputs of a resumed run are identical to223those of an uninterrupted one for all deterministic steps (ingestion, normalisation, linkage, corpus224definition, classification). The embedding step is the exception: shards were computed on several nodes and225devices, and the per-host manifests record for each shard where it was computed, so that any numerical226difference between devices can be traced; the embeddings are stored in half precision and are not claimed227to be bit-identical across hardware.228229\subsection{Protocol amendments}230\label{app:repro-amendments}231232The protocol was frozen on 2026-11-02 before any analysis of the corpus, and every later change is an233amendment with an identifier, a reason and an approver (\texttt{protocol/\allowbreak amendments.\allowbreak csv}). All six amendments234of Table~\ref{tab:appH-amendments} are approved by the executing agent and pending the principal235investigator's signature at the checkpoint of the corresponding phase; the manuscript marks the affected236conclusions accordingly.237238\begin{table}[htbp]239\begin{singlespace}240\centering241\caption{Protocol amendments (\texttt{protocol/\allowbreak amendments.\allowbreak csv}).}242\label{tab:appH-amendments}243\footnotesize244\begin{tabularx}{\textwidth}{l l l X X}245\toprule246Id & Date & Phase & Change & Reason \\247\midrule248A-000 & 2026-11-02 & 0 & \S14 of the mandate completed from \S1--\S13 & The pasted mandate was truncated by the terminal \\249A-001 & 2026-11-03 & 1 & Eligibility type list corrected: conference-paper and software-paper are kept; DBLP-linked records are kept whatever their type unless hard-excluded; XPAC records kept when DBLP-linked (\texttt{xpac\_\allowbreak kept\_\allowbreak dblp}) & The first run excluded 2.5~M conference-paper records (1.09~M DBLP-linked) through an outdated type list \\250A-002 & 2026-11-03 & 1 & Records whose primary source is a generic deposit platform are excluded unless DBLP- or arXiv-linked (E7); \texttt{date\_\allowbreak precision} added, monthly series use month-precision records only & Zenodo alone contributed 138{,}533 otherwise eligible 2026 records (deposits of slides, datasets and reports typed as articles); 18--28\,\% of records carry a year-only date \\251A-003 & 2026-11-03 & 2 & LLM rating budget for the taxonomy validation fixed at 25~USD (two raters, structured outputs) & Mandate \S7 requires agent-based validation with human checkpoints; the PI rates 200 works \\252A-004 & 2026-11-03 & 3 & Knowledge-graph extraction from abstracts of the high-priority set with \texttt{claude-sonnet-5-5}, provenance spans and machine verification of spans; budget 150~USD & Mandate \S6.4 requires provenance, confidence and verification status on every inferred relationship \\253A-005 & 2026-11-03 & 1 & Exclusion code E7 redefined as the generic-deposit exclusion; the CS penumbra is a membership flag, not an exclusion code & The Part~IV writer found the protocol and code labels inconsistent \\254\bottomrule255\end{tabularx}256\end{singlespace}257\end{table}258259\subsection{Sources, licences and what is redistributed}260\label{app:repro-licences}261262Table~\ref{tab:appH-raw} lists each raw source as obtained, with its size, integrity record and licence.263Nothing under \texttt{data/\allowbreak raw/\allowbreak } or \texttt{data/\allowbreak processed/\allowbreak } is committed to the repository264(\texttt{.gitignore} excludes both, together with every Parquet and JSONL file, except the provenance265\texttt{README} and the metadata directory); the copies live on the compute node. What the released266repository contains is the code, the ontology and its audit table, the manifests, ledgers and hashes, the267PRISMA counts and the linkage report, the aggregated result tables, the figures, the generated number macros268and the manuscript (protocol \S P8). Record-level derived tables may be released where the source licence269permits: OpenAlex is CC0, DBLP is ODC-BY~1.0, arXiv metadata obtained through OAI-PMH is under the CC0270terms of that feed, and the ACL Anthology is CC~BY~4.0; a derived record table therefore carries the271attribution required by ODC-BY and CC~BY for the DBLP and ACL fields it contains. Full texts are never272redistributed and were never obtained through paywalls. The Semantic Scholar Academic Graph was not used:273bulk access requires an API key that was not available and anonymous calls were refused, and the mandate's274instruction to record inaccessible data explicitly is satisfied by this note; influential-citation and275citation-intent signals derived from that graph are consequently absent from the analyses.276277\begin{table}[htbp]278\begin{singlespace}279\centering280\caption{Raw sources as obtained (\texttt{data/\allowbreak raw/\allowbreak README.\allowbreak md}), with integrity record and licence.}281\label{tab:appH-raw}282\footnotesize283\begin{tabularx}{\textwidth}{p{2.6cm} X p{3.6cm} p{2.0cm}}284\toprule285Source & What was obtained, when, size & Integrity & Licence \\286\midrule287OpenAlex works snapshot, release 2026-10-14 & \texttt{data/\allowbreak jsonl/\allowbreak works/\allowbreak }: 1{,}898 part files, 464{,}765{,}485 works, 675.3~GB gzip; streamed 2026-11-02 21:19--23:05~ET over HTTPS with 8 parallel streams; retained: CS subset 20~GB (15{,}490{,}159 records) and slim table 9.3~GB (all works) & manifest; per-file content length and SHA-256 in \texttt{works/\allowbreak ledger.\allowbreak sqlite} (1{,}898/1{,}898 ok, 0 parse errors, record total = manifest total) & CC0 \\288OpenAlex entity snapshots & topics 4{,}516; subfields 252; fields 26; domains 4; sources 268{,}629; institutions 143{,}455; publishers 10{,}713; funders 41{,}799; concepts 65{,}026; 2026-11-02; 0.6~GB & \texttt{entities\_\allowbreak ledger.\allowbreak json} (SHA-256 per file) & CC0 \\289OpenAlex API increment & works with any CS topic, publication date 2026-10-01 to 2026-11-02, sliced by day and CS-primary status, basic paging $\le$10{,}000 per slice; from 2026-11-03 (public budget 0.10~USD/day, several days) & raw JSON pages; \texttt{api\_\allowbreak increment/\allowbreak ledger.\allowbreak json} (counts, cost) & CC0 \\290DBLP & \texttt{dblp.\allowbreak xml.\allowbreak gz} (2026-11-02 22:39~UTC), \texttt{dblp.\allowbreak dtd}, \texttt{.md5}; 1.12~GB & MD5 \texttt{ff1c424c\ldots27c0} verified; parse report (8{,}840{,}866 records) & ODC-BY 1.0 \\291arXiv OAI-PMH & set \texttt{cs}, metadata format \texttt{arXiv}, datestamps 2018-01-01 to 2026-11-02 in monthly windows, raw XML pages kept; 2026-11-02/03 & 758 pages, 915{,}115 unique records; \texttt{harvest\_\allowbreak state.\allowbreak json}, parse report & CC0 (metadata) \\292ACL Anthology & \texttt{anthology+abstracts.\allowbreak bib.\allowbreak gz}; 2026-11-02; 46.7~MB, 138{,}796 entries & SHA-256 \texttt{44c3f7e9\ldots58e3} & CC BY 4.0 \\293\bottomrule294\end{tabularx}295\end{singlespace}296\end{table}297298\subsection{Minimal reproduction sequence}299\label{app:repro-minimal}300301A reader with a macOS or Linux machine, disk for the retained outputs (the CS subset and the slim table302occupy about 30~GB; the 675.3~GB of gzip parts are streamed and deleted after parsing unless303\texttt{--keep-raw} is given), memory for the DuckDB steps as configured (the scripts set304\texttt{memory\_\allowbreak limit} to 60--70~GB, to be lowered on smaller machines at the cost of time) and no305credentials can reproduce the corpus and the306bibliometric tables by creating the environment (\texttt{uv venv --python 3.\allowbreak 12 .\allowbreak venv \&\& uv pip install -r307requirements.\allowbreak txt}), downloading the manifest of the 2026-10-14 release, and running steps~1--11 of308Table~\ref{tab:appH-steps} in order, with the second pass of step~9 between steps~8 and~10. The snapshot309release is versioned, so a later release will not reproduce the counts; the manifest date is the parameter310that pins them. Steps~12 and~14 need no credentials but benefit from several nodes; step~13 and the311knowledge-graph extraction of amendment A-004 need an Anthropic API key and a budget of 25 and 150~USD312respectively, and their outputs (ratings, extracted edges) are released so that the downstream statistics313can be recomputed without re-rating. Step~15 regenerates every figure, table and number macro from the314result files, and step~16 compiles the manuscript; a missing result file surfaces as an undefined macro at315compilation, which is the intended way of detecting that a number has no source.316
Files · 3918d4e4926d8d1246df8fcc68d0c9d62046b20f
Menu

Theme