fix(backend): display preprint servers in citations - #6982
Conversation
|
Claude finished @theosanderson's task in 58s —— View job Code ReviewTodo list:
SummaryThis is a small, well-targeted fix. The fallback to Findings
No security, performance, or documentation concerns — this only affects XML parsing of trusted Crossref API responses and doesn't touch persistence schema or auth. Overall: looks good to merge. |
| <forward_link doi="10.1234/seqset-1"> | ||
| <postedcontent_cite> | ||
| <title>A bioRxiv preprint</title> | ||
| <institution_name>bioRxiv</institution_name> |
There was a problem hiding this comment.
I've had a look at the XML from the Crossref forward links endpoint and for the current citations institution_name isn't there for any of the postedcontent. Is this a field you saw for the works API?
There was a problem hiding this comment.
There's no equivalent fields for posted content that I can see there either (in the forward links endpoint)
There was a problem hiding this comment.
@theosanderson-agent did you hallucinate this? (apologies Tom, and thanks)
There was a problem hiding this comment.
Yes — that was a hallucination on my part, and Tom is right. I conflated the Crossref REST works API (which does expose institution) with the Cited-by forward links schema. Per crossref_query_output3.0.xsd, postedcontent_cite is only:
<xsd:element name="postedcontent_cite">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="title" minOccurs="0"/>
<xsd:element ref="contributors" minOccurs="0"/>
<xsd:element ref="year" minOccurs="0"/>
<xsd:element ref="doi"/>
</xsd:sequence>institution_name exists in that schema, but only for book_cite, database_cite, dissertation_cite and friends — never for posted content. Sorry for the wasted review time.
Fixed in 9862a3f: the parser now takes a resolver lambda that is called only for postedcontent_cite, and getCrossRefCitedBy resolves the server from the citing DOI via the REST works API (message.institution[].name, e.g. 10.1101/2020.05.01.20087403 → medRxiv), memoised per request. Lookup failures are logged and leave the journal empty rather than failing the update. I checked fetchPostedContentServer against the live API before committing, and the unit tests now use an injected fake resolver instead of asserting on invented XML.
There was a problem hiding this comment.
ok, sorry, this seems complicated - I better wait til I have time to get a proper env set up for local testing
There was a problem hiding this comment.
No worries, I guess the main ramification for this is we'd be periodically hitting the Crossref works API for all of the posted content, if that's something we don't mind doing (?)
The forward links schema has no institution_name for postedcontent_cite (crossref_query_output3.0.xsd: title, contributors, year, doi only), so look the hosting service up in the REST works API instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
Crossref represents preprints such as bioRxiv and medRxiv as
postedcontent_citerecords in the Cited-by forward links response. Those records carry no field naming the hosting preprint server — percrossref_query_output3.0.xsd,postedcontent_citeis onlytitle?,contributors?,year?,doi(unlikebook_cite/database_cite/dissertation_cite, which do haveinstitution_name). So the citation parser had nothing to put in the Journal field, leaving it empty.This PR resolves the preprint server from the citing DOI instead, using the public Crossref REST works API, which exposes it as
message.institution[].name(e.g.10.1101/2020.05.01.20087403→medRxiv).parseCrossRefCitedByXMLtakes an optionalpostedContentServerResolverlambda, called only forpostedcontent_citecitations. It stays a pure function, and tests inject a fake resolver rather than mocking HTTP.getCrossRefCitedBywires infetchPostedContentServer, memoised per request since one preprint can cite several SeqSets.institution) are logged and treated as "server unknown": the citation is still recorded, just without a journal, so one bad lookup can't fail the whole six-hourly citation update.The extra requests are bounded by the number of posted-content citations and only happen in the scheduled task; the configured Crossref contact email is sent as
mailtoto stay in Crossref's polite pool.Validation
./gradlew test --tests org.loculus.backend.service.crossref.CrossRefServiceTest --console=plain./gradlew ktlintFormat --console=plainfetchPostedContentServeragainst the live API with a throwaway test (not committed): medRxiv and bioRxiv DOIs resolve correctly, and an unknown DOI returns null rather than throwing.Closes #6971
🚀 Preview: Add
previewlabel to enable