"""Переиспользуемая проверка контракта ответа на правку ячеек. Каждая строка ответа PATCH /cell(s) должна совпасть (data и sort_order) со строкой того же (row_type, depth, sort_order) из последующего GET /sheet. Используется в AURORA-1844 и далее (AURORA-1850: пересчёт только затронутого поддерева). """ def row_key(row: dict) -> tuple: return (row["row_type"], row["depth"], row["sort_order"]) def assert_patch_rows_match_sheet(patch_rows: list[dict], sheet_rows: list[dict]) -> None: """Строки ответа на правку целиком совпадают со строками листа.""" sheet_by_key = {row_key(r): r for r in sheet_rows} assert patch_rows, "ответ на правку пуст" keys = [row_key(r) for r in patch_rows] assert len(keys) == len(set(keys)), "в ответе дубли строк" for row in patch_rows: key = row_key(row) assert key in sheet_by_key, f"строки {key} нет в GET /sheet" assert row["data"] == sheet_by_key[key]["data"], f"data строки {key} расходится с GET"