v4.1.1 — Fix BUG-001 (db_loader crash)
v4.1.1 — Bug Fix Release
🐛 Fix: BUG-001 (Critical)
load_records_from_db() no longer crashes when records have NULL year or citation_count.
Root cause: SQLite stores nullable INTEGER columns as empty strings "" when not set. The loader passed these "" values directly to Pydantic's Record constructor, which expects int | None and rejected empty strings with int_parsing validation errors.
Impact: After importing any bibliographic file with incomplete metadata (missing year or citation count), all subsequent analysis commands (stats, text, network, trend) crashed.
Fix: Added _opt_int() helper in src/citationer/utils/db_loader.py:103-111 that converts empty strings, None, or whitespace-only strings to None before passing to Pydantic.
def _opt_int(value):
if value is None:
return None
if isinstance(value, int):
return value
if value == "" or str(value).strip() == "":
return None
return value✅ Regression Tests
3 new tests in tests/test_database.py::TestBug001Regression:
test_load_with_null_year— Pydantic Record accepts NULL yeartest_load_with_empty_string_year— Manual SQL UPDATE sets int columns to NULL → load succeedstest_round_trip_orphan_record— Full round-trip with all year/citation_count fields missing
📊 Status
- Tests: 562 passing (was 559)
- Coverage: 80.49% (CI gate 80% met)
- Lint: ruff clean
🐞 Remaining Defects (not fixed in 4.1.1)
- #16 BUG-002: Institution.name_en not serialized
- #17 BUG-003: en/zh keywords not split on load
- #19 BUG-004: trend baseline median polluted by burst
- #20 BUG-005: trend strategy recomputes in second pass
Closes #15