Skip to content

feat(bib): bib diff — entry-level structural diff (#135 sub-feature C of 3)#181

Merged
gerchowl merged 1 commit intodevfrom
feat/135c-bib-diff
Apr 28, 2026
Merged

feat(bib): bib diff — entry-level structural diff (#135 sub-feature C of 3)#181
gerchowl merged 1 commit intodevfrom
feat/135c-bib-diff

Conversation

@gerchowl
Copy link
Copy Markdown
Contributor

Summary

  • New scitadel bib diff <file_a> [<file_b>] [--question-id <id>] — entry-level (added / removed / changed) structural diff between two bibliographies, the human-readable explainer when bib verify says drift detected. Auto-detects BibTeX vs CSL-JSON by content sniff; the two flavors are interchangeable in either argument slot.
  • Identity rule per the design: citekey → DOI → arxiv_id → (title, year), strict per-rung first-match-wins. Lists sorted by citekey for deterministic output.
  • Hand-rolled ANSI in scitadel-export::diff_format (no new color/diff crates), TTY-detect via std::io::IsTerminal, --no-color for CI.
  • --format json for structured CI consumption; serde-derived round-trip.
  • Exit codes 0 (no diff) / 1 (any diff) mirror git diff.
  • MCP tool bib_diff mirroring the CLI for agent workflows.

Test plan

  • 34 unit tests in scitadel-export (4 identity-rung tests, 6 field-change tests, sort determinism, JSON round-trip, mixed-format zero-diff, format detection, ANSI color toggle)
  • 7 end-to-end CLI tests (identical files exit 0, drifted files exit 1 with the documented text report, --no-color strips ANSI, --format json round-trips, BibTeX-vs-CSL-JSON of the same shortlist exit 0, --question-id form against a seeded DB, missing-second-side error)
  • 6 inline CLI plumbing tests (TTY toggle, exit-code derivation, format dispatch)
  • 335 workspace tests passing (excluding scitadel-tui per quality gate)
  • just lint clean

Closes

Closes #135 (after #180 sub-feature A and #151 sub-feature B landed)

[tape-exempt: text-only --help addition under bib diff; output is colored text on stdout, not TUI rendering]

… of 3)

`bib verify` already prints a unified line-based diff on drift, but
that's mechanically useful and editorially noisy: a citekey rename
ripples through dozens of lines and the reader has to reconstruct
meaning by eye. `bib diff` gives the meaning directly: which entries
were added, removed, changed (and which fields changed).

- New `scitadel-export::diff` module: pure logic over a format-neutral
  `Entry` shape. Identity rule per spec: citekey → DOI → arxiv_id →
  (title, year), strict per-rung first-match-wins. All output lists
  sorted by citekey for byte-stable output.
- New `scitadel-export::diff_input`: format sniff (content-first; JSON
  parse trial, fallback to BibTeX) so `.bib` and `.json` are
  interchangeable on the command line.
- New `scitadel-export::diff_format`: hand-rolled ANSI text renderer +
  serde JSON renderer. No new color/diff crates.
- CLI `scitadel bib diff <file_a> [<file_b>] [--question-id <id>]
  [--format text|json] [--no-color] [--reader <r>]`. Exit 0 if no
  diff, 1 if any diff (mirrors `git diff`). Color auto-off on
  non-TTY via `std::io::IsTerminal`.
- MCP tool `bib_diff` mirroring CLI; returns the structured BibDiff
  JSON unconditionally so callers can branch.

Tests: 34 unit tests in scitadel-export (4 identity-rung tests, 6
field-change tests, sort determinism, JSON round-trip, mixed-format
zero-diff, format detection, format renderer color toggle). 7 CLI
integration tests (identical files exit 0, drifted files exit 1 with
text report, --no-color strips ANSI, --format json round-trips,
mixed-format zero-diff, --question-id form against seeded DB,
missing-second-side error). 6 inline CLI tests. 335 total tests pass.

Closes #135 (after sub-features A and B already landed in #180 and
#137 iter 2).

[tape-exempt: text-only --help addition under bib diff; output is
colored text on stdout, not TUI rendering]
@gerchowl gerchowl merged commit 930c709 into dev Apr 28, 2026
12 checks passed
@gerchowl gerchowl deleted the feat/135c-bib-diff branch April 28, 2026 12:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant