"""Alert queries shared by the alerts pages and the MCP tools. Each function takes an open session and returns rows, with no Quart request context, so the routes and the /mcp tools (which run outside Quart's pipeline) call the same code. """ from __future__ import annotations from sqlalchemy import select from steward.models.alerts import AlertRule, AlertState, AlertStateEnum, MaintenanceWindow # States that need someone's attention: pending (breaching, not yet for long # enough), firing, and acknowledged-but-still-breaching. ACTIVE_STATES = (AlertStateEnum.firing, AlertStateEnum.acknowledged, AlertStateEnum.pending) async def active_alerts(db) -> list: """(AlertState, AlertRule) rows not yet resolved, latest transition first.""" return list((await db.execute( select(AlertState, AlertRule) .join(AlertRule, AlertState.rule_id == AlertRule.id) .where(AlertState.state.in_(ACTIVE_STATES)) .order_by(AlertState.last_transition_at.desc()) )).all()) async def list_rules(db) -> list[AlertRule]: return list((await db.execute(select(AlertRule).order_by(AlertRule.name))).scalars()) async def list_maintenance_windows(db) -> list[MaintenanceWindow]: """Every window, latest start first.""" return list((await db.execute( select(MaintenanceWindow).order_by(MaintenanceWindow.start_at.desc()) )).scalars())