The Principia Machina/TPC-PY/gen biblio corpus.py: Difference between revisions
Appearance
TPC-PY source gen_biblio_corpus.py (0.1.0), SHA-256 7548da4dd9ff6b17; conformed TPS 0.4.0; PROPOSED, not declared (TPC-PY 0.2.0) |
m 1 revision imported |
(No difference)
| |
Latest revision as of 02:11, 30 September 2026
"""gen_biblio_corpus 0.1.0: builds biblio_corpus.json for tpc_biblio 0.1.0.
Every expectation is computed by tpc_biblio.py and pinned. A case given a
hand expectation (a literal written from the rule, or a digest computed
by an external sha256sum over the preimage the case shows) is marked
hand_checked, and the generator refuses to write the corpus if the code
disagrees with any of them. Deterministic: no randomness.
Fixtures: the Wakefield 1998 Lancet record (BR V-2, V-11: title, year,
first author, DOI, ISSN, PMID and the RETRACTED: marker are observed
facts; the notice identifiers are fixtures), the Teece 1997 SICI DOI
(V-2), Wikipedia's ISBN and ISSN worked examples (V-13, V-14). Every
other entry, identifier, record and account is fictional."""
import hashlib
import json
import sys
from tpc_biblio import run_case, biblio_preimage
cases = []
def add(name, fn, args, hand=None):
cases.append((name, fn, args, hand))
def lines(*ls):
return "\n".join(ls)
CAPS = {"entry_max": 16384, "title": 1000, "text": 500, "name": 200,
"url": 2000, "names": 100}
WAKE_DOI = "10.1016/S0140-6736(97)11096-0"
WAKE_DOI_LC = "10.1016/s0140-6736(97)11096-0"
WAKE_TITLE = ("Ileal-lymphoid-nodular hyperplasia, non-specific colitis, and "
"pervasive developmental disorder in children")
WAKE_KEY = ("ileallymphoidnodular hyperplasia nonspecific colitis and "
"pervasive developmental disorder in children")
TEECE_DOI = "10.1002/(SICI)1097-0266(199708)18:7<509::AID-SMJ882>3.0.CO;2-Z"
TEECE_LC = "10.1002/(sici)1097-0266(199708)18:7<509::aid-smj882>3.0.co;2-z"
# ----------------------------------------------------------------- doi
K = [
("DO01 a bare DOI, case kept, folded key", WAKE_DOI,
"doi|DOI|%s|%s" % (WAKE_DOI, WAKE_DOI_LC)),
("DO02 the doi: wrapper in any ASCII case", "Doi:" + WAKE_DOI,
"doi|DOI|%s|%s" % (WAKE_DOI, WAKE_DOI_LC)),
("DO03 an https doi.org URL", "https://doi.org/" + WAKE_DOI,
"doi|DOI|%s|%s" % (WAKE_DOI, WAKE_DOI_LC)),
("DO04 an http dx.doi.org URL, host case free", "HTTP://DX.DOI.ORG/" + WAKE_DOI,
"doi|DOI|%s|%s" % (WAKE_DOI, WAKE_DOI_LC)),
("DO05 a SICI DOI with < > ; raw", TEECE_DOI, "doi|DOI|%s|%s" % (TEECE_DOI, TEECE_LC)),
("DO06 a SICI DOI in a URL, < > ; percent-encoded once (V-2)",
"https://doi.org/10.1002/(SICI)1097-0266(199708)18:7%3C509::AID-SMJ882%3E3.0.CO;2-Z",
"doi|DOI|%s|%s" % (TEECE_DOI, TEECE_LC)),
("DO07 the arXiv DOI held as its ARXIV id", "10.48550/arXiv.2601.12345",
"doi|ARXIV|10.48550/arXiv.2601.12345|2601.12345"),
("DO08 the arXiv DOI lower-cased as DataCite returns it (F13), with a version",
"10.48550/arxiv.2601.12345v2", "doi|ARXIV|10.48550/arxiv.2601.12345v2|2601.12345v2"),
("DO09 the arXiv DOI in doi: form", "doi:10.48550/ARXIV.hep-th/0701999",
"doi|ARXIV|10.48550/ARXIV.hep-th/0701999|hep-th/0701999"),
("DO10 the arXiv DOI in URL form", "https://doi.org/10.48550/arXiv.2601.12345",
"doi|ARXIV|10.48550/arXiv.2601.12345|2601.12345"),
("DO11 a registrant code with a sub-division", "10.1000.10/abc",
"doi|DOI|10.1000.10/abc|10.1000.10/abc"),
("DO12 a non-ASCII suffix kept; only A-Z fold", "10.1000/\u00c9t\u00e9-\u03a9",
"doi|DOI|10.1000/\u00c9t\u00e9-\u03a9|10.1000/\u00c9t\u00e9-\u03a9"),
("DO13 a suffix in NFD is stored NFC", "10.1000/e\u0301", "doi|DOI|10.1000/\u00e9|10.1000/\u00e9"),
("DO14 an arXiv DOI whose suffix is not arXiv. refused", "10.48550/other.1", "ERROR:doi"),
("DO15 an arXiv DOI whose id does not parse refused", "10.48550/arXiv.2601.1", "ERROR:doi"),
("DO16 no slash refused", "10.1000", "ERROR:doi"),
("DO17 an empty suffix refused", "10.1000/", "ERROR:doi"),
("DO18 a directory indicator other than 10 refused (named limit)", "11.1000/abc", "ERROR:doi"),
("DO19 a prefix without a registrant code refused", "10./abc", "ERROR:doi"),
("DO20 white space refused", "10.1000/a b", "ERROR:doi"),
("DO21 a control character refused", "10.1000/a\tb", "ERROR:doi"),
("DO22 a format character (zero-width space) refused", "10.1000/a\u200bb", "ERROR:doi"),
("DO23 a bidi override refused (text safety)", "10.1000/a\u202eb", "ERROR:doi"),
("DO24 empty text refused", "", "ERROR:doi"),
("DO25 a number refused", 10.1, "ERROR:doi"),
("DO26 a bad percent-escape in the URL form refused", "https://doi.org/10.1000/a%zz", "ERROR:doi"),
("DO27 percent-decoded bytes that are not UTF-8 refused", "https://doi.org/10.1000/a%C0%AE", "ERROR:doi"),
("DO28 the doi: wrapper with a space refused", "doi: " + WAKE_DOI, "ERROR:doi"),
("DO29 an https URL with an unknown host is a bare text and fails the shape",
"https://example.org/" + WAKE_DOI, "ERROR:doi"),
("DO30 percent-encoding is decoded once only", "https://doi.org/10.1000/a%2520b",
"doi|DOI|10.1000/a%20b|10.1000/a%20b"),
]
for name, text, hand in K:
add(name, "doi", {"text": text}, hand)
# --------------------------------------------------------------- shape
K = [
("SH01 a bare DOI", WAKE_DOI, "shape|true"),
("SH02 a SICI DOI", TEECE_DOI, "shape|true"),
("SH03 the arXiv DOI is DOI-shaped", "10.48550/arXiv.2601.12345", "shape|true"),
("SH04 the doi: wrapper is not the shape", "doi:" + WAKE_DOI, "shape|false"),
("SH05 the URL form is not the shape", "https://doi.org/" + WAKE_DOI, "shape|false"),
("SH06 no slash", "10.1000", "shape|false"),
("SH07 an empty suffix", "10.1000/", "shape|false"),
("SH08 directory indicator 11", "11.1000/x", "shape|false"),
("SH09 a space", "10.1000/a b", "shape|false"),
("SH10 a control", "10.1000/\u0001", "shape|false"),
("SH11 a non-ASCII suffix", "10.1000/\u00e9", "shape|true"),
("SH12 a number", 5, "shape|false"),
("SH13 empty", "", "shape|false"),
("SH14 a sub-divided registrant", "10.1000.10/x", "shape|true"),
]
for name, text, hand in K:
add(name, "shape", {"text": text}, hand)
# --------------------------------------------------------------- arxiv
K = [
("AX01 new scheme, five digits, no version", "2601.12345", "arxiv|2601.12345|0|2601.12345|NEW"),
("AX02 new scheme with a version", "2601.12345v3", "arxiv|2601.12345v3|3|2601.12345|NEW"),
("AX03 new scheme, four digits (2007-04 to 2014-12)", "0704.0001", "arxiv|0704.0001|0|0704.0001|NEW"),
("AX04 four digits at the last month, 1412", "1412.9999v1", "arxiv|1412.9999v1|1|1412.9999|NEW"),
("AX05 five digits from 1501", "1501.00001", "arxiv|1501.00001|0|1501.00001|NEW"),
("AX06 the arXiv: wrapper in any case", "ARXIV:2601.12345v2", "arxiv|2601.12345v2|2|2601.12345|NEW"),
("AX07 an abs URL", "https://arxiv.org/abs/2601.12345v2", "arxiv|2601.12345v2|2|2601.12345|NEW"),
("AX08 old scheme with an archive", "hep-th/0701999", "arxiv|hep-th/0701999|0|hep-th/0701999|OLD"),
("AX09 old scheme with a subject class and a version", "math.GT/0309136v2",
"arxiv|math.GT/0309136v2|2|math.GT/0309136|OLD"),
("AX10 old scheme in 1991", "hep-th/9108001", "arxiv|hep-th/9108001|0|hep-th/9108001|OLD"),
("AX11 old scheme at the last month, 0703", "cond-mat/0703999", "arxiv|cond-mat/0703999|0|cond-mat/0703999|OLD"),
("AX12 old scheme in an http URL", "http://arxiv.org/abs/hep-th/0701999v1",
"arxiv|hep-th/0701999v1|1|hep-th/0701999|OLD"),
("AX13 five digits before 1501 refused", "1412.12345", "ERROR:arxiv"),
("AX14 four digits after 1412 refused", "1501.0001", "ERROR:arxiv"),
("AX15 four digits before 0704 refused", "0703.0001", "ERROR:arxiv"),
("AX16 month 13 refused", "2613.12345", "ERROR:arxiv"),
("AX17 month 00 refused", "2600.12345", "ERROR:arxiv"),
("AX18 old scheme after 0703 refused", "hep-th/0704001", "ERROR:arxiv"),
("AX19 old scheme in 1990 refused", "hep-th/9001001", "ERROR:arxiv"),
("AX20 version 0 refused", "2601.12345v0", "ERROR:arxiv"),
("AX21 a version with a leading zero refused", "2601.12345v01", "ERROR:arxiv"),
("AX22 a lower-case subject class refused (named limit, RD-5)", "cond-mat.mes-hall/0309136", "ERROR:arxiv"),
("AX23 an archive of one letter refused", "a/0309136", "ERROR:arxiv"),
("AX24 an upper-case archive refused", "HEP-TH/0701999", "ERROR:arxiv"),
("AX25 trailing text refused", "2601.12345 ", "ERROR:arxiv"),
("AX26 the arXiv DOI is not an arXiv id", "10.48550/arXiv.2601.12345", "ERROR:arxiv"),
("AX27 a number refused", 2601.12345, "ERROR:arxiv"),
("AX28 a six-digit number refused", "2601.123456", "ERROR:arxiv"),
]
for name, text, hand in K:
add(name, "arxiv", {"text": text}, hand)
# ---------------------------------------------------------------- isbn
K = [
("IB01 V-13's ISBN-10 with hyphens, converted", "0-306-40615-2", "isbn|9780306406157|10"),
("IB02 V-13's ISBN-13", "978-0-306-40615-7", "isbn|9780306406157|13"),
("IB03 ISBN-10 without hyphens", "0306406152", "isbn|9780306406157|10"),
("IB04 ISBN-10 with spaces", "0 306 40615 2", "isbn|9780306406157|10"),
("IB05 ISBN-10 ending in X (upper)", "080442957X", "isbn|9780804429573|10"),
("IB06 ISBN-10 ending in x (lower)", "0-8044-2957-x", "isbn|9780804429573|10"),
("IB07 a 979 ISBN-13", "979-10-90636-07-1", "isbn|9791090636071|13"),
("IB08 ISBN-10 with a wrong check refused", "0-306-40615-3", "ERROR:isbn"),
("IB09 ISBN-13 with a wrong check refused", "978-0-306-40615-8", "ERROR:isbn"),
("IB10 an X inside the number refused", "0X0640615 2", "ERROR:isbn"),
("IB11 twelve digits refused", "978030640615", "ERROR:isbn"),
("IB12 an ISBN-13 not starting 978 or 979 refused", "977-0-306-40615-8", "ERROR:isbn"),
("IB13 an ISBN prefix word refused", "ISBN 0-306-40615-2", "ERROR:isbn"),
("IB14 an ISBN-13 ending in X refused", "978030640615X", "ERROR:isbn"),
("IB15 a number refused", 9780306406157, "ERROR:isbn"),
("IB16 the converted 13 verifies as a 13", "9780306406157", "isbn|9780306406157|13"),
("IB17 a Unicode hyphen is not removed", "0\u2010306\u201040615\u20102", "ERROR:isbn"),
]
for name, text, hand in K:
add(name, "isbn", {"text": text}, hand)
# ---------------------------------------------------------------- issn
K = [
("IS01 V-14's example", "0378-5955", "issn|0378-5955"),
("IS02 The Lancet (V-2)", "0140-6736", "issn|0140-6736"),
("IS03 a check of X, upper", "2434-561X", "issn|2434-561X"),
("IS04 a check of x, lower, returned upper", "2434-561x", "issn|2434-561X"),
("IS05 a check of 0", "2470-0010", "issn|2470-0010"),
("IS14 Teece's second ISSN (V-2)", "1097-0266", "issn|1097-0266"),
("IS06 a wrong check refused", "0378-5956", "ERROR:issn"),
("IS07 no hyphen refused", "03785955", "ERROR:issn"),
("IS08 X where a digit is due refused", "0378-595X", "ERROR:issn"),
("IS09 a space refused", "0378 5955", "ERROR:issn"),
("IS10 an ISSN prefix word refused", "ISSN 0378-5955", "ERROR:issn"),
("IS11 nine characters refused", "0378-59555", "ERROR:issn"),
("IS12 a number refused", 3785955, "ERROR:issn"),
("IS13 a letter in the digits refused", "O378-5955", "ERROR:issn"),
]
for name, text, hand in K:
add(name, "issn", {"text": text}, hand)
# ------------------------------------------------------------ pmid, pmcid
K = [
("PM01 a PMID (V-11)", "9500320", "pmid|9500320"),
("PM02 the first PMID", "1", "pmid|1"),
("PM03 a leading zero refused", "09500320", "ERROR:pmid"),
("PM04 zero refused", "0", "ERROR:pmid"),
("PM05 a PMID: prefix refused", "PMID:9500320", "ERROR:pmid"),
("PM06 a space refused", "9500 320", "ERROR:pmid"),
("PM07 a number refused", 9500320, "ERROR:pmid"),
("PM08 empty refused", "", "ERROR:pmid"),
("PM09 a non-ASCII digit refused", "\u0663", "ERROR:pmid"),
("PM10 a negative refused", "-5", "ERROR:pmid"),
("PM11 a long PMID", "123456789012", "pmid|123456789012"),
("PM12 a hidden character refused", "9500320\u200b", "ERROR:pmid"),
]
for name, text, hand in K:
add(name, "pmid", {"text": text}, hand)
K = [
("PC01 a PMCID", "PMC8243230", "pmcid|PMC8243230"),
("PC02 lower-case letters returned upper", "pmc8243230", "pmcid|PMC8243230"),
("PC03 leading zeros kept (RD-5 says digits)", "PMC0012", "pmcid|PMC0012"),
("PC04 digits only refused", "8243230", "ERROR:pmcid"),
("PC05 no digits refused", "PMC", "ERROR:pmcid"),
("PC06 a space refused", "PMC 8243230", "ERROR:pmcid"),
("PC07 a number refused", 8243230, "ERROR:pmcid"),
("PC08 a PMCID: prefix refused", "PMCID:PMC8243230", "ERROR:pmcid"),
("PC09 trailing text refused", "PMC8243230v1", "ERROR:pmcid"),
("PC10 empty refused", "", "ERROR:pmcid"),
("PC11 a hidden character refused", "PMC\u00ad8243230", "ERROR:pmcid"),
("PC12 mixed case letters", "PmC1", "pmcid|PMC1"),
]
for name, text, hand in K:
add(name, "pmcid", {"text": text}, hand)
# ------------------------------------------------------------- key form
K = [
("KF01 the Wakefield title", WAKE_TITLE, "title", "key|" + WAKE_KEY),
("KF02 the same with the RETRACTED: marker (V-2)", "RETRACTED: " + WAKE_TITLE, "title", "key|" + WAKE_KEY),
("KF03 the marker in any case, no space after the colon", "Retracted:" + WAKE_TITLE, "title", "key|" + WAKE_KEY),
("KF04 RETRACTED ARTICLE:", "RETRACTED ARTICLE: " + WAKE_TITLE, "title", "key|" + WAKE_KEY),
("KF05 WITHDRAWN:", "WITHDRAWN: A note", "title", "key|a note"),
("KF06 WITHDRAWN ARTICLE: after leading space", " WITHDRAWN ARTICLE: A note", "title", "key|a note"),
("KF07 the marker is not stripped from a name", "RETRACTED: Smith", "name", "key|retracted smith"),
("KF08 the marker without a colon stays", "RETRACTED A note", "title", "key|retracted a note"),
("KF09 only one marker is stripped", "RETRACTED: WITHDRAWN: A note", "title", "key|withdrawn a note"),
("KF10 <i> and <sup> tags removed", "The <i>E. coli</i> genome<sup>2</sup>", "title", "key|the e coli genome2"),
("KF11 a closing tag and an attribute tag", "<span class=\"x\">Bold</span> text", "title", "key|bold text"),
("KF12 a lone < is not markup (no letter or slash after it)", "a < b", "title", "key|a b"),
("KF13 & decoded then removed as punctuation", "Salt & Pepper", "title", "key|salt pepper"),
("KF14 ’ and ’ decoded to a quotation mark, removed", "Don’t ’go", "title", "key|dont go"),
("KF15 <i> decodes to literal brackets, which are symbols", "<i>x", "title", "key|ix"),
("KF16 an unknown named entity stays (named limit)", "a b", "title", "key|a nbsp b"),
("KF17 � decodes to a control, removed", "a�b", "title", "key|ab"),
("KF18 a numeric entity above 10FFFF stays", "a�b", "title", "key|a1114112b"),
("KF19 an accented family name against its bare form", "M\u00fcller", "name", "key|muller"),
("KF20 the bare form", "Muller", "name", "key|muller"),
("KF21 NFD input equals NFC input", "Mu\u0308ller", "name", "key|muller"),
("KF22 U+00D8 keeps its case (no ASCII decomposition, named limit)", "\u00d8stergaard", "name", "key|\u00d8stergaard"),
("KF23 an em dash removed, spaces collapsed", "Word \u2014 word", "title", "key|word word"),
("KF24 hyphens removed join the words", "non-specific", "title", "key|nonspecific"),
("KF25 white space of every kind collapses", "a\t\n\r\u00a0\u2003\u3000b", "title", "key|a b"),
("KF26 a zero-width space is removed, joining", "a\u200bb", "title", "key|ab"),
("KF27 currency and math symbols removed", "$5 + 3 = 8%", "title", "key|5 3 8"),
("KF28 Greek keeps its case", "\u03a9mega", "name", "key|\u03a9mega"),
("KF29 empty text", "", "title", "key|"),
("KF30 punctuation only", "...", "title", "key|"),
("KF31 a wrong kind refused", "x", "TITLE", "ERROR:key"),
("KF32 a number refused", 5, "title", "ERROR:key"),
("KF33 CJK and digits kept", "\u91cf\u5b50 2026", "title", "key|\u91cf\u5b50 2026"),
("KF34 a ligature stays (NFD, not NFKD)", "\ufb01ne", "title", "key|\ufb01ne"),
("KF35 a Hangul syllable recomposes", "\u1100\u1161", "title", "key|\uac00"),
("KF36 the ANGSTROM SIGN loses its ring (NFD) and folds", "\u212bngstr\u00f6m", "name", "key|angstrom"),
]
for name, text, kind, hand in K:
add(name, "key", {"text": text, "kind": kind}, hand)
# ---------------------------------------------------------------- dupe
K = [
("DK01 the DOI folded", {"DOI": WAKE_DOI, "ISSN": "0140-6736", "PMID": "9500320"}, "dupe|DOI|" + WAKE_DOI_LC),
("DK02 the DOI wins over ARXIV and ISBN", {"DOI": "10.1000/X", "ARXIV": "2601.12345", "ISBN": "0-306-40615-2"}, "dupe|DOI|10.1000/x"),
("DK03 the arXiv key without its version", {"ARXIV": "2601.12345v4"}, "dupe|ARXIV|2601.12345"),
("DK04 the arXiv key wins over ISBN", {"ARXIV": "hep-th/0701999v2", "ISBN": "0-306-40615-2"}, "dupe|ARXIV|hep-th/0701999"),
("DK05 the ISBN-13 from an ISBN-10", {"ISBN": "0-306-40615-2"}, "dupe|ISBN|9780306406157"),
("DK06 the ISBN-13 as given", {"ISBN": "9780306406157"}, "dupe|ISBN|9780306406157"),
("DK07 ISSN alone is no key", {"ISSN": "0140-6736"}, "dupe|NONE|"),
("DK08 PMID alone is no key", {"PMID": "9500320"}, "dupe|NONE|"),
("DK09 no identifiers", {}, "dupe|NONE|"),
("DK10 an arXiv DOI in the DOI slot refused", {"DOI": "10.48550/arXiv.2601.12345"}, "ERROR:identifier:DOI"),
("DK11 a bad ISBN refused", {"ISBN": "0-306-40615-3"}, "ERROR:identifier:ISBN"),
("DK12 a bad ARXIV refused", {"ARXIV": "2601.1"}, "ERROR:identifier:ARXIV"),
("DK13 an unknown key refused", {"ORCID": "0000-0002-1825-0097"}, "ERROR:identifiers"),
("DK14 a list refused", ["DOI"], "ERROR:identifiers"),
("DK15 a bad PMCID refused", {"PMCID": "8243230"}, "ERROR:identifier:PMCID"),
("DK16 a bad ISSN refused", {"ISSN": "0378-5956"}, "ERROR:identifier:ISSN"),
("DK17 a bad PMID refused", {"PMID": "0"}, "ERROR:identifier:PMID"),
("DK18 the DOI in doi: form is accepted and folded", {"DOI": "doi:10.1000/ABC"}, "dupe|DOI|10.1000/abc"),
]
for name, ids, hand in K:
add(name, "dupe", {"identifiers": ids}, hand)
# --------------------------------------------------------------- check
WAKE = {"type": "article-journal", "title": WAKE_TITLE,
"author": [{"family": "Wakefield", "given": "A J"}, {"family": "Murch", "given": "S H"}],
"issued": {"date-parts": [[1998, 2, 28]]}, "container-title": "The Lancet",
"volume": "351", "issue": "9103", "page": "637-641", "DOI": WAKE_DOI,
"ISSN": "0140-6736", "PMID": "9500320"}
WAKE_IDS = {"DOI": WAKE_DOI, "ISSN": "0140-6736", "PMID": "9500320"}
PRE = {"type": "article", "title": "Vacuum structure of a fixture field",
"author": [{"family": "Santos", "given": "Sara Oliveira"}],
"issued": {"date-parts": [[2026, 1]]}, "DOI": "10.48550/arXiv.2601.12345"}
PRE_IDS = {"ARXIV": "2601.12345v2"}
PUB = {"type": "article-journal", "title": "Vacuum structure of a fixture field",
"author": [{"family": "Santos", "given": "Sara Oliveira"}],
"issued": {"date-parts": [[2026, 6]]}, "container-title": "Fixture Review D",
"DOI": "10.1103/FixRevD.113.012345"}
PUB_IDS = {"DOI": "10.1103/FixRevD.113.012345", "ARXIV": "2601.12345v2"}
BOOK = {"type": "book", "title": "Fixture Handbook",
"editor": [{"family": "Editor", "given": "E"}],
"issued": {"date-parts": [[2020]]}, "publisher": "Fixture Press",
"ISBN": "0-306-40615-2"}
BOOK_IDS = {"ISBN": "978-0-306-40615-7"}
REPORT = {"type": "report", "title": "Fixture Report",
"author": [{"literal": "Fixture Collaboration"}],
"issued": {"date-parts": [[2019, 12, 31]], "circa": True}}
def entry(item, ids, sup=None):
return {"item": item, "identifiers": ids, "supersedes": sup}
def ck(name, e, hand, existing=(), caps=CAPS):
add(name, "check", {"entry": e, "existing": list(existing), "caps": caps}, hand)
def item(base, **kw):
d = dict(base)
for k, v in kw.items():
if v is None:
d.pop(k, None)
else:
d[k] = v
return d
WAKE_OK = lines("check|OK|DOI|" + WAKE_DOI_LC, "id|DOI|" + WAKE_DOI, "id|ISSN|0140-6736", "id|PMID|9500320")
ck("CK01 the Wakefield entry", entry(WAKE, WAKE_IDS), WAKE_OK)
ck("CK02 a preprint keyed by its arXiv id", entry(PRE, PRE_IDS),
lines("check|OK|ARXIV|2601.12345", "id|ARXIV|2601.12345v2"))
ck("CK03 its published version keyed by its DOI: two entries", entry(PUB, PUB_IDS),
lines("check|OK|DOI|10.1103/fixrevd.113.012345", "id|DOI|10.1103/FixRevD.113.012345", "id|ARXIV|2601.12345v2"))
ck("CK04 the published version beside the landed preprint is no duplicate", entry(PUB, PUB_IDS),
lines("check|OK|DOI|10.1103/fixrevd.113.012345", "id|DOI|10.1103/FixRevD.113.012345", "id|ARXIV|2601.12345v2"),
[["ARXIV", "2601.12345", "RR-BIB1"]])
ck("CK05 a book with an editor only, ISBN-10 in the item and 13 in IDENTIFIERS", entry(BOOK, BOOK_IDS),
lines("check|OK|ISBN|9780306406157", "id|ISBN|9780306406157"))
ck("CK06 a literal name for a collaboration; no identifier; circa", entry(REPORT, {}),
"check|OK|NONE|")
FULL = {"type": "chapter", "id": "RR-BIB7", "title": "T", "title-short": "T", "author": [{"family": "A", "given": "B",
"dropping-particle": "de", "non-dropping-particle": "van", "suffix": "Jr"}],
"editor": [{"literal": "Ed"}], "translator": [{"family": "Tr"}], "container-author": [{"family": "Ca"}],
"collection-editor": [{"family": "Ce"}], "issued": {"date-parts": [[2001, 1, 1], [2002, 12, 31]]},
"accessed": {"date-parts": [[2026, 9, 26]]}, "original-date": {"date-parts": [[-500]], "circa": True},
"container-title": "C", "container-title-short": "C", "collection-title": "S", "collection-number": "3",
"publisher": "P", "publisher-place": "Q", "volume": "1", "issue": "2", "page": "3-4", "number": "5",
"number-of-pages": "6", "edition": "2nd", "genre": "g", "medium": "print", "event-title": "E",
"event-place": "F", "chapter-number": "7", "version": "1.0", "language": "en-GB", "DOI": "10.1000/full",
"ISBN": "978-0-306-40615-7", "ISSN": "0378-5955", "PMID": "1", "PMCID": "PMC1", "URL": "https://example.org/x",
"original-title": "O", "archive": "Ar", "archive_location": "Al"}
FULL_IDS = {"DOI": "10.1000/full", "ISBN": "9780306406157", "ISSN": "0378-5955", "PMID": "1", "PMCID": "PMC1"}
ck("CK07 every field of the subset present", entry(FULL, FULL_IDS),
lines("check|OK|DOI|10.1000/full", "id|DOI|10.1000/full", "id|ISBN|9780306406157", "id|ISSN|0378-5955",
"id|PMID|1", "id|PMCID|PMC1"))
ck("CK08 abstract refused (BR F29)", entry(item(WAKE, abstract="text"), WAKE_IDS), "ERROR:subset:abstract")
ck("CK09 note refused", entry(item(WAKE, note="n"), WAKE_IDS), "ERROR:subset:note")
ck("CK10 custom refused", entry(item(WAKE, custom={"k": "v"}), WAKE_IDS), "ERROR:subset:custom")
ck("CK11 a name key outside NAME_KEYS refused", entry(item(WAKE, author=[{"family": "W", "comma-suffix": True}]), WAKE_IDS),
"ERROR:subset:author")
ck("CK12 a raw date refused (RD-3: date-parts and circa only)", entry(item(WAKE, issued={"raw": "1998"}), WAKE_IDS),
"ERROR:subset:issued")
ck("CK13 an unknown type refused", entry(item(WAKE, type="preprint"), WAKE_IDS), "ERROR:type:type")
ck("CK14 a numeric page refused (strings only)", entry(item(WAKE, page=637), WAKE_IDS), "ERROR:type:page")
ck("CK15 an empty title refused", entry(item(WAKE, title=""), WAKE_IDS), "ERROR:type:title")
ck("CK16 author not a list refused", entry(item(WAKE, author={"family": "W"}), WAKE_IDS), "ERROR:type:author")
ck("CK17 a name with given only refused", entry(item(WAKE, author=[{"given": "A"}]), WAKE_IDS), "ERROR:type:author")
ck("CK18 date-parts as strings refused (RD-3: integers)", entry(item(WAKE, issued={"date-parts": [["1998"]]}), WAKE_IDS),
"ERROR:type:issued")
ck("CK19 month 13 refused", entry(item(WAKE, issued={"date-parts": [[1998, 13]]}), WAKE_IDS), "ERROR:type:issued")
ck("CK20 circa not a boolean refused", entry(item(WAKE, issued={"date-parts": [[1998]], "circa": "yes"}), WAKE_IDS),
"ERROR:type:issued")
ck("CK21 a bidi override in the title refused (text safety)", entry(item(WAKE, title="A\u202eB"), WAKE_IDS),
"ERROR:text:title")
ck("CK22 a zero-width space in a name refused", entry(item(WAKE, author=[{"family": "W\u200b"}]), WAKE_IDS),
"ERROR:text:author")
ck("CK23 type missing refused", entry(item(WAKE, type=None), WAKE_IDS), "ERROR:required:type")
ck("CK24 title missing refused", entry(item(WAKE, title=None), WAKE_IDS), "ERROR:required:title")
ck("CK25 issued missing refused", entry(item(WAKE, issued=None), WAKE_IDS), "ERROR:required:issued")
ck("CK26 no author and no editor refused (a translator does not serve)",
entry(item(WAKE, author=None, translator=[{"family": "T"}]), WAKE_IDS), "ERROR:required:author")
ck("CK27 empty author and editor lists refused", entry(item(WAKE, author=[], editor=[]), WAKE_IDS), "ERROR:required:author")
ck("CK28 the title cap", entry(item(WAKE, title="x" * 1001), WAKE_IDS), "ERROR:cap:title")
ck("CK29 the title at its cap passes (code points, not bytes)", entry(item(WAKE, title="\u00e9" * 1000), WAKE_IDS), WAKE_OK)
ck("CK30 the text cap on container-title", entry(item(WAKE, **{"container-title": "x" * 501}), WAKE_IDS),
"ERROR:cap:container-title")
ck("CK31 the URL cap", entry(item(WAKE, URL="https://example.org/" + "x" * 1990), WAKE_IDS), "ERROR:cap:URL")
ck("CK32 the name-part cap", entry(item(WAKE, author=[{"family": "x" * 201}]), WAKE_IDS), "ERROR:cap:author")
ck("CK33 the names-per-role cap", entry(item(WAKE, author=[{"family": "x"}] * 101), WAKE_IDS), "ERROR:cap:author")
ck("CK34 caps are arguments: a smaller title cap refuses", entry(WAKE, WAKE_IDS), "ERROR:cap:title",
caps=dict(CAPS, title=50))
ck("CK35 an unknown identifier kind refused", entry(WAKE, dict(WAKE_IDS, ORCID="x")), "ERROR:identifiers")
ck("CK36 a bad DOI in IDENTIFIERS refused", entry(WAKE, dict(WAKE_IDS, DOI="10.1016")), "ERROR:identifier:DOI")
ck("CK37 a bad ISSN check refused", entry(WAKE, dict(WAKE_IDS, ISSN="0140-6737")), "ERROR:identifier:ISSN")
ck("CK38 the item's DOI must equal IDENTIFIERS.DOI after folding", entry(WAKE, dict(WAKE_IDS, DOI="10.1016/other")),
"ERROR:mismatch:DOI")
ck("CK39 the item's DOI in URL form and a lower-cased IDENTIFIERS.DOI agree",
entry(item(WAKE, DOI="https://doi.org/" + WAKE_DOI), dict(WAKE_IDS, DOI=WAKE_DOI_LC)),
lines("check|OK|DOI|" + WAKE_DOI_LC, "id|DOI|" + WAKE_DOI_LC, "id|ISSN|0140-6736", "id|PMID|9500320"))
ck("CK40 an item DOI with no IDENTIFIERS.DOI refused", entry(WAKE, {"ISSN": "0140-6736"}), "ERROR:mismatch:DOI")
ck("CK41 an arXiv DOI in the item requires ARXIV and no DOI", entry(PRE, {"DOI": "10.1000/x", "ARXIV": "2601.12345v2"}),
"ERROR:mismatch:DOI")
ck("CK42 an arXiv DOI in the item with a different ARXIV refused", entry(PRE, {"ARXIV": "2601.12346"}), "ERROR:mismatch:DOI")
ck("CK43 an arXiv DOI in the item with the ARXIV at another version passes (keys equal)",
entry(PRE, {"ARXIV": "2601.12345"}), lines("check|OK|ARXIV|2601.12345", "id|ARXIV|2601.12345"))
ck("CK44 the item's ISBN must equal IDENTIFIERS.ISBN as 13", entry(BOOK, {"ISBN": "979-10-90636-07-1"}), "ERROR:mismatch:ISBN")
ck("CK45 the item's ISSN must equal IDENTIFIERS.ISSN", entry(WAKE, dict(WAKE_IDS, ISSN="0378-5955")), "ERROR:mismatch:ISSN")
ck("CK46 the item's PMID must equal IDENTIFIERS.PMID", entry(WAKE, dict(WAKE_IDS, PMID="1")), "ERROR:mismatch:PMID")
ck("CK47 a duplicate DOI differing in case refused with the existing BIB ID", entry(WAKE, WAKE_IDS),
"ERROR:duplicate:RR-BIB3", [["DOI", WAKE_DOI_LC, "RR-BIB3"]])
ck("CK48 the duplicate waived when SUPERSEDES names it", entry(WAKE, WAKE_IDS, "RR-BIB3"), WAKE_OK,
[["DOI", WAKE_DOI_LC, "RR-BIB3"]])
ck("CK49 SUPERSEDES naming another entry does not waive", entry(WAKE, WAKE_IDS, "RR-BIB2"), "ERROR:duplicate:RR-BIB3",
[["DOI", WAKE_DOI_LC, "RR-BIB3"]])
ck("CK50 a duplicate arXiv id at another version refused", entry(PRE, {"ARXIV": "2601.12345v3"}), "ERROR:duplicate:RR-BIB1",
[["ARXIV", "2601.12345", "RR-BIB1"]])
ck("CK51 a duplicate ISBN given as 10 against a landed 13 refused", entry(BOOK, {"ISBN": "0-306-40615-2"}), "ERROR:duplicate:RR-BIB9",
[["ISBN", "9780306406157", "RR-BIB9"]])
ck("CK52 an entry with no key is never a duplicate", entry(REPORT, {}), "check|OK|NONE|",
[["DOI", "10.1000/x", "RR-BIB1"]])
ck("CK53 the size cap on the canonical text", entry(WAKE, WAKE_IDS), "ERROR:size", caps=dict(CAPS, entry_max=200))
ck("CK54 an entry without supersedes refused", {"item": WAKE, "identifiers": WAKE_IDS}, "ERROR:entry")
ck("CK55 supersedes not a text refused", entry(WAKE, WAKE_IDS, 5), "ERROR:entry")
ck("CK56 existing keys malformed refused", entry(WAKE, WAKE_IDS), "ERROR:existing", [["DOI", "x"]])
ck("CK57 caps missing a key refused", entry(WAKE, WAKE_IDS), "ERROR:caps", caps={"entry_max": 1})
ck("CK58 a cap of zero refused", entry(WAKE, WAKE_IDS), "ERROR:caps", caps=dict(CAPS, names=0))
ck("CK59 the item not an object refused", entry([WAKE], WAKE_IDS), "ERROR:type:item")
ck("CK60 a second issued range date passes", entry(item(WAKE, issued={"date-parts": [[1998, 2], [1998, 3]]}), WAKE_IDS), WAKE_OK)
ck("CK61 a year of -10000 refused", entry(item(WAKE, issued={"date-parts": [[-10000]]}), WAKE_IDS), "ERROR:type:issued")
ck("CK62 three date-parts lists refused", entry(item(WAKE, issued={"date-parts": [[1998], [1999], [2000]]}), WAKE_IDS),
"ERROR:type:issued")
ck("CK63 a boolean year refused (ints are never bools)", entry(item(WAKE, issued={"date-parts": [[True]]}), WAKE_IDS),
"ERROR:type:issued")
ck("CK64 the checks run in order: a subset failure before a required one",
entry({"abstract": "x"}, {}), "ERROR:subset:abstract")
ck("CK65 identifiers checked after caps", entry(item(WAKE, title="x" * 1001), {"DOI": "bad"}), "ERROR:cap:title")
# --------------------------------------------------------------- canon
CN_ARGS = {"bib_id": "RR-BIB1", "proposed_by": "DeltaS Zero", "landed_by": "Prime AI",
"landed": "2026-09-26T12:00:00Z", "supersedes": None, "identifiers": WAKE_IDS, "item": WAKE}
WAKE_TEXT = ('{"type":"article-journal","id":"RR-BIB1","title":"' + WAKE_TITLE + '",'
'"author":[{"family":"Wakefield","given":"A J"},{"family":"Murch","given":"S H"}],'
'"issued":{"date-parts":[[1998,2,28]]},"container-title":"The Lancet","volume":"351",'
'"issue":"9103","page":"637-641","DOI":"' + WAKE_DOI + '","ISSN":"0140-6736","PMID":"9500320"}')
def ns(fields):
return "".join("%d:%s" % (len(f.encode("utf-8")), f) for f in fields)
PRE_WAKE = ns(["TPC-BIB", "1", "RR-BIB1", "DeltaS Zero", "Prime AI", "2026-09-26T12:00:00Z", "",
"DOI", WAKE_DOI, "ARXIV", "", "ISBN", "", "ISSN", "0140-6736", "PMID", "9500320", "PMCID", "",
WAKE_TEXT])
D_WAKE = hashlib.sha256(PRE_WAKE.encode("utf-8")).hexdigest() # checked against sha256sum in the run log
add("CA01 the Wakefield entry's canonical text and digest", "canon", CN_ARGS, lines("canon|" + D_WAKE, WAKE_TEXT))
add("CA02 the same preimage as text", "preimage", CN_ARGS, "preimage|" + PRE_WAKE)
add("CA03 the item's key order is fixed whatever the input order", "canon",
dict(CN_ARGS, item={"PMID": "9500320", "ISSN": "0140-6736", "DOI": WAKE_DOI, "page": "637-641", "issue": "9103",
"volume": "351", "container-title": "The Lancet", "issued": {"date-parts": [[1998, 2, 28]]},
"author": [{"given": "A J", "family": "Wakefield"}, {"given": "S H", "family": "Murch"}],
"title": WAKE_TITLE, "type": "article-journal"}),
lines("canon|" + D_WAKE, WAKE_TEXT))
add("CA04 an item id equal to bib_id passes", "canon", dict(CN_ARGS, item=item(WAKE, id="RR-BIB1")),
lines("canon|" + D_WAKE, WAKE_TEXT))
add("CA05 an item id differing from bib_id refused", "canon", dict(CN_ARGS, item=item(WAKE, id="RR-BIB2")), "ERROR:id")
SUP_ARGS = dict(CN_ARGS, bib_id="RR-BIB2", supersedes="RR-BIB1", identifiers={"ISSN": "0140-6736"},
item=item(WAKE, DOI=None, PMID=None, title="A title with \"quotes\", a \\ backslash and a\ttab"))
SUP_TEXT = ('{"type":"article-journal","id":"RR-BIB2","title":"A title with \\"quotes\\", a \\\\ backslash and a\\u0009tab",'
'"author":[{"family":"Wakefield","given":"A J"},{"family":"Murch","given":"S H"}],'
'"issued":{"date-parts":[[1998,2,28]]},"container-title":"The Lancet","volume":"351",'
'"issue":"9103","page":"637-641","ISSN":"0140-6736"}')
PRE_SUP = ns(["TPC-BIB", "1", "RR-BIB2", "DeltaS Zero", "Prime AI", "2026-09-26T12:00:00Z", "RR-BIB1",
"DOI", "", "ARXIV", "", "ISBN", "", "ISSN", "0140-6736", "PMID", "", "PMCID", "", SUP_TEXT])
D_SUP = hashlib.sha256(PRE_SUP.encode("utf-8")).hexdigest()
add("CA07 a superseding entry: escapes for quote, backslash and TAB; SUPERSEDES in the digest", "canon", SUP_ARGS,
lines("canon|" + D_SUP, SUP_TEXT.replace("\\", "\\\\")))
add("CA08 its preimage", "preimage", SUP_ARGS, "preimage|" + PRE_SUP.replace("\\", "\\\\"))
FULL_ARGS = dict(CN_ARGS, bib_id="RR-BIB7", identifiers=FULL_IDS, item=FULL)
FULL_TEXT = ('{"type":"chapter","id":"RR-BIB7","title":"T","title-short":"T","author":[{"family":"A","given":"B",'
'"dropping-particle":"de","non-dropping-particle":"van","suffix":"Jr"}],"editor":[{"literal":"Ed"}],'
'"translator":[{"family":"Tr"}],"container-author":[{"family":"Ca"}],"collection-editor":[{"family":"Ce"}],'
'"issued":{"date-parts":[[2001,1,1],[2002,12,31]]},"accessed":{"date-parts":[[2026,9,26]]},'
'"original-date":{"date-parts":[[-500]],"circa":true},"container-title":"C","container-title-short":"C",'
'"collection-title":"S","collection-number":"3","publisher":"P","publisher-place":"Q","volume":"1",'
'"issue":"2","page":"3-4","number":"5","number-of-pages":"6","edition":"2nd","genre":"g","medium":"print",'
'"event-title":"E","event-place":"F","chapter-number":"7","version":"1.0","language":"en-GB",'
'"DOI":"10.1000/full","ISBN":"978-0-306-40615-7","ISSN":"0378-5955","PMID":"1","PMCID":"PMC1",'
'"URL":"https://example.org/x","original-title":"O","archive":"Ar","archive_location":"Al"}')
PRE_FULL = ns(["TPC-BIB", "1", "RR-BIB7", "DeltaS Zero", "Prime AI", "2026-09-26T12:00:00Z", "",
"DOI", "10.1000/full", "ARXIV", "", "ISBN", "9780306406157", "ISSN", "0378-5955", "PMID", "1",
"PMCID", "PMC1", FULL_TEXT])
D_FULL = hashlib.sha256(PRE_FULL.encode("utf-8")).hexdigest()
add("CA09 every field: names in NAME_KEYS order, a date range, circa, a negative year", "canon", FULL_ARGS,
lines("canon|" + D_FULL, FULL_TEXT))
add("CA10 its preimage", "preimage", FULL_ARGS, "preimage|" + PRE_FULL)
add("CA11 the item's ISBN stays as written while IDENTIFIERS carries the 13", "canon",
dict(CN_ARGS, bib_id="RR-BIB9", identifiers=BOOK_IDS, item=BOOK))
add("CA12 a non-ASCII title: NFC in the text, UTF-8 byte lengths in the netstring", "preimage",
dict(CN_ARGS, identifiers={}, item=item(WAKE, title="\u00c9tude", DOI=None, ISSN=None, PMID=None)),
"preimage|" + ns(["TPC-BIB", "1", "RR-BIB1", "DeltaS Zero", "Prime AI", "2026-09-26T12:00:00Z", "",
"DOI", "", "ARXIV", "", "ISBN", "", "ISSN", "", "PMID", "", "PMCID", "",
'{"type":"article-journal","id":"RR-BIB1","title":"\u00c9tude","author":[{"family":"Wakefield",'
'"given":"A J"},{"family":"Murch","given":"S H"}],"issued":{"date-parts":[[1998,2,28]]},'
'"container-title":"The Lancet","volume":"351","issue":"9103","page":"637-641"}']))
add("CA06 the same title in NFD gives the same preimage (NFC before the digest)", "preimage",
dict(CN_ARGS, identifiers={}, item=item(WAKE, title="E\u0301tude", DOI=None, ISSN=None, PMID=None)),
"preimage|" + ns(["TPC-BIB", "1", "RR-BIB1", "DeltaS Zero", "Prime AI", "2026-09-26T12:00:00Z", "",
"DOI", "", "ARXIV", "", "ISBN", "", "ISSN", "", "PMID", "", "PMCID", "",
'{"type":"article-journal","id":"RR-BIB1","title":"\u00c9tude","author":[{"family":"Wakefield",'
'"given":"A J"},{"family":"Murch","given":"S H"}],"issued":{"date-parts":[[1998,2,28]]},'
'"container-title":"The Lancet","volume":"351","issue":"9103","page":"637-641"}']))
add("CA13 an empty bib_id refused", "canon", dict(CN_ARGS, bib_id=""), "ERROR:bib_id")
add("CA14 proposed_by with a hidden character refused", "canon", dict(CN_ARGS, proposed_by="x\u200b"), "ERROR:proposed_by")
add("CA15 landed_by missing refused", "canon", dict(CN_ARGS, landed_by=None), "ERROR:landed_by")
add("CA16 landed not a text refused", "canon", dict(CN_ARGS, landed=1758888000), "ERROR:landed")
add("CA17 supersedes not a text refused", "canon", dict(CN_ARGS, supersedes=5), "ERROR:supersedes")
add("CA18 identifiers with a bad DOI refused", "canon", dict(CN_ARGS, identifiers={"DOI": "x"}), "ERROR:identifier:DOI")
add("CA19 an item outside the subset refused", "canon", dict(CN_ARGS, item=item(WAKE, abstract="a")), "ERROR:subset:abstract")
add("CA20 an item without required fields still serializes (the write check gates)", "canon",
dict(CN_ARGS, identifiers={}, item={"type": "book"}),
lines("canon|" + hashlib.sha256(ns(["TPC-BIB", "1", "RR-BIB1", "DeltaS Zero", "Prime AI", "2026-09-26T12:00:00Z", "",
"DOI", "", "ARXIV", "", "ISBN", "", "ISSN", "", "PMID", "", "PMCID", "",
'{"type":"book","id":"RR-BIB1"}']).encode("utf-8")).hexdigest(),
'{"type":"book","id":"RR-BIB1"}'))
add("CA21 the digest excludes the status lines: the same fields give the same digest", "canon",
dict(CN_ARGS, item=dict(WAKE)), lines("canon|" + D_WAKE, WAKE_TEXT))
add("CA22 a LF inside a string escapes as \\u000a; CRLF is normalized to LF first", "preimage",
dict(CN_ARGS, identifiers={}, item={"type": "book", "title": "a\r\nb"}),
"preimage|" + ns(["TPC-BIB", "1", "RR-BIB1", "DeltaS Zero", "Prime AI", "2026-09-26T12:00:00Z", "",
"DOI", "", "ARXIV", "", "ISBN", "", "ISSN", "", "PMID", "", "PMCID", "",
'{"type":"book","id":"RR-BIB1","title":"a\\u000ab"}']).replace("\\", "\\\\"))
# ----------------------------------------------------------------- url
D_RA = {"kind": "DOI-RA", "template": "https://doi.org/ra/{ID}", "name": "doi.org agency lookup"}
D_CR = {"kind": "DOI-CROSSREF", "template": "https://api.crossref.org/v1/works/{ID}"}
D_DC = {"kind": "DOI-DATACITE", "template": "https://api.datacite.org/dois/{ID}"}
D_AX = {"kind": "ARXIV", "template": "https://export.arxiv.org/api/query?id_list={ID}"}
D_PM = {"kind": "PMID", "template": "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&retmode=json&id={ID}"}
D_PC = {"kind": "PMCID", "template": "https://pmc.ncbi.nlm.nih.gov/tools/idconv/api/v1/articles/?format=json&ids={ID}"}
def ur(name, decl, ident, hand):
add(name, "url", {"declaration": decl, "identifier": ident}, hand)
ur("UR01 the agency lookup with a plain DOI (V-1)", D_RA, WAKE_DOI, "url|https://doi.org/ra/" + WAKE_DOI)
ur("UR02 Crossref with the SICI DOI: < > ; encoded, ( ) : / raw (V-2)", D_CR, TEECE_DOI,
"url|https://api.crossref.org/v1/works/10.1002/(SICI)1097-0266(199708)18:7%3C509::AID-SMJ882%3E3.0.CO%3B2-Z")
ur("UR03 DataCite with a DOI given in doi: form", D_DC, "doi:10.5281/zenodo.1234567",
"url|https://api.datacite.org/dois/10.5281/zenodo.1234567")
ur("UR04 arXiv with a versioned id in the query (RD-7)", D_AX, "2601.12345v2",
"url|https://export.arxiv.org/api/query?id_list=2601.12345v2")
ur("UR05 arXiv with an old-scheme id: the slash stays raw", D_AX, "arXiv:hep-th/0701999",
"url|https://export.arxiv.org/api/query?id_list=hep-th/0701999")
ur("UR06 PubMed esummary", D_PM, "9500320",
"url|https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&retmode=json&id=9500320")
ur("UR07 the PMC ID converter", D_PC, "pmc8243230",
"url|https://pmc.ncbi.nlm.nih.gov/tools/idconv/api/v1/articles/?format=json&ids=PMC8243230")
ur("UR08 a non-ASCII DOI suffix percent-encoded as UTF-8, upper-case hex", D_CR, "10.1000/\u00e9",
"url|https://api.crossref.org/v1/works/10.1000/%C3%A9")
ur("UR09 a space cannot occur; % # ? & = + in a suffix are encoded", D_CR, "10.1000/a%b#c?d&e=f+g",
"url|https://api.crossref.org/v1/works/10.1000/a%25b%23c%3Fd%26e%3Df%2Bg")
ur("UR10 the arXiv DOI is never looked up as a DOI", D_RA, "10.48550/arXiv.2601.12345", "ERROR:identifier")
ur("UR11 a DOI in the ARXIV slot refused", D_AX, WAKE_DOI, "ERROR:identifier")
ur("UR12 a bad PMID refused", D_PM, "0", "ERROR:identifier")
ur("UR13 a template with no slot refused", dict(D_CR, template="https://api.crossref.org/v1/works/"), WAKE_DOI,
"ERROR:template")
ur("UR14 a template with two slots refused", dict(D_CR, template="https://api.crossref.org/{ID}/{ID}"), WAKE_DOI,
"ERROR:template")
ur("UR15 an http template refused", dict(D_CR, template="http://api.crossref.org/v1/works/{ID}"), WAKE_DOI,
"ERROR:template")
ur("UR16 a template with a fragment refused", dict(D_CR, template="https://api.crossref.org/v1/works/{ID}#x"), WAKE_DOI,
"ERROR:template")
ur("UR17 a template with another brace refused", dict(D_CR, template="https://api.crossref.org/{v}/works/{ID}"), WAKE_DOI,
"ERROR:template")
ur("UR18 a template with a space refused", dict(D_CR, template="https://api.crossref.org/v1 /works/{ID}"), WAKE_DOI,
"ERROR:template")
ur("UR19 a template with no path refused", dict(D_CR, template="https://api.crossref.org{ID}"), WAKE_DOI,
"ERROR:template")
ur("UR20 an unknown declaration kind refused", {"kind": "OPENALEX", "template": "https://api.openalex.org/works/{ID}"},
WAKE_DOI, "ERROR:declaration")
ur("UR21 a declaration missing its template refused", {"kind": "DOI-RA"}, WAKE_DOI, "ERROR:declaration")
ur("UR22 a declaration with an extra key refused", dict(D_RA, pacing=3), WAKE_DOI, "ERROR:declaration")
ur("UR23 a template that is not a string refused", dict(D_RA, template=5), WAKE_DOI, "ERROR:template")
ur("UR24 the slot in the host is refused (no path)", dict(D_RA, template="https://{ID}.example.org/"), WAKE_DOI,
"ERROR:template")
ur("UR25 a port in the template passes", dict(D_RA, template="https://example.org:8443/ra/{ID}"), "10.1000/x",
"url|https://example.org:8443/ra/10.1000/x")
ur("UR26 a DOI suffix with a .. segment is refused: a client would fetch another path (RFC 3986 5.2.4)",
D_CR, "10.1000/../x", "ERROR:identifier")
ur("UR27 a DOI suffix with a . segment is refused", D_RA, "10.1000/a/./b", "ERROR:identifier")
ur("UR28 a DOI suffix ending in .. is refused", D_RA, "10.1000/a/..", "ERROR:identifier")
ur("UR29 dots inside a segment are not a dot segment", D_RA, "10.1000/a..b/.c/d.", "url|https://doi.org/ra/10.1000/a..b/.c/d.")
ur("UR30 a dot segment in a query slot is harmless", dict(D_AX, kind="DOI-RA"), "10.1000/../x",
"url|https://export.arxiv.org/api/query?id_list=10.1000/../x")
# --------------------------------------------------------------- compare
FIELDS0 = {"year": None, "title": None, "subtitle": None, "family": None, "name_form": None, "doi": None,
"issn": [], "isbn": [], "arxiv_doi": None, "arxiv_id": None}
def fields(**kw):
f = dict(FIELDS0)
f.update(kw)
return f
def rec_doi(ident, ra, registry=None, status=None, f=None, notices=()):
return {"kind": "DOI", "identifier": ident, "ra": ra, "registry": registry, "status": status,
"fields": f, "notices": list(notices)}
def rec(kind, ident, status, f=None, notices=()):
return {"kind": kind, "identifier": ident, "registry": "arxiv" if kind == "ARXIV" else "pubmed",
"status": status, "fields": f, "notices": list(notices)}
RA_CR = {"status": "FOUND", "ra": "Crossref"}
RA_DC = {"status": "FOUND", "ra": "DataCite"}
RA_NO = {"status": "NOT FOUND", "ra": None}
RA_FAIL = {"status": "FAILED", "ra": None}
RA_OTHER = {"status": "FOUND", "ra": "mEDRA"}
WAKE_CR = fields(year=1998, title="RETRACTED: " + WAKE_TITLE, family="Wakefield", name_form="FAMILY",
doi=WAKE_DOI_LC, issn=["0140-6736"])
N_RETR = {"type": "retraction", "identifier": "10.1016/s0140-6736(10)60175-4", "date": "2010-02-06", "source": "retraction-watch"}
N_CORR = {"type": "correction", "identifier": "10.1016/s0140-6736(04)15715-2", "date": "2004-03-06", "source": "retraction-watch"}
N_EOC = {"type": "expression_of_concern", "identifier": "10.1016/s0140-6736(04)15716-4", "date": "2004-02-28", "source": "publisher"}
N_REIN = {"type": "Reinstatement", "identifier": None, "date": None, "source": "retraction-watch"}
WAKE_PM = fields(year=1998, title=WAKE_TITLE + ".", family="Wakefield AJ", name_form="FAMILY INITIALS", doi=WAKE_DOI_LC)
N_PM1 = {"type": "Retracted Publication", "identifier": None, "date": None, "source": "pubmed"}
N_PM2 = {"type": "Retraction in", "identifier": "20137807", "date": None, "source": "pubmed"}
N_PM3 = {"type": "Expression of concern in", "identifier": "14976303", "date": None, "source": "pubmed"}
DATE = "2026-09-26"
def cp(name, e, records, hand, date=DATE):
add(name, "compare", {"entry": {"item": e[0], "identifiers": e[1]}, "records": records, "date": date}, hand)
WAKE_E = (WAKE, WAKE_IDS)
WAKE_RECS = [rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", WAKE_CR, [N_RETR, N_CORR]),
rec("PMID", "9500320", "FOUND", WAKE_PM, [N_PM1, N_PM2, N_PM3])]
cp("CP01 the Wakefield entry: CONFIRMED through the RETRACTED: marker, every notice type", WAKE_E, WAKE_RECS,
lines("compare|CONFIRMED",
"DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|CONFIRMED|", "ISSN|0140-6736|CONFIRMED|",
"notice|retraction-watch|10.1016/s0140-6736(10)60175-4|2010-02-06|retraction",
"notice|retraction-watch|10.1016/s0140-6736(04)15715-2|2004-03-06|correction",
"notice|pubmed|-|-|retracted publication",
"notice|pubmed|20137807|-|retraction in",
"notice|pubmed|14976303|-|expression of concern in",
"line|CHECK 2026-09-26 CONFIRMED ; DOI %s CONFIRMED ; PMID 9500320 CONFIRMED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|NOTICES 2026-09-26 ; retraction-watch 10.1016/s0140-6736(10)60175-4 2010-02-06 retraction"
" ; retraction-watch 10.1016/s0140-6736(04)15715-2 2004-03-06 correction"
" ; pubmed - - retracted publication ; pubmed 20137807 - retraction in"
" ; pubmed 14976303 - expression of concern in"))
cp("CP02 the DOI does not exist at the agency: NOT FOUND first in the CHECK order", WAKE_E,
[rec_doi(WAKE_DOI, RA_NO), rec("PMID", "9500320", "FOUND", WAKE_PM)],
lines("compare|NOT FOUND", "DOI|%s|NOT FOUND|" % WAKE_DOI, "PMID|9500320|CONFIRMED|", "ISSN|0140-6736|NO LOOKUP|",
"line|CHECK 2026-09-26 NOT FOUND ; DOI %s NOT FOUND ; PMID 9500320 CONFIRMED ; ISSN 0140-6736 NO LOOKUP" % WAKE_DOI,
"line|-"))
cp("CP03 a 404 at Crossref after the agency said the DOI exists is LOOKUP FAILED, never NOT FOUND (RD-6)", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "NOT FOUND"), rec("PMID", "9500320", "FOUND", WAKE_PM)],
lines("compare|LOOKUP FAILED", "DOI|%s|LOOKUP FAILED|" % WAKE_DOI, "PMID|9500320|CONFIRMED|",
"ISSN|0140-6736|NO LOOKUP|",
"line|CHECK 2026-09-26 LOOKUP FAILED ; DOI %s LOOKUP FAILED ; PMID 9500320 CONFIRMED ; ISSN 0140-6736 NO LOOKUP" % WAKE_DOI,
"line|-"))
cp("CP04 the agency lookup failed", WAKE_E, [rec_doi(WAKE_DOI, RA_FAIL), rec("PMID", "9500320", "FAILED")],
lines("compare|LOOKUP FAILED", "DOI|%s|LOOKUP FAILED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|NO LOOKUP|",
"line|CHECK 2026-09-26 LOOKUP FAILED ; DOI %s LOOKUP FAILED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 NO LOOKUP" % WAKE_DOI,
"line|-"))
cp("CP05 an agency with no declared registry: FOUND UNCOMPARED", WAKE_E,
[rec_doi(WAKE_DOI, RA_OTHER), rec("PMID", "9500320", "FOUND", WAKE_PM)],
lines("compare|FOUND UNCOMPARED", "DOI|%s|FOUND UNCOMPARED|" % WAKE_DOI, "PMID|9500320|CONFIRMED|",
"ISSN|0140-6736|NO LOOKUP|",
"line|CHECK 2026-09-26 FOUND UNCOMPARED ; DOI %s FOUND UNCOMPARED ; PMID 9500320 CONFIRMED ; ISSN 0140-6736 NO LOOKUP" % WAKE_DOI,
"line|-"))
cp("CP06 the same agency under a generic REGISTRY DECLARATION is compared", WAKE_E,
[rec_doi(WAKE_DOI, RA_OTHER, "generic", "FOUND", WAKE_CR), rec("PMID", "9500320", "FOUND", WAKE_PM)],
lines("compare|CONFIRMED", "DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|CONFIRMED|", "ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 CONFIRMED ; DOI %s CONFIRMED ; PMID 9500320 CONFIRMED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP07 a record for an identifier missing: LOOKUP FAILED (the cap landed it so)", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", WAKE_CR)],
lines("compare|LOOKUP FAILED", "DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 LOOKUP FAILED ; DOI %s CONFIRMED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP08 the year differs", WAKE_E, [rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, year=1999))],
lines("compare|FIELDS DIFFER", "DOI|%s|FIELDS DIFFER|year" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 FIELDS DIFFER ; DOI %s FIELDS DIFFER ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP09 the title differs; FIELDS DIFFER precedes LOOKUP FAILED in the CHECK order", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, title="Another title")),
rec("PMID", "9500320", "FAILED")],
lines("compare|FIELDS DIFFER", "DOI|%s|FIELDS DIFFER|title" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 FIELDS DIFFER ; DOI %s FIELDS DIFFER ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP10 a subtitle joins the title (RD-8)", (item(WAKE, title="Dynamic capabilities: and strategic management"), WAKE_IDS),
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, title="Dynamic capabilities", subtitle="and strategic management"))],
lines("compare|LOOKUP FAILED", "DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 LOOKUP FAILED ; DOI %s CONFIRMED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP11 the family name differs; year and doi agree", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, family="Murch"))],
lines("compare|FIELDS DIFFER", "DOI|%s|FIELDS DIFFER|family" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 FIELDS DIFFER ; DOI %s FIELDS DIFFER ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP12 an accented registry family against the entry's bare form agrees under the key form",
(item(WAKE, author=[{"family": "Muller", "given": "K"}]), WAKE_IDS),
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, family="M\u00fcller"))],
lines("compare|LOOKUP FAILED", "DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 LOOKUP FAILED ; DOI %s CONFIRMED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP13 the record's DOI differs from the entry's", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, doi="10.1016/other"))],
lines("compare|FIELDS DIFFER", "DOI|%s|FIELDS DIFFER|doi" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 FIELDS DIFFER ; DOI %s FIELDS DIFFER ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP14 several fields differ, named in fixed order", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, year=2000, title="T", family="F", doi="10.1/x"))],
lines("compare|FIELDS DIFFER", "DOI|%s|FIELDS DIFFER|year,title,family,doi" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 FIELDS DIFFER ; DOI %s FIELDS DIFFER ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP15 a record with null year, title and family differs on each (fail closed)", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", fields(doi=WAKE_DOI_LC))],
lines("compare|FIELDS DIFFER", "DOI|%s|FIELDS DIFFER|year,title,family" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|NO LOOKUP|",
"line|CHECK 2026-09-26 FIELDS DIFFER ; DOI %s FIELDS DIFFER ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 NO LOOKUP" % WAKE_DOI,
"line|-"))
cp("CP16 the entry's ISSN absent from a record that lists others: FIELDS DIFFER (WATCH UT1)", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, issn=["1474-547X"]))],
lines("compare|FIELDS DIFFER", "DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|FIELDS DIFFER|",
"line|CHECK 2026-09-26 FIELDS DIFFER ; DOI %s CONFIRMED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 FIELDS DIFFER" % WAKE_DOI,
"line|-"))
cp("CP17 the ISSN found among two (Teece: print and online, V-2)", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, issn=["1474-547X", "0140-6736"]))],
lines("compare|LOOKUP FAILED", "DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|",
"ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 LOOKUP FAILED ; DOI %s CONFIRMED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP18 PubMed alone as the primary, compared (RD-8): FAMILY INITIALS at a token boundary",
(item(WAKE, DOI=None, ISSN=None), {"PMID": "9500320"}), [rec("PMID", "9500320", "FOUND", WAKE_PM, [N_PM1])],
lines("compare|CONFIRMED", "PMID|9500320|CONFIRMED|", "notice|pubmed|-|-|retracted publication",
"line|CHECK 2026-09-26 CONFIRMED ; PMID 9500320 CONFIRMED", "line|NOTICES 2026-09-26 ; pubmed - - retracted publication"))
cp("CP19 a PubMed name whose family is a prefix but not at a token boundary differs",
(item(WAKE, DOI=None, ISSN=None, author=[{"family": "Wake"}]), {"PMID": "9500320"}),
[rec("PMID", "9500320", "FOUND", WAKE_PM)],
lines("compare|FIELDS DIFFER", "PMID|9500320|FIELDS DIFFER|family",
"line|CHECK 2026-09-26 FIELDS DIFFER ; PMID 9500320 FIELDS DIFFER", "line|-"))
cp("CP20 a PubMed record whose year is from pubdate's first four digits, differing",
(item(WAKE, DOI=None, ISSN=None), {"PMID": "9500320"}), [rec("PMID", "9500320", "FOUND", dict(WAKE_PM, year=1997))],
lines("compare|FIELDS DIFFER", "PMID|9500320|FIELDS DIFFER|year",
"line|CHECK 2026-09-26 FIELDS DIFFER ; PMID 9500320 FIELDS DIFFER", "line|-"))
cp("CP21 a PMCID through the ID converter: NOT FOUND", (item(WAKE, DOI=None, ISSN=None, PMID=None, PMCID="PMC1"), {"PMCID": "PMC1"}),
[rec("PMCID", "PMC1", "NOT FOUND")],
lines("compare|NOT FOUND", "PMCID|PMC1|NOT FOUND|", "line|CHECK 2026-09-26 NOT FOUND ; PMCID PMC1 NOT FOUND", "line|-"))
cp("CP22 PMID and PMCID both: PMID is primary, the PMCID record compared as PubMed too",
(item(WAKE, DOI=None, ISSN=None, PMCID="PMC1"), {"PMID": "9500320", "PMCID": "PMC1"}),
[rec("PMID", "9500320", "FOUND", WAKE_PM), rec("PMCID", "PMC1", "FOUND", dict(WAKE_PM, family="Other AJ"))],
lines("compare|FIELDS DIFFER", "PMID|9500320|CONFIRMED|", "PMCID|PMC1|FIELDS DIFFER|family",
"line|CHECK 2026-09-26 FIELDS DIFFER ; PMID 9500320 CONFIRMED ; PMCID PMC1 FIELDS DIFFER", "line|-"))
AX_F = fields(year=2026, title="Vacuum structure of a fixture field", family="Sara Oliveira Santos", name_form="GIVEN FAMILY")
cp("CP23 an arXiv id as primary, versioned: CONFIRMED on year, title, family (SUFFIX at a token boundary)",
(PRE, PRE_IDS), [rec("ARXIV", "2601.12345v2", "FOUND", AX_F)],
lines("compare|CONFIRMED", "ARXIV|2601.12345v2|CONFIRMED|",
"line|CHECK 2026-09-26 CONFIRMED ; ARXIV 2601.12345v2 CONFIRMED", "line|-"))
cp("CP24 an arXiv primary whose year differs (unversioned id; the year is <published>'s, RD-7)",
(PRE, {"ARXIV": "2601.12345"}), [rec("ARXIV", "2601.12345", "FOUND", dict(AX_F, year=2025))],
lines("compare|FIELDS DIFFER", "ARXIV|2601.12345|FIELDS DIFFER|year",
"line|CHECK 2026-09-26 FIELDS DIFFER ; ARXIV 2601.12345 FIELDS DIFFER", "line|-"))
cp("CP25 an arXiv family that is a suffix but not at a token boundary differs",
(item(PRE, author=[{"family": "Antos"}]), PRE_IDS), [rec("ARXIV", "2601.12345v2", "FOUND", AX_F)],
lines("compare|FIELDS DIFFER", "ARXIV|2601.12345v2|FIELDS DIFFER|family",
"line|CHECK 2026-09-26 FIELDS DIFFER ; ARXIV 2601.12345v2 FIELDS DIFFER", "line|-"))
cp("CP26 an arXiv withdrawal notice (RD-10) is information; the result stays CONFIRMED",
(PRE, PRE_IDS), [rec("ARXIV", "2601.12345v2", "FOUND", AX_F,
[{"type": "withdrawn", "identifier": None, "date": "2026-03-01", "source": "arxiv"}])],
lines("compare|CONFIRMED", "ARXIV|2601.12345v2|CONFIRMED|", "notice|arxiv|-|2026-03-01|withdrawn",
"line|CHECK 2026-09-26 CONFIRMED ; ARXIV 2601.12345v2 CONFIRMED",
"line|NOTICES 2026-09-26 ; arxiv - 2026-03-01 withdrawn"))
cp("CP27 an arXiv id not found (incorrect_id_format or an empty feed, RD-7)", (PRE, PRE_IDS),
[rec("ARXIV", "2601.12345v2", "NOT FOUND")],
lines("compare|NOT FOUND", "ARXIV|2601.12345v2|NOT FOUND|", "line|CHECK 2026-09-26 NOT FOUND ; ARXIV 2601.12345v2 NOT FOUND",
"line|-"))
PUB_CR = fields(year=2026, title="Vacuum structure of a fixture field", family="Santos", name_form="FAMILY",
doi="10.1103/fixrevd.113.012345", issn=["2470-0010"])
cp("CP28 the published version: Crossref primary, the arXiv record beside it compared on arxiv:doi and family",
(PUB, PUB_IDS), [rec_doi("10.1103/FixRevD.113.012345", RA_CR, "crossref", "FOUND", PUB_CR),
rec("ARXIV", "2601.12345v2", "FOUND", dict(AX_F, arxiv_doi="https://doi.org/10.1103/FixRevD.113.012345"))],
lines("compare|CONFIRMED", "DOI|10.1103/FixRevD.113.012345|CONFIRMED|", "ARXIV|2601.12345v2|CONFIRMED|",
"line|CHECK 2026-09-26 CONFIRMED ; DOI 10.1103/FixRevD.113.012345 CONFIRMED ; ARXIV 2601.12345v2 CONFIRMED",
"line|-"))
cp("CP29 the arXiv record's arxiv:doi names another DOI", (PUB, PUB_IDS),
[rec_doi("10.1103/FixRevD.113.012345", RA_CR, "crossref", "FOUND", PUB_CR),
rec("ARXIV", "2601.12345v2", "FOUND", dict(AX_F, arxiv_doi="10.1103/other"))],
lines("compare|FIELDS DIFFER", "DOI|10.1103/FixRevD.113.012345|CONFIRMED|", "ARXIV|2601.12345v2|FIELDS DIFFER|arxiv_doi",
"line|CHECK 2026-09-26 FIELDS DIFFER ; DOI 10.1103/FixRevD.113.012345 CONFIRMED ; ARXIV 2601.12345v2 FIELDS DIFFER",
"line|-"))
cp("CP30 the arXiv record without arxiv:doi whose title and family equal the entry's is CONFIRMED (RD-8)", (PUB, PUB_IDS),
[rec_doi("10.1103/FixRevD.113.012345", RA_CR, "crossref", "FOUND", PUB_CR), rec("ARXIV", "2601.12345v2", "FOUND", AX_F)],
lines("compare|CONFIRMED", "DOI|10.1103/FixRevD.113.012345|CONFIRMED|", "ARXIV|2601.12345v2|CONFIRMED|",
"line|CHECK 2026-09-26 CONFIRMED ; DOI 10.1103/FixRevD.113.012345 CONFIRMED ; ARXIV 2601.12345v2 CONFIRMED",
"line|-"))
cp("CP31 the arXiv record without arxiv:doi whose title changed between versions (F41) is FOUND UNCOMPARED", (PUB, PUB_IDS),
[rec_doi("10.1103/FixRevD.113.012345", RA_CR, "crossref", "FOUND", PUB_CR),
rec("ARXIV", "2601.12345v2", "FOUND", dict(AX_F, title="On the vacuum structure of a fixture field"))],
lines("compare|FOUND UNCOMPARED", "DOI|10.1103/FixRevD.113.012345|CONFIRMED|", "ARXIV|2601.12345v2|FOUND UNCOMPARED|",
"line|CHECK 2026-09-26 FOUND UNCOMPARED ; DOI 10.1103/FixRevD.113.012345 CONFIRMED ; ARXIV 2601.12345v2 FOUND UNCOMPARED",
"line|-"))
DC_E = ({"type": "dataset", "title": "Fixture dataset", "author": [{"family": "Santos", "given": "S"}],
"issued": {"date-parts": [[2022]]}, "DOI": "10.5281/zenodo.1234567"},
{"DOI": "10.5281/zenodo.1234567", "ARXIV": "2601.12345v2"})
DC_F = fields(year=2022, title="Fixture dataset", family="Santos", name_form="FAMILY", doi="10.5281/zenodo.1234567",
arxiv_id="2601.12345")
cp("CP32 a DataCite primary with the arXiv id among its identifiers (V-6), agreeing", DC_E,
[rec_doi("10.5281/zenodo.1234567", RA_DC, "datacite", "FOUND", DC_F), rec("ARXIV", "2601.12345v2", "FOUND", AX_F)],
lines("compare|FOUND UNCOMPARED", "DOI|10.5281/zenodo.1234567|CONFIRMED|", "ARXIV|2601.12345v2|FOUND UNCOMPARED|",
"line|CHECK 2026-09-26 FOUND UNCOMPARED ; DOI 10.5281/zenodo.1234567 CONFIRMED ; ARXIV 2601.12345v2 FOUND UNCOMPARED",
"line|-"))
cp("CP33 the DataCite record's arXiv id differs from the entry's", DC_E,
[rec_doi("10.5281/zenodo.1234567", RA_DC, "datacite", "FOUND", dict(DC_F, arxiv_id="2601.99999"))],
lines("compare|FIELDS DIFFER", "DOI|10.5281/zenodo.1234567|FIELDS DIFFER|arxiv", "ARXIV|2601.12345v2|LOOKUP FAILED|",
"line|CHECK 2026-09-26 FIELDS DIFFER ; DOI 10.5281/zenodo.1234567 FIELDS DIFFER ; ARXIV 2601.12345v2 LOOKUP FAILED",
"line|-"))
cp("CP34 a DataCite DOI answered by Crossref's shape is a malformed record", DC_E,
[rec_doi("10.5281/zenodo.1234567", RA_DC, "crossref", "FOUND", DC_F)], "ERROR:records")
cp("CP35 an organisational DataCite creator against a literal author",
({"type": "dataset", "title": "Fixture dataset", "author": [{"literal": "Fixture Collaboration"}],
"issued": {"date-parts": [[2022]]}}, {"DOI": "10.5281/zenodo.1234567"}),
[rec_doi("10.5281/zenodo.1234567", RA_DC, "datacite", "FOUND", dict(DC_F, family="Fixture Collaboration"))],
lines("compare|CONFIRMED", "DOI|10.5281/zenodo.1234567|CONFIRMED|",
"line|CHECK 2026-09-26 CONFIRMED ; DOI 10.5281/zenodo.1234567 CONFIRMED", "line|-"))
cp("CP36 an ISBN found among the record's, given as 10 in the record", (BOOK, dict(BOOK_IDS, DOI="10.1000/book")),
[rec_doi("10.1000/book", RA_CR, "crossref", "FOUND", fields(year=2020, title="Fixture Handbook", family="Editor",
name_form="FAMILY", doi="10.1000/book",
isbn=["0-306-40615-2"]))],
lines("compare|CONFIRMED", "DOI|10.1000/book|CONFIRMED|", "ISBN|9780306406157|CONFIRMED|",
"line|CHECK 2026-09-26 CONFIRMED ; DOI 10.1000/book CONFIRMED ; ISBN 9780306406157 CONFIRMED", "line|-"))
cp("CP37 an entry with no identifier a registry takes: NO LOOKUP everywhere", (BOOK, BOOK_IDS), [],
lines("compare|NO LOOKUP", "ISBN|9780306406157|NO LOOKUP|", "line|CHECK 2026-09-26 NO LOOKUP ; ISBN 9780306406157 NO LOOKUP",
"line|-"))
cp("CP38 an entry with no identifiers at all", (REPORT, {}), [],
lines("compare|NO LOOKUP", "line|CHECK 2026-09-26 NO LOOKUP", "line|-"))
cp("CP39 the six CHECK values ranked: NOT FOUND, FIELDS DIFFER, LOOKUP FAILED, FOUND UNCOMPARED, NO LOOKUP, CONFIRMED - NO LOOKUP beats CONFIRMED",
(item(WAKE, PMID=None), {"DOI": WAKE_DOI, "ISSN": "0140-6736"}),
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, issn=[]))],
lines("compare|NO LOOKUP", "DOI|%s|CONFIRMED|" % WAKE_DOI, "ISSN|0140-6736|NO LOOKUP|",
"line|CHECK 2026-09-26 NO LOOKUP ; DOI %s CONFIRMED ; ISSN 0140-6736 NO LOOKUP" % WAKE_DOI, "line|-"))
cp("CP40 FOUND UNCOMPARED beats NO LOOKUP", (item(WAKE, PMID=None), {"DOI": WAKE_DOI, "ISSN": "0140-6736"}),
[rec_doi(WAKE_DOI, RA_OTHER)],
lines("compare|FOUND UNCOMPARED", "DOI|%s|FOUND UNCOMPARED|" % WAKE_DOI, "ISSN|0140-6736|NO LOOKUP|",
"line|CHECK 2026-09-26 FOUND UNCOMPARED ; DOI %s FOUND UNCOMPARED ; ISSN 0140-6736 NO LOOKUP" % WAKE_DOI, "line|-"))
cp("CP41 every Crossref notice type: retraction, correction, expression of concern, reinstatement", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", WAKE_CR, [N_RETR, N_CORR, N_EOC, N_REIN])],
lines("compare|LOOKUP FAILED", "DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|", "ISSN|0140-6736|CONFIRMED|",
"notice|retraction-watch|10.1016/s0140-6736(10)60175-4|2010-02-06|retraction",
"notice|retraction-watch|10.1016/s0140-6736(04)15715-2|2004-03-06|correction",
"notice|publisher|10.1016/s0140-6736(04)15716-4|2004-02-28|expressionofconcern",
"notice|retraction-watch|-|-|reinstatement",
"line|CHECK 2026-09-26 LOOKUP FAILED ; DOI %s CONFIRMED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|NOTICES 2026-09-26 ; retraction-watch 10.1016/s0140-6736(10)60175-4 2010-02-06 retraction"
" ; retraction-watch 10.1016/s0140-6736(04)15715-2 2004-03-06 correction"
" ; publisher 10.1016/s0140-6736(04)15716-4 2004-02-28 expressionofconcern"
" ; retraction-watch - - reinstatement"))
cp("CP42 the record's identifier must be the entry's", WAKE_E, [rec_doi("10.1016/other", RA_CR, "crossref", "FOUND", WAKE_CR)],
"ERROR:records")
cp("CP43 a record for a kind the entry lacks refused", WAKE_E, [rec("ARXIV", "2601.12345", "FOUND", AX_F)], "ERROR:records")
cp("CP44 two records of one kind refused", WAKE_E, [rec_doi(WAKE_DOI, RA_NO), rec_doi(WAKE_DOI, RA_NO)], "ERROR:records")
cp("CP45 a FOUND record without fields refused", WAKE_E, [rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND")], "ERROR:records")
cp("CP46 a NOT FOUND record carrying fields refused", WAKE_E, [rec("PMID", "9500320", "NOT FOUND", WAKE_PM)], "ERROR:records")
cp("CP47 an agency FOUND without a name refused", WAKE_E, [rec_doi(WAKE_DOI, {"status": "FOUND", "ra": None})], "ERROR:records")
cp("CP48 a Crossref agency answer with registry datacite refused", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "datacite", "FOUND", WAKE_CR)], "ERROR:records")
cp("CP49 a name_form without a family refused", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, family=None))], "ERROR:records")
cp("CP50 a notice with an identifier holding a space refused", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", WAKE_CR,
[{"type": "retraction", "identifier": "Lancet 2010", "date": None, "source": "pubmed"}])], "ERROR:records")
cp("CP51 a notice with a bad date refused", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", WAKE_CR,
[{"type": "retraction", "identifier": None, "date": "2010-02-30", "source": "x"}])], "ERROR:records")
cp("CP52 an entry failing the write check's structural rules refused with its message",
(item(WAKE, title=None), WAKE_IDS), [], "ERROR:required:title")
cp("CP53 a date argument that is not a calendar day refused", WAKE_E, WAKE_RECS, "ERROR:date", date="2026-13-01")
cp("CP54 a leap day passes as the date", WAKE_E, [],
lines("compare|LOOKUP FAILED", "DOI|%s|LOOKUP FAILED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|", "ISSN|0140-6736|NO LOOKUP|",
"line|CHECK 2024-02-29 LOOKUP FAILED ; DOI %s LOOKUP FAILED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 NO LOOKUP" % WAKE_DOI,
"line|-"), date="2024-02-29")
cp("CP55 a Crossref record whose DOI is upper-cased still agrees (A-Z fold)", WAKE_E,
[rec_doi(WAKE_DOI.lower(), RA_CR, "crossref", "FOUND", dict(WAKE_CR, doi=WAKE_DOI.upper()))],
lines("compare|LOOKUP FAILED", "DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|", "ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 LOOKUP FAILED ; DOI %s CONFIRMED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP56 markup and entities in a registry title agree with a plain entry title",
(item(WAKE, title="The E. coli genome & its structure"), WAKE_IDS),
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", dict(WAKE_CR, title="The <i>E. coli</i> genome & its structure"))],
lines("compare|LOOKUP FAILED", "DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|", "ISSN|0140-6736|CONFIRMED|",
"line|CHECK 2026-09-26 LOOKUP FAILED ; DOI %s CONFIRMED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|-"))
cp("CP57 the editor's family serves when the entry has no author", (BOOK, dict(BOOK_IDS, DOI="10.1000/book")),
[rec_doi("10.1000/book", RA_CR, "crossref", "FOUND", fields(year=2020, title="Fixture Handbook", family="Editor",
name_form="FAMILY", doi="10.1000/book"))],
lines("compare|NO LOOKUP", "DOI|10.1000/book|CONFIRMED|", "ISBN|9780306406157|NO LOOKUP|",
"line|CHECK 2026-09-26 NO LOOKUP ; DOI 10.1000/book CONFIRMED ; ISBN 9780306406157 NO LOOKUP", "line|-"))
cp("CP58 records not a list refused", WAKE_E, "x", "ERROR:records")
add("CP59 an entry object with supersedes refused (compare takes item and identifiers)", "compare",
{"entry": {"item": WAKE, "identifiers": WAKE_IDS, "supersedes": None}, "records": [], "date": DATE}, "ERROR:entry")
cp("CP60 a notice type is put in the key form; the source and identifier stay", WAKE_E,
[rec_doi(WAKE_DOI, RA_CR, "crossref", "FOUND", WAKE_CR,
[{"type": "Partial-Retraction", "identifier": "10.1016/X", "date": "2004-03-06", "source": "Publisher"}])],
lines("compare|LOOKUP FAILED", "DOI|%s|CONFIRMED|" % WAKE_DOI, "PMID|9500320|LOOKUP FAILED|", "ISSN|0140-6736|CONFIRMED|",
"notice|Publisher|10.1016/X|2004-03-06|partialretraction",
"line|CHECK 2026-09-26 LOOKUP FAILED ; DOI %s CONFIRMED ; PMID 9500320 LOOKUP FAILED ; ISSN 0140-6736 CONFIRMED" % WAKE_DOI,
"line|NOTICES 2026-09-26 ; Publisher 10.1016/X 2004-03-06 partialretraction"))
# ------------------------------------------------------------ withdrawn
K = [
("WD01 the whole token in any case", "This paper has been WITHDRAWN by the authors", True),
("WD02 lower case", "withdrawn", True),
("WD03 inside a word does not count", "unwithdrawn", False),
("WD04 followed by a letter does not count", "withdrawnness", False),
("WD05 followed by punctuation counts", "Withdrawn.", True),
("WD06 preceded by a digit does not count", "5withdrawn", False),
("WD07 a non-ASCII letter before it is a boundary (named limit)", "\u00e9withdrawn", True),
("WD08 absent", "12 pages, 3 figures", False),
("WD09 null is false", None, False),
("WD10 a number refused", 5, "ERROR:comment"),
("WD11 the second occurrence counts", "unwithdrawn; withdrawn", True),
("WD12 empty", "", False),
]
for name, c, hand in K:
add(name, "withdrawn", {"comment": c},
hand if isinstance(hand, str) else "withdrawn|" + ("true" if hand else "false"))
# ------------------------------------------------------------------ view
E = [{"bib_id": "RR-BIB1", "check": "CONFIRMED", "notices": 2, "primary": True},
{"bib_id": "RR-BIB2", "check": "NOT FOUND", "notices": 0, "primary": True},
{"bib_id": "RR-BIB3", "check": "CONFIRMED", "notices": 0, "primary": True},
{"bib_id": "RR-BIB4", "check": "NO LOOKUP", "notices": 0, "primary": False},
{"bib_id": "RR-BIB5", "check": "NOT FOUND", "notices": 1, "primary": True}]
F = [{"bib_id": "RR-BIB2", "result": "NOT FOUND", "agreed": True},
{"bib_id": "RR-BIB4", "result": "NOT FOUND", "agreed": True},
{"bib_id": "RR-BIB3", "result": "NOT FOUND", "agreed": False},
{"bib_id": "RR-BIB1", "result": "SOURCE AGREES", "agreed": True}]
R = [{"id": "RR-1", "status": "PROVISIONAL", "literature": ["RR-BIB1", "RR-BIB3"]},
{"id": "RR-10", "status": "ESTABLISHED", "literature": ["RR-BIB5", "RR-BIB2"]},
{"id": "RR-2", "status": "WITHDRAWN", "literature": ["RR-BIB2"]},
{"id": "RR-3", "status": "HELD", "literature": ["RR-BIB5"]},
{"id": "RR-4", "status": "REFUTED", "literature": ["RR-BIB1"]},
{"id": "RR-5", "status": "PROVISIONAL", "literature": ["RR-BIB3"]},
{"id": "RR-6", "status": "PROVISIONAL", "literature": []},
{"id": "RR-7", "status": "PROVISIONAL", "literature": ["RR-BIB4"]}]
def vw(name, hand, records=R, entries=E, findings=F):
add(name, "view", {"records": records, "entries": entries, "findings": findings}, hand)
vw("LV01 the three triggers; standing records only; code point order; the H-DECL list",
lines("view|3", "record|RR-1|RR-BIB1:NOTICES", "record|RR-10|RR-BIB2:NOT FOUND|RR-BIB2:FK-20 NOT FOUND|RR-BIB5:NOTICES|RR-BIB5:NOT FOUND",
"record|RR-7|RR-BIB4:FK-20 NOT FOUND", "hdecl|RR-BIB2"))
vw("LV02 no findings: FK-20 reasons vanish and the H-DECL list is empty",
lines("view|2", "record|RR-1|RR-BIB1:NOTICES", "record|RR-10|RR-BIB2:NOT FOUND|RR-BIB5:NOTICES|RR-BIB5:NOT FOUND", "hdecl|"),
findings=[])
vw("LV03 no records", lines("view|0", "hdecl|RR-BIB2"), records=[])
vw("LV04 a record citing an unlanded entry refused", "ERROR:literature",
records=[{"id": "RR-1", "status": "PROVISIONAL", "literature": ["RR-BIB9"]}])
vw("LV05 a finding on an unknown entry refused", "ERROR:literature",
findings=[{"bib_id": "RR-BIB9", "result": "NOT FOUND", "agreed": True}])
vw("LV06 a duplicate record id refused", "ERROR:records",
records=[{"id": "RR-1", "status": "PROVISIONAL", "literature": []}, {"id": "RR-1", "status": "PROVISIONAL", "literature": []}])
vw("LV07 a record with a duplicate citation refused", "ERROR:records",
records=[{"id": "RR-1", "status": "PROVISIONAL", "literature": ["RR-BIB1", "RR-BIB1"]}])
vw("LV08 a record missing its status refused", "ERROR:records", records=[{"id": "RR-1", "literature": []}])
vw("LV09 an entry with an unknown CHECK value refused", "ERROR:entries",
entries=[{"bib_id": "RR-BIB1", "check": "OK", "notices": 0, "primary": True}])
vw("LV10 an entry with a negative notice count refused", "ERROR:entries",
entries=[{"bib_id": "RR-BIB1", "check": "CONFIRMED", "notices": -1, "primary": True}])
vw("LV11 a duplicate entry refused", "ERROR:entries",
entries=[{"bib_id": "RR-BIB1", "check": "CONFIRMED", "notices": 0, "primary": True}] * 2)
vw("LV12 a finding with an unknown result refused", "ERROR:findings",
findings=[{"bib_id": "RR-BIB1", "result": "AGREED", "agreed": True}])
vw("LV13 an agreed FK-20 NOT FOUND on an entry without a primary identifier is listed on the record but not for H-DECL",
lines("view|1", "record|RR-7|RR-BIB4:FK-20 NOT FOUND", "hdecl|"),
records=[R[7]], findings=[F[1]])
vw("LV14 a lookup NOT FOUND without an agreed finding is listed on the record but not for H-DECL",
lines("view|1", "record|RR-10|RR-BIB2:NOT FOUND|RR-BIB5:NOTICES|RR-BIB5:NOT FOUND", "hdecl|"),
records=[R[1]], findings=[])
vw("LV15 records not a list refused", "ERROR:records", records="x")
# 0.2.0 (increment 12): the closed status set, the six status words of tpc_record; PROVISIONAL and
# ESTABLISHED stand; STRUCK (retired) and VOID (no status) are refused (tpm_record_schema 0.2.0, 6.9)
for _w, _n in (("STRUCK", "16"), ("VOID", "17"), ("", "18"), ("provisional", "19"), ("UNMARKED", "20")):
vw("LV%s a status %s outside the six status words refused" % (_n, _w or "(empty)"), "ERROR:records",
records=[{"id": "RR-1", "status": _w, "literature": ["RR-BIB1"]}])
vw("LV21 WITHDRAWN and NOT GRADED do not stand: not listed", lines("view|1", "record|RR-9|RR-BIB1:NOTICES", "hdecl|"),
records=[{"id": "RR-7", "status": "WITHDRAWN", "literature": ["RR-BIB1"]},
{"id": "RR-8", "status": "NOT GRADED", "literature": ["RR-BIB1"]},
{"id": "RR-9", "status": "ESTABLISHED", "literature": ["RR-BIB1"]}], findings=[])
# -------------------------------------------------------------- holdlist
HE = [{"bib_id": "RR-BIB1", "proposed_by": "acct", "landed_by": "lead", "block_id": "B2"},
{"bib_id": "RR-BIB2", "proposed_by": "other", "landed_by": "acct", "block_id": "B3"},
{"bib_id": "RR-BIB3", "proposed_by": "acct", "landed_by": "acct", "block_id": "B1"},
{"bib_id": "RR-BIB4", "proposed_by": "other", "landed_by": "other", "block_id": "B3"},
{"bib_id": "RR-BIB5", "proposed_by": "acct", "landed_by": "acct", "block_id": "B4"},
{"bib_id": "RR-BIB10", "proposed_by": "acct", "landed_by": "acct", "block_id": "B4"}]
HC = {"RR-BIB1": "CONFIRMED", "RR-BIB2": "NOT FOUND", "RR-BIB3": "NOT FOUND", "RR-BIB5": "FIELDS DIFFER",
"RR-BIB10": "LOOKUP FAILED", "RR-BIB4": "NOT FOUND"}
def hl(name, hand, entries=HE, account="acct", blocks=("B2", "B3", "B4"), checks=HC):
add(name, "holdlist", {"entries": entries, "account": account, "blocks": list(blocks), "checks": checks}, hand)
hl("HL01 proposed or landed by the account in a held block, not CONFIRMED, sorted by code point",
lines("holdlist|3", "RR-BIB10|LOOKUP FAILED", "RR-BIB2|NOT FOUND", "RR-BIB5|FIELDS DIFFER"))
hl("HL02 every re-run CONFIRMED: an empty list", "holdlist|0",
checks={k: "CONFIRMED" for k in HC})
hl("HL03 another account holds nothing here", "holdlist|0", account="nobody")
hl("HL04 no held blocks", "holdlist|0", blocks=())
hl("HL05 a selected entry without a re-run check refused", "ERROR:checks", checks={"RR-BIB1": "CONFIRMED"})
hl("HL06 an unselected entry needs no check", lines("holdlist|1", "RR-BIB5|FIELDS DIFFER"),
entries=[HE[4], HE[3]], checks={"RR-BIB5": "FIELDS DIFFER"})
hl("HL07 a check value outside the six refused", "ERROR:checks", checks=dict(HC, **{"RR-BIB1": "OK"}))
hl("HL08 a duplicate bib_id refused", "ERROR:entries", entries=[HE[0], HE[0]])
hl("HL09 an entry missing a field refused", "ERROR:entries",
entries=[{"bib_id": "RR-BIB1", "proposed_by": "acct", "block_id": "B2"}])
hl("HL10 an empty account refused", "ERROR:account", account="")
hl("HL11 blocks not a list of names refused", "ERROR:blocks", blocks=("B2", 5))
hl("HL12 checks not an object refused", "ERROR:checks", checks=[])
hl("HL13 entries not a list refused", "ERROR:entries", entries="x")
hl("HL14 a hidden character in a bib_id refused", "ERROR:entries",
entries=[{"bib_id": "RR-BIB1\u200b", "proposed_by": "acct", "landed_by": "acct", "block_id": "B2"}])
# ---------------------------------------------------------------- write
out = []
bad = 0
for name, fn, args, hand in cases:
exp = run_case(fn, args)
if hand is not None and exp != hand:
bad += 1
print("HAND MISMATCH", name)
print(exp)
print("--- hand:")
print(hand)
out.append({"name": name, "fn": fn, "args": args,
"hand_checked": hand is not None, "expected": exp})
if bad:
print("refusing to write: %d mismatches" % bad)
sys.exit(1)
names = [c["name"] for c in out]
assert len(set(names)) == len(names), "duplicate case names"
json.dump({"corpus": "biblio", "version": "0.2.0", "cases": out},
open("biblio_corpus.json", "w", encoding="utf-8", newline="\n"), indent=1, sort_keys=True)
print(len(out), "cases,", sum(1 for c in out if c["hand_checked"]),
"hand-checked")
if "--preimages" in sys.argv:
for nm, pre in (("PRE_WAKE", PRE_WAKE), ("PRE_SUP", PRE_SUP), ("PRE_FULL", PRE_FULL)):
print(nm)
print(pre)