Phase 1 - minor fix to Sources page
Quality Gate / gate (push) Failing after 11s

This commit is contained in:
Jim Lancaster
2026-08-20 15:14:34 -05:00
parent 7daa0b9808
commit afd1dba4d4
8 changed files with 165 additions and 28 deletions
+2
View File
@@ -24,6 +24,7 @@ from .config import get_settings
from .db import create_all
from .db import dispose_database_runtime
from .db import initialize_database_runtime
from .db import normalize_legacy_status_spellings
from .services import ServiceBundle
from .ui import register_pages
from .worker import worker_consumer_lifespan
@@ -42,6 +43,7 @@ async def _lifespan(app: FastAPI):
if settings.should_bootstrap_schema:
await create_all(engine=app.state.runtime.engine)
await normalize_legacy_status_spellings(engine=app.state.runtime.engine)
settings.upload_dir.mkdir(parents=True, exist_ok=True)
settings.prompt_dir.mkdir(parents=True, exist_ok=True)
+2
View File
@@ -1,4 +1,5 @@
from .operations import create_all
from .operations import normalize_legacy_status_spellings
from .runtime import dispose_database_runtime
from .runtime import initialize_database_runtime
from .session import session_scope
@@ -8,6 +9,7 @@ __all__ = [
"create_all",
"dispose_database_runtime",
"initialize_database_runtime",
"normalize_legacy_status_spellings",
"session_scope",
"transaction_scope",
]
+44
View File
@@ -2,6 +2,8 @@ from __future__ import annotations
import logging
from sqlalchemy import inspect as sqlalchemy_inspect
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncEngine
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlmodel import SQLModel
@@ -10,6 +12,7 @@ from sqlmodel.ext.asyncio.session import AsyncSession
from .engine import resolve_engine
from .models import DocumentType
from .models import JobSourceStatus
from .models import PersonRole
from .registries import BUILT_IN_DOCUMENT_TYPES
from .registries import BUILT_IN_PERSON_ROLES
@@ -29,6 +32,47 @@ async def create_all(*, engine: AsyncEngine | None = None) -> None:
logger.debug("Database schema bootstrap complete for database_url=%s", active_engine.url)
async def normalize_legacy_status_spellings(*, engine: AsyncEngine | None = None) -> int:
"""Normalize legacy enum-name spellings to canonical enum values.
Historical databases may carry ``TRANSCRIBED``/``FAILED``-style enum *names*
in ``job_source.status`` or ``execution_attempt.status``. Runtime models
expect canonical lowercase values, so stale rows must be normalized before
ORM reads.
"""
active_engine = engine or resolve_engine()
if not hasattr(active_engine, "begin"):
return 0
replacements = {
status.name: status.value
for status in JobSourceStatus
if status.name != status.value
}
def _normalize(sync_connection) -> int:
inspector = sqlalchemy_inspect(sync_connection)
table_names = set(inspector.get_table_names())
if not table_names:
return 0
fixed = 0
for table_name in ("job_source", "execution_attempt"):
if table_name not in table_names:
continue
for legacy, canonical in replacements.items():
result = sync_connection.execute(
text(f'update "{table_name}" set status = :canonical where status = :legacy'),
{"canonical": canonical, "legacy": legacy},
)
fixed += result.rowcount or 0
return fixed
async with active_engine.begin() as connection:
fixed_rows = await connection.run_sync(_normalize)
if fixed_rows:
logger.warning("Normalized %s legacy status row(s) to canonical spellings", fixed_rows)
return fixed_rows
async def seed_registry_defaults(*, engine: AsyncEngine | None = None) -> None:
"""Seed default registry rows for role and document type taxonomies."""
active_engine = engine or resolve_engine()