chore(tradein): _manifest_applied.txt отстал на 27 имён — гейт от коллизий номеров миграций не работает между ветками #2683

Closed
opened 2026-08-05 22:08:23 +00:00 by bot-backend · 5 comments
Collaborator

Выяснилось при ревью PR #2682: пока ветка была в работе, смержился #2681 с 212_sber_index_pull_weekly.sql, и в PR оказался второй файл с номером 212. Разбор показал, что защита от такого не сработала не случайно.

Гейт от коллизий работает только внутри одного дерева

tests/test_migrations_manifest.py::test_new_files_do_not_reuse_prefix считает «занятыми» префиксы из _manifest_applied.txt плюс префиксы других новых файлов в том же рабочем дереве. Смерженный в main 212_sber в ветке физически отсутствует — сравнивать было не с чем.

Проверено симуляцией (копия data/sql + stub 212_sber): с номером 212 тест краснеет («212 уже у нового 212_sber»), с 213 — зелёный. То есть гейт исправен, но срабатывает только после rebase/merge, когда номер уже мог разойтись по двум PR.

Единственный механизм, который делает номер «занятым» между ветками, — это манифест: он один файл, он мержится и конфликтует. Но он не заполняется.

Манифест отстал на 27 имён

В data/sql 205 файлов, в манифесте 178. Не перечислены:

  • 171_scrape_schedules_seed_geoportal_coords_backfill.sql
  • 187_web_support_chat.sql, 188_tg_support_chat_id_scope.sqlисключение задокументировано в хвосте файла (веб-чат поддержки #2532/#2533 дорабатывался параллельно, прецедент L5 про заморозку имени до мержа)
  • 189211 — 23 файла подряд, без каких-либо пояснений
  • 213_listings_snapshots_status_vocab.sql — новый, из PR #2682

Нарушений правила 1 (имя в манифесте без файла на диске) нет — то есть файл не сломан, он просто перестал пополняться где-то после 186.

В самом контракте противоречие

Шапка манифеста, строки 3-4:

Отсортированный список ВСЕХ имён миграций (bare filename) в data/sql/, которые на момент коммита уже применены/забейслайнены на проде.

Правило 3 там же:

Добавляя новую миграцию — допиши её имя сюда В ТОМ ЖЕ PR (список отсортирован).

Для любой новой миграции это взаимоисключающие требования: в момент коммита она на проде ещё не применена. То же противоречие в тексте ассерта test_new_files_do_not_reuse_prefix («добавь имя файла в _manifest_applied.txt в ЭТОМ ЖЕ PR»).

Разрешает его docstring соседнего теста — и в пользу шапки, а не правила 3:

Этот тест НЕ требует, чтобы новый файл уже был в manifest (иначе PR с новой миграцией всегда красный).

Плюс прецедент L5 (commit 5eadae1e), процитированный в хвосте манифеста: имя, вписанное до мержа, замораживается, и переименовать его потом мешает тест «нельзя rename applied». В PR #2682 это ровно и случилось бы — файл пришлось переименовать 212 → 213 уже после коммита.

Что решить

  1. Какое чтение контракта операционное — «только применённое» (шапка + docstring теста + L5) или «в том же PR» (правило 3 + текст ассерта). Одно из двух место надо переписать, сейчас они противоречат друг другу и оба процитированы как контракт.
  2. Добить манифест до текущего состояния: 23 файла 189-211 + 171 (плюс 213 и 187/188, когда их фича осядет). Проверять по _schema_migrations на проде, а не по списку файлов.
  3. Если победит чтение «только применённое» — гейт от кросс-ветковых коллизий надо строить не на манифесте (он тогда принципиально отстаёт от незамерженных PR). Дешёвый вариант: проверять занятость номера по origin/main в CI, а не только по рабочему дереву.

Пока не решено — при добавлении миграции проверять номер через git fetch origin && git ls-tree --name-only origin/main tradein-mvp/backend/data/sql/, а не по локальному ls.

Выяснилось при ревью PR #2682: пока ветка была в работе, смержился #2681 с `212_sber_index_pull_weekly.sql`, и в PR оказался второй файл с номером 212. Разбор показал, что защита от такого не сработала не случайно. ## Гейт от коллизий работает только внутри одного дерева `tests/test_migrations_manifest.py::test_new_files_do_not_reuse_prefix` считает «занятыми» префиксы из `_manifest_applied.txt` плюс префиксы других **новых файлов в том же рабочем дереве**. Смерженный в main `212_sber` в ветке физически отсутствует — сравнивать было не с чем. Проверено симуляцией (копия `data/sql` + stub `212_sber`): с номером 212 тест краснеет («212 уже у нового `212_sber`»), с 213 — зелёный. То есть гейт исправен, но срабатывает только после rebase/merge, когда номер уже мог разойтись по двум PR. Единственный механизм, который делает номер «занятым» **между ветками**, — это манифест: он один файл, он мержится и конфликтует. Но он не заполняется. ## Манифест отстал на 27 имён В `data/sql` 205 файлов, в манифесте 178. Не перечислены: - `171_scrape_schedules_seed_geoportal_coords_backfill.sql` - `187_web_support_chat.sql`, `188_tg_support_chat_id_scope.sql` — **исключение задокументировано** в хвосте файла (веб-чат поддержки #2532/#2533 дорабатывался параллельно, прецедент L5 про заморозку имени до мержа) - `189` … `211` — 23 файла подряд, без каких-либо пояснений - `213_listings_snapshots_status_vocab.sql` — новый, из PR #2682 Нарушений правила 1 (имя в манифесте без файла на диске) нет — то есть файл не сломан, он просто перестал пополняться где-то после 186. ## В самом контракте противоречие Шапка манифеста, строки 3-4: > Отсортированный список ВСЕХ имён миграций (bare filename) в data/sql/, которые **на момент коммита уже применены/забейслайнены на проде**. Правило 3 там же: > Добавляя новую миграцию — допиши её имя сюда **В ТОМ ЖЕ PR** (список отсортирован). Для любой новой миграции это взаимоисключающие требования: в момент коммита она на проде ещё не применена. То же противоречие в тексте ассерта `test_new_files_do_not_reuse_prefix` («добавь имя файла в _manifest_applied.txt в ЭТОМ ЖЕ PR»). Разрешает его docstring соседнего теста — и в пользу шапки, а не правила 3: > Этот тест **НЕ требует**, чтобы новый файл уже был в manifest (иначе PR с новой миграцией всегда красный). Плюс прецедент L5 (commit `5eadae1e`), процитированный в хвосте манифеста: имя, вписанное до мержа, замораживается, и переименовать его потом мешает тест «нельзя rename applied». В PR #2682 это ровно и случилось бы — файл пришлось переименовать 212 → 213 уже после коммита. ## Что решить 1. Какое чтение контракта операционное — «только применённое» (шапка + docstring теста + L5) или «в том же PR» (правило 3 + текст ассерта). Одно из двух место надо переписать, сейчас они противоречат друг другу и оба процитированы как контракт. 2. Добить манифест до текущего состояния: 23 файла `189`-`211` + `171` (плюс `213` и `187`/`188`, когда их фича осядет). Проверять по `_schema_migrations` на проде, а не по списку файлов. 3. Если победит чтение «только применённое» — гейт от кросс-ветковых коллизий надо строить не на манифесте (он тогда принципиально отстаёт от незамерженных PR). Дешёвый вариант: проверять занятость номера по `origin/main` в CI, а не только по рабочему дереву. Пока не решено — при добавлении миграции проверять номер через `git fetch origin && git ls-tree --name-only origin/main tradein-mvp/backend/data/sql/`, а не по локальному `ls`.
Author
Collaborator

Половина задачи закрыта в PR #2692 (смержен): манифест догнан до факта прода — было заморожено 178 имён при 209 применённых, добавлено 31 (171, 187-216). Расхождение оказалось строго односторонним, поэтому правка чисто добавочная.

Вторая половина — та, из-за которой задача и заведена, — не закрыта и этим способом не закрывается. Гейт сравнивает NN-префиксы в пределах ОДНОГО рабочего дерева; два параллельных PR друг друга не видят по построению, и коллизию номеров между ними тест поймать не может. Сегодня это ловилось руками: три параллельные задачи получили диапазоны 217-218 / 219-220 / 221-222 распоряжением сверху, а не проверкой.

Актуальный манифест эту ручную разводку хотя бы делает возможной: без него непонятно, какие номера уже заняты. Но настоящее решение — проверка на стороне сервера (сравнивать номера нового файла с номерами во ВСЕХ открытых PR), либо отказ от сквозной нумерации в пользу имени, которое не может столкнуться.

Половина задачи закрыта в PR #2692 (смержен): манифест догнан до факта прода — было заморожено 178 имён при 209 применённых, добавлено 31 (171, 187-216). Расхождение оказалось строго односторонним, поэтому правка чисто добавочная. Вторая половина — та, из-за которой задача и заведена, — **не закрыта и этим способом не закрывается**. Гейт сравнивает NN-префиксы в пределах ОДНОГО рабочего дерева; два параллельных PR друг друга не видят по построению, и коллизию номеров между ними тест поймать не может. Сегодня это ловилось руками: три параллельные задачи получили диапазоны 217-218 / 219-220 / 221-222 распоряжением сверху, а не проверкой. Актуальный манифест эту ручную разводку хотя бы делает возможной: без него непонятно, какие номера уже заняты. Но настоящее решение — проверка на стороне сервера (сравнивать номера нового файла с номерами во ВСЕХ открытых PR), либо отказ от сквозной нумерации в пользу имени, которое не может столкнуться.
Author
Collaborator

Проверка 2026-08-07: манифест разъехался снова — за сутки на 13 имён

Все три пункта проверил заново.

п.1 (какое чтение контракта операционное) — не разрешён. Шапка _manifest_applied.txt
по-прежнему говорит «которые на момент коммита уже применены на проде», правило 3 там же —
по-прежнему «допиши её имя сюда В ТОМ ЖЕ PR». Оба текста на месте, ни один не переписан.
Хвост файла добавил третью формулировку — «self-maintenance-контракт требует дописывать только
СВОЙ файл в СВОЁМ PR», — то есть противоречивых мест стало не меньше, а больше.

п.2 (догнать манифест) — сделан PR #2692 и уже снова разъехался.

имён в манифесте:            213
файлов в data/sql:           226
применено на проде:          226   (_schema_migrations)
имён в манифесте без файла:    0   (правило 1 не нарушено)

Не хватает 13: 217-221, 223, 224, 227-232. Все они на проде применены.
Расхождение снова строго одностороннее.

Это, на мой взгляд, и есть эмпирический ответ на п.1: за сутки после того, как манифест догнали
руками, он отстал на 13 имён — значит чтение «допиши в том же PR» операционным не является,
его просто не выполняют. Хвост манифеста это фиксирует прямым текстом: «их авторы не дописали
имена в тот же PR — это чужой пробел, не наш».

п.3 (кросс-ветковый гейт) — не сделан, и вы сами это записали: тест сравнивает NN-префиксы в
пределах одного рабочего дерева, два параллельных PR друг друга не видят по построению.
Разводка диапазонов 217-218 / 219-220 / 221-222 делалась распоряжением, а не проверкой.

Задача остаётся открытой. Оговорка из её хвоста (проверять номер через
git ls-tree origin/main, а не по локальному ls) продолжает действовать.

## Проверка 2026-08-07: манифест разъехался снова — за сутки на 13 имён Все три пункта проверил заново. **п.1 (какое чтение контракта операционное) — не разрешён.** Шапка `_manifest_applied.txt` по-прежнему говорит «которые **на момент коммита уже применены** на проде», правило 3 там же — по-прежнему «допиши её имя сюда **В ТОМ ЖЕ PR**». Оба текста на месте, ни один не переписан. Хвост файла добавил третью формулировку — «self-maintenance-контракт требует дописывать только СВОЙ файл в СВОЁМ PR», — то есть противоречивых мест стало не меньше, а больше. **п.2 (догнать манифест) — сделан PR #2692 и уже снова разъехался.** ``` имён в манифесте: 213 файлов в data/sql: 226 применено на проде: 226 (_schema_migrations) имён в манифесте без файла: 0 (правило 1 не нарушено) ``` Не хватает **13**: `217`-`221`, `223`, `224`, `227`-`232`. Все они на проде применены. Расхождение снова строго одностороннее. Это, на мой взгляд, и есть эмпирический ответ на п.1: за сутки после того, как манифест догнали руками, он отстал на 13 имён — значит чтение «допиши в том же PR» операционным **не является**, его просто не выполняют. Хвост манифеста это фиксирует прямым текстом: «их авторы не дописали имена в тот же PR — это чужой пробел, не наш». **п.3 (кросс-ветковый гейт) — не сделан**, и вы сами это записали: тест сравнивает NN-префиксы в пределах одного рабочего дерева, два параллельных PR друг друга не видят по построению. Разводка диапазонов 217-218 / 219-220 / 221-222 делалась распоряжением, а не проверкой. Задача остаётся открытой. Оговорка из её хвоста (проверять номер через `git ls-tree origin/main`, а не по локальному `ls`) продолжает действовать.
Author
Collaborator

PR #2786 — открыт, ждёт владельца (правка гейта = управляющий контур, самомерж запрещён). 8/8 чеков зелёные.

Гипотеза «тест смотрит только на файлы из диффа» опровергнута: диффа он не видит вовсе, там glob("*.sql"). Реальная причина — «новым» считался файл, которого нет в манифесте, а новые файлы от манифеста освобождены явным решением (докстринг test_manifest_covers_all_but_new_files). Забытое имя и новая миграция PR неразличимы, поэтому покраснеть от дрейфа гейт не мог никогда. Замер на main сегодня: 228 файлов / 213 имён / не дописано 15 (за сутки после #2692 выросло с 13), pytest — 4 passed.

Из трёх вариантов выбран первый: файл не нужен. Оба инварианта выводимы из git — «применено на проде» = «доехало до main», потому что deploy-tradein.yml гоняет каждый data/sql/*.sql из main под ON_ERROR_STOP. Манифест был ручной копией git ls-tree origin/main, всегда отстающей. Удалён; дрейфовать нечему.

Удаление/переименование сверяется с точкой ветвления, номера — с полным origin/main. Поэтому недельная ветка не краснеет за чужие миграции (проверено: ветка от 30.07 при +43 миграциях — зелёная), а кросс-ветковая коллизия ловится.

Коллизия 234 ловится. На реальном дереве открытого PR #2754: новый гейт красный (234_trade_in_estimates_retain_until.sql — номер 234 уже занят: 234_scrape_runs_ban_kind_unknown.sql), старый на том же дереве — 4 passed.

Дополнительно из логов раннера: этот Forgejo не публикует refs/pull/N/merge (ls-remote: 1620 */head, ноль */merge), и checkout берёт refs/pull/N/head. То есть тестируется голова ветки, а перепрогона при движении main не бывает — CI PR #2754 отзеленел 06.08 19:53, а 234_scrape приехал в main в 23:18. Зелёный чек там устарел и сам об этом не узнает.

Мелочь, но она вводила в заблуждение: рецепт git ls-tree --name-only origin/main -- tradein-mvp/backend/data/sql без -r печатает каталог одной строкой, а не файлы. Он в таком виде записан в хвосте этого issue и в .claude/rules/tradein.md — исправлен.

13 (уже 15) недостающих имён намеренно не дописаны.

PR #2786 — открыт, ждёт владельца (правка гейта = управляющий контур, самомерж запрещён). 8/8 чеков зелёные. **Гипотеза «тест смотрит только на файлы из диффа» опровергнута**: диффа он не видит вовсе, там `glob("*.sql")`. Реальная причина — «новым» считался файл, **которого нет в манифесте**, а новые файлы от манифеста освобождены явным решением (докстринг `test_manifest_covers_all_but_new_files`). Забытое имя и новая миграция PR неразличимы, поэтому покраснеть от дрейфа гейт не мог никогда. Замер на main сегодня: 228 файлов / 213 имён / **не дописано 15** (за сутки после #2692 выросло с 13), `pytest` — 4 passed. **Из трёх вариантов выбран первый: файл не нужен.** Оба инварианта выводимы из git — «применено на проде» = «доехало до main», потому что `deploy-tradein.yml` гоняет каждый `data/sql/*.sql` из main под `ON_ERROR_STOP`. Манифест был ручной копией `git ls-tree origin/main`, всегда отстающей. Удалён; дрейфовать нечему. Удаление/переименование сверяется с **точкой ветвления**, номера — с **полным origin/main**. Поэтому недельная ветка не краснеет за чужие миграции (проверено: ветка от 30.07 при +43 миграциях — зелёная), а кросс-ветковая коллизия ловится. **Коллизия 234 ловится.** На реальном дереве открытого PR #2754: новый гейт красный (`234_trade_in_estimates_retain_until.sql — номер 234 уже занят: 234_scrape_runs_ban_kind_unknown.sql`), старый на том же дереве — `4 passed`. Дополнительно из логов раннера: этот Forgejo **не публикует** `refs/pull/N/merge` (ls-remote: 1620 `*/head`, ноль `*/merge`), и checkout берёт `refs/pull/N/head`. То есть тестируется голова ветки, а перепрогона при движении main не бывает — CI PR #2754 отзеленел 06.08 19:53, а `234_scrape` приехал в main в 23:18. Зелёный чек там устарел и сам об этом не узнает. Мелочь, но она вводила в заблуждение: рецепт `git ls-tree --name-only origin/main -- tradein-mvp/backend/data/sql` **без `-r`** печатает каталог одной строкой, а не файлы. Он в таком виде записан в хвосте этого issue и в `.claude/rules/tradein.md` — исправлен. 13 (уже 15) недостающих имён намеренно **не** дописаны.
Author
Collaborator

Замер 12.08: дрейф вырос до 18, PR #2786 по-прежнему ждёт владельца

Задачу не закрываю — правка гейта это управляющий контур, самомерж запрещён.

Числа на origin/main сегодня (голова 4d31a0ee):

файлов data/sql .............. 235
имён в манифесте ............. 217
не дописано .................. 18
имён без файла (правило 1) ....  0

Ряд дрейфа: 13 (07.08 утро) → 15 (07.08 вечер) → 18 (12.08). Расхождение остаётся строго односторонним — файл не сломан, он просто не пополняется.

Недостающие имена:

217_position_in_serp_unexpressible        228_scrape_proxies_browser_health
218_scrape_runs_ban_kind                  229_trade_in_estimates_consent_proof
219_deactivate_stale_health_gate          230_house_merge_log
220_listings_sale_type_domclick_dialect   231_trade_in_privacy_retention
221_backfill_house_suggestions_image_link 232_listings_observation_time_meaning
223_scrape_runs_time_columns_meaning      238_listings_ceiling_height_unify
224_houses_house_type_canon               239_scrape_schedules_seed_house_coords_from_listings
227_drop_position_in_serp                 253_scrape_proxy_domclick_affinity_release
                                          255_trade_in_estimates_revival_relaxations
                                          256_trade_in_estimates_revival_completed_at

Все они применены на проде (_schema_migrations); последняя — 256_trade_in_estimates_revival_completed_at.sql, applied_at 2026-08-11 05:57:40.

Эмпирический ответ на п.1 (какое чтение контракта операционное) с 07.08 только окреп: за пять суток после ручной догонки в #2692 манифест отстал ещё на 5 имён. Чтение «допиши в том же PR» операционным не является — его не выполняют, и одиннадцать разных авторов подряд не могут ошибаться случайно.

п.3 (кросс-ветковый гейт) — по-прежнему существует только в #2786. До его мержа продолжает действовать ручной рецепт из хвоста задачи, с -r:

git fetch origin && git ls-tree -r --name-only origin/main -- tradein-mvp/backend/data/sql/
## Замер 12.08: дрейф вырос до 18, PR #2786 по-прежнему ждёт владельца Задачу **не закрываю** — правка гейта это управляющий контур, самомерж запрещён. Числа на `origin/main` сегодня (голова `4d31a0ee`): ``` файлов data/sql .............. 235 имён в манифесте ............. 217 не дописано .................. 18 имён без файла (правило 1) .... 0 ``` Ряд дрейфа: 13 (07.08 утро) → 15 (07.08 вечер) → **18** (12.08). Расхождение остаётся строго односторонним — файл не сломан, он просто не пополняется. Недостающие имена: ``` 217_position_in_serp_unexpressible 228_scrape_proxies_browser_health 218_scrape_runs_ban_kind 229_trade_in_estimates_consent_proof 219_deactivate_stale_health_gate 230_house_merge_log 220_listings_sale_type_domclick_dialect 231_trade_in_privacy_retention 221_backfill_house_suggestions_image_link 232_listings_observation_time_meaning 223_scrape_runs_time_columns_meaning 238_listings_ceiling_height_unify 224_houses_house_type_canon 239_scrape_schedules_seed_house_coords_from_listings 227_drop_position_in_serp 253_scrape_proxy_domclick_affinity_release 255_trade_in_estimates_revival_relaxations 256_trade_in_estimates_revival_completed_at ``` Все они применены на проде (`_schema_migrations`); последняя — `256_trade_in_estimates_revival_completed_at.sql`, applied_at 2026-08-11 05:57:40. Эмпирический ответ на п.1 (какое чтение контракта операционное) с 07.08 только окреп: за пять суток после ручной догонки в #2692 манифест отстал ещё на 5 имён. Чтение «допиши в том же PR» операционным **не является** — его не выполняют, и одиннадцать разных авторов подряд не могут ошибаться случайно. п.3 (кросс-ветковый гейт) — по-прежнему существует только в #2786. До его мержа продолжает действовать ручной рецепт из хвоста задачи, с `-r`: ``` git fetch origin && git ls-tree -r --name-only origin/main -- tradein-mvp/backend/data/sql/ ```
lekss361 added the
chore
ci
scope/devops
tradein
labels 2026-08-16 10:25:15 +00:00
Owner

Закрываю по итогам разбора трекера 16.08.2026

Вердикт: сделано кодом.

Проблема дрейфа манифеста снята радикально: эталон занятых номеров берётся из git-истории, сам _manifest_applied.txt удалён — поддерживать его больше не нужно.

Доказательство: commit 2e20b630 «fix(tradein): гейт номеров миграций берёт эталон из git, ручной манифест удалён» (PR #2786) в forgejo/main; проверено на проде 15-16.08

Независимая проверка. Вердикт отдельно проверялся вторым проходом, задачей которого было именно опровергнуть закрытие, а не подтвердить его:

Проверил своими глазами и опровергнуть не смог. git ls-tree forgejo/main tradein-mvp/backend/data/sql_manifest_applied.txt в дереве нет; вместо него tradein-mvp/backend/tests/test_migration_numbering.py: удаления/переименования сверяются с merge-base, номера — с полным origin/main, при отсутствии git-эталона тест в CI не skip'ается, а pytest.fail (анти-вакуумные ассерты на пустой эталон тоже есть). CI-обвязка на месте: .forgejo/workflows/ci-tradein.yml (backend-tests) и deploy-tradein.yml (test) — fetch-depth: 0 с явным обоснованием #2683; фильтр путей ловит tradein-mvp/backend/**. Все три пункта «Что решить» закрыты: противоречие контракта снято вместе с файлом (единственная формулировка — докстринг теста, .claude/rules/tradein.md обновлён), догонять нечего, кросс-ветковый гейт сделан ровно предложенным в задаче «дешёвым вариантом» и показан красным на реальных деревьях #2754/#2546. PR #2786 смержен владельцем (lekss361) 15.08 20:04. Оговорка, не отменяющая вердикт: остаётся известная дыра ЭТОГО Forgejo — refs/pull/N/merge не публикуется, поэтому устаревшая зелёная галка PR не перепроверяется при движении main; это отдельный дефект CI, а не предмет #2683, и его стоит завести отдельной задачей, если он ещё не заведён.

Если что-то из перечисленного всё же живо — переоткройте задачу, разбор мог упустить частный случай.

## Закрываю по итогам разбора трекера 16.08.2026 **Вердикт:** сделано кодом. Проблема дрейфа манифеста снята радикально: эталон занятых номеров берётся из git-истории, сам _manifest_applied.txt удалён — поддерживать его больше не нужно. **Доказательство:** commit 2e20b630 «fix(tradein): гейт номеров миграций берёт эталон из git, ручной манифест удалён» (PR #2786) в forgejo/main; проверено на проде 15-16.08 **Независимая проверка.** Вердикт отдельно проверялся вторым проходом, задачей которого было именно опровергнуть закрытие, а не подтвердить его: > Проверил своими глазами и опровергнуть не смог. `git ls-tree forgejo/main tradein-mvp/backend/data/sql` — `_manifest_applied.txt` в дереве нет; вместо него tradein-mvp/backend/tests/test_migration_numbering.py: удаления/переименования сверяются с merge-base, номера — с полным origin/main, при отсутствии git-эталона тест в CI не skip'ается, а `pytest.fail` (анти-вакуумные ассерты на пустой эталон тоже есть). CI-обвязка на месте: .forgejo/workflows/ci-tradein.yml (backend-tests) и deploy-tradein.yml (test) — `fetch-depth: 0` с явным обоснованием #2683; фильтр путей ловит tradein-mvp/backend/**. Все три пункта «Что решить» закрыты: противоречие контракта снято вместе с файлом (единственная формулировка — докстринг теста, .claude/rules/tradein.md обновлён), догонять нечего, кросс-ветковый гейт сделан ровно предложенным в задаче «дешёвым вариантом» и показан красным на реальных деревьях #2754/#2546. PR #2786 смержен владельцем (lekss361) 15.08 20:04. Оговорка, не отменяющая вердикт: остаётся известная дыра ЭТОГО Forgejo — `refs/pull/N/merge` не публикуется, поэтому устаревшая зелёная галка PR не перепроверяется при движении main; это отдельный дефект CI, а не предмет #2683, и его стоит завести отдельной задачей, если он ещё не заведён. Если что-то из перечисленного всё же живо — переоткройте задачу, разбор мог упустить частный случай.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2683
No description provided.