fix(mera/estimate): убран предикат d.rooms в коридоре ДКП — он был вторым фильтром по площади (#3256) #3445

Merged
bot-backend merged 4 commits from fix/3256-asking-to-sold-buckets into main 2026-09-11 21:59:19 +00:00
Collaborator

Работа по #3256. Таблицу asking_to_sold_ratios не трогал — и это главный вывод, а не отказ от работы. Вместо подгонки коэффициента убран предикат, который оказался вторым фильтром по площади.

Почему постановку нельзя выполнить как написано

Ось per_area_bucket, на которой стоит критерий приёмки, слепа по построению: deals.rooms — синтетика из площади (321 559 из 321 560 сделок имеют rooms == area_bucket(area_m2), max(rooms)=4, границы точно совпадают с CASE в deploy/import-rosreestr.sh:71-78). В обеих прод-фикстурах (1500 + 4000 целей) 0 из 5500 имеют настоящую комнатность, тогда как у реальных клиентов с ≥85 м²: 115 трёхкомнатных, 40 четырёх-, 16 пяти-, 11 шести-, 9 двух- — 79 % получают другой пул аналогов, чем харнес.

«Починка» коэффициента под эту ось (+11 % к бакету 4) компенсировала бы −10 % занижения числителя харнеса и дала бы в проде переплату ~10 % по крупному жилью. Поэтому деривация не тронута; в докстринг scripts/backtest_estimator.py добавлена каверза (e) с перекрёстной ссылкой на (d) — они складываются (неправильное МЕСТО + неправильный СЕГМЕНТ), обе бьют по ≥85 м².

Что починено: предикат d.rooms удалён

Так как deals.rooms ≡ area_bucket(deals.area_m2), условие d.rooms = <комнаты клиента> тождественно второму фильтру по площади — и он спорит с полосой ±15 %, стоящей в двух строках от него. Доля полосы, переживающей предикат:

вариант медиана доли полосы последствия
(а) как на проде — комнаты клиента 77.8 % у 180 клиентов полоса вырезана целиком (коридор невозможен)
(б) area_bucket 90.0 % пустых нет, но у 902 из 1179 полоса усечена (44.0 м² → 50 %, 62.0 м² → 50 %)
(в) без предиката (выбран) 100 % по построению

Оба ключа сжимают коридор внутрь: p90 (от неё cap) у 58 клиентов ниже более чем на 10 %, p10 (от неё floor) у 68 выше более чем на 10 %. Пример: Челюскинцев 60, 1к/49 м² — p90 равен 168 632 (а) / 107 345 (б) / 154 147 (в); headline 236 085 / 150 283 / 215 806. Отрезая низ полосы, бакет выбрасывает мелкие лоты с высоким ₽/м².

Замер на 1179 реальных запросах, все три пути влияния коридора

Доступность коридора:

вариант n≥1 n≥3 n≥10 против (а) при n≥3 при n≥10
(а) прод 809 769 567
(б) area_bucket 895 850 623 +86 / −5 +66 / −10
(в) без предиката 897 874 691 +105 / −0 +126 / −2

Сдвиг headline (база — (а) на том же снимке; пути: cap/floor, sufficiency-гейт #oblast-E, deals-fallback; якорь Tier A иммунен):

вариант сдвинулось медиана p10 >10 % >25 %
(б) area_bucket 28 +1.0 % −30.6 % 10 4
(в) без предиката 120 −1.6 % −8.6 % 10 2

Теряют цену (headline был, стал 0) — 0 в обоих вариантах.

Худший случай из ревью не подтвердился: «Белинского 86, −50 %» идёт путём якоря Tier C, где deals-fallback заблокирован гардом anchor is None, а sufficiency-гейт headline не переписывает. Реальный эффект там — только cap: −14.2 % (б) / −9.7 % (в). Правило тонкого листинга было применено к анкерной строке: сохранённый n_analogs у таких строк — это anchor["n"], а не размер радиусной выборки.

Настоящий худший случай общий для обоих вариантов и от выбора ключа не зависит: Малышева 84, 1к/54 м², радиусная медиана 446 366 ₽/м², коридор (а) пуст → (б)=(в) n=21, p90 185 558 → cap до 259 781 (−41.8 %). Возникает от самого появления коридора: премиальный лот прижимается к коридору обычной вторички улицы. Вынесено отдельно (#3450), это решение продукта, а не дефект правки.

Реплика замера фальсифицирована: прогнал продовый SQL для 58 оценок × 3 варианта (жирные коридоры, флип-случаи, не-ЕКБ с widen) — 174/174 совпадений по count; воспроизводит и числа предыдущего замера (809→895, 567→623), и числа ревьюера (769→850, +86/−5) из независимого кода.

Поправленные факты

  • «у 818 клиентов выборка не меняется» → 793 (прежняя классификация через min(max(rooms,0),4) затянула 27 клиентов с 5-6 комнатами). Эти 27 прироста всё равно не получают: метраж 158-456 м², в основном вне окна импорта area BETWEEN 18 AND 200.
  • Каверза (e): фраза «бакеты 0-2 чисты» убрана — по пулу, который реально видит _fetch_analogs, совпадение rooms == area_bucket: бакет 0 — 69.8 %, 1 — 63.5 %, 2 — 60.1 %, 3 — 54.6 %, 4 — 30.9 % (мода 3). Формулировка теперь «в бакетах 0-3 модальная комнатность совпадает с бакетом, в бакете 4 — нет; остальные не чисты, а лишь меньше смещены».
  • trade_in.py:2282/:2314 печатали rooms=%d комнатностью клиента, хотя фильтра по ней уже нет — теперь печатают фактический ключ (полосу площади).

Тест-якорь против молчаливого возврата

tests/test_3256_deals_rooms_key.py::test_importer_case_still_matches_area_bucket парсит CASE … AS rooms прямо из deploy/import-rosreestr.sh и сверяет границы с area_bucket(); у самого CASE — комментарий-якорь с указанием вернуться в #3256. Сдвиг границы 62→60 в скрипте роняет тест (расхождение на area=61.9), замена CASE настоящей колонкой — тоже (CASE … не найден).

Фальсификация основной правки: откат к пред-PR коду дал 5 failed, но _fetch_deals падал TypeError («возможности нет», а не «значение неверно»), поэтому сделана хирургическая подмена — новая сигнатура, возвращён только предикат: assert ['AND rooms = :rooms'] == []. Отдельно: тест test_dkp_corridor_keeps_full_area_band оставался зелёным при всех подменах, то есть не охранял ничего — усилен до «полоса единственная».

Прогоны: 5747 passed, 35 skipped (rc=0); ruff чисто.

Критерии приёмки issue — честно не выполнены

«Ни один бакет хуже 8 %» и «MAPE не хуже 14.28» по оси per_area_bucket достижимы только оракульным подбором под ту же выборку (in-sample до нулевого смещения даёт 13.38, любая принципиальная деривация 14.13-14.56) — ловушка #2255. Пока нет источника настоящей комнатности сделок, калибровка по этой оси калибрует по пулу, которого у клиента нет.

Работа по #3256. **Таблицу `asking_to_sold_ratios` не трогал — и это главный вывод, а не отказ от работы.** Вместо подгонки коэффициента убран предикат, который оказался вторым фильтром по площади. ## Почему постановку нельзя выполнить как написано Ось `per_area_bucket`, на которой стоит критерий приёмки, **слепа по построению**: `deals.rooms` — синтетика из площади (**321 559 из 321 560** сделок имеют `rooms == area_bucket(area_m2)`, `max(rooms)=4`, границы точно совпадают с CASE в `deploy/import-rosreestr.sh:71-78`). В обеих прод-фикстурах (1500 + 4000 целей) **0 из 5500** имеют настоящую комнатность, тогда как у реальных клиентов с ≥85 м²: 115 трёхкомнатных, 40 четырёх-, 16 пяти-, 11 шести-, 9 двух- — **79 % получают другой пул аналогов, чем харнес**. «Починка» коэффициента под эту ось (+11 % к бакету 4) компенсировала бы −10 % занижения числителя харнеса и дала бы в проде **переплату ~10 % по крупному жилью**. Поэтому деривация не тронута; в докстринг `scripts/backtest_estimator.py` добавлена каверза (e) с перекрёстной ссылкой на (d) — они складываются (неправильное МЕСТО + неправильный СЕГМЕНТ), обе бьют по ≥85 м². ## Что починено: предикат `d.rooms` удалён Так как `deals.rooms ≡ area_bucket(deals.area_m2)`, условие `d.rooms = <комнаты клиента>` тождественно второму фильтру по площади — и он спорит с полосой ±15 %, стоящей в двух строках от него. Доля полосы, переживающей предикат: | вариант | медиана доли полосы | последствия | |---|---|---| | (а) как на проде — комнаты клиента | 77.8 % | **у 180 клиентов полоса вырезана целиком** (коридор невозможен) | | (б) `area_bucket` | 90.0 % | пустых нет, но **у 902 из 1179 полоса усечена** (44.0 м² → 50 %, 62.0 м² → 50 %) | | (в) **без предиката** (выбран) | 100 % | по построению | Оба ключа сжимают коридор внутрь: `p90` (от неё cap) у 58 клиентов ниже более чем на 10 %, `p10` (от неё floor) у 68 выше более чем на 10 %. Пример: Челюскинцев 60, 1к/49 м² — p90 равен 168 632 (а) / **107 345** (б) / 154 147 (в); headline 236 085 / **150 283** / 215 806. Отрезая низ полосы, бакет выбрасывает мелкие лоты с высоким ₽/м². ## Замер на 1179 реальных запросах, все три пути влияния коридора Доступность коридора: | вариант | n≥1 | n≥3 | n≥10 | против (а) при n≥3 | при n≥10 | |---|---|---|---|---|---| | (а) прод | 809 | 769 | 567 | — | — | | (б) area_bucket | 895 | 850 | 623 | +86 / −5 | +66 / −10 | | (в) **без предиката** | 897 | **874** | **691** | **+105 / −0** | +126 / −2 | Сдвиг headline (база — (а) на том же снимке; пути: cap/floor, sufficiency-гейт #oblast-E, deals-fallback; якорь Tier A иммунен): | вариант | сдвинулось | медиана | p10 | >10 % | >25 % | |---|---|---|---|---|---| | (б) area_bucket | 28 | +1.0 % | −30.6 % | 10 | 4 | | (в) **без предиката** | 120 | **−1.6 %** | **−8.6 %** | 10 | **2** | Теряют цену (headline был, стал 0) — **0** в обоих вариантах. **Худший случай из ревью не подтвердился:** «Белинского 86, −50 %» идёт путём якоря Tier C, где deals-fallback заблокирован гардом `anchor is None`, а sufficiency-гейт headline не переписывает. Реальный эффект там — только cap: −14.2 % (б) / −9.7 % (в). Правило тонкого листинга было применено к анкерной строке: сохранённый `n_analogs` у таких строк — это `anchor["n"]`, а не размер радиусной выборки. **Настоящий худший случай общий для обоих вариантов** и от выбора ключа не зависит: Малышева 84, 1к/54 м², радиусная медиана 446 366 ₽/м², коридор (а) пуст → (б)=(в) n=21, p90 185 558 → cap до 259 781 (**−41.8 %**). Возникает от самого появления коридора: премиальный лот прижимается к коридору обычной вторички улицы. Вынесено отдельно (#3450), это решение продукта, а не дефект правки. **Реплика замера фальсифицирована:** прогнал продовый SQL для 58 оценок × 3 варианта (жирные коридоры, флип-случаи, не-ЕКБ с widen) — 174/174 совпадений по count; воспроизводит и числа предыдущего замера (809→895, 567→623), и числа ревьюера (769→850, +86/−5) из независимого кода. ## Поправленные факты - «у 818 клиентов выборка не меняется» → **793** (прежняя классификация через `min(max(rooms,0),4)` затянула 27 клиентов с 5-6 комнатами). Эти 27 прироста всё равно не получают: метраж 158-456 м², в основном вне окна импорта `area BETWEEN 18 AND 200`. - Каверза (e): фраза «бакеты 0-2 чисты» **убрана** — по пулу, который реально видит `_fetch_analogs`, совпадение `rooms == area_bucket`: бакет 0 — 69.8 %, 1 — 63.5 %, 2 — 60.1 %, 3 — 54.6 %, 4 — 30.9 % (мода 3). Формулировка теперь «в бакетах 0-3 модальная комнатность совпадает с бакетом, в бакете 4 — нет; остальные не чисты, а лишь меньше смещены». - `trade_in.py:2282/:2314` печатали `rooms=%d` комнатностью клиента, хотя фильтра по ней уже нет — теперь печатают фактический ключ (полосу площади). ## Тест-якорь против молчаливого возврата `tests/test_3256_deals_rooms_key.py::test_importer_case_still_matches_area_bucket` парсит `CASE … AS rooms` прямо из `deploy/import-rosreestr.sh` и сверяет границы с `area_bucket()`; у самого CASE — комментарий-якорь с указанием вернуться в #3256. Сдвиг границы 62→60 в скрипте роняет тест (`расхождение на area=61.9`), замена CASE настоящей колонкой — тоже (`CASE … не найден`). **Фальсификация основной правки:** откат к пред-PR коду дал 5 failed, но `_fetch_deals` падал `TypeError` («возможности нет», а не «значение неверно»), поэтому сделана хирургическая подмена — новая сигнатура, возвращён только предикат: `assert ['AND rooms = :rooms'] == []`. Отдельно: тест `test_dkp_corridor_keeps_full_area_band` оставался зелёным при всех подменах, то есть не охранял ничего — усилен до «полоса единственная». **Прогоны:** `5747 passed, 35 skipped` (rc=0); ruff чисто. ## Критерии приёмки issue — честно не выполнены «Ни один бакет хуже 8 %» и «MAPE не хуже 14.28» по оси `per_area_bucket` достижимы только оракульным подбором под ту же выборку (in-sample до нулевого смещения даёт 13.38, любая принципиальная деривация 14.13-14.56) — ловушка #2255. Пока нет источника настоящей комнатности сделок, калибровка по этой оси калибрует по пулу, которого у клиента нет.
bot-backend added 1 commit 2026-09-11 20:11:42 +00:00
fix(estimator): ключевать сделки Росреестра area-бакетом, а не комнатностью клиента
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 11s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m10s
a780e3e66e
`deals.rooms` — не комнатность, а синтетика из площади: import-rosreestr.sh пишет
тот же CASE 30/44/62/85, что `asking_to_sold_ratio.area_bucket`. Прод-замер
2026-09-11: 321 559 из 321 560 сделок удовлетворяют rooms == area_bucket(area_m2),
max(rooms) = 4. Значит предикат `deals.rooms = <РЕАЛЬНЫЕ комнаты клиента>` — это
переодетый фильтр по площади, который противоречит area-полосе ±15% рядом с ним,
как только комнатность клиента нетипична для метража, и НИКОГДА не совпадает у
клиентов с 5+ комнатами.

Замер по 1177 реальным запросам (trade_in_estimates): ключ расходился с
area-бакетом у 359 (30.5%); коридор ДКП пуст у 46.2% из них против 8.2% у
совпадающих. По крупному жилью (≥85 м²): «3 комнаты» — 83.5% пустых коридоров,
«5 комнат» и «6 комнат» — 100%, «4 комнаты» — 5%. Т.е. блок «реальные сделки»
и клампы коридора (cap headline + radius-floor) молча выключались ровно у
крупных лотов.

Прогон тех же 1177 запросов через `_fetch_dkp_corridor` с обоими ключами:
непустых коридоров 809 → 895, пригодных для клампа (n≥10) 567 → 623 (+66, −10),
у 818 клиентов с совпадающей комнатностью выборка не меняется вовсе. Из 66
восстановленных коридоров 7 (5 из них ≥85 м²) обрезали бы headline вниз на
медианных −10.1% — то есть сейчас часть крупных лотов оценивается выше, чем
поддерживают реальные ДКП на той же улице.

Правка — одно и то же во всех четырёх местах, где сделки фильтруются под
клиента: `_fetch_dkp_corridor` (street + city-wide widen), `_fetch_deals`
(радиус) и витрина `/street-deals`.

Бэктест этим НЕ измеряется и в докстринг харнеса добавлена причина (каверза (e)):
у всех 5500 сделок обеих прод-фикстур rooms == area_bucket, т.е. харнес кормит
спайн синтетическим ключом и поэтому по построению не видит расхождения, которое
в проде есть у 30.5% запросов.

Refs #3256
Light1YT added 2 commits 2026-09-11 21:39:40 +00:00
Разворот предыдущего коммита ветки (a780e3e6) на корень: вместо подстановки
`area_bucket(area)` в предикат `d.rooms = ...` предикат УДАЛЁН во всех трёх местах.

ПОЧЕМУ НЕ БАКЕТ. `deals.rooms` — синтетика из площади (321 559 из 321 560 сделок
удовлетворяют `rooms == area_bucket(area_m2)`, max(rooms)=4), значит `d.rooms = X`
тождественно `d.area_m2 ∈ [граница_X, граница_X+1)`. Это ВТОРОЙ, ступенчатый фильтр
по площади поверх полосы `area_m2 BETWEEN :area_min AND :area_max`, стоящей строкой
ниже. Прод-замер по 1179 реальным запросам (trade_in_estimates, 2026-09-12) — какая
доля полосы ±15% переживает предикат:

  d.rooms = комнаты клиента   медиана 77.8%, у 180 запросов полоса вырезана ЦЕЛИКОМ
                              (пересечение пусто ⇒ коридора нет никогда)
  d.rooms = area_bucket(area) медиана 90.0%, пустых нет, НО у 902 из 1179 полоса
                              всё ещё усечена: 44.0 м² → сохраняется 50% полосы,
                              62.0 м² → 50%, 82.6 м² → 59.7%. Величину усечения
                              задаёт не модель, а случайное положение метража
                              относительно границ 30/44/62/85.
  без предиката               100% по построению

Т.е. бакет-ключ чинит катастрофический случай (пустое пересечение) и оставляет
произвольное усечение у 76.5% запросов. Полоса ±15% уже выражает «похожие по
площади сделки» — второго фильтра по тому же признаку быть не должно.

ЗАМЕР ЭФФЕКТА НА ЦЕНУ (1179 запросов, все три пути влияния коридора на headline:
cap/floor, sufficiency-гейт #oblast-E, deals-headline-fallback; листинговая сторона
берётся из сохранённой оценки, коридор пересчитан на сегодняшнем снимке deals для
всех вариантов, поэтому сравнение apples-to-apples; реплика сверена с ПРОДОВЫМ SQL
на 58 оценках × 3 варианта — 174/174 совпадений):

  коридор доступен   n>=3: 769 → 850 (бакет, +86/−5) → 874 (без ключа, +105/−0)
                    n>=10: 567 → 623 (бакет, +66/−10) → 691 (без ключа, +126/−2)

  сдвиг headline vs текущий прод   бакет            без ключа
    клиентов сдвинулось            28               120
    медиана сдвига                 +1.0%            −1.6%
    p10 / p90                      −30.6% / +6.1%   −8.6% / +4.3%
    сдвиг > ±10%                   10 (все вниз)    10 (7 вниз, 3 вверх)
    сдвиг > ±25%                   4                2

  по путям (медиана сдвига):       бакет            без ключа
    cap/floor, радиусная медиана   +3.9% (p10 −36.3%)   −1.7% (p10 −5.9%)
    cap/floor, якорь Tier C        −10.1% (5 сдвигов, 4 из них >10% вниз)  −0.8%
    sufficiency-гейт               −0.4%            +0.3%
    deals-fallback                 +3.5% (p10 −20.8%)   −0.1%
    якорь Tier A                   0 (коридор не влияет: cap exempt, floor требует
                                      anchor_tier is None)

Вариант без ключа даёт больше покрытия (+105/−0 против +86/−5), сдвиг с медианой
около нуля и БЕЗ кластера сильных падений, тогда как бакет-ключ несёт кластер
Tier C с медианой −10.1%. Худший случай (−41.8%, Малышева 84, 1к/54 м²: премиальный
лот прижимается cap'ом к коридору улицы) ОБЩИЙ для обоих вариантов — он появляется
от самого факта наличия коридора, а не от выбора ключа.

УТОЧНЕНИЕ ФАКТА ИЗ a780e3e6: «у 818 клиентов выборка не меняется» — неверно, их
793. Скрипт классифицировал через `min(max(rooms,0),4) == area_bucket`, из-за чего
27 клиентов с 5-6 комнатами попали в «совпадающие», хотя у них выборка меняется с
пустой на непустую. (Практического прироста они всё равно не получают: их метраж
158-456 м² в основном вне окна импорта `area BETWEEN 18 AND 200`.)

ЯКОРЬ ПРОТИВ МОЛЧАЛИВОГО ВОЗВРАТА. Ни один тест не краснел, если импортёр начнёт
писать настоящую комнатность. tests/test_3256_deals_rooms_key.py теперь ПАРСИТ CASE
из deploy/import-rosreestr.sh и сверяет его границы с `area_bucket()` (поточечно, на
границах и между ними); у самого CASE стоит комментарий-якорь «поменяешь на реальную
комнатность — вернись в #3256».

Каверза (e) харнеса: формулировка «бакеты 0-2 чисты» УБРАНА как неверная. Замер по
тому же пулу, который видит `_fetch_analogs` (свежесть 14 дней, вторичка, регион 66):
совпадение rooms == area_bucket — бакет 0: 69.8%, 1: 63.5%, 2: 60.1%, 3: 54.6%,
4: 30.9%. В бакетах 0-3 модальная комнатность совпадает с бакетом, в бакете 4 — нет
(мода 3, 54.5% пула). Добавлена перекрёстная ссылка: каверзы (d) и (e) СКЛАДЫВАЮТСЯ
(неправильное МЕСТО + неправильный СЕГМЕНТ), а не спорят.

Логи витрины `/street-deals` называли `rooms=%d` комнатностью клиента, хотя фильтра
по ней в запросе уже нет — теперь печатают фактический ключ (полосу площади), а
комнатность помечена как контекст запроса.

НЕ входит в этот PR (заводится отдельно): TVF `street_sales_vs_listings`
(data/sql/211_*.sql:89,113) — там асимметричный ключ (`d.rooms` синтетика,
`l.rooms` настоящая), копипастой не чинится; каверза (e) для
app/tasks/landing_showcase_deals.py:415/426.

Refs #3256
test(estimator): полоса площади — единственный фильтр похожести, а не просто «есть»
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m6s
6df6f92a2b
`test_dkp_corridor_keeps_full_area_band` проверял только присутствие полосы ±15% в
bind-параметрах — она есть и на origin/main, и на варианте с бакет-ключом, поэтому
тест был зелёным по построению и ничего не охранял (мутационная проверка: при
восстановлении предиката он оставался зелёным, пока остальные 4 краснели).

Утверждение усилено до «полоса единственная»: тест дополнительно требует отсутствия
предиката по rooms рядом с ней. На origin/main фильтров по площади ДВА (полоса и
бакет через d.rooms), итоговое окно — их пересечение, поэтому теперь тест краснеет
значением вместе с остальными.

Refs #3256
bot-backend changed title from fix(mera/estimate): коридор ДКП ключуется по площади, а не по синтетическим комнатам — +66 пригодных коридоров на 1177 реальных запросов (#3256) to fix(mera/estimate): убран предикат d.rooms в коридоре ДКП — он был вторым фильтром по площади (#3256) 2026-09-11 21:42:45 +00:00
Light1YT added 1 commit 2026-09-11 21:53:08 +00:00
docs(#3256): докстринг коридора без «та же rooms»; якорь называет оставшегося потребителя (TVF 211)
All checks were successful
CI / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m7s
CI Trade-In / changes (pull_request) Successful in 8s
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
86cba37218
bot-backend merged commit c4315b3dfb into main 2026-09-11 21:59:19 +00:00
Sign in to join this conversation.
No reviewers
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#3445
No description provided.