Интерфейс чатов при удалении чата стирает чат и сообщения, а загруженные в него файлы оставляет в томе — настройки на это у него нет. Уборку я написал сам: файл удаляется, когда на него не ссылается ничто живое. Хотел, чтобы «ничто живое» значило именно это.
Споткнулся на отчёте безопасности. Он нашёл, что «файл свободен» мой проход решает по трём предположениям о чужой схеме, и ни одно из них ничто в репозитории не проверяло. Хуже: тест строил стенд из того же предположения, что и код, — то есть подтверждал сам себя.
Пошёл читать схему и код образа в живом контейнере. Два предположения из трёх оказались верными. Третье — опасным с неожиданной стороны: связку файла с чатом образ пишет при отправке сообщения, но у временного чата строки в таблице чатов нет вовсе. Его вложение выглядит ровно как файл удалённого чата, то есть как мусор, который можно забрать немедленно.
Там же нашлись ещё два отказа. Мутация, выключавшая учёт времени привязки к чату, пережила все 64 теста модуля — закрылось одной строкой стенда. И файл без времени загрузки превращался в возраст с начала эпохи: удаление в первый же проход.
Решил: объявление таблиц и столбцов стало отдельной сущностью, из которой собирается запрос, и программа внутри контейнера сверяет это объявление со схемой живой базы перед каждым проходом, а отдельной командой — в гейте. Нет объявленной таблицы или столбца — отказ, а не удаление. Появилась в базе таблица со столбцом связки, которой объявление не знает, — тоже отказ: это ссылка, о которой запрос не знает, и файл из неё выглядел бы свободным. В объявлении 18 таблиц, живая схема совпала.
Выдержку в сутки распространил на обе ветки удаления, а не только на файл, никогда не привязанный к чату. Несостоявшийся проход пишет в свой журнал код причины из закрытого списка: поток ошибок у планировщика не ротируется и на хаб не уходит, и наглухо выключенная уборка иначе выглядела бы как уборка на прибранном томе.
Динамический перечень таблиц — брать всё, где есть столбец связки, — я отверг. Он молча расширяется и молча сужается, а задача ровно в том, чтобы изменение схемы было видно глазами.
Чем плачу. Файл удалённого чата живёт в томе до суток, а не до часа. Живая сверка ловит исчезнувшие и появившиеся таблицы, но не смену смысла столбца под тем же именем — это ловит только чтение кода образа, то есть руки, и к каждому обновлению. И проход теперь умеет отказываться там, где раньше тихо удалял: его отказ — мой разбор в гейте, а не чей-то потерянный файл.
#отказ