"""Typed read-only projections consumed by the supply workbench.""" from typing import Annotated, Literal from pydantic import AwareDatetime, BeforeValidator, Field, JsonValue, model_validator from app.domain.schemas.shared import ( NonEmptyStr, NonNegativeInt, PositiveInt, StrictBool, StrictModel, ) def _workbench_datetime_wire_value(value: object): from datetime import datetime if not isinstance(value, (datetime, str)): raise ValueError("datetime input must be an RFC3339 string or datetime instance") return value WorkbenchDateTime = Annotated[ AwareDatetime, BeforeValidator(_workbench_datetime_wire_value) ] ProjectionAvailability = Literal["ready", "not_configured", "degraded"] class WorkbenchRuntimeCondition(StrictModel): id: NonEmptyStr task_id: Literal["backend-schedule"] session_id: NonEmptyStr title: NonEmptyStr summary: NonEmptyStr status: Literal["pending", "running", "completed", "warning", "error"] risk_level: Literal["normal", "attention", "critical"] scheduled_at: WorkbenchDateTime updated_at: WorkbenchDateTime detail: NonEmptyStr recommendation: NonEmptyStr | None evidence: list[NonEmptyStr] model_name: Literal["TJWater scheduler"] class WorkbenchAlertSource(StrictModel): task_type: Literal["scheduled_task", "analysis_task", "other_task"] task_id: NonEmptyStr run_id: NonEmptyStr class WorkbenchRuntimeAlert(StrictModel): id: NonEmptyStr condition_id: NonEmptyStr | None source: WorkbenchAlertSource title: NonEmptyStr description: NonEmptyStr occurred_at: WorkbenchDateTime severity: Literal["warning", "critical"] class WorkbenchPersistedAlert(StrictModel): alert_id: NonEmptyStr condition_id: NonEmptyStr | None source: WorkbenchAlertSource title: NonEmptyStr description: NonEmptyStr occurred_at: WorkbenchDateTime severity: Literal["warning", "critical"] status: Literal["active", "acknowledged", "resolved"] producer_id: NonEmptyStr | None = None updated_at: WorkbenchDateTime | None = None class WorkbenchRuntimeScenario(StrictModel): id: NonEmptyStr run_id: NonEmptyStr name: NonEmptyStr description: NonEmptyStr status: Literal["draft", "active", "review"] run_type: NonEmptyStr run_type_label: NonEmptyStr run_status: NonEmptyStr created_at: WorkbenchDateTime class WorkbenchRuntimeAnalysisFact(StrictModel): label: NonEmptyStr value: NonEmptyStr class WorkbenchRuntimeAnalysisResult(StrictModel): result_type: NonEmptyStr created_at: WorkbenchDateTime facts: list[WorkbenchRuntimeAnalysisFact] class WorkbenchRuntimeLatestAnalysis(StrictModel): run_id: NonEmptyStr name: NonEmptyStr run_type: NonEmptyStr run_type_label: NonEmptyStr status: NonEmptyStr status_label: NonEmptyStr created_by: NonEmptyStr created_at: WorkbenchDateTime started_at: WorkbenchDateTime results: list[WorkbenchRuntimeAnalysisResult] map_payload: dict[str, JsonValue] | None class WorkbenchAnalysisHistoryItem(StrictModel): run_id: NonEmptyStr name: NonEmptyStr run_type: NonEmptyStr run_type_label: NonEmptyStr status: NonEmptyStr status_label: NonEmptyStr created_by: NonEmptyStr created_at: WorkbenchDateTime started_at: WorkbenchDateTime has_results: StrictBool class WorkbenchAnalysisHistoryPage(StrictModel): items: list[WorkbenchAnalysisHistoryItem] limit: PositiveInt offset: NonNegativeInt next_offset: NonNegativeInt | None class WorkOrderActivity(StrictModel): sequence: PositiveInt occurred_at: WorkbenchDateTime actor: NonEmptyStr kind: Literal["created", "updated", "feedback"] title: NonEmptyStr detail: NonEmptyStr class WorkbenchRuntimeWorkOrder(StrictModel): id: NonEmptyStr code: NonEmptyStr scheduled_at: WorkbenchDateTime title: NonEmptyStr summary: NonEmptyStr status: Literal["pending", "running", "awaiting_reply", "completed"] risk_level: Literal["normal", "attention", "critical"] updated_at: WorkbenchDateTime detail: NonEmptyStr recommendation: NonEmptyStr | None duration_minutes: PositiveInt source: NonEmptyStr dispatcher: NonEmptyStr location: NonEmptyStr | None = None assignee: NonEmptyStr | None = None priority: Literal["normal", "urgent"] feedback_requirements: list[NonEmptyStr] = Field(default_factory=list) activity: list[WorkOrderActivity] = Field(default_factory=list) @model_validator(mode="before") @classmethod def accept_legacy_document(cls, value): if not isinstance(value, dict) or "subtasks" not in value: return value document = {key: item for key, item in value.items() if key != "subtasks"} subtasks = value.get("subtasks") or [] first = subtasks[0] if subtasks else {} document.setdefault("location", first.get("location")) document.setdefault("assignee", first.get("assignee")) document.setdefault("feedback_requirements", list(dict.fromkeys( requirement for subtask in subtasks for requirement in subtask.get("reply_requirements", []) ))) document.setdefault("activity", []) return document class WorkbenchRuntimeSnapshot(StrictModel): availability: ProjectionAvailability source: Literal["none", "scheduled_tasks"] scenario_availability: ProjectionAvailability artifact_availability: ProjectionAvailability schedule_availability: ProjectionAvailability work_order_availability: ProjectionAvailability alert_availability: ProjectionAvailability generated_at: WorkbenchDateTime conditions: list[WorkbenchRuntimeCondition] alerts: list[WorkbenchRuntimeAlert] scenarios: list[WorkbenchRuntimeScenario] latest_analysis: WorkbenchRuntimeLatestAnalysis | None work_orders: list[WorkbenchRuntimeWorkOrder]