Link Checker: rolling issue + Crossref DOI validation

Merged
LU
6mo ago
+147-9

Summary

Three improvements to the weekly Link Checker workflow:

  1. Rolling issue instead of weekly duplicates. The workflow now finds the most recent open issue labelled `link-check` and edits its body in place, leaving a short comment so subscribers see the refresh. A new issue is created only if none is open. (Six older duplicates already closed manually; #751 is now the rolling issue.)

  2. Registry-agnostic DOI validation. `doi.org` / `dx.doi.org` are excluded from lychee (which was following the redirect to publishers and getting bot-blocked), and a new step extracts every DOI from the rendered HTML and checks each against the DOI Handle API at `doi.org/api/handles/{doi}`. The Handle API resolves Crossref, DataCite (Zenodo / OSF / institutional repositories), JaLC, mEDRA, etc. — `responseCode` `1` means the handle exists, `100` means it doesn't. The original Crossref-only check produced 43/58 false positives on the local site.

  3. Balanced-paren DOI extraction. SICI-style DOIs like `10.1016/0277-9536(95)00127-S` legitimately contain parens. The extractor now allows them in the DOI body and strips only unbalanced trailing `)` / `]` afterwards.

    Other implementation notes:

    • DOIs in HTML are sometimes URL-encoded (e.g. `%2F` for `/`) — decode before re-encoding for the API call to avoid double-encoding.
    • 429 / 5xx retried with exponential backoff; concurrency capped at 6.
    • Polite User-Agent uses `info@forrt.org`.

    On the local site, validating ~2000 unique DOIs takes ~25s and reports 11 genuine 404s (vs. 58 false positives + true positives mixed together with the Crossref-only check).

Test plan

  • Trigger via `workflow_dispatch` and confirm #751 is updated rather than a new issue created.
  • Confirm the issue body's "Broken DOIs" section now flags only genuine typos (no Zenodo / OSF / Cambridge / etc. false positives).
  • Spot-check a couple of the reported broken DOIs to verify they really are unregistered.

šŸ¤– Generated with Claude Code