  # #region TranslateSchemas [C:3] [TYPE Module] [SEMANTICS pydantic, translate, schema, translate-job-create]
  # @defgroup Schemas Module group.
  # @BRIEF Pydantic v2 schemas for translation API request/response serialization.
  # @LAYER API
  # @RELATION DEPENDS_ON -> [EXT:Library:pydantic]
  
! from datetime import datetime
! import re
! from typing import Any
  
! from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
  
  
! def _validate_bcp47_list(v: list[str] | None) -> list[str] | None:
!     """Validate that each item in target_languages is a valid BCP-47 tag."""
!     if not v:
!         return v
!     for tag in v:
!         if not tag or not tag.strip():
!             raise ValueError(f"Invalid BCP-47 tag: '{tag}' — must be a non-empty string")
!         if not re.match(r'^[a-zA-Z]{2,8}(-[a-zA-Z0-9]{1,8})*$', tag.strip()):
!             raise ValueError(
!                 f"Invalid BCP-47 tag: '{tag}'. "
!                 "Expected format like 'en', 'ru', 'zh-CN', 'pt-BR'."
!             )
!     return v
  
  
  # #region TranslateJobCreate [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for creating a new translation job.
! class TranslateJobCreate(BaseModel):
!     name: str
!     description: str | None = None
!     source_dialect: str = Field(..., description="Source database dialect (e.g. postgresql, clickhouse)")
!     target_dialect: str = Field(..., description="Target database dialect (e.g. postgresql, clickhouse)")
!     database_dialect: str | None = Field(None, description="Detected dialect from Superset connection at save time")
!     source_datasource_id: str | None = Field(None, description="Superset datasource ID")
!     source_table: str | None = Field(None, description="Source table name")
!     target_schema: str | None = Field(None, description="Target table schema")
!     target_table: str | None = Field(None, description="Target table name")
!     source_key_cols: list[str] | None = Field(default_factory=list, description="Source key column names")
!     target_key_cols: list[str] | None = Field(default_factory=list, description="Target key column names")
!     translation_column: str | None = Field(None, description="Source column to translate")
!     target_column: str | None = Field(None, description="Target column for translated output (defaults to translation_column)")
!     target_language_column: str | None = Field(None, description="Target column for language code (e.g. 'ru', 'en')")
!     target_source_column: str | None = Field(None, description="Target column for source/original text")
!     target_source_language_column: str | None = Field(None, description="Target column for detected source language (BCP-47)")
!     context_columns: list[str] | None = Field(default_factory=list, description="Context column names")
!     target_language: str | None = Field(None, description="Target language code [DEPRECATED: use target_languages]")
!     target_languages: list[str] | None = Field(default_factory=list, description="List of BCP-47 target language codes")
!     provider_id: str | None = Field(None, description="LLM provider ID")
  
!     _validate_target_languages = field_validator("target_languages")(_validate_bcp47_list)
!     batch_size: int = Field(50, description="Records per batch")
!     disable_reasoning: bool = Field(False, description="If true, pass reasoning_effort:none to LLM to save output tokens")
!     upsert_strategy: str = Field("MERGE", description="UPSERT strategy: MERGE, INSERT, UPDATE")
!     dictionary_ids: list[str] | None = Field(default_factory=list, description="Associated terminology dictionary IDs")
!     environment_id: str | None = Field(None, description="Superset environment ID")
!     target_database_id: str | None = Field(None, description="Superset database ID for SQL Lab insert target")
      # Direct DB insert
!     insert_method: str = Field("sqllab", description="Insert execution method: sqllab|direct_db")
!     connection_id: str | None = Field(None, description="UUID referencing a DatabaseConnection in GlobalSettings.connections (required when insert_method=direct_db)")
  
!     @model_validator(mode="after")
!     def validate_insert_method(self):
!         if self.insert_method == "direct_db" and not self.connection_id:
!             raise ValueError("connection_id is required when insert_method='direct_db'")
!         return self
  # #endregion TranslateJobCreate
  
  
  # #region TranslateJobUpdate [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for updating an existing translation job.
