# Online Resource 3 — analysis scripts, derived tables and frozen data

Everything needed to regenerate every number, table and figure in the manuscript.

## Quick start

```
reproduce.cmd                          REM uses "python" from PATH
reproduce.cmd C:\path\to\python.exe    REM or point at a specific interpreter
```

The script resolves all paths relative to its own location, so this package can be unpacked
anywhere. It checks dependencies and inputs before doing any work and stops with a clear
message if either is missing. Set `REPRO_ROOT` to override the root.

Requirements: Python 3.12 with `numpy==2.5.1` and `scipy==1.18.0`. Figure regeneration
additionally needs Windows PowerShell with System.Drawing.

## The input snapshot is not included

The Retraction Watch database is not redistributed here. It is compiled by Retraction Watch and
the Center for Scientific Integrity, acquired by Crossref in September 2023, and published at
https://gitlab.com/crossref/retraction-watch-data, rebuilt each working day. Because it changes
daily, you must check out the exact analysed commit:

```
git clone https://gitlab.com/crossref/retraction-watch-data
git -C retraction-watch-data checkout dda8c8749c6ac35923f69162936c53fc9b9f5e3c
copy retraction-watch-data\retraction_watch.csv data\retraction_watch_gitlab.csv
```

Verify before use. The file must be 65,517,426 bytes with SHA-256:

```
1B61BABC73AD7F9861175ECB5DECC2B5C3BE33E0464C40489355A5BB96B9EF2F
```

`certutil -hashfile data\retraction_watch_gitlab.csv SHA256`

Results will not match the manuscript against any other build of the database.

## Layout

| Path | Contents |
|---|---|
| `reproduce.cmd` | Runner. Executes the whole pipeline in order. |
| `scripts/` | All analysis code. No absolute paths. |
| `tables/` | Every derived table, numbered in generation order. |
| `reports/` | Generated run reports. |
| `99-claims-map.md` | Every quantitative claim in the manuscript traced to its source file. |
| `ESM_2_python_validation.md` | Independent implementation comparison. |

## Scripts

| Script | Produces |
|---|---|
| `matched_dispersion.py` | Section 4.4 and Table 7. Exact-publisher stratification, the publisher-group sensitivity, and the Hindawi-removed-from-both-cohorts sensitivity. Writes `t45`, `t46`. |
| `referee_reanalysis.py` | Table 16 (citation rematch, deduplicated by DOI), Table 14 (twenty-pattern terminology audit) and Table 6 (10,000-replicate cluster bootstrap with singleton handling for unavailable notice DOIs). Writes `t47`–`t50`. Accepts `all`, `cite`, `term` or `boot`. |
| `regen_esm1.py` | Online Resources 1 and 1b, including the populated adjudication columns and the coding rules. |
| `validate_stats.py` | Online Resource 2, the numpy/scipy reimplementation. |
| `verify_references.py` | Checks every DOI and arXiv identifier against Crossref and arXiv. Requires network. |
| `New-FiguresTiff.ps1` | Fig. 1 and Fig. 2 at 600 dpi. |
| `New-Fig3Forest.ps1` | Fig. 3, the stratum-ratio forest plot. |

## Key tables

| File | Contents |
|---|---|
| `t45_stratum_dispersion.csv` | Stratum-specific dispersion for all three configurations (Fig. 3) |
| `t46_matched_dispersion_summary.csv` | Matched dispersion summary, three configurations (Table 7) |
| `t47_citation_rematched.csv` | Citation rematch on baseline citations (Table 16) |
| `t48_terminology_broadened.csv` | Per-pattern counts with the regular expressions (Table 14) |
| `t49_terminology_specific_matches.csv` | The 21 specific-term records |
| `t50_bootstrap_10k.csv` | Cluster bootstrap, 10,000 replicates, with Monte Carlo error (Table 6) |
| `t21_followup_restricted_regime.csv` | Complete regime × follow-up grid abbreviated in Table 13 |
| `t37_caliper_subsets.csv` | Caliper restriction under the initial matched design |
| `t38_baseline_stratified.csv` | Paired difference within baseline citation bands |
| `t19_citations_full.csv` | Frozen OpenAlex extract for every queried article |
| `t39_control_candidates_openalex.csv` | Frozen control candidate pool used for rematching |
| `t42_openalex_topics.csv` | Primary topic and field per DOI |
| `references_verified_all.csv` | Registry verification of every reference |

## Control candidate pool

`t39_control_candidates_openalex.csv` is supplied frozen because OpenAlex is continuously
revised and requires an API key. Its construction is described in Section 3.9 of the
manuscript: the source population was all retractions not carrying the machine-attributed
reason and holding a parseable DOI and date pair; eligibility required sharing a publication
year and retraction year with at least one machine-attributed record; eligible DOIs were queried
in publication-year order until the daily allowance was reached, giving 24,976 candidates.
Publisher and journal are taken from the Retraction Watch record, not from OpenAlex, so
publisher agreement is defined on the same field in both cohorts. Selection preceded any
inspection of outcomes. Regenerating the pool from scratch requires a free OpenAlex API key and
is not performed by `reproduce.cmd`; the rematching steps read the frozen pool and make no
network calls.

## Determinism

Seed 20260731 throughout. Bootstrap and permutation counts are 10,000. Given the same input
snapshot, all outputs are byte-reproducible except `verify_references.py`, which reflects live
registry state.

## Attribution

Retraction data: Retraction Watch and the Center for Scientific Integrity, distributed by
Crossref. Citation data: OpenAlex (OurResearch).
