fix: gate setups on SEC filing completeness

This commit is contained in:
2026-08-03 23:47:07 +02:00
parent 7d703ea524
commit 3a6900d45a
11 changed files with 723 additions and 56 deletions
+50 -1
View File
@@ -15,6 +15,7 @@ from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_asyn
from app.database import Base
import app.models # noqa: F401
from app.models.fundamental_snapshot import FundamentalSnapshot
from app.models.sec_filing_gap import SecFilingGap
from app.models.system_event import SystemEvent
from app.models.ticker import Ticker
from app.services.data_import import (
@@ -374,7 +375,7 @@ async def test_recovers_facts_misfiled_under_coregistrant(engine):
# Stamped to the issuer that filed, NOT the co-registrant whose file it came from.
assert q2.cik == "0000320193"
assert q2.revenue == 254940 and q2.shares_outstanding == 14687
assert "coregistrant_recovery" in codes
assert "coregistrant_recovery" not in codes
async def test_coregistrant_recovery_rejects_discontinuous_share_count(engine):
@@ -425,11 +426,59 @@ async def test_unresolved_filing_stops_blocking_after_retry_window(engine):
assert run.source_max_date == date(2026, 5, 2) # and the index advances
summary = json.loads(run.validation_json or "{}")
assert summary["missing_xbrl_count"] == 1 and summary["missing_xbrl_blocking"] == 0
assert await _count(factory, SecFilingGap) == 1
async with factory() as s:
events = (await s.execute(select(SystemEvent))).scalars().all()
unresolved = [e for e in events if e.code == "unresolved_filing"]
assert len(unresolved) == 1 and "GHOST" in unresolved[0].message
assert "automatic SEC retry" in unresolved[0].message
# The next scheduled run retries even though the SEC daily-index revision
# has not changed. Company Facts is a separate SEC product and may catch up
# independently, so the generic revision no-op must not suppress this work.
still_missing_run = await run_import(
_importer(incr, today=date(2026, 5, 11)),
engine=engine,
)
assert still_missing_run.status == STATUS_PROMOTED
assert still_missing_run.revision is None
assert await _count(factory, SecFilingGap) == 1
# A later normal scheduled import retries only the queued issuer. Once SEC
# publishes the accession in Company Facts, it is inserted and unblocked
# without a full-universe reparse or operator action.
cf_ghost = _rev("2025-09-28", "2026-03-28", 254940, 2026, "Q2", "GHOST")
sh_ghost = _shares("2026-04-17", 14687, "GHOST", 2026, "Q2")
healed = FakeSecClient(
tickers={"AAPL": 320193},
companyfacts={
320193: _companyfacts(
[CF_K, CF_Q1, cf_ghost],
[SH_K, SH_Q1, sh_ghost],
)
},
submissions={
320193: _submissions(SUB_FILINGS + [
_filing(
"GHOST",
"10-Q",
"2026-03-28",
"2026-05-01",
"2026-05-01T10:01:00.000Z",
)
])
},
latest_index=date(2026, 5, 2),
)
healed_run = await run_import(
_importer(healed, today=date(2026, 5, 12)),
engine=engine,
)
assert healed_run.status == STATUS_PROMOTED
assert await _count(factory, FundamentalSnapshot) == 3
assert await _count(factory, SecFilingGap) == 0
async def test_non_xbrl_amendment_skipped_not_failed(engine):