! class TranslateJobUpdate(BaseModel):
!     name: str | None = None
!     description: str | None = None
!     source_dialect: str | None = None
!     target_dialect: str | None = None
!     database_dialect: str | None = None
!     source_datasource_id: str | None = None
!     source_table: str | None = None
!     target_schema: str | None = None
!     target_table: str | None = None
!     source_key_cols: list[str] | None = None
!     target_key_cols: list[str] | None = None
!     translation_column: str | None = None
!     target_column: str | None = None
!     target_language_column: str | None = None
!     target_source_column: str | None = None
!     target_source_language_column: str | None = None
!     context_columns: list[str] | None = None
!     target_language: str | None = None
!     target_languages: list[str] | None = None
!     provider_id: str | None = None
  
!     _validate_target_languages = field_validator("target_languages")(_validate_bcp47_list)
!     batch_size: int | None = None
!     disable_reasoning: bool | None = None
!     upsert_strategy: str | None = None
!     status: str | None = None
!     dictionary_ids: list[str] | None = None
!     environment_id: str | None = None
!     target_database_id: str | None = None
!     insert_method: str | None = None
!     connection_id: str | None = None
  # #endregion TranslateJobUpdate
  
  
  # #region TranslateJobResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for translation job API responses.
! class TranslateJobResponse(BaseModel):
!     id: str
!     name: str
!     description: str | None = None
!     source_dialect: str
!     target_dialect: str
!     database_dialect: str | None = None
!     source_datasource_id: str | None = None
!     source_table: str | None = None
!     target_schema: str | None = None
!     target_table: str | None = None
!     source_key_cols: list[str] | None = None
!     target_key_cols: list[str] | None = None
!     translation_column: str | None = None
!     target_column: str | None = None
!     target_language_column: str | None = None
!     target_source_column: str | None = None
!     target_source_language_column: str | None = None
!     context_columns: list[str] | None = None
      # source_language removed — deprecated, per-row auto-detected
!     target_languages: list[str] | None = None
!     provider_id: str | None = None
!     batch_size: int = 50
!     disable_reasoning: bool = False
!     upsert_strategy: str = "MERGE"
!     status: str
!     created_by: str | None = None
!     created_at: datetime
!     updated_at: datetime | None = None
!     dictionary_ids: list[str] | None = None
!     environment_id: str | None = None
!     target_database_id: str | None = None
!     insert_method: str = "sqllab"
!     connection_id: str | None = None
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion TranslateJobResponse
  
  
  # #region DatasourceColumnResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for datasource column metadata response.
! class DatasourceColumnResponse(BaseModel):
!     name: str
!     type: str | None = None
!     is_physical: bool = True
!     is_dttm: bool = False
!     description: str | None = None
  
  # #endregion DatasourceColumnResponse
  
  # #region DatasourceColumnsResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for datasource columns endpoint response.
! class DatasourceColumnsResponse(BaseModel):
!     datasource_id: int
!     datasource_name: str | None = None
!     schema_name: str | None = None
!     database_dialect: str
!     columns: list[DatasourceColumnResponse] = []
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion DatasourceColumnsResponse
  
  
  # #region DuplicateJobResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for duplicate job response.
! class DuplicateJobResponse(BaseModel):
!     id: str
!     name: str
!     message: str = "Job duplicated successfully"
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion DuplicateJobResponse
  
  
  # #region DictionaryCreate [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for creating a new terminology dictionary.
! class DictionaryCreate(BaseModel):
!     name: str
!     description: str | None = None
!     is_active: bool = True
  # #endregion DictionaryCreate
  
  
  # #region DictionaryImport [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for importing entries into a terminology dictionary.
! class DictionaryImport(BaseModel):
!     content: str = Field(..., description="CSV or TSV content as raw string")
!     delimiter: str | None = Field(None, description="Detected or forced delimiter: ',' or '\\t'. Auto-detect if omitted.")
!     on_conflict: str = Field("overwrite", description="'overwrite' or 'keep_existing' or 'cancel'")
!     preview_only: bool = Field(False, description="If true, return preview without applying")
!     default_source_language: str | None = Field(None, description="Default BCP-47 source language when column missing in data")
!     default_target_language: str | None = Field(None, description="Default BCP-47 target language when column missing in data")
  # #endregion DictionaryImport
  
  
  # #region DictionaryResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for terminology dictionary API responses.
