fix(tickers): let an SEC confirmation upgrade a manual delisting mark

mark_delisted returned early on any already-delisted row, so the sequence an
operator actually hits — mark EA by hand today, Form 25-NSE surfaces three days
later dated 2026-08-04 — left the estimated date and "manual" reason in place
permanently. Form 25 carries the real effective date, so it now replaces an
operator's estimate; a confirmed row is never downgraded or re-probed.

Also cover _get_ohlcv_priority_tickers, the one place active_only wraps a
compound select rather than a bare one — the unit suite reached none of it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 16:58:51 +02:00
co-authored by Claude Opus 5
parent 6501b7e9a0
commit d950fcf70e
2 changed files with 66 additions and 5 deletions
+51
View File
@@ -181,3 +181,54 @@ async def test_confirm_delisting_waits_before_spending_a_request(session: AsyncS
assert await ticker_service.confirm_delisting(
session, "EA", last_bar=None, today=date(2026, 8, 11)
) is None
async def test_sec_confirmation_upgrades_a_manual_mark(session: AsyncSession, monkeypatch):
"""An operator's estimated date is a guess; Form 25 carries the real one."""
session.add(Ticker(symbol="EA", cik="0000712515"))
await session.commit()
await ticker_service.mark_delisted(session, "EA", delisted_on=date(2026, 8, 11))
monkeypatch.setattr(
ticker_service,
"_sec_client_factory",
lambda: _sec_client(_submissions(["25-NSE"], ["2026-08-04"])),
raising=False,
)
assert await ticker_service.confirm_delisting(
session, "EA", last_bar=date(2026, 8, 4), today=date(2026, 8, 11)
) == date(2026, 8, 4)
row = (await session.execute(select(Ticker).where(Ticker.symbol == "EA"))).scalar_one()
assert row.delisted_on == date(2026, 8, 4)
assert row.delisted_reason == ticker_service.REASON_FORM_25
async def test_a_confirmed_row_is_never_reprobed(session: AsyncSession, monkeypatch):
session.add(Ticker(symbol="EA", cik="0000712515"))
await session.commit()
await ticker_service.mark_delisted(
session, "EA", delisted_on=date(2026, 8, 4),
reason=ticker_service.REASON_FORM_25,
)
def _explode():
raise AssertionError("a SEC-confirmed row must not cost another request")
monkeypatch.setattr(ticker_service, "_sec_client_factory", _explode, raising=False)
assert await ticker_service.confirm_delisting(
session, "EA", last_bar=date(2026, 8, 4), today=date(2026, 9, 1)
) is None
async def test_ohlcv_priority_ordering_skips_delisted(session: AsyncSession):
"""Covers the one statement where active_only wraps a compound select."""
from app.scheduler import _get_ohlcv_priority_tickers
session.add_all([Ticker(symbol="AAPL"), Ticker(symbol="EA"), Ticker(symbol="MSFT")])
await session.commit()
await ticker_service.mark_delisted(session, "EA", delisted_on=date(2026, 8, 4))
symbols = await _get_ohlcv_priority_tickers(session)
assert "EA" not in symbols
assert sorted(symbols) == ["AAPL", "MSFT"]