% ============================================================================ % Appendix E — Data dictionary % Written by Agent L (appendices A/E/H instance), 2026-11-03. Derived from the code that creates each table: % ingestion/openalex_snapshot.py (slim schema), ingestion/dblp_parse.py, ingestion/arxiv_oai.py, ingestion/acl_parse.py, % ingestion/build_corpus.py (schemas S), ingestion/link_sources.py (key and linkage tables), % systematic_review/define_corpus.py (corpus_works), bibliometrics/03_citation_impact.py (work_citation_windows), % knowledge_graph/01_citation_graph.py (edge tables), taxonomy/classify.py (classification tables), % embeddings/embed_corpus.py (embedding shards). Column names and types are those of the Arrow schemas or of the % DuckDB statements; "source" gives the OpenAlex JSON path or the derivation. No corpus number appears here. % ============================================================================ \section{Data Dictionary} \label{app:datadict} This appendix defines every column of every table that the analyses of Parts~VIII--IX read, in the order in which the pipeline creates them (Appendix~\ref{app:repro} gives the commands). The dictionary was derived from the code rather than from the data: the Arrow schemas declared in the ingestion scripts and the \texttt{SELECT} lists of the DuckDB statements are the sources, and a column is described as the code computes it, including the conventions that the raw sources do not share (integer identifiers, lower-cased DOIs, booleans that are never null). A reader who wants to recompute an indicator of Part~IX should be able to do so from this appendix and the released aggregate tables without reading the scripts. \subsection{Conventions} \label{app:datadict-conventions} \paragraph{Identifiers.} OpenAlex identifiers are stored as integers with the entity letter removed: \texttt{https:/\allowbreak /\allowbreak openalex.\allowbreak org/\allowbreak W2741809807} becomes the \texttt{int64} value 2741809807, and the same rule applies to authors (A), institutions (I), sources (S), topics (T), subfields, fields, domains and funders (function \texttt{oid} in \texttt{build\_\allowbreak corpus.\allowbreak py}; a tail that is not numeric yields a null). DBLP records are identified by their DBLP key (\texttt{conf/\allowbreak nips/\allowbreak VaswaniSPUJGKP17}), arXiv records by the bare arXiv identifier without version suffix and in lower case (\texttt{2303.\allowbreak 08774}, \texttt{cs/\allowbreak 0112017}), ACL Anthology entries by their anthology identifier (\texttt{2020.\allowbreak acl-main.\allowbreak 207}). DOIs are stored without the \texttt{https:/\allowbreak /\allowbreak doi.\allowbreak org/\allowbreak } prefix and in lower case, on every side of every linkage. \paragraph{Types.} Types are Apache Arrow types as declared in the schemas (\texttt{int64}, \texttt{int32}, \texttt{int16}, \texttt{float32}, \texttt{bool}, \texttt{string}, \texttt{list}, \texttt{list}); DuckDB-created tables use the corresponding DuckDB types (\texttt{BIGINT}, \texttt{INTEGER}, \texttt{DOUBLE}, \texttt{BOOLEAN}, \texttt{VARCHAR}). Dates are ISO-8601 strings (\texttt{YYYY-MM-DD}); a missing date is null, never a sentinel. Booleans produced by \texttt{build\_\allowbreak corpus.\allowbreak py} are coerced with \texttt{bool()} and are therefore never null (a missing flag reads as false); booleans produced by DuckDB expressions can be null only where the definition says so. \paragraph{Files and views.} The normalised OpenAlex tables are written as one Zstandard-compressed Parquet file per snapshot part (\texttt{data/\allowbreak processed/\allowbreak tables/\allowbreak /\allowbreak .\allowbreak parquet}), then compacted into one file per table (\texttt{data/\allowbreak processed/\allowbreak compact/\allowbreak
.\allowbreak parquet}) because DuckDB could not open 1{,}898 files per table within the macOS file-descriptor limit (incident I-2, Appendix~\ref{app:repro}). The second snapshot pass writes the same tables with the suffix \texttt{\_\allowbreak p2}; \texttt{link\_\allowbreak sources.\allowbreak py} exposes each table as a DuckDB view \texttt{oa\_\allowbreak
} that unions the two passes by column name. The raw-source tables are exposed as \texttt{dblp\_\allowbreak raw}, \texttt{arxiv\_\allowbreak raw}, \texttt{acl\_\allowbreak raw} and \texttt{oa\_\allowbreak slim}. The database file is \texttt{data/\allowbreak processed/\allowbreak wp44.\allowbreak duckdb}; it is a derived artefact and is not redistributed, whereas every table it contains can be rebuilt from the Parquet files. \paragraph{Reading the tables.} Each dictionary table lists the column, its type, its definition and its source: an OpenAlex JSON path (for instance \texttt{primary\_\allowbreak topic.\allowbreak subfield.\allowbreak id}) for fields copied from the snapshot, a DBLP, arXiv-OAI or BibTeX element for the other sources, or the derivation for computed columns. Columns are listed in schema order. \subsection{Raw-source tables} \label{app:datadict-raw} The four raw sources are parsed once each into a Parquet table that keeps the source's own vocabulary; nothing is harmonised at this stage except the identifier conventions above. The OpenAlex \emph{slim} table is the only table that covers every work of the snapshot, not only computer science; it exists so that references to works outside the corpus can be resolved to a publication year, type and field (Section~\ref{app:datadict-graph}). \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.0cm} p{1.7cm} p{6.1cm} p{4.6cm}@{}} \caption{\texttt{slim} (\texttt{data/\allowbreak raw/\allowbreak openalex/\allowbreak works/\allowbreak slim/\allowbreak *.\allowbreak parquet}, compacted to \texttt{compact/\allowbreak slim\_\allowbreak all\_\allowbreak works.\allowbreak parquet}; DuckDB view \texttt{oa\_\allowbreak slim}): one row for every work of the OpenAlex snapshot (\texttt{openalex\_\allowbreak snapshot.\allowbreak py}, \texttt{SLIM\_\allowbreak SCHEMA}).} \label{tab:appE-slim}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{\texttt{slim} (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \texttt{id} & int64 & OpenAlex work identifier (letter stripped) & \texttt{id} \\ \texttt{doi} & string & DOI, lower case, prefix removed; null if absent & \texttt{doi} \\ \texttt{publication\_\allowbreak year} & int32 & Publication year & \texttt{publication\_\allowbreak year} \\ \texttt{publication\_\allowbreak date} & string & Publication date, \texttt{YYYY-MM-DD} & \texttt{publication\_\allowbreak date} \\ \texttt{type} & string & OpenAlex work type (article, preprint, conference-paper, \ldots) & \texttt{type} \\ \texttt{cited\_\allowbreak by\_\allowbreak count} & int32 & Citations received, all years, as of the snapshot & \texttt{cited\_\allowbreak by\_\allowbreak count} \\ \texttt{primary\_\allowbreak topic\_\allowbreak id} & int32 & Primary topic & \texttt{primary\_\allowbreak topic.\allowbreak id} \\ \texttt{primary\_\allowbreak subfield\_\allowbreak id} & int32 & Subfield of the primary topic & \texttt{primary\_\allowbreak topic.\allowbreak subfield.\allowbreak id} \\ \texttt{primary\_\allowbreak field\_\allowbreak id} & int32 & Field of the primary topic (17 = Computer Science) & \texttt{primary\_\allowbreak topic.\allowbreak field.\allowbreak id} \\ \texttt{primary\_\allowbreak domain\_\allowbreak id} & int32 & Domain of the primary topic & \texttt{primary\_\allowbreak topic.\allowbreak domain.\allowbreak id} \\ \texttt{cs\_\allowbreak any\_\allowbreak topic} & bool & True if any of the work's topics, or its primary topic, is in field~17 & \texttt{topics[].\allowbreak field.\allowbreak id}, \texttt{primary\_\allowbreak topic.\allowbreak field.\allowbreak id} \\ \texttt{is\_\allowbreak xpac} & bool & OpenAlex ``extended publication and citation'' flag (records of lower provenance) & \texttt{is\_\allowbreak xpac} \\ \texttt{is\_\allowbreak oa} & bool & Open-access flag & \texttt{open\_\allowbreak access.\allowbreak is\_\allowbreak oa} \\ \texttt{is\_\allowbreak retracted} & bool & Retraction flag & \texttt{is\_\allowbreak retracted} \\ \texttt{language} & string & ISO language code & \texttt{language} \\ \texttt{source\_\allowbreak id} & int64 & Source (venue) of the primary location & \texttt{primary\_\allowbreak location.\allowbreak source.\allowbreak id} \\ \texttt{n\_\allowbreak refs} & int32 & Number of referenced works & length of \texttt{referenced\_\allowbreak works} \\ \texttt{n\_\allowbreak authors} & int32 & Number of authors & \texttt{authors\_\allowbreak count}, else length of \texttt{authorships} \\ \texttt{has\_\allowbreak abstract} & bool & True if an inverted-index abstract is present & \texttt{abstract\_\allowbreak inverted\_\allowbreak index} $\neq$ null \\ \texttt{fwci} & float32 & Field-weighted citation impact as computed by OpenAlex & \texttt{fwci} \\ \end{longtable} \end{footnotesize} \end{singlespace} \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.0cm} p{1.7cm} p{6.1cm} p{4.6cm}@{}} \caption{\texttt{dblp\_\allowbreak publications} (\texttt{data/\allowbreak raw/\allowbreak dblp/\allowbreak dblp\_\allowbreak publications.\allowbreak parquet}; view \texttt{dblp\_\allowbreak raw}): one row per DBLP publication record of every year (\texttt{dblp\_\allowbreak parse.\allowbreak py}). Record types \texttt{www} are skipped.} \label{tab:appE-dblp}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{\texttt{dblp\_\allowbreak publications} (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \texttt{key} & string & DBLP record key, unique & element attribute \texttt{key} \\ \texttt{rec\_\allowbreak type} & string & Record type: article, inproceedings, proceedings, book, incollection, phdthesis, mastersthesis & element name \\ \texttt{mdate} & string & Last modification date of the record & attribute \texttt{mdate} \\ \texttt{publtype} & string & Publication sub-type (e.g.\ informal, survey, withdrawn); null if absent & attribute \texttt{publtype} \\ \texttt{title} & string & Title, inner markup flattened to text & \texttt{} \\ \texttt{year} & int32 & Year & \texttt{<year>} \\ \texttt{authors} & list<string> & Author names in order & \texttt{<author>} \\ \texttt{author\_\allowbreak pids} & list<string> & DBLP person identifiers of the authors & \texttt{<author pid=.\allowbreak .\allowbreak .\allowbreak >} \\ \texttt{editors} & list<string> & Editor names & \texttt{<editor>} \\ \texttt{journal} & string & Journal name (articles) & \texttt{<journal>} \\ \texttt{booktitle} & string & Proceedings or book title & \texttt{<booktitle>} \\ \texttt{volume}, \texttt{number}, \texttt{pages} & string & Bibliographic locators & \texttt{<volume>}, \texttt{<number>}, \texttt{<pages>} \\ \texttt{publisher}, \texttt{series} & string & Publisher and series & \texttt{<publisher>}, \texttt{<series>} \\ \texttt{doi} & string & DOI when DBLP records one & \texttt{<ee>} with a doi.org URL \\ \texttt{ee} & list<string> & Electronic-edition URLs (DOI, arXiv, publisher) & \texttt{<ee>} \\ \texttt{url} & string & DBLP-internal URL (table of contents) & \texttt{<url>} \\ \texttt{crossref} & string & Key of the enclosing proceedings or book & \texttt{<crossref>} \\ \texttt{stream} & string & Venue stream: the key with its last path component removed (\texttt{conf/\allowbreak nips}, \texttt{journals/\allowbreak corr}); null if the key has no slash & derived from \texttt{key} \\ \end{longtable} \end{footnotesize} \end{singlespace} \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.0cm} p{1.7cm} p{6.1cm} p{4.6cm}@{}} \caption{\texttt{arxiv\_\allowbreak cs} (\texttt{data/\allowbreak raw/\allowbreak arxiv/\allowbreak arxiv\_\allowbreak cs.\allowbreak parquet}; view \texttt{arxiv\_\allowbreak raw}): one row per arXiv record of set \texttt{cs} harvested by OAI-PMH with the \texttt{arXiv} metadata format (\texttt{arxiv\_\allowbreak oai.\allowbreak py}); records returned in several monthly windows are kept once, the latest datestamp winning.} \label{tab:appE-arxiv}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{\texttt{arxiv\_\allowbreak cs} (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \texttt{arxiv\_\allowbreak id} & string & arXiv identifier without version & \texttt{<id>} \\ \texttt{datestamp} & string & OAI datestamp (last update of the record) & header \texttt{<datestamp>} \\ \texttt{created} & string & Date of the first submitted version & \texttt{<created>} \\ \texttt{updated} & string & Date of the latest version & \texttt{<updated>} \\ \texttt{title}, \texttt{abstract} & string & Title and abstract & \texttt{<title>}, \texttt{<abstract>} \\ \texttt{authors} & list<string> & Author names & \texttt{<authors>/\allowbreak <author>} \\ \texttt{categories} & list<string> & All categories (primary first, then cross-lists) & \texttt{<categories>} \\ \texttt{primary\_\allowbreak category} & string & First category & first token of \texttt{<categories>} \\ \texttt{comments}, \texttt{journal\_\allowbreak ref} & string & Author comments and journal reference & \texttt{<comments>}, \texttt{<journal-ref>} \\ \texttt{doi} & string & DOI declared by the authors & \texttt{<doi>} \\ \texttt{license} & string & Licence URL of the e-print & \texttt{<license>} \\ \texttt{report\_\allowbreak no}, \texttt{msc\_\allowbreak class}, \texttt{acm\_\allowbreak class} & string & Report number, MSC and ACM classes & corresponding elements \\ \texttt{set\_\allowbreak specs} & list<string> & OAI set memberships & header \texttt{<setSpec>} \\ \end{longtable} \end{footnotesize} \end{singlespace} \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.0cm} p{1.7cm} p{6.1cm} p{4.6cm}@{}} \caption{\texttt{acl\_\allowbreak anthology} (\texttt{data/\allowbreak raw/\allowbreak acl/\allowbreak acl\_\allowbreak anthology.\allowbreak parquet}; view \texttt{acl\_\allowbreak raw}): one row per entry of the ACL Anthology BibTeX export with abstracts (\texttt{acl\_\allowbreak parse.\allowbreak py}). All fields are strings copied from the BibTeX entry; braces are removed.} \label{tab:appE-acl}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{\texttt{acl\_\allowbreak anthology} (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \texttt{acl\_\allowbreak id} & string & Anthology identifier (BibTeX citation key) & entry key \\ \texttt{entry\_\allowbreak type} & string & BibTeX entry type (inproceedings, article, proceedings, \ldots), lower case & entry type \\ \texttt{title}, \texttt{author}, \texttt{editor} & string & Title, author list, editor list as written in BibTeX & fields \\ \texttt{booktitle}, \texttt{journal} & string & Venue & fields \\ \texttt{month}, \texttt{year} & string & Month and year (year is cast to integer in \texttt{acl\_\allowbreak keys}) & fields \\ \texttt{address}, \texttt{publisher} & string & Place and publisher & fields \\ \texttt{url}, \texttt{doi} & string & Anthology URL and DOI & fields \\ \texttt{pages}, \texttt{volume}, \texttt{number} & string & Locators & fields \\ \texttt{abstract} & string & Abstract when the export carries one & field \\ \end{longtable} \end{footnotesize} \end{singlespace} \subsection{Normalised OpenAlex tables} \label{app:datadict-openalex} \texttt{build\_\allowbreak corpus.\allowbreak py} reads the full JSON record of every work retained by the snapshot filter (any topic in field~17 and publication year 2018--2026, or, in the second pass, membership of the list of DBLP- and arXiv-linked identifiers) and writes nine relational tables. The \texttt{works} table has one row per work; the eight others are one-to-many and are keyed by \texttt{work\_\allowbreak id}. Nested JSON is flattened without loss of the fields used downstream; fields not listed here (for instance \texttt{sustainable\_\allowbreak development\_\allowbreak goals}, \texttt{mesh}, \texttt{concepts}) are not extracted. \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.0cm} p{4.6cm}@{}} \caption{\texttt{works} (\texttt{compact/\allowbreak works.\allowbreak parquet}; view \texttt{oa\_\allowbreak works}): one row per OpenAlex work of the CS extraction (\texttt{build\_\allowbreak corpus.\allowbreak py}, schema \texttt{S["works"]}).} \label{tab:appE-works}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{\texttt{works} (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \texttt{id} & int64 & Work identifier & \texttt{id} \\ \texttt{doi} & string & DOI, lower case, prefix removed; null if empty & \texttt{doi} \\ \texttt{title} & string & Title; \texttt{display\_\allowbreak name} when \texttt{title} is absent & \texttt{title}, \texttt{display\_\allowbreak name} \\ \texttt{publication\_\allowbreak year} & int32 & Publication year & \texttt{publication\_\allowbreak year} \\ \texttt{publication\_\allowbreak date} & string & Publication date; OpenAlex sets \texttt{YYYY-01-01} when only the year is known (see \texttt{date\_\allowbreak precision}, Table~\ref{tab:appE-corpus}) & \texttt{publication\_\allowbreak date} \\ \texttt{created\_\allowbreak date} & string & Date the record entered OpenAlex (used for indexing-lag diagnostics) & \texttt{created\_\allowbreak date} \\ \texttt{updated\_\allowbreak date} & string & Last update, date part only & \texttt{updated\_\allowbreak date[:10]} \\ \texttt{type} & string & OpenAlex work type & \texttt{type} \\ \texttt{type\_\allowbreak crossref} & string & Crossref type when the record has one & \texttt{type\_\allowbreak crossref} \\ \texttt{language} & string & ISO language code & \texttt{language} \\ \texttt{cited\_\allowbreak by\_\allowbreak count} & int32 & Citations received, all years, at snapshot date & \texttt{cited\_\allowbreak by\_\allowbreak count} \\ \texttt{fwci} & float32 & OpenAlex field-weighted citation impact & \texttt{fwci} \\ \texttt{citation\_\allowbreak percentile} & float32 & Citation-normalised percentile & \texttt{citation\_\allowbreak normalized\_\allowbreak percentile.\allowbreak value} \\ \texttt{is\_\allowbreak top1}, \texttt{is\_\allowbreak top10} & bool & Top 1\,\% / top 10\,\% flags of that percentile & \texttt{...is\_\allowbreak in\_\allowbreak top\_\allowbreak 1\_\allowbreak percent}, \texttt{...is\_\allowbreak in\_\allowbreak top\_\allowbreak 10\_\allowbreak percent} \\ \texttt{is\_\allowbreak oa} & bool & Open-access flag & \texttt{open\_\allowbreak access.\allowbreak is\_\allowbreak oa} \\ \texttt{oa\_\allowbreak status} & string & gold, green, hybrid, bronze, diamond, closed & \texttt{open\_\allowbreak access.\allowbreak oa\_\allowbreak status} \\ \texttt{license} & string & Licence of the best OA location, else of the primary location & \texttt{best\_\allowbreak oa\_\allowbreak location.\allowbreak license}, \texttt{primary\_\allowbreak location.\allowbreak license} \\ \texttt{is\_\allowbreak retracted} & bool & Retraction flag & \texttt{is\_\allowbreak retracted} \\ \texttt{is\_\allowbreak paratext} & bool & Paratext flag (front matter, tables of contents) & \texttt{is\_\allowbreak paratext} \\ \texttt{is\_\allowbreak xpac} & bool & Extended-provenance flag & \texttt{is\_\allowbreak xpac} \\ \texttt{n\_\allowbreak refs} & int32 & Number of referenced works in the record & length of \texttt{referenced\_\allowbreak works} \\ \texttt{n\_\allowbreak authors} & int32 & Number of authors & \texttt{authors\_\allowbreak count}, else length of \texttt{authorships} \\ \texttt{n\_\allowbreak institutions} & int32 & Number of distinct institution identifiers over all authorships & \texttt{authorships[].\allowbreak institutions[].\allowbreak id} \\ \texttt{n\_\allowbreak countries} & int32 & Number of distinct country codes over all authorships & \texttt{authorships[].\allowbreak countries} \\ \texttt{countries} & list<string> & Sorted distinct country codes & \texttt{authorships[].\allowbreak countries} \\ \texttt{institution\_\allowbreak types} & list<string> & Sorted distinct institution types (education, company, government, \ldots) & \texttt{authorships[].\allowbreak institutions[].\allowbreak type} \\ \texttt{primary\_\allowbreak topic\_\allowbreak id} & int32 & Primary topic & \texttt{primary\_\allowbreak topic.\allowbreak id} \\ \texttt{primary\_\allowbreak subfield\_\allowbreak id} & int32 & Subfield of the primary topic & \texttt{primary\_\allowbreak topic.\allowbreak subfield.\allowbreak id} \\ \texttt{primary\_\allowbreak field\_\allowbreak id} & int32 & Field of the primary topic & \texttt{primary\_\allowbreak topic.\allowbreak field.\allowbreak id} \\ \texttt{primary\_\allowbreak domain\_\allowbreak id} & int32 & Domain of the primary topic & \texttt{primary\_\allowbreak topic.\allowbreak domain.\allowbreak id} \\ \texttt{cs\_\allowbreak primary} & bool & Primary topic in field~17 & \texttt{primary\_\allowbreak topic.\allowbreak field.\allowbreak id} \\ \texttt{cs\_\allowbreak any} & bool & Any topic in field~17 & \texttt{topics[].\allowbreak field.\allowbreak id} \\ \texttt{source\_\allowbreak id} & int64 & Venue of the primary location & \texttt{primary\_\allowbreak location.\allowbreak source.\allowbreak id} \\ \texttt{source\_\allowbreak name} & string & Venue name & \texttt{primary\_\allowbreak location.\allowbreak source.\allowbreak display\_\allowbreak name} \\ \texttt{source\_\allowbreak type} & string & journal, conference, repository, ebook platform, \ldots & \texttt{primary\_\allowbreak location.\allowbreak source.\allowbreak type} \\ \texttt{host\_\allowbreak organization} & string & Publisher or host organisation of the venue & \texttt{primary\_\allowbreak location.\allowbreak source.\allowbreak host\_\allowbreak organization\_\allowbreak name} \\ \texttt{is\_\allowbreak in\_\allowbreak doaj} & bool & Venue listed in DOAJ & \texttt{primary\_\allowbreak location.\allowbreak source.\allowbreak is\_\allowbreak in\_\allowbreak doaj} \\ \texttt{arxiv\_\allowbreak id} & string & arXiv identifier: from \texttt{ids.\allowbreak arxiv}; else from a DOI of the form \texttt{10.\allowbreak 48550/\allowbreak arxiv.\allowbreak <id>}; else from an \texttt{arxiv.\allowbreak org/\allowbreak abs} or \texttt{/\allowbreak pdf} URL among the locations, version suffix removed & \texttt{ids.\allowbreak arxiv}, \texttt{doi}, \texttt{locations[].\allowbreak landing\_\allowbreak page\_\allowbreak url}, \texttt{locations[].\allowbreak pdf\_\allowbreak url} \\ \texttt{pmid} & string & PubMed identifier (tail of the URL) & \texttt{ids.\allowbreak pmid} \\ \texttt{mag} & string & Microsoft Academic Graph identifier & \texttt{ids.\allowbreak mag} \\ \texttt{has\_\allowbreak abstract} & bool & An abstract could be reconstructed & \texttt{abstract\_\allowbreak inverted\_\allowbreak index} \\ \texttt{has\_\allowbreak fulltext} & bool & OpenAlex has indexed full text & \texttt{has\_\allowbreak fulltext} or \texttt{has\_\allowbreak content} \\ \texttt{n\_\allowbreak locations} & int32 & Number of locations (hosting copies) & length of \texttt{locations} \\ \texttt{indexed\_\allowbreak in} & list<string> & Indexes that list the work (crossref, pubmed, doaj, arxiv, \ldots) & \texttt{indexed\_\allowbreak in} \\ \texttt{referenced\_\allowbreak works\_\allowbreak count} & int32 & Reference count declared by OpenAlex; falls back to \texttt{n\_\allowbreak refs} & \texttt{referenced\_\allowbreak works\_\allowbreak count} \\ \texttt{n\_\allowbreak grants} & int32 & Number of grant entries & length of \texttt{grants} \\ \texttt{apc\_\allowbreak paid\_\allowbreak usd} & int32 & Article-processing charge paid, USD, when known & \texttt{apc\_\allowbreak paid.\allowbreak value\_\allowbreak usd} \\ \texttt{is\_\allowbreak authors\_\allowbreak truncated} & bool & Author list truncated by OpenAlex & \texttt{is\_\allowbreak authors\_\allowbreak truncated} \\ \texttt{part} & string & Snapshot part file of origin (\texttt{updated\_\allowbreak date=...\_\allowbreak \_\allowbreak part\_\allowbreak NNNN}) & file name \\ \end{longtable} \end{footnotesize} \end{singlespace} \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.0cm} p{4.6cm}@{}} \caption{\texttt{authorships} (view \texttt{oa\_\allowbreak authorships}): one row per (work, author position).} \label{tab:appE-authorships}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{\texttt{authorships} (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \texttt{work\_\allowbreak id} & int64 & Work & \texttt{id} of the work \\ \texttt{position} & int32 & Zero-based index in the authorship list & list index \\ \texttt{author\_\allowbreak position} & string & first, middle or last & \texttt{authorships[].\allowbreak author\_\allowbreak position} \\ \texttt{author\_\allowbreak id} & int64 & OpenAlex author & \texttt{authorships[].\allowbreak author.\allowbreak id} \\ \texttt{author\_\allowbreak name} & string & Author display name & \texttt{authorships[].\allowbreak author.\allowbreak display\_\allowbreak name} \\ \texttt{orcid} & string & ORCID URL when known & \texttt{authorships[].\allowbreak author.\allowbreak orcid} \\ \texttt{is\_\allowbreak corresponding} & bool & Corresponding-author flag & \texttt{authorships[].\allowbreak is\_\allowbreak corresponding} \\ \texttt{institution\_\allowbreak ids} & list<int64> & Institutions of this authorship, in order & \texttt{authorships[].\allowbreak institutions[].\allowbreak id} \\ \texttt{institution\_\allowbreak names} & list<string> & Their display names & \texttt{...institutions[].\allowbreak display\_\allowbreak name} \\ \texttt{institution\_\allowbreak types} & list<string> & Their types & \texttt{...institutions[].\allowbreak type} \\ \texttt{countries} & list<string> & Country codes of this authorship & \texttt{authorships[].\allowbreak countries} \\ \texttt{n\_\allowbreak raw\_\allowbreak affiliations} & int32 & Number of raw affiliation strings & length of \texttt{authorships[].\allowbreak raw\_\allowbreak affiliation\_\allowbreak strings} \\ \end{longtable} \end{footnotesize} \end{singlespace} \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.0cm} p{4.6cm}@{}} \caption{Small one-to-many tables of the CS extraction: \texttt{work\_\allowbreak topics}, \texttt{work\_\allowbreak keywords}, \texttt{references}, \texttt{abstracts}, \texttt{grants}, \texttt{counts\_\allowbreak by\_\allowbreak year} (views \texttt{oa\_\allowbreak <table>}). Every table carries \texttt{work\_\allowbreak id} (int64) as its first column.} \label{tab:appE-small}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{Small one-to-many tables (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \multicolumn{4}{@{}l}{\textit{\texttt{work\_\allowbreak topics}: one row per topic of the work, at most three}} \\ \texttt{rank} & int16 & Zero-based position in the topic list (0 = primary) & list index \\ \texttt{topic\_\allowbreak id} & int32 & Topic & \texttt{topics[].\allowbreak id} \\ \texttt{score} & float32 & OpenAlex topic score & \texttt{topics[].\allowbreak score} \\ \texttt{subfield\_\allowbreak id}, \texttt{field\_\allowbreak id}, \texttt{domain\_\allowbreak id} & int32 & Hierarchy of the topic & \texttt{topics[].\allowbreak subfield.\allowbreak id}, \texttt{.field.\allowbreak id}, \texttt{.domain.\allowbreak id} \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{work\_\allowbreak keywords}: one row per OpenAlex keyword}} \\ \texttt{keyword} & string & Keyword display name & \texttt{keywords[].\allowbreak display\_\allowbreak name} \\ \texttt{score} & float32 & Keyword score & \texttt{keywords[].\allowbreak score} \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{references}: one row per referenced work (the citation graph)}} \\ \texttt{ref\_\allowbreak id} & int64 & Cited work identifier; may lie outside the CS extraction & \texttt{referenced\_\allowbreak works[]} \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{abstracts}: one row per work with an abstract}} \\ \texttt{abstract} & string & Abstract text rebuilt by sorting the inverted index by position and joining with spaces & \texttt{abstract\_\allowbreak inverted\_\allowbreak index} \\ \texttt{n\_\allowbreak words} & int32 & Number of whitespace-separated tokens & derived \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{grants}: one row per grant entry}} \\ \texttt{funder\_\allowbreak id} & int64 & Funder & \texttt{grants[].\allowbreak funder} \\ \texttt{funder\_\allowbreak name} & string & Funder name & \texttt{grants[].\allowbreak funder\_\allowbreak display\_\allowbreak name} \\ \texttt{award\_\allowbreak id} & string & Award identifier & \texttt{grants[].\allowbreak award\_\allowbreak id} \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{counts\_\allowbreak by\_\allowbreak year}: one row per (work, calendar year) with citations received}} \\ \texttt{year} & int16 & Calendar year of the citing works & \texttt{counts\_\allowbreak by\_\allowbreak year[].\allowbreak year} \\ \texttt{cited\_\allowbreak by\_\allowbreak count} & int32 & Citations received in that year & \texttt{counts\_\allowbreak by\_\allowbreak year[].\allowbreak cited\_\allowbreak by\_\allowbreak count} \\ \end{longtable} \end{footnotesize} \end{singlespace} \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.0cm} p{4.6cm}@{}} \caption{\texttt{locations} (view \texttt{oa\_\allowbreak locations}): one row per hosting location of the work.} \label{tab:appE-locations}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{\texttt{locations} (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \texttt{work\_\allowbreak id} & int64 & Work & \texttt{id} of the work \\ \texttt{rank} & int16 & Zero-based position in the location list & list index \\ \texttt{is\_\allowbreak primary} & bool & Landing-page and PDF URLs equal those of \texttt{primary\_\allowbreak location} & derived \\ \texttt{is\_\allowbreak best\_\allowbreak oa} & bool & Landing-page URL equals that of \texttt{best\_\allowbreak oa\_\allowbreak location} & derived \\ \texttt{source\_\allowbreak id}, \texttt{source\_\allowbreak name}, \texttt{source\_\allowbreak type} & int64, string & Venue of the location & \texttt{locations[].\allowbreak source.\allowbreak id}, \texttt{.display\_\allowbreak name}, \texttt{.type} \\ \texttt{landing\_\allowbreak page\_\allowbreak url}, \texttt{pdf\_\allowbreak url} & string & URLs & \texttt{locations[].\allowbreak landing\_\allowbreak page\_\allowbreak url}, \texttt{.pdf\_\allowbreak url} \\ \texttt{is\_\allowbreak oa} & bool & Location is open access & \texttt{locations[].\allowbreak is\_\allowbreak oa} \\ \texttt{license} & string & Licence of this copy & \texttt{locations[].\allowbreak license} \\ \texttt{version} & string & submittedVersion, acceptedVersion or publishedVersion & \texttt{locations[].\allowbreak version} \\ \texttt{is\_\allowbreak accepted}, \texttt{is\_\allowbreak published} & bool & Version flags & \texttt{locations[].\allowbreak is\_\allowbreak accepted}, \texttt{.is\_\allowbreak published} \\ \end{longtable} \end{footnotesize} \end{singlespace} \subsection{Key tables and linkage tables} \label{app:datadict-linkage} \texttt{link\_\allowbreak sources.\allowbreak py} derives from each source a \emph{key table} that carries only the identifiers used for matching, in the shared conventions of Section~\ref{app:datadict-conventions}, and then builds three linkage tables by the cascade of Section~\ref{sec:m-cascade}. In every key table \texttt{ntitle} is the title in lower case with every run of characters other than \texttt{a--z} and \texttt{0--9} removed, and \texttt{tlen} is the length of the original title; title matching requires \texttt{tlen} $\ge 25$ and a normalised title that is unique on both sides. \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.0cm} p{4.6cm}@{}} \caption{Key tables (DuckDB tables \texttt{oa\_\allowbreak keys}, \texttt{dblp\_\allowbreak keys}, \texttt{arxiv\_\allowbreak keys}, \texttt{acl\_\allowbreak keys}).} \label{tab:appE-keys}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{Key tables (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \multicolumn{4}{@{}l}{\textit{\texttt{oa\_\allowbreak keys}: every work of \texttt{oa\_\allowbreak works} (both passes)}} \\ \texttt{oa\_\allowbreak id} & BIGINT & Work identifier & \texttt{oa\_\allowbreak works.\allowbreak id} \\ \texttt{doi} & VARCHAR & DOI & \texttt{oa\_\allowbreak works.\allowbreak doi} \\ \texttt{arxiv\_\allowbreak id} & VARCHAR & arXiv identifier, lower case, version suffix removed & \texttt{oa\_\allowbreak works.\allowbreak arxiv\_\allowbreak id} \\ \texttt{year} & INTEGER & Publication year & \texttt{oa\_\allowbreak works.\allowbreak publication\_\allowbreak year} \\ \texttt{ntitle}, \texttt{tlen} & VARCHAR, INTEGER & Normalised title and original title length & \texttt{oa\_\allowbreak works.\allowbreak title} \\ \texttt{type} & VARCHAR & OpenAlex type & \texttt{oa\_\allowbreak works.\allowbreak type} \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{dblp\_\allowbreak keys}: DBLP records with year 2018--2026 and type article, inproceedings, incollection, book, phdthesis or data}} \\ \texttt{dblp\_\allowbreak key} & VARCHAR & DBLP key & \texttt{dblp\_\allowbreak raw.\allowbreak key} \\ \texttt{rec\_\allowbreak type}, \texttt{year} & VARCHAR, INTEGER & Record type and year & \texttt{dblp\_\allowbreak raw} \\ \texttt{doi} & VARCHAR & DOI & \texttt{dblp\_\allowbreak raw.\allowbreak doi} \\ \texttt{arxiv\_\allowbreak id} & VARCHAR & arXiv identifier extracted from an \texttt{arxiv.\allowbreak org/\allowbreak abs/\allowbreak } URL among \texttt{ee}, version removed; null when none & \texttt{dblp\_\allowbreak raw.\allowbreak ee} \\ \texttt{ntitle}, \texttt{tlen} & VARCHAR, INTEGER & Normalised title and length & \texttt{dblp\_\allowbreak raw.\allowbreak title} \\ \texttt{stream} & VARCHAR & Venue stream & \texttt{dblp\_\allowbreak raw.\allowbreak stream} \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{arxiv\_\allowbreak keys}: every record of \texttt{arxiv\_\allowbreak raw}}} \\ \texttt{arxiv\_\allowbreak id} & VARCHAR & Identifier, lower case & \texttt{arxiv\_\allowbreak raw.\allowbreak arxiv\_\allowbreak id} \\ \texttt{created}, \texttt{created\_\allowbreak year} & VARCHAR, INTEGER & First-submission date and its year & \texttt{arxiv\_\allowbreak raw.\allowbreak created} \\ \texttt{doi} & VARCHAR & Declared DOI & \texttt{arxiv\_\allowbreak raw.\allowbreak doi} \\ \texttt{primary\_\allowbreak category}, \texttt{categories} & VARCHAR, list & Categories & \texttt{arxiv\_\allowbreak raw} \\ \texttt{ntitle} & VARCHAR & Normalised title & \texttt{arxiv\_\allowbreak raw.\allowbreak title} \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{acl\_\allowbreak keys}: entries of type inproceedings or article}} \\ \texttt{acl\_\allowbreak id} & VARCHAR & Anthology identifier & \texttt{acl\_\allowbreak raw.\allowbreak acl\_\allowbreak id} \\ \texttt{year} & INTEGER & Year (\texttt{try\_\allowbreak cast}; null if not numeric) & \texttt{acl\_\allowbreak raw.\allowbreak year} \\ \texttt{doi} & VARCHAR & DOI, lower case & \texttt{acl\_\allowbreak raw.\allowbreak doi} \\ \texttt{url}, \texttt{ntitle}, \texttt{entry\_\allowbreak type} & VARCHAR & URL, normalised title, entry type & \texttt{acl\_\allowbreak raw} \\ \end{longtable} \end{footnotesize} \end{singlespace} \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.0cm} p{4.6cm}@{}} \caption{Linkage tables and the second-pass identifier list. Each linkage table has one row per matched pair; the cascade inserts a pair only when neither side is already linked by an earlier method (for \texttt{link\_\allowbreak arxiv\_\allowbreak oa} and \texttt{link\_\allowbreak acl\_\allowbreak oa}, when the source-side key is not already linked and, for title matches, the OpenAlex side is not either).} \label{tab:appE-links}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{Linkage tables (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \multicolumn{4}{@{}l}{\textit{\texttt{link\_\allowbreak dblp\_\allowbreak oa}}} \\ \texttt{dblp\_\allowbreak key}, \texttt{oa\_\allowbreak id} & VARCHAR, BIGINT & Matched DBLP record and OpenAlex work & key tables \\ \texttt{method} & VARCHAR & \texttt{doi} (equal DOIs); \texttt{arxiv} (equal arXiv identifiers, both sides unlinked); \texttt{title\_\allowbreak year} (unique normalised titles, $|\Delta\text{year}| \le 1$, and equal first-author surname when both sides have one) & cascade \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{link\_\allowbreak arxiv\_\allowbreak oa}}} \\ \texttt{arxiv\_\allowbreak id}, \texttt{oa\_\allowbreak id} & VARCHAR, BIGINT & Matched arXiv record and OpenAlex work & key tables \\ \texttt{method} & VARCHAR & \texttt{arxiv\_\allowbreak id} (equal identifiers); \texttt{doi}; \texttt{title\_\allowbreak year} (unique titles, $|\Delta\text{year}| \le 2$ between arXiv creation year and OpenAlex year) & cascade \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{link\_\allowbreak acl\_\allowbreak oa}}} \\ \texttt{acl\_\allowbreak id}, \texttt{oa\_\allowbreak id} & VARCHAR, BIGINT & Matched ACL entry and OpenAlex work & key tables \\ \texttt{method} & VARCHAR & \texttt{doi}; \texttt{url} (an OpenAlex location whose landing page is \texttt{aclanthology.\allowbreak org/\allowbreak <acl\_\allowbreak id>}); \texttt{title\_\allowbreak year} (unique titles, $|\Delta\text{year}| \le 1$) & cascade, \texttt{oa\_\allowbreak locations} \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{needed\_\allowbreak oa\_\allowbreak ids}: identifiers extracted in the second snapshot pass}} \\ \texttt{oa\_\allowbreak id} & BIGINT & Work present in \texttt{oa\_\allowbreak slim} but absent from the CS extraction & \texttt{oa\_\allowbreak slim.\allowbreak id} \\ \texttt{why} & VARCHAR & \texttt{dblp\_\allowbreak doi} (DOI of an unlinked DBLP record) or \texttt{arxiv\_\allowbreak doi} (DOI of an unlinked arXiv record) & derivation \\ \end{longtable} \end{footnotesize} \end{singlespace} The linkage report (\texttt{data/\allowbreak metadata/\allowbreak linkage\_\allowbreak report.\allowbreak json}) records, for each source, the number of keys, the number of keys with a DOI or an arXiv identifier, the links by method, the number of distinct linked keys, the unlinked records by type, the unlinked DBLP records whose DOI nevertheless resolves in the slim table (the trigger for the second pass), the identifiers needed for the second pass by reason, the size of the slim table and the number of slim rows with a CS topic in 2018--2026. These are the quantities quoted in Part~III through the \texttt{\textbackslash Link*} macros. \subsection{The corpus table} \label{app:datadict-corpus} \texttt{define\_\allowbreak corpus.\allowbreak py} creates \texttt{corpus\_\allowbreak works} (also exported to \texttt{data/\allowbreak processed/\allowbreak corpus/\allowbreak corpus\_\allowbreak works.\allowbreak parquet}) from \texttt{oa\_\allowbreak works}, adding the membership, dating, duplicate and eligibility columns of Table~\ref{tab:appE-corpus}. The constants are those of the protocol: the observation window is 2018-01-01 to 2026-11-02 with the boundary 2022-11-30; the kept types are article, conference-paper, preprint, book-chapter, book, dissertation, report, review and software-paper; the hard-excluded types, which exclude even a DBLP-linked record, are editorial, erratum, retraction, peer-review, paratext, conference-abstract, reference-entry, dataset, software, supplementary-materials, libguides, letter, grant and standard; the generic deposit platforms of amendment A-002 are Zenodo, Figshare, IRDB, LA~Referencia, Dialnet, DOAJ-as-source and OSTI. Every row of \texttt{oa\_\allowbreak works} is present, including excluded ones, so that PRISMA counts can be recomputed from the flags. \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.6cm} p{4.0cm}@{}} \caption{\texttt{corpus\_\allowbreak works}: columns added to those of \texttt{works} (Table~\ref{tab:appE-works}).} \label{tab:appE-corpus}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{\texttt{corpus\_\allowbreak works} (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \texttt{ntitle} & VARCHAR & Normalised title & \texttt{title} \\ \texttt{in\_\allowbreak dblp} & BOOLEAN & The work is linked to a DBLP record & \texttt{link\_\allowbreak dblp\_\allowbreak oa} \\ \texttt{in\_\allowbreak acl} & BOOLEAN & The work is linked to an ACL Anthology entry & \texttt{link\_\allowbreak acl\_\allowbreak oa} \\ \texttt{arxiv\_\allowbreak id\_\allowbreak linked} & VARCHAR & arXiv identifier of a linked arXiv record (any one, if several) & \texttt{link\_\allowbreak arxiv\_\allowbreak oa}, \texttt{arxiv\_\allowbreak keys} \\ \texttt{arxiv\_\allowbreak created} & VARCHAR & Earliest first-submission date among linked arXiv records & \texttt{arxiv\_\allowbreak keys.\allowbreak created} \\ \texttt{arxiv\_\allowbreak primary} & VARCHAR & Primary arXiv category of a linked record & \texttt{arxiv\_\allowbreak keys.\allowbreak primary\_\allowbreak category} \\ \texttt{arxiv\_\allowbreak cs\_\allowbreak primary} & BOOLEAN & \texttt{arxiv\_\allowbreak primary} starts with \texttt{cs.\allowbreak }; null when no linked record & derived \\ \texttt{is\_\allowbreak arxiv\_\allowbreak doi} & BOOLEAN & The DOI is an arXiv DOI (\texttt{10.\allowbreak 48550/\allowbreak arxiv.\allowbreak }) & \texttt{doi} \\ \texttt{duplicate\_\allowbreak of} & BIGINT & For a preprint-like record that has a published twin: identifier of the twin; null otherwise & \texttt{dup\_\allowbreak pairs} \\ \texttt{preprint\_\allowbreak work\_\allowbreak id} & BIGINT & For a published record that has a preprint twin: identifier of the preprint & \texttt{dup\_\allowbreak pairs} \\ \texttt{first\_\allowbreak date} & VARCHAR & First public appearance: the earliest of the publication date, the twin preprint's date and the arXiv creation date; when the publication date is year-only (\texttt{-01-01}) and a preprint or arXiv date exists, the earliest of those two instead & derived (eq.~\ref{eq:first-date}) \\ \texttt{version\_\allowbreak relationship} & VARCHAR & On the published twin: \texttt{title\_\allowbreak year} or \texttt{arxiv\_\allowbreak id}, the relation by which the pair was found & \texttt{dup\_\allowbreak pairs.\allowbreak relation} \\ \texttt{e1\_\allowbreak outside\_\allowbreak window} & BOOLEAN & Publication date null, before 2018-01-01 or after 2026-11-02 & \texttt{publication\_\allowbreak date} \\ \texttt{e2\_\allowbreak type} & BOOLEAN & Type not in the kept list, unless DBLP-linked and not hard-excluded & \texttt{type}, \texttt{in\_\allowbreak dblp} \\ \texttt{e3\_\allowbreak xpac} & BOOLEAN & XPAC record not linked to DBLP & \texttt{is\_\allowbreak xpac}, \texttt{in\_\allowbreak dblp} \\ \texttt{xpac\_\allowbreak kept\_\allowbreak dblp} & BOOLEAN & XPAC record kept because DBLP-linked (A-001) & \texttt{is\_\allowbreak xpac}, \texttt{in\_\allowbreak dblp} \\ \texttt{e7\_\allowbreak generic\_\allowbreak deposit} & BOOLEAN & Primary source is a generic deposit platform and the record is neither DBLP- nor arXiv-linked (A-002) & \texttt{source\_\allowbreak name} \\ \texttt{date\_\allowbreak precision} & VARCHAR & \texttt{year} when the publication date is \texttt{YYYY-01-01} and no preprint or arXiv date exists; \texttt{month} otherwise & derived \\ \texttt{e4\_\allowbreak no\_\allowbreak title} & BOOLEAN & Title null or blank & \texttt{title} \\ \texttt{e5\_\allowbreak duplicate} & BOOLEAN & The record is the preprint member of a duplicate pair & \texttt{duplicate\_\allowbreak of} \\ \texttt{e6\_\allowbreak retracted} & BOOLEAN & Retracted (flag, not an exclusion: retracted works stay eligible and are excluded from citation indicators) & \texttt{is\_\allowbreak retracted} \\ \texttt{cs\_\allowbreak core} & BOOLEAN & DBLP-linked, or CS primary topic, or CS topic with a \texttt{cs.\allowbreak } arXiv primary category & derived \\ \texttt{cs\_\allowbreak penumbra} & BOOLEAN & Any CS topic but not \texttt{cs\_\allowbreak core} & derived \\ \texttt{eligible} & BOOLEAN & Not E1--E5, not E7, and \texttt{cs\_\allowbreak core} & derived (eq.~\ref{eq:eligible}) \\ \texttt{period} & VARCHAR & \texttt{pre} (before 2018-01-01), \texttt{baseline} (before 2022-11-30), \texttt{post} (to 2026-11-02), \texttt{future}, by \texttt{first\_\allowbreak date} & derived \\ \texttt{first\_\allowbreak month} & VARCHAR & \texttt{YYYY-MM} of \texttt{first\_\allowbreak date} & derived \\ \end{longtable} \end{footnotesize} \end{singlespace} Two auxiliary tables accompany it. \texttt{dup\_\allowbreak pairs} (columns \texttt{preprint\_\allowbreak id}, \texttt{published\_\allowbreak id}, \texttt{preprint\_\allowbreak date}, \texttt{published\_\allowbreak date}, \texttt{relation}) holds the one-to-one preprint-to-published pairs after the ranking columns \texttt{rn\_\allowbreak pub} and \texttt{rn\_\allowbreak pre} have been used to keep, for each published work, the earliest preprint, and for each preprint, the earliest published twin; a candidate pair is a preprint-like record (type preprint or arXiv DOI) and a non-preprint record in the window that passes E1--E4, with equal normalised titles of at least 25 characters and years at most two apart (\texttt{title\_\allowbreak year}), or with the same arXiv identifier (\texttt{arxiv\_\allowbreak id}). \texttt{dblp\_\allowbreak only\_\allowbreak counts} (\texttt{year}, \texttt{rec\_\allowbreak type}, \texttt{n}, \texttt{with\_\allowbreak doi}) counts the DBLP records of 2018--2026 that have no OpenAlex record after both passes. The PRISMA file \texttt{prisma\_\allowbreak counts.\allowbreak json} stores the identified records per source, the links, each exclusion flag counted alone and sequentially in the order E1, E2, E3, E4, E5, E7, the remainder, the eligible counts by period, year, type, membership and date precision, and the strict core (DBLP-linked and CS primary); its keys are the \texttt{\textbackslash Prisma*} macros of the manuscript. \subsection{Citation windows} \label{app:datadict-citations} \texttt{bibliometrics/\allowbreak 03\_\allowbreak citation\_\allowbreak impact.\allowbreak py} builds \texttt{work\_\allowbreak citation\_\allowbreak windows} (also \texttt{data/\allowbreak processed/\allowbreak corpus/\allowbreak work\_\allowbreak citation\_\allowbreak windows.\allowbreak parquet}) for the eligible, non-retracted works. The yearly citation counts of a published work and of its merged preprint twin are summed, so that a citation to either version counts for the canonical node (Section~\ref{sec:m-citations}); fixed windows are then formed from calendar years, and each window is normalised by the mean of the same window over works of the same publication year, type and primary subfield. \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.6cm} p{4.0cm}@{}} \caption{\texttt{work\_\allowbreak citation\_\allowbreak windows}: one row per eligible, non-retracted work.} \label{tab:appE-citwin}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{\texttt{work\_\allowbreak citation\_\allowbreak windows} (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \texttt{work\_\allowbreak id} & BIGINT & Work & \texttt{corpus\_\allowbreak works.\allowbreak id} \\ \texttt{year} & INTEGER & Publication year $y$ & \texttt{publication\_\allowbreak year} \\ \texttt{type} & VARCHAR & OpenAlex type, \texttt{unknown} when null & \texttt{type} \\ \texttt{sf} & INTEGER & Primary subfield, $-1$ when null & \texttt{primary\_\allowbreak subfield\_\allowbreak id} \\ \texttt{cited\_\allowbreak by\_\allowbreak count} & INTEGER & All-time citations at snapshot date (the canonical record only) & \texttt{cited\_\allowbreak by\_\allowbreak count} \\ \texttt{fwci} & DOUBLE & OpenAlex FWCI (secondary indicator) & \texttt{fwci} \\ \texttt{c12} & BIGINT & Citations received in years $\le y+1$ (publication year and the following year), work plus merged preprint & \texttt{oa\_\allowbreak counts\_\allowbreak by\_\allowbreak year} \\ \texttt{c36} & BIGINT & Citations received in years $\le y+2$ & idem \\ \texttt{c48} & BIGINT & Citations received in years $\le y+3$ & idem \\ \texttt{c12\_\allowbreak complete}, \texttt{c36\_\allowbreak complete}, \texttt{c48\_\allowbreak complete} & BOOLEAN & The window closes in a complete calendar year: $y+1 \le 2025$, $y+2 \le 2025$, $y+3 \le 2025$ & derived \\ \texttt{ncs12}, \texttt{ncs36} & DOUBLE & \texttt{c12}, \texttt{c36} divided by the mean of the same quantity over works with the same \texttt{year}, \texttt{type} and \texttt{sf}; null when that mean is zero & derived (eq.~\ref{eq:ncs}) \\ \end{longtable} \end{footnotesize} \end{singlespace} The accompanying result tables are \texttt{citation\_\allowbreak windows\_\allowbreak yearly.\allowbreak csv} (per year: $n$, completeness flags, means and median of the windows, shares uncited at 12 and 36 months, the 99th percentile and maximum of \texttt{c36}, Gini coefficients of \texttt{c36} and \texttt{c12}, mean and median FWCI), \texttt{top\_\allowbreak cited\_\allowbreak by\_\allowbreak year.\allowbreak csv} (the fifty works with the largest \texttt{c36} per year, with title, venue, type and the window counts) and \texttt{fwci\_\allowbreak summary\_\allowbreak yearly.\allowbreak csv}. \subsection{Citation-graph edge tables} \label{app:datadict-graph} \texttt{knowledge\_\allowbreak graph/\allowbreak 01\_\allowbreak citation\_\allowbreak graph.\allowbreak py} splits the references of eligible works into two edge tables according to whether the cited work is itself eligible. External edges are resolved through the slim table, which is why the slim table covers the whole snapshot: a reference to a work outside computer science is attributed a year, a type and a field without that work ever being extracted in full. References whose target is in neither table (identifiers absent from the snapshot) appear in neither edge table and are counted only through \texttt{n\_\allowbreak refs}. \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.6cm} p{4.0cm}@{}} \caption{Edge tables \texttt{cit\_\allowbreak edges\_\allowbreak internal} and \texttt{cit\_\allowbreak edges\_\allowbreak external} (\texttt{data/\allowbreak processed/\allowbreak graph/\allowbreak }).} \label{tab:appE-edges}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{Edge tables (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \multicolumn{4}{@{}l}{\textit{\texttt{cit\_\allowbreak edges\_\allowbreak internal}: both ends eligible}} \\ \texttt{citing\_\allowbreak id}, \texttt{cited\_\allowbreak id} & BIGINT & Citing and cited work & \texttt{oa\_\allowbreak references} \\ \texttt{citing\_\allowbreak year}, \texttt{cited\_\allowbreak year} & INTEGER & Publication years of the two ends & \texttt{corpus\_\allowbreak works.\allowbreak publication\_\allowbreak year} \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{cit\_\allowbreak edges\_\allowbreak external}: citing work eligible, cited work not eligible but present in the snapshot}} \\ \texttt{citing\_\allowbreak id}, \texttt{cited\_\allowbreak id} & BIGINT & Citing and cited work & \texttt{oa\_\allowbreak references} \\ \texttt{citing\_\allowbreak year} & INTEGER & Year of the citing work & \texttt{corpus\_\allowbreak works} \\ \texttt{cited\_\allowbreak year} & INTEGER & Year of the cited work & \texttt{oa\_\allowbreak slim.\allowbreak publication\_\allowbreak year} \\ \texttt{cited\_\allowbreak field\_\allowbreak id} & INTEGER & Primary field of the cited work & \texttt{oa\_\allowbreak slim.\allowbreak primary\_\allowbreak field\_\allowbreak id} \\ \texttt{cited\_\allowbreak type} & VARCHAR & Type of the cited work & \texttt{oa\_\allowbreak slim.\allowbreak type} \\ \texttt{cited\_\allowbreak cs\_\allowbreak any} & BOOLEAN & The cited work has a CS topic (it is then a non-eligible CS record, e.g.\ outside the window) & \texttt{oa\_\allowbreak slim.\allowbreak cs\_\allowbreak any\_\allowbreak topic} \\ \end{longtable} \end{footnotesize} \end{singlespace} The derived result tables are \texttt{field\_\allowbreak flows\_\allowbreak yearly.\allowbreak csv} (\texttt{citing\_\allowbreak year}, \texttt{kind} internal or external, \texttt{cited\_\allowbreak field\_\allowbreak id}, \texttt{n}), \texttt{cited\_\allowbreak age\_\allowbreak yearly.\allowbreak csv} (\texttt{citing\_\allowbreak year}, \texttt{age} = citing year minus cited year, \texttt{n}, over both tables) and \texttt{reference\_\allowbreak coverage\_\allowbreak yearly.\allowbreak csv} (\texttt{year}, \texttt{n\_\allowbreak works}, \texttt{n\_\allowbreak refs\_\allowbreak declared}, \texttt{n\_\allowbreak internal}, \texttt{n\_\allowbreak external}). Category-level flows, co-classification and modularity tables (\texttt{knowledge\_\allowbreak graph/\allowbreak 02\_\allowbreak category\_\allowbreak flows.\allowbreak py}) join the internal edges with the classification tables below; the semantic edges of \texttt{04\_\allowbreak semantic\_\allowbreak edges.\allowbreak py} (\texttt{work\_\allowbreak id}, \texttt{neighbour\_\allowbreak id}, \texttt{cosine\_\allowbreak similarity}, \texttt{rank}) are computed from the embeddings of Section~\ref{app:datadict-embeddings}; and the extracted method, dataset and claim nodes and typed edges of \texttt{03\_\allowbreak extract\_\allowbreak entities.\allowbreak py} carry, for every edge, the work, the quoted span from the abstract, a model-reported confidence and a verification status (\texttt{unverified}, \texttt{machine-verified} when the span is found verbatim, \texttt{human-verified} after review), as the mandate requires. \subsection{Classification tables} \label{app:datadict-classification} \texttt{taxonomy/\allowbreak classify.\allowbreak py} first exports its input (\texttt{--prepare}) and then scores it (\texttt{--run}), with the ontology of Appendix~\ref{app:taxonomy} and the rule of equations~\eqref{eq:score}--\eqref{eq:assign}. The population is the eligible corpus together with the penumbra, so that sensitivity analyses on the wider set need no second run. \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.6cm} p{4.0cm}@{}} \caption{Classification input and output tables (\texttt{data/\allowbreak processed/\allowbreak classification/\allowbreak }).} \label{tab:appE-classification}\\ \toprule Column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{Classification tables (continued).}\\ \toprule Column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \multicolumn{4}{@{}l}{\textit{\texttt{input/\allowbreak chunk=N/\allowbreak *.\allowbreak parquet}: one row per work with \texttt{eligible} or \texttt{cs\_\allowbreak penumbra}}} \\ \texttt{id} & BIGINT & Work & \texttt{corpus\_\allowbreak works.\allowbreak id} \\ \texttt{year} & INTEGER & Publication year & \texttt{publication\_\allowbreak year} \\ \texttt{title}, \texttt{abstract} & VARCHAR & Text scored by the keyword rules (abstract null when absent) & \texttt{corpus\_\allowbreak works}, \texttt{oa\_\allowbreak abstracts} \\ \texttt{topic\_\allowbreak ids} & list<int> & Topic identifiers in rank order & \texttt{oa\_\allowbreak work\_\allowbreak topics} \\ \texttt{subfield\_\allowbreak ids} & list<int> & Subfield identifiers in rank order & \texttt{oa\_\allowbreak work\_\allowbreak topics} \\ \texttt{arxiv\_\allowbreak cats} & list<string> & All categories of all linked arXiv records, flattened & \texttt{link\_\allowbreak arxiv\_\allowbreak oa}, \texttt{arxiv\_\allowbreak keys.\allowbreak categories} \\ \texttt{dblp\_\allowbreak streams} & list<string> & Distinct streams of the linked DBLP records & \texttt{link\_\allowbreak dblp\_\allowbreak oa}, \texttt{dblp\_\allowbreak keys.\allowbreak stream} \\ \texttt{chunk} & INTEGER & Chunk index (default 100{,}000 rows per chunk) & derived \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{work\_\allowbreak categories} (\texttt{cats/\allowbreak *.\allowbreak parquet}): one row per (work, assigned category)}} \\ \texttt{work\_\allowbreak id} & int64 & Work & input \\ \texttt{category\_\allowbreak id} & string & Leaf identifier (Table~\ref{tab:appA-leaves}) & ontology \\ \texttt{score} & float32 & Total score $s_k(w)$, rounded to three decimals & eq.~\eqref{eq:score} \\ \texttt{s\_\allowbreak topic}, \texttt{s\_\allowbreak subfield}, \texttt{s\_\allowbreak arxiv}, \texttt{s\_\allowbreak dblp}, \texttt{s\_\allowbreak kw} & float32 & Capped contribution of each signal type (each in $[0,1]$) & eq.~\eqref{eq:score} \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{work\_\allowbreak primary} (\texttt{primary/\allowbreak *.\allowbreak parquet}): one row per work with at least one category}} \\ \texttt{work\_\allowbreak id} & int64 & Work & input \\ \texttt{primary\_\allowbreak category} & string & Argmax category with the tie-breaking of Section~\ref{sec:m-score} & derived \\ \texttt{n\_\allowbreak categories} & int16 & Number of assigned categories $|C(w)|$ & derived \\ \texttt{primary\_\allowbreak score} & float32 & Score of the primary category & derived \\ \end{longtable} \end{footnotesize} \end{singlespace} A work with no category has no row in either output table; the number of such works is the difference between the \texttt{works} and \texttt{classified} fields of \texttt{classification\_\allowbreak report.\allowbreak json}, which also records the ontology version and the timestamp of the run. The validation tables (\texttt{taxonomy/\allowbreak validation/\allowbreak sample.\allowbreak parquet}, \texttt{ratings\_\allowbreak <model>.\allowbreak jsonl}, \texttt{metrics.\allowbreak json}, \texttt{disagreements.\allowbreak csv}) carry, per sampled work, the rule categories and primary, and per rater the label set, primary, confidence and rationale returned under the JSON schema of \texttt{VALIDATION.\allowbreak md}. \subsection{Embedding shards} \label{app:datadict-embeddings} \texttt{embeddings/\allowbreak embed\_\allowbreak corpus.\allowbreak py} exports the text to embed (\texttt{--prepare}) and encodes it (\texttt{--run}) with a sentence-embedding model, by default SPECTER2 \citep{cohan2020specter,singh2023scirepeval} as served through \texttt{sentence-transformers} \citep{reimers2019sbert}, in shards that can be distributed over nodes. \begin{singlespace} \begin{footnotesize} \begin{longtable}{@{}p{3.2cm} p{1.6cm} p{6.6cm} p{4.0cm}@{}} \caption{Embedding input and output files (\texttt{data/\allowbreak processed/\allowbreak embeddings/\allowbreak }).} \label{tab:appE-embeddings}\\ \toprule File or column & Type & Definition & Source \\ \midrule \endfirsthead \caption[]{Embedding files (continued).}\\ \toprule File or column & Type & Definition & Source \\ \midrule \endhead \midrule \multicolumn{4}{r}{continued on next page}\\ \endfoot \bottomrule \endlastfoot \multicolumn{4}{@{}l}{\textit{\texttt{input/\allowbreak shard=K/\allowbreak *.\allowbreak parquet}: eligible works with an abstract, ordered by identifier, 50{,}000 per shard by default}} \\ \texttt{work\_\allowbreak id} & BIGINT & Work & \texttt{corpus\_\allowbreak works.\allowbreak id} \\ \texttt{text} & VARCHAR & Title, a full stop and a space, then the first 2{,}000 characters of the abstract & \texttt{title}, \texttt{oa\_\allowbreak abstracts.\allowbreak abstract} \\ \texttt{shard} & INTEGER & Shard index $K$ & derived \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{<model\_\allowbreak tag>/\allowbreak shard\_\allowbreak KKKK.\allowbreak npy}}} \\ array & float16, $n \times d$ & One L2-normalised embedding per text, in input order; $d$ is the model's output dimension; maximum sequence length 256 tokens, batch 128 by default & model output \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{<model\_\allowbreak tag>/\allowbreak shard\_\allowbreak KKKK.\allowbreak ids.\allowbreak npy}}} \\ array & int64, $n$ & The \texttt{work\_\allowbreak id} of each row of the embedding array & input \\ \addlinespace \multicolumn{4}{@{}l}{\textit{\texttt{<model\_\allowbreak tag>/\allowbreak manifest\_\allowbreak <host>.\allowbreak json}}} \\ \texttt{model}, \texttt{max\_\allowbreak seq\_\allowbreak length}, \texttt{device}, \texttt{host} & -- & Model name, sequence limit, \texttt{mps} or \texttt{cpu}, host name & run parameters \\ \texttt{shards[K]} & -- & Per shard: number of texts, seconds taken, timestamp & run \\ \end{longtable} \end{footnotesize} \end{singlespace} The model tag is the model name with \texttt{/\allowbreak } replaced by \texttt{\_\allowbreak \_\allowbreak }; a second model produces a second directory with the same layout, which is how the comparison of embedding approaches required by the mandate is organised. Shards already present are skipped on resumption, so a shard computed on one node and copied to another is never recomputed.