! class DictionaryResponse(BaseModel):
!     id: str
!     name: str
!     description: str | None = None
!     is_active: bool
!     created_by: str | None = None
!     created_at: datetime
!     updated_at: datetime | None = None
!     entry_count: int | None = None
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion DictionaryResponse
  
  
  # #region DictionaryEntryCreate [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for adding/editing a dictionary entry with language pair support.
! class DictionaryEntryCreate(BaseModel):
!     source_term: str = Field(..., description="Source term to translate")
!     target_term: str = Field(..., description="Target/translated term")
!     context_notes: str | None = Field(None, description="Optional context notes")
!     source_language: str = Field("und", description="BCP-47 source language code (default: und)")
!     target_language: str = Field("und", description="BCP-47 target language code (default: und)")
!     is_regex: bool = Field(False, description="Whether source_term is a regex pattern")
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion DictionaryEntryCreate
  
  
  # #region DictionaryEntryResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for dictionary entry API responses.
! class DictionaryEntryResponse(BaseModel):
!     id: str
!     dictionary_id: str
!     source_term: str
!     source_term_normalized: str
!     target_term: str
!     source_language: str | None = None
!     target_language: str | None = None
!     context_notes: str | None = None
!     context_data: dict[str, Any] | None = None
!     usage_notes: str | None = None
!     has_context: bool = False
!     is_regex: bool = False
!     context_source: str | None = None
!     origin_source_language: str | None = None
!     created_at: datetime
!     updated_at: datetime | None = None
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion DictionaryEntryResponse
  
  
  # #region DictionaryImportResult [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for dictionary import result.
! class DictionaryImportResult(BaseModel):
!     total: int = 0
!     created: int = 0
!     updated: int = 0
!     skipped: int = 0
!     errors: list[dict[str, Any]] = Field(default_factory=list)
!     preview: list[dict[str, Any]] = Field(default_factory=list, description="Preview rows with conflict flags")
  # #endregion DictionaryImportResult
  
  
  # #region PreviewRequest [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for triggering a translation preview.
! class PreviewRequest(BaseModel):
!     sample_size: int = Field(10, ge=1, le=100, description="Number of sample rows to preview")
!     prompt_template: str | None = Field(None, description="Optional custom prompt template")
!     env_id: str | None = Field(None, description="Superset environment ID for preview data fetch")
  # #endregion PreviewRequest
  
  
  # #region PreviewRowUpdate [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for approving/editing/rejecting a preview row.
! class PreviewRowUpdate(BaseModel):
!     action: str = Field(..., description="'approve', 'reject', or 'edit'")
!     translation: str | None = Field(None, description="Edited translation (required for 'edit' action)")
!     feedback: str | None = Field(None, description="Optional feedback/comment")
!     language_code: str | None = Field(None, description="BCP-47 language code for per-language actions (optional, applies to all if omitted)")
  # #endregion PreviewRowUpdate
  
  
  # #region PreviewAcceptResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for preview accept response.
! class PreviewAcceptResponse(BaseModel):
!     id: str
!     job_id: str
!     status: str
!     created_by: str | None = None
!     created_at: datetime
!     expires_at: datetime | None = None
!     records: list['PreviewRow'] = []
!     target_languages: list[str] = Field(default_factory=list, description="Target languages for this preview")
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion PreviewAcceptResponse
  
  
  # #region CostEstimate [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for cost estimation in preview response.
! class CostEstimate(BaseModel):
!     sample_size: int = 0
!     num_languages: int = 1
!     sample_prompt_tokens: int = 0
!     sample_output_tokens: int = 0
!     sample_total_tokens: int = 0
!     sample_cost: float = 0.0
!     estimated_total_rows: int = 0
!     estimated_tokens: int = 0
!     estimated_cost: float = 0.0
!     warning: str | None = None
  # #endregion CostEstimate
  
  
  # #region TermCorrectionSubmit [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for submitting a term correction in a translation preview.
