"""GET /api/operator/cohort — practice + assist volume view (TASK-08-01, TASK-10-02, D-053, D-057). Auth-gated (Depends(current_operator)). Returns k-anonymized practice + assist volume aggregates from cohort_aggregates: sessions_count + active_learners_count (practice) + assist_shifts_count + assist_turns_count (assist) per path. Suppressed cells have value=null + cell_suppressed=true; the frontend renders \"— (<10 learners)\". No per-learner drill-down (R-DASH-02). last_updated = max(updated_at) for freshness (REQ-NFR-DASH-02). D-062: assist metrics are new metric strings in the same cohort_aggregates table (no schema change). The view returns practice + assist volume side-by-side so operators see both modes per path. """ 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-cohort"]) # Practice volume metrics (v0.4) + assist volume metrics (v0.5 — TASK-10-02). PRACTICE_METRICS = { "sessions_count", "active_learners_count", "assist_shifts_count", "assist_turns_count", } @router.get("/cohort", response_model=ViewResponse) async def cohort_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) views, last_updated = group_by_path(rows, PRACTICE_METRICS) return ViewResponse(views=views, last_updated=last_updated) __all__ = ["router"]