Парсер починен в #2815, но уже записанные строки сами не вылечатся: апсерт пишет
address = COALESCE(listings.address, EXCLUDED.address) — при конфликте адрес
осознанно не перезаписывается (#2777). Миграция 254 режет хвост «·<цифра>» по
ДОСЛОВНО парсерному правилу _NOT_ADDRESS_TAIL_RE.
Паритет проверен не по глазам: все 1123 сырых адреса выгружены с прода и
прогнаны через живой _clean_address в боевом контейнере tradein-scraper —
rows=1123 mismatches=0. Dry-run на проде (BEGIN…ROLLBACK) экзактным файлом:
UPDATE 1123, загрязнённых после 0, районные хвосты «· р-н Академический»
сохранены 296/296.
Обратимость без новой таблицы: прежнее значение уже лежит в
raw_payload->>'address' (пишется на INSERT, отсутствует в ON CONFLICT DO UPDATE
SET, совпадает с address побайтово у 1123 из 1123). Откат-предикат в шапке
миграции проверен в dry-run: 1123 совпадения по всей таблице, все наши,
восстановление побайтовое; 10 строк с грязным raw_payload и уже нормализованным
адресом он не берёт.
geocode_tried_at сбрасывается: метка backoff'а привязана к тексту адреса, а
текст сменился. После миграции 1122 строки (854 пары) попадают в выборку
geocode_missing_listings; 245 строк закрываются мгновенно из geocode_cache.