! class TermCorrectionSubmit(BaseModel):
!     source_term: str
!     incorrect_target_term: str
!     corrected_target_term: str
!     dictionary_id: str | None = Field(None, description="Target dictionary ID (language-filtered)")
!     origin_run_id: str | None = Field(None, description="Run ID from which this correction originated")
!     origin_row_key: str | None = Field(None, description="Row key within the run")
!     context_data: dict[str, Any] | None = Field(None, description="Context data for the dictionary entry")
!     usage_notes: str | None = Field(None, description="Usage notes for the dictionary entry")
!     keep_context: bool = Field(True, description="If false, clear context_data and set has_context=False on dictionary entry")
  # #endregion TermCorrectionSubmit
  
  
  # #region TermCorrectionBulkSubmit [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for submitting multiple term corrections atomically.
! class TermCorrectionBulkSubmit(BaseModel):
!     corrections: list[TermCorrectionSubmit]
!     dictionary_id: str = Field(..., description="Target dictionary ID for all corrections")
  # #endregion TermCorrectionBulkSubmit
  
  
  # #region CorrectionConflictResult [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for reporting conflicts in correction submission.
! class CorrectionConflictResult(BaseModel):
!     source_term: str
!     existing_target_term: str
!     submitted_target_term: str
!     action: str = "keep_existing"
  # #endregion CorrectionConflictResult
  
  
  # #region CorrectionSubmitResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for correction submission response.
! class CorrectionSubmitResponse(BaseModel):
!     entry_id: str | None = None
!     action: str  # "created", "updated", "conflict_detected", "skipped"
!     source_term: str
!     target_term: str
!     conflict: CorrectionConflictResult | None = None
!     message: str | None = None
  # #endregion CorrectionSubmitResponse
  
  
  # #region ScheduleConfig [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for configuring a recurring translation schedule.
! class ScheduleConfig(BaseModel):
!     cron_expression: str = Field(..., description="Cron expression for scheduling (e.g. '0 2 * * *')")
!     timezone: str = Field("UTC", description="Timezone for the cron schedule (e.g. 'UTC', 'Europe/Moscow')")
!     is_active: bool = True
!     execution_mode: str = Field("full", description="Translation execution mode: 'full' or 'new_key_only'")
  # #endregion ScheduleConfig
  
  
  # #region ScheduleResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for schedule API responses.
! class ScheduleResponse(BaseModel):
!     id: str
!     job_id: str
!     cron_expression: str
!     timezone: str
!     is_active: bool
!     execution_mode: str = "full"
!     last_run_at: datetime | None = None
!     next_run_at: datetime | None = None
!     created_by: str | None = None
!     created_at: datetime
!     updated_at: datetime | None = None
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion ScheduleResponse
  
  
  # #region NextExecutionResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for next execution preview.
! class NextExecutionResponse(BaseModel):
!     job_id: str
!     cron_expression: str
!     timezone: str
!     next_executions: list[str] = []
  # #endregion NextExecutionResponse
  
  
  # #region TranslationRunResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for translation run API responses.
! class TranslationRunResponse(BaseModel):
!     id: str
!     job_id: str
!     status: str
!     trigger_type: str | None = None
!     started_at: datetime | None = None
!     completed_at: datetime | None = None
!     error_message: str | None = None
!     total_records: int = 0
!     successful_records: int = 0
!     failed_records: int = 0
!     skipped_records: int = 0
!     cache_hits: int = 0
!     insert_status: str | None = None
!     insert_method: str | None = None
!     connection_snapshot: dict[str, Any] | None = None
!     superset_execution_id: str | None = None
!     config_snapshot: dict[str, Any] | None = None
!     key_hash: str | None = None
!     config_hash: str | None = None
!     dict_snapshot_hash: str | None = None
!     created_by: str | None = None
!     created_at: datetime
!     language_stats: list['TranslationRunLanguageStatsResponse'] | None = None
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion TranslationRunResponse
  
  
  # #region RunDetailResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for detailed run response including records, events, and config snapshot.
