03ef89e06e
Проверка прав доступа по прошлой миграции вскрыла утечку: внешний ключ на сообщение не защищал от чужого клиента, потому что проверки целостности в PostgreSQL идут в обход RLS, а робот ходит под ролью с кросс-тенантным доступом. Он молча увёз бы документ одного клиента в модерацию кампании другого. Обе дыры воспроизведены вживую до правок. v9.13 — составной ключ по кампании: документ обязан принадлежать той же кампании. v9.15 — составные ключи по клиенту на заданиях и на ленте: клиент задания обязан совпадать с клиентом кампании. Понадобилась потому, что моя запись про v9.13 оказалась сильнее самой защиты — поймано повторной проверкой. v9.14 — GRANT SELECT на ленту служебной роли, иначе робот и админский экран увидели бы ноль строк молча. Заодно исправлены два неверных утверждения, написанных мной же: перезапуск 03_service_bypass_policies.sql в этом выкате обязателен, а не не нужен, и шапка журнала схемы врала только про счётчик записей, но не про номер версии. Три записи выкатываются только вместе. Проверка в коде задачи 16 остаётся вторым рубежом. Портал 350/350 в том числе на пересозданной с нуля базе, робот 60/60, все миграции проверены вверх-вниз-вверх, мест снятия заморозки денег по-прежнему четыре. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>