"""GET /api/operator/failure-patterns — failure patterns view (TASK-08-03, D-053). Auth-gated. Returns failure pattern metrics: failure_mode frequency (cells with metric prefix `failure_mode:`) + branch outcome distribution (cells with metric prefix `branch:`). Weak-spot rubric criteria (mean < 3.0) are highlighted by the frontend. All k-anonymized. """ from __future__ import annotations import datetime as _dt from fastapi import APIRouter, Depends, Request from server.auth.dependencies import current_operator from server.auth.models import Operator from server.operator._common import ( ViewResponse, all_recent_aggregates, group_by_path, require_pg_store, ) router = APIRouter(prefix="/api/operator", tags=["operator-failure-patterns"]) def _is_failure_metric(metric: str) -> bool: return metric.startswith("failure_mode:") or metric.startswith("branch:") @router.get("/failure-patterns", response_model=ViewResponse) async def failure_patterns_view( request: Request, op: Operator = Depends(current_operator), ) -> ViewResponse: pg_store = await require_pg_store(request) since = _dt.date.today() - _dt.timedelta(days=30) rows = await all_recent_aggregates(pg_store, since) failure_rows = [r for r in rows if _is_failure_metric(r.get("metric", ""))] views, last_updated = group_by_path(failure_rows) return ViewResponse(views=views, last_updated=last_updated) __all__ = ["router"]