! class RunDetailResponse(BaseModel):
!     run: TranslationRunResponse
!     records: list[dict[str, Any]] = Field(default_factory=list, description="Paginated translation records")
!     events: list[dict[str, Any]] = Field(default_factory=list, description="Run events")
!     event_invariants: dict[str, Any] | None = None
!     batch_count: int = 0
  # #endregion RunDetailResponse
  
  
  # #region RunHistoryFilter [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for filtering run history.
! class RunHistoryFilter(BaseModel):
!     job_id: str | None = None
!     status: str | None = None
!     trigger_type: str | None = None
!     created_by: str | None = None
!     date_from: datetime | None = None
!     date_to: datetime | None = None
!     page: int = 1
!     page_size: int = 20
  # #endregion RunHistoryFilter
  
  
  # #region RunListResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for paginated run list response.
! class RunListResponse(BaseModel):
!     items: list[TranslationRunResponse] = []
!     total: int = 0
!     page: int = 1
!     page_size: int = 20
  # #endregion RunListResponse
  
  
  # #region AggregatedMetricsResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for aggregated per-job metrics.
! class AggregatedMetricsResponse(BaseModel):
!     job_id: str
!     total_runs: int = 0
!     successful_runs: int = 0
!     failed_runs: int = 0
!     cancelled_runs: int = 0
!     total_records: int = 0
!     successful_records: int = 0
!     failed_records: int = 0
!     skipped_records: int = 0
!     cumulative_tokens: int | None = None
!     cumulative_cost: float | None = None
!     avg_duration_ms: float | None = None
!     last_run_at: datetime | None = None
!     next_scheduled_run: datetime | None = None
  # #endregion AggregatedMetricsResponse
  
  
  # #region TranslationPreviewLanguageResponse [C:1] [TYPE Class]
  # @BRIEF Schema for per-language preview data in API responses.
! class TranslationPreviewLanguageResponse(BaseModel):
!     language_code: str
!     source_language_detected: str | None = None
!     translated_value: str | None = None
!     user_edit: str | None = None
!     final_value: str | None = None
!     status: str = "pending"
!     needs_review: bool = False
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion TranslationPreviewLanguageResponse
  
  
  # #region PreviewRow [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF A single row in a translation preview showing original and translated content side by side.
! class PreviewRow(BaseModel):
!     id: str
!     source_sql: str | None = None
!     target_sql: str | None = None
!     source_object_type: str | None = None
!     source_object_id: str | None = None
!     source_object_name: str | None = None
!     status: str = "PENDING"
!     feedback: str | None = None
!     source_language_detected: str | None = None
!     needs_review: bool = False
!     languages: list[TranslationPreviewLanguageResponse] = Field(default_factory=list, description="Per-language translation data")
  # #endregion PreviewRow
  
  
  # #region TranslationPreviewResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for translation preview session API responses.
! class TranslationPreviewResponse(BaseModel):
!     id: str
!     job_id: str
!     run_id: str | None = None
!     status: str
!     created_by: str | None = None
!     created_at: datetime
!     expires_at: datetime | None = None
!     records: list[PreviewRow] = []
!     target_languages: list[str] = Field(default_factory=list, description="Target languages for this preview")
!     cost_estimate: CostEstimate | None = None
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion TranslationPreviewResponse
  
  
  # #region TranslationBatchResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for translation batch API responses.
! class TranslationBatchResponse(BaseModel):
!     id: str
!     run_id: str
!     batch_index: int
!     status: str
!     total_records: int = 0
!     successful_records: int = 0
!     failed_records: int = 0
!     started_at: datetime | None = None
!     completed_at: datetime | None = None
!     created_at: datetime
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion TranslationBatchResponse
  
  
  # #region MetricsResponse [TYPE Class]
  # @defgroup Schemas Module group.
  # @BRIEF Schema for translation metrics API responses.
