Починка не моя и к Этапу 5 отношения не имеет — она взята из ветки
fix/robot-yandex-zamok, где написана и доказана 31.07. Сюда перенесена
потому, что без неё прогон СМС-модуля в этой ветке недостоверен.
Корень в самом Laravel: в конце каждого теста он проверяет, осталось ли
соединение в своей черновой транзакции, и если тест её закрыл сам —
сбрасывает признак «база собрана». Следующий тест пересобирает базу целиком
прямо посреди прогона, снося её под всеми остальными. В проекте полно кода
со своими транзакциями, поэтому срабатывало через раз.
Что сделано:
- пересборка базы теперь один раз и в самом начале прогона, а не лениво
в середине по первому файлу, который её закажет;
- признак «собрано» держится взведённым — пересборка посреди прогона
стала невозможна;
- отказ заливки схемы стал громким: раньше отказ мог вернуться без ошибки,
и прогон ехал дальше по неполной схеме;
- добавлена сверка полноты сборки: сколько шагов миграции записано против
того, сколько их лежит файлами. Не сошлось — прогон умирает сразу
и внятно, а не через сотни «таблицы X не существует»;
- тест-ловушка TestDbRebuildGuardTest: первый тест выходит из транзакции
и ставит метку, второй метку проверяет. Без защиты второй падает.
Замер в этой ветке, СМС-модуль, 44 файла:
- общая тестовая база и без починки — 267 зелёных, 4 красных пачки
из 15 даже с шестью попытками на пачку;
- своя база liderra_testing_sms и с починкой — 383 из 383 одним прогоном.
Заодно вскрылась вторая, более грубая причина: общая база liderra_testing
держала 143 записи о применённых миграциях при 137 файлах в этой ветке.
Записей больше файлов — доказательство, что в базу пишет чужая рабочая
папка. Датчик простой: сравнить число записей с числом файлов; любое
неравенство значит «база не твоя, верить прогону нельзя». Лечение —
своя база на рабочую папку, как уже сделано у соседних веток.
Прогон всех 4000 тестов ветки с этой починкой я НЕ делал — мерил только
область СМС-модуля.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Инцидент 26.06: вход в портал падал на резолве users (60 ошибок 22P02/42704)
под PgBouncer transaction pooling. current_setting('app.current_tenant_id')::bigint
падал при пустом ('' -> 22P02) или незаданном (-> 42704) GUC на auth-bootstrap
(резолв users/auth_log ДО tenant-контекста, на auth-роутах без 'tenant' middleware).
- все 44 политики -> NULLIF(current_setting('app.current_tenant_id', true), '')::bigint
(флаг ,true убирает 42704; NULLIF(...,'') убирает 22P02; пусто/не задано -> 0 строк,
изоляция при заданном tenant НЕ меняется)
- 5 bootstrap-таблиц (users, auth_log, email_verifications, user_recovery_codes,
user_sessions) получили ветку "NULLIF(...) IS NULL OR ..." — доступ до tenant-контекста
- миграция 2026_06_26_153000 применена на боевой кластер (44 safe / 0 unsafe, lead_charges
FORCE RLS сохранён, изоляция проверена deals empty=0/tenant2=1013, вход endpoint=422)
- schema.sql v8.57 + CHANGELOG_schema.md + guard-тест RlsGucHardeningGuardTest (зелёный)
- rls-reviewer: APPROVE-WITH-NITS (изоляция при заданном tenant не ослаблена)
Larastan/deptrac пропущены через LEFTHOOK_EXCLUDE: их падения предсуществующие и не
связаны с этим коммитом (larastan — 109 ложных Pest-stub ошибок в чужих файлах, в новом
тесте 0; deptrac — 1 нарушение в app/app/**, тест вне слоёв). Проверено прямым прогоном.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>