"""Pack a Modelling Run's resolved properties into SQS-message-sized batches. Batches stay postcode-grouped — properties sharing a postcode ride the same message so the workers' prediction cohort cache keeps paying (ADR-0055), the same packing the trigger script has been running. """ from backend.app.modelling.property_filters import FilteredProperty BATCH_SIZE = 50 def pack_postcode_batches( properties: list[FilteredProperty], batch_size: int = BATCH_SIZE ) -> list[list[FilteredProperty]]: """Pack *properties* into batches of ~*batch_size*, never splitting a postcode across batches. A single postcode larger than *batch_size* becomes its own oversized batch.""" groups: dict[str, list[FilteredProperty]] = {} for prop in properties: groups.setdefault(prop.postcode or "", []).append(prop) batches: list[list[FilteredProperty]] = [] current: list[FilteredProperty] = [] for group in groups.values(): if current and len(current) + len(group) > batch_size: batches.append(current) current = list(group) else: current.extend(group) if current: batches.append(current) return batches