fix(startup): the reconcile guard catches the same errors the rest of main.py does (#1540)

The start-up reconcile runs at import, before the coordinator starts,
inside a try that named five exception types and left out `TypeError`.
`main.py` already defines `_IMPORT_OPERATIONAL_ERRORS` for this shape
and the other module-level guards use it, so this switches to it. An
unexpected `TypeError` from the reconcile would otherwise fail the
import of `shelfmark.main`, and the worker would fail to boot on every
restart.

I didn't use `except Exception` because BLE001 is on and nothing in
main.py does.

The test reloads main with the reconcile raising `TypeError`, and with
`OSError` as the control (that one already passes on main). Full non-e2e
suite passes, ruff and basedpyright are clean.

Found in a Claude pass over 1.5.0.
This commit is contained in:
splitsec2 authored and GitHub committed 2026-10-22 20:22:21 -04:00
1 parent f560b31ee4
commit 08fdb7ea87
2 files changed
+40 -1

No files matched your search

+1 -1
View File
@@ -285,7 +285,7 @@ if user_db is not None and download_history_service is not None:
_reconciled["marked"],
_reconciled["reopened"],
)
except (ImportError, OSError, RuntimeError, ValueError, sqlite3.Error) as exc:
except _IMPORT_OPERATIONAL_ERRORS as exc:
logger.warning("Could not reconcile interrupted downloads at startup: %s", exc)
# Start download coordinator
@@ -0,0 +1,39 @@
"""A reconcile that cannot run must never stop the app from starting."""
from __future__ import annotations
import importlib
from unittest.mock import patch
import pytest
from shelfmark.core.logger import CustomLogger
@pytest.mark.parametrize("error", [TypeError("unexpected row shape"), OSError("disk went away")])
def test_a_failing_startup_reconcile_only_logs_a_warning(error):
"""The module-level guard in main.py runs before the coordinator starts.
An error it does not catch fails the import of shelfmark.main, and the worker then
fails to boot on every restart.
"""
# Patch the class, not main.logger: reloading main builds a new logger object.
with (
patch("shelfmark.download.orchestrator.start"),
patch("shelfmark.download.warmup.start"),
patch(
"shelfmark.core.startup_reconcile.reconcile_interrupted_downloads",
side_effect=error,
) as reconcile,
patch.object(CustomLogger, "warning") as warning,
):
import shelfmark.main as main
importlib.reload(main)
# Importing and then reloading runs the module body twice, so only check it was reached.
assert reconcile.called
assert any(
"Could not reconcile interrupted downloads at startup" in str(call.args[0])
for call in warning.call_args_list
)