Skip to main content

Module diff

Module diff 

Source
Expand description

Entry-level structural diff between two bibliography snapshots (#135 sub-feature C).

bib verify already prints a unified line-based diff when drift is detected, but that output is mechanically useful and editorially noisy: a one-character change in a citekey ripples through dozens of lines of BibTeX, and the reader has to reconstruct the meaning by eye. bib diff gives the reader the meaning directly: which entries were added, which were removed, which changed (and which fields changed).

§Identity rule

Two entries refer to the same paper iff one of these matches — tried strictly in order, first-match-wins:

  1. citekey (exact, case-sensitive — citekeys are deterministic)
  2. DOI (lowercased, prefix-stripped — see crate::import::parse::normalize_doi)
  3. arxiv_id (trimmed)
  4. (title, year) — last-resort fallback when all three persistent identifiers are missing, e.g. an old NeurIPS PDF with no DOI yet

Strict per-rung means we don’t try multiple at once: if citekey matches we don’t even look at DOI. This matters for ambiguous cases (e.g. the citekey was renamed but DOI still matches — we treat that as added/removed, not a rename, because the user’s manuscripts still cite by the citekey).

§Determinism

All output lists are sorted by citekey lexicographically before return so callers (CLI, MCP, tests) see stable output across runs regardless of input order.

§Format-neutral

The diff operates on Entry — a deliberately narrow shape that both BibTeX and CSL-JSON parsers can populate. That way a BibTeX file and a CSL-JSON file with the same papers produce zero diff (verified by [tests::mixed_format_same_papers_produce_zero_diff]).

Structs§

BibDiff
Structural diff between two entry lists. Lists are sorted by citekey ascending so output is byte-stable across runs.
ChangedEntry
One entry whose identity matched on both sides but whose fields differ. field_changes is sorted alphabetically by field name for deterministic output.
Entry
Format-neutral bibliography entry. Populated by the BibTeX parser (via Entry::from_bib_entry) or the CSL-JSON parser (via Entry::from_csl_value) so the diff layer doesn’t care which flavor it’s looking at.
FieldChange
One field that differs between two matched entries.

Functions§

diff_entries
Compute the structural diff between two entry lists. Pure: no I/O, no global state. Deterministic: same inputs ⇒ same output, lists sorted by citekey.