"""Finite read scopes available to operational investigations.""" from datetime import timedelta from typing import Literal from pydantic import Field, JsonValue, model_validator from app.domain.schemas.shared import NonEmptyStr, StrictModel from app.domain.schemas.workbench_runtime import WorkbenchDateTime TaskDataSource = Literal[ "workbench_runtime", "scada_devices", "scada_readings", "peripheral_points", "peripheral_work_orders", "peripheral_observations", "peripheral_test_data", ] McpSnapshotSource = Literal[ 'get_mutation_status', 'query_nearby_elements', 'list_regions', 'get_region', 'get_region_nodes', 'get_node_connections', 'query_network_extent', 'list_major_nodes', 'get_model_configuration', 'list_model_configurations', 'search_project_places', 'reverse_geocode', 'get_project_info', 'export_project_model', 'get_sensor_placement_candidate', 'export_sensor_placement', 'list_task_schedules', 'get_task_run_history', 'calculate_demand_allocation', 'run_burst_simulation', 'edit_model_element', 'edit_model_configuration', 'clean_scada_readings', 'write_scada_readings', 'delete_scada_readings', 'save_simulation_scenario', 'create_sensor_placement', 'update_sensor_placement', 'create_operational_task', 'create_task_schedule', 'update_task_schedule', 'retry_operational_task', 'cancel_task_run', 'run_simulation', 'run_contaminant_simulation', 'analyze_valve_closure', 'analyze_flushing', 'analyze_pressure_regulation', 'optimize_sensor_placement', 'run_burst_detection', 'run_burst_location', 'analyze_valve_isolation', 'run_leakage_identification', 'get_element_properties', 'list_elements', 'get_network_options', 'get_network_schema', 'list_scada_devices', 'get_scada_device', 'query_scada_readings', 'query_model_baseline_series', 'get_model_baseline_at_time', 'query_model_baseline_field', 'query_analysis_series', 'query_analysis_values', 'list_analysis_runs', 'get_analysis_run', 'list_analysis_results', 'list_sensor_placement_runs', 'get_sensor_placement_run', 'query_element_history', 'get_element_gis_properties', 'get_source_gis_properties', 'get_workbench_runtime', 'get_task_context', 'query_peripheral_data', 'get_task_evidence', ] TaskSnapshotSource = TaskDataSource | McpSnapshotSource class TaskDataQuery(StrictModel): source: TaskDataSource device_ids: list[NonEmptyStr] = Field(default_factory=list, max_length=20) point_id: NonEmptyStr | None = None start: WorkbenchDateTime | None = None end: WorkbenchDateTime | None = None @model_validator(mode="after") def validate_window(self): if self.source in {"scada_readings", "peripheral_observations"}: if self.start is None or self.end is None: raise ValueError("time series queries require start and end") if not timedelta(0) < self.end - self.start <= timedelta(days=1): raise ValueError("query window must be positive and at most 24 hours") if self.source == "scada_readings" and not self.device_ids: raise ValueError("SCADA queries require device_ids") if self.source == "peripheral_observations" and not self.point_id: raise ValueError("peripheral queries require point_id") return self class TaskDataSnapshot(StrictModel): source: TaskSnapshotSource source_ref: NonEmptyStr queried_at: WorkbenchDateTime origin: Literal["system_data", "synthetic"] data: JsonValue truncated: bool