Skip to content

Evaluation

bibr's evaluation harness scores saved extraction JSON against printed-paper ground truth. It reports title, DOI, abstract, author, and reference metrics, plus paper-level pass rates and cohort coverage. Primary metrics participate in the optional --threshold mean gate. Diagnostic metrics support analysis and do not participate in that gate.

Source checkout required

Run uv run python -m evaluation.evaluate from a source checkout with the development dependencies installed. The harness is not part of the published bibr package.

Bring your own ground truth

Reference corpora and extraction captures are not distributed with bibr. Supply independently prepared gold exports with --gold-dirs. The harness fails when no gold directory exists or no predictions match ground truth.

Quick start

# Use your own predictions and independently prepared gold exports
uv run python -m evaluation.evaluate \
    --results-dir outputs/local \
    --gold-dirs /path/to/gold \
    --output outputs/local-eval.json

Gold directories contain one bibr-shaped JSON export per paper. The harness matches predictions by normalized DOI, falling back to filename, and prints aggregate metrics. Keep gold independent of the predictions being evaluated; copying an extraction into gold would preserve the same errors on both sides.

Fixed cohorts and regression gates

uv run python -m evaluation.evaluate \
    --results-dir outputs/local \
    --gold-dirs /path/to/gold \
    --expected-ids /path/to/expected-paper-ids.json \
    --output outputs/local-eval.json \
    --threshold 0.80

--expected-ids accepts a JSON file containing a list of paper IDs or an object with members or ids. Expected IDs without a prediction are added with zero scores on the paper-level floor metrics. Otherwise, missing files would disappear from the denominator. --ids-file separately restricts scoring to prediction filenames listed one per line (without .json).

The --threshold flag exits with status 1 if any primary metric's non-null mean is below the supplied value. It does not gate missing/unmatched counts, abstention rate, or paper-level pass rate. Inspect those fields too when comparing runs. Choose a threshold from a recorded baseline scored with the same metric version and cohort; 0.80 above is only an example.

Public CI tests the evaluator using small synthetic examples. It checks scoring behavior and software contracts; passing CI does not establish extraction accuracy for your papers.

Ground truth

Always provide --gold-dirs explicitly. Gold represents what is printed in your papers, including reference fields; enrichment output is not extraction ground truth. Keep the gold revision fixed when comparing saved runs and record how each field was checked against its source.

Running extraction for evaluation

Evaluate against exports produced by your own bibr chew run:

uv run bibr chew papers/ -o outputs/local/
uv run python -m evaluation.evaluate \
    --results-dir outputs/local/ \
    --gold-dirs /path/to/gold

Metrics reference

Metric scores are in [0, 1], with higher being better. A metric can be null when gold provides nothing to score; those entries are excluded from its mean. The current definitions are metrics_version: 4, recorded in every saved evaluation. Re-score predictions when definitions change rather than comparing means from different versions.

Title

Metric Tier Description
title_soft primary Exact match after case, punctuation, and whitespace normalization, or a word-aligned prefix retaining at least 70% of the longer normalized title. The shorter side needs at least two words, or six characters in supported scripts without inter-word spaces.

DOI

Metric Tier Description
doi_match primary 1.0 for equal normalized DOIs. An asserted DOI against empty gold scores 0; when both are empty there is no score.

Abstract

Metric Tier Description
abstract_rouge_l primary ROUGE-L F1 score using whitespace tokenization and longest common subsequence
abstract_ned diagnostic Normalized Edit Distance similarity (1 - NED), following OmniDocBench methodology

Predictions are scored from info.abstract only. The evaluator does not recover an absent exported abstract from section text. Gold may use its abstract-typed sections because some gold records store their abstract there.

Authors

Metric Tier Description
authors_fullname_f1 primary F1 on full printed names ("given family") using fuzzy similarity — boundary-insensitive to the given/family split
authors_f1 diagnostic F1 on normalized family names with fuzzy, globally greedy bipartite matching
first_author diagnostic Fuzzy similarity (token_sort_ratio) on the first author's family name

Per-author front-matter fields (affiliation_sim, email_f1, orcid_f1, corresponding_acc) and keywords_f1 are also emitted as diagnostics; they score only over papers whose gold carries the field.

References

Metric Tier Description
ref_matching_f1 primary F1 for individual reference matching using a four-level cascade: DOI match (1.0) > fuzzy title match (0.9) > first-author + year (0.7) > unstructured citation string (0.6). Uses globally-greedy bipartite matching
ref_title_acc primary Among matched GT references that have titles, fraction with a correct title (fuzzy token_sort_ratio >= 85)
ref_year_acc primary Among matched GT references that have years, fraction with a correct year
ref_doi_recall primary Among all gold references with DOIs, fraction recovered with the correct DOI. Unmatched gold references with DOIs count as misses.
ref_count_ratio diagnostic min/max ratio of reference counts
ref_author_acc diagnostic Among matched gold references with authors, fraction where every gold surname is recalled
ref_journal_acc diagnostic Among matched GT references with a container/journal, fraction correct
ref_volume_acc diagnostic Among matched GT references with a volume, fraction correct
ref_pages_acc diagnostic Among matched GT references with page ranges, fraction correct

Sparse GT fields

The ref_*_acc metrics use matched pairs where gold has the field. ref_doi_recall instead uses all gold references with a DOI. Saved results include field coverage, counts, and micro-averaged scores to make these denominators visible.

Output format

--output writes a JSON artifact containing:

Fields Meaning
metrics_version, generated_at, bibr_commit Metric definitions, scoring timestamp, and commit of the evaluator checkout
predictions_dir, predictions_tree_sha256 Prediction source and content digest; the evaluator commit alone does not identify the code that produced these predictions
papers_attempted, papers_evaluated, papers_missing, missing_ids Cohort accounting, including missing expected predictions
papers_unmatched, unmatched_ids Predictions that matched no gold record and were excluded from aggregates
metrics Per-metric mean, p10, median, min, max, and non-null count n, with additional abstention and reference-coverage fields where applicable
pass_rate, pass_rate_n Fraction passing the paper-level floors and the exact denominator used
abstention_rate, n_abstained, abstained_ids Front-matter abstentions and their share of evaluated predictions
per_paper Individual scores, flags, and reference-field counts for investigation

pass_rate uses these floors: title_soft >= 0.9, doi_match >= 1.0, authors_fullname_f1 >= 0.9, and ref_matching_f1 >= 0.8. A null field is excluded from that paper's floor checks. Missing expected predictions and front-matter abstentions count as failures in the headline rate. The legacy survivors-only rate is retained separately as pass_rate_excl_abstained with its own denominator; it is not interchangeable with pass_rate.

Front-matter abstentions suppress affected field scores from ordinary metric means. mean_incl_abstained reports the companion mean including their pre-suppression scores. Always read mean accuracy alongside abstention and cohort coverage.

Section-text evaluation

The same entry point can score saved exports against *.sectiongold.json artifacts:

uv run python -m evaluation.evaluate \
    --results-dir outputs/local \
    --sections \
    --section-gold-dirs /path/to/section-gold \
    --output outputs/local-sections.json

This mode emits section recall, coverage, and a drop report. It has a separate output shape from metadata scoring, and returns before the metadata --threshold gate. Per-type section recall is diagnostic.

Interpreting results

Compare runs on the same papers, gold revision, metric version, and extraction configuration. Record the extraction build and model identities separately from the scoring commit. Review missing and unmatched papers before interpreting accuracy changes, and use per_paper to separate OCR/native-text failures, metadata errors, and reference segmentation or parsing errors. Historical scores without this provenance are not a baseline for current main.