from typing import List, Literal, Optional from pydantic import BaseModel class PostcodeSplitterTriggerRequest(BaseModel): task_id: str sub_task_id: str s3_uri: str class CombinerTriggerRequest(BaseModel): task_id: str sub_task_id: str class LandlordOverridesTriggerRequest(BaseModel): task_id: str sub_task_id: str s3_uri: str portfolio_id: int # category -> source CSV header (the classifier subset of the upload mapping) column_mapping: dict[str, str] class FinaliserTriggerRequest(BaseModel): task_id: str sub_task_id: str s3_uri: str # combiner output (combined_output_s3_uri) portfolio_id: int bulk_upload_id: str # v2 (ADR-0006): inputs for the property_overrides write. Forwarded verbatim to # the finaliser Lambda. classifier_s3_uri is null when no classifier columns # were mapped; multi_entry_ordering / column_mapping default empty. classifier_s3_uri: Optional[str] = None multi_entry_ordering: dict[str, List[int]] = {} column_mapping: dict[str, str] = {} class FlagsSummary(BaseModel): duplicates: int missing: int matched: int class CombinedResultRow(BaseModel): row_index: int input_address: str internal_reference: Optional[str] = None uprn: Optional[str] = None matched_address: Optional[str] = None lexiscore: Optional[float] = None score_bucket: Optional[Literal["high", "med", "low"]] = None flags: List[Literal["duplicate", "missing"]] = [] class CombinedResultsResponse(BaseModel): task_id: str total: int offset: int limit: int flags_summary: FlagsSummary rows: List[CombinedResultRow]