Research Scan
Type to search documentation.

Verification

Every ranked paper is checked against the live record before it ships. What is checked, what the mismatch codes mean, and why a failure is flagged rather than repaired.

verify is the last stage before emit. It checks every ranked paper against the live record and records what did not match.

It runs late on purpose. Verification is cheap relative to screening, and running it on the papers that will actually be delivered means the check covers exactly the set that matters.

What gets checked

For each ranked paper: the DOI resolves, and the title, year and first author on the live record agree with what the pipeline holds.

Verification is done against Crossref, with OpenAlex as the fallback if Crossref is unreachable. Crossref is never a retrieval source — it appears in the pipeline only here.

The verification record

Every EvidencePacket carries one, and emit refuses to run without it.

FieldWhat it holds
verifiedWhether the record checked out.
verified_byWhich sources confirmed it: crossref, openalex, arxiv, s2.
verified_onWhen the check ran.
title_match_ratio0–100. Fuzzy match between the held title and the live one.
mismatchesWhat disagreed, if anything.

Mismatch codes

CodeMeaning
doi_unresolvedThe DOI did not resolve.
no_recordNo record was found to compare against.
titleThe title did not match closely enough.
yearThe publication year disagreed.
authorThe first author disagreed.
retractedThe live record marks the paper as retracted.

The matching threshold

Titles are compared fuzzily, because punctuation, subtitles and capitalisation differ legitimately between sources. The default threshold is a 90 match ratio.

Terminal window
research-scan verify --strict

--strict requires 95 instead of 90. Use it when a false positive is more expensive than a manual check.

Flagged, not repaired

This is the rule that matters most, and it is worth being exact about.

A paper whose DOI did not resolve, or whose title, year or first author disagreed with the live record, ships anyway — with its mismatches[] populated and an [UNVERIFIED — check manually] marker in the rendered Markdown.

It is not silently corrected. It is not silently dropped.

Correcting it would mean writing metadata that came from somewhere other than a source of record, which is precisely the failure this pipeline exists to prevent. Dropping it would hide the fact that something in the chain produced a record that does not check out — information you want, especially if it recurs.

The one exception is retraction. A paper the live record marks as retracted is removed. Everything else is flagged and kept, and the reader decides.

Reading it

In evidence.json, filter on the verification record directly:

Terminal window
jq '.[] | select(.verification.verified | not)
| {rank, title, mismatches: .verification.mismatches}' evidence.json

In evidence.md, unverified papers carry their marker inline, so a human reading the deliverable sees the same caveat the JSON records.

Per-call detail is in verify.log.jsonl.

What verification is not

It confirms that a record exists and that the bibliographic details match. It says nothing about whether the paper is any good, whether its claims replicate, or whether the abstract accurately describes the work — no PDF is fetched, parsed or read anywhere in the pipeline.

Verification is a check against fabrication and drift, not a quality judgement. The quality judgement is the rerank, and it is the agent’s.

Last updated Aug 21, 2026