! class MetricsResponse(BaseModel):
!     job_id: str
!     snapshot_date: datetime
!     total_jobs: int = 0
!     total_runs: int = 0
!     total_records: int = 0
!     successful_records: int = 0
!     failed_records: int = 0
!     skipped_records: int = 0
!     avg_duration_ms: int | None = None
!     p50_duration_ms: int | None = None
!     p95_duration_ms: int | None = None
!     p99_duration_ms: int | None = None
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion MetricsResponse
  
  
  # #region TranslationLanguageResponse [C:1] [TYPE Class]
  # @BRIEF Schema for per-language translation data in API responses.
! class TranslationLanguageResponse(BaseModel):
!     language_code: str
!     source_language_detected: str | None = None
!     translated_value: str | None = None
!     user_edit: str | None = None
!     final_value: str | None = None
!     status: str = "pending"
!     needs_review: bool = False
!     language_overridden: bool = False
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion TranslationLanguageResponse
  
  
  # #region TranslationRunLanguageStatsResponse [C:1] [TYPE Class]
  # @BRIEF Schema for per-language statistics in run API responses.
! class TranslationRunLanguageStatsResponse(BaseModel):
!     language_code: str
!     total_rows: int = 0
!     translated_rows: int = 0
!     failed_rows: int = 0
!     skipped_rows: int = 0
!     token_count: int = 0
!     estimated_cost: float = 0.0
  
!     model_config = ConfigDict(from_attributes=True)
  # #endregion TranslationRunLanguageStatsResponse
  
  
  # #region OverrideLanguageRequest [C:1] [TYPE Class]
  # @BRIEF Schema for manually overriding the detected source language of a translation.
! class OverrideLanguageRequest(BaseModel):
!     source_language: str = Field(..., description="BCP-47 language code to override with")
  # #endregion OverrideLanguageRequest
  
  
  # #region BulkFindReplaceRequest [C:1] [TYPE Class]
  # @BRIEF Schema for bulk find-and-replace within translations for a target language.
! class BulkFindReplaceRequest(BaseModel):
!     find_pattern: str = Field(..., description="Text or regex pattern to find", max_length=500)
!     is_regex: bool = Field(False, description="Whether find_pattern is a regular expression")
!     replacement_text: str = Field(..., description="Replacement text")
!     target_language: str = Field(..., description="BCP-47 language code to target")
!     preview: bool = Field(True, description="If true, return matches without applying replacements")
!     submit_to_dictionary: bool = Field(False, description="If true, also submit corrections to dictionary")
!     dictionary_id: str | None = Field(None, description="Target dictionary ID for submitting corrections")
!     usage_notes: str | None = Field(None, description="Usage notes for dictionary entries")
!     submit_to_dictionary_with_context: bool = Field(False, description="If true, auto-capture source row context when submitting to dictionary")
  
!     @field_validator("find_pattern")
!     @classmethod
!     def validate_pattern_length(cls, v: str) -> str:
!         """Reject patterns longer than 500 characters to prevent ReDoS."""
!         if len(v) > 500:
!             raise ValueError("Pattern too long (max 500 characters)")
!         return v
  # #endregion BulkFindReplaceRequest
  
  
  # #region InlineEditRequest [C:1] [TYPE Class]
  # @BRIEF Schema for inline editing a translated value on a completed run result.
! class InlineEditRequest(BaseModel):
!     final_value: str = Field(..., description="Corrected/edited translation text")
!     submit_to_dictionary: bool = Field(False, description="If true, also save correction to dictionary")
!     dictionary_id: str | None = Field(None, description="Target dictionary ID for saving correction")
!     context_data_override: dict[str, Any] | None = Field(None, description="Override auto-captured context data for dictionary entry")
!     usage_notes: str | None = Field(None, description="Usage notes for the dictionary entry")
!     keep_context: bool = Field(True, description="If false, clear context_data and set has_context=False on dictionary entry")
  # #endregion InlineEditRequest
  
  
  # #region BulkReplacePreviewItem [C:1] [TYPE Class]
  # @BRIEF A single item in a bulk replace preview list.
