Attaches an open-access PDF to Zotero items that lack a full text.
Built on the selection, ledger and attach machinery from PR #826
(feat/zot-fetch-z1, left untouched on its branch); delivery is the
stack's legal open-access cascade only — every Unpaywall location →
Semantic Scholar openAccessPdf → PMC S3 → PMC OA service → Europe PMC
(prisma.fetch.fetch_one with no proxied client, so its mirror tier
never runs). No DOI? a Crossref title match first. Downloads must be
real PDFs before they are attached; the run ledgers every attempt
(attached / no_candidate / error; misses wait 30 days unless --retry).
From the #828 review list:
- Lazy selection: select_ids() is one cheap query (deleted and
full-text items excluded in SQL for --all) and iter_refs() reads each
item only when the run reaches it, so --limit bites before ~167k
file-less items are materialised while the desktop is held down.
- A locked database (--no-hold with the desktop writing) aborts the run
with a usage error that names the Zotero desktop, instead of a raw
sqlite3.OperationalError — or one error per item.
- --dry-run reads only (checked against the running desktop), so it no
longer stops/starts zotero; UNPAYWALL_EMAIL is documented in --help.
Tests: 66 (scratch Zotero DB, no network), 100% of src/zot/fetch.