! class BulkReplacePreviewItem(BaseModel):
!     record_id: str
!     language_code: str
!     source_term: str
!     current_value: str
!     new_value: str
!     source_language_detected: str | None = None
  # #endregion BulkReplacePreviewItem
  
  
  # #region BulkReplaceResponse [C:1] [TYPE Class]
  # @BRIEF Response for bulk find-and-replace operation.
! class BulkReplaceResponse(BaseModel):
!     rows_affected: int = 0
!     corrections_submitted: int = 0
!     preview: list[BulkReplacePreviewItem] = Field(default_factory=list)
  # #endregion BulkReplaceResponse
  
  
  # #region InlineCorrectionSubmit [C:1] [TYPE Class]
  # @BRIEF Schema for submitting an inline correction for a specific translated record.
! class InlineCorrectionSubmit(BaseModel):
!     record_id: str = Field(..., description="Translation record ID")
!     language_code: str = Field(..., description="BCP-47 language code of the translated value")
!     source_term: str = Field(..., description="Original source term that was incorrectly translated")
!     corrected_term: str = Field(..., description="Corrected translation")
!     dictionary_id: str = Field(..., description="Target dictionary ID to also save the correction")
!     source_language: str = Field(..., description="BCP-47 source language code")
  # #endregion InlineCorrectionSubmit
  
  
  # #region TargetSchemaValidationRequest [C:1] [TYPE Class]
  # @BRIEF Schema for requesting target table schema validation.
! class TargetSchemaValidationRequest(BaseModel):
!     environment_id: str = Field(..., description="Superset environment ID")
!     target_database_id: str = Field(..., description="Superset database ID for the target DB (SQL Lab)")
!     target_schema: str = Field("public", description="Target table schema (default: public)")
!     target_table: str = Field(..., description="Target table name")
      # Column mapping from job config (everything that affects expected columns)
!     target_key_cols: list[str] | None = Field(default_factory=list, description="Target key column names")
!     target_column: str | None = Field(None, description="Target column for translated output")
!     translation_column: str | None = Field(None, description="Source column name (fallback for target_column)")
!     target_language_column: str | None = Field(None, description="Column for language code")
!     target_source_column: str | None = Field(None, description="Column for source text")
!     target_source_language_column: str | None = Field(None, description="Column for detected source language")
      # Direct DB support — when insert_method=direct_db, use connection_id instead of target_database_id
!     insert_method: str | None = Field(None, description="Insert method: 'sqllab' or 'direct_db'")
!     connection_id: str | None = Field(None, description="Direct DB connection ID (required when insert_method=direct_db)")
  # #endregion TargetSchemaValidationRequest
  
  
  # #region TargetSchemaColumnInfo [C:1] [TYPE Class]
  # @BRIEF Schema for a single column in the schema validation response.
! class TargetSchemaColumnInfo(BaseModel):
!     name: str
!     data_type: str | None = None
!     is_nullable: bool = True
  # #endregion TargetSchemaColumnInfo
  
  
  # #region TargetSchemaValidationResponse [C:1] [TYPE Class]
  # @BRIEF Schema for target table schema validation response.
! class TargetSchemaValidationResponse(BaseModel):
!     table_exists: bool = False
!     error: str | None = None
!     expected_columns: list[TargetSchemaColumnInfo] = Field(default_factory=list, description="Columns that the INSERT expects")
!     actual_columns: list[TargetSchemaColumnInfo] = Field(default_factory=list, description="Columns that exist in the target table")
!     missing_columns: list[TargetSchemaColumnInfo] = Field(default_factory=list, description="Expected columns NOT found in target table")
!     extra_columns: list[TargetSchemaColumnInfo] = Field(default_factory=list, description="Actual columns NOT in expected list")
!     all_present: bool = False
!     database_name: str | None = Field(default=None, description="Actual database name queried (from Superset)")
!     database_backend: str | None = Field(default=None, description="Actual database backend dialect (from Superset)")
  # #endregion TargetSchemaValidationResponse
  
  
  # #endregion TranslateSchemas
