(medium) recommend_mix: success-boost меняет share_pct, но не пересчитывает units/revenue/velocity → внутренне противоречивый ответ #1359

Closed
opened 2026-06-14 18:09:07 +00:00 by bot-backend · 1 comment
Collaborator

Описание

units_planned, revenue_planned_rub, velocity_per_month, months_to_sellout, total_units, liquidity_24mo и months_to_sellout_total вычисляются раньше (строки 2425-2428, 2675-2718, 2772-2797) из ИСХОДНОЙ доли бакета. Блок #25 (success boost) затем переписывает share_pct каждого бакета (топ +10%, остальные rescale), но НЕ пересчитывает units/revenue/velocity под новые доли. В ответе API share_pct больше не соответствует units/revenue/sellout, выведенным из неподнятых долей — «рекомендуемый микс» в UI внутренне противоречив (share говорит 40%, а units_planned отражает старые 30%).

Корень

Мутация только share_pctis_top_success) после того, как все производные величины уже аллоцированы; срабатывает при непустом success_ranking с записью success_score>0 и n_deals>=30.

Evidence

analytics_queries.py:2719-2740:

boost = top_b["share_pct"] * 0.10
top_b["share_pct"] = round(top_b["share_pct"] + boost, 1)
scale = (100.0 - top_b["share_pct"]) / other_sum
for b in buckets:
    if b["bucket"] != top_bucket_name:
        b["share_pct"] = round(b["share_pct"] * scale, 1)
# units_planned/revenue/velocity НЕ пересчитываются

Suggested fix

Применять success-boost к долям ДО аллокации units/revenue/velocity (переместить блок выше allocation-loop шага 5), либо после boost заново прогнать аллокацию units/revenue/months_to_sellout по новым share_pct, чтобы все производные оставались согласованными с заявленным миксом.

Обоснование severity

medium: видимая пользователю расчётная несогласованность ответа, но не persistent-порча и не security. confidence 0.92.


week ревью 1 · multi-agent аудит 2026-06-14 · severity=medium · category=data-integrity

Затронутые файлы:

  • /Users/anton/Птица/gendesign/backend/app/services/analytics_queries.py
## Описание `units_planned`, `revenue_planned_rub`, `velocity_per_month`, `months_to_sellout`, `total_units`, `liquidity_24mo` и `months_to_sellout_total` вычисляются раньше (строки 2425-2428, 2675-2718, 2772-2797) из ИСХОДНОЙ доли бакета. Блок #25 (success boost) затем переписывает `share_pct` каждого бакета (топ +10%, остальные rescale), но НЕ пересчитывает units/revenue/velocity под новые доли. В ответе API `share_pct` больше не соответствует units/revenue/sellout, выведенным из неподнятых долей — «рекомендуемый микс» в UI внутренне противоречив (share говорит 40%, а units_planned отражает старые 30%). ## Корень Мутация только `share_pct` (и `is_top_success`) после того, как все производные величины уже аллоцированы; срабатывает при непустом `success_ranking` с записью `success_score>0` и `n_deals>=30`. ## Evidence `analytics_queries.py:2719-2740`: ```python boost = top_b["share_pct"] * 0.10 top_b["share_pct"] = round(top_b["share_pct"] + boost, 1) scale = (100.0 - top_b["share_pct"]) / other_sum for b in buckets: if b["bucket"] != top_bucket_name: b["share_pct"] = round(b["share_pct"] * scale, 1) # units_planned/revenue/velocity НЕ пересчитываются ``` ## Suggested fix Применять success-boost к долям ДО аллокации units/revenue/velocity (переместить блок выше allocation-loop шага 5), либо после boost заново прогнать аллокацию units/revenue/months_to_sellout по новым `share_pct`, чтобы все производные оставались согласованными с заявленным миксом. ## Обоснование severity medium: видимая пользователю расчётная несогласованность ответа, но не persistent-порча и не security. confidence 0.92. --- _week ревью 1 · multi-agent аудит 2026-06-14 · severity=**medium** · category=`data-integrity`_ Затронутые файлы: - `/Users/anton/Птица/gendesign/backend/app/services/analytics_queries.py`
bot-backend added the
week ревью 1
label 2026-06-14 18:09:07 +00:00
bot-backend added the
scope/backend
label 2026-06-15 11:01:52 +00:00
Owner

🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)

Текущее состояние кода: backend/app/services/analytics_queries.py:2665-2686 (блок «#25 Success-driven mix») в recommend_mix.

Корень: блок при непустом success_ranking с записью success_score > 0 AND n_deals >= 30 (:2667-2671) переписывает share_pct top-бакета (+10%, :2677-2678) и rescale остальных (:2683-2686) + ставит is_top_success. Но units_planned / revenue_planned_rub / velocity_per_month / months_to_sellout уже аллоцированы выше из ИСХОДНЫХ долей (allocation-loop до :2645), и блок их НЕ пересчитывает. Хуже — производные агрегаты считаются ПОСЛЕ мутации, но из старых per-bucket величин: liquidity_24mo (:2718-2729) и months_to_sellout_total (:2734-2743) читают units_planned/velocity_per_month от неподнятых долей. Итог: в ответе API share_pct не соответствует units/revenue/sellout → «рекомендуемый микс» внутренне противоречив.

Что править:

  • Применять success-boost к share_pct ДО allocation-loop (переместить блок :2665-2686 выше шага аллокации units/revenue/velocity), ЛИБО
  • после boost заново прогнать аллокацию units_planned/revenue/months_to_sellout/velocity по новым share_pct, и только затем считать liquidity_24mo / months_to_sellout_total / avg_ticket.

Что посмотреть:

  • Код: analytics_queries.py:2602-2686 (success_ranking + boost), allocation-loop выше (~2620-2664), агрегаты :2695-2746. _bucket_success_ranking (:2158). Тест: district/class с top-success бакетом (n_deals>=30) → проверить, что sum(units_planned) и revenue согласованы с поднятым share_pct.
  • Vault: релевантных заметок не найдено.
**🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)** **Текущее состояние кода:** `backend/app/services/analytics_queries.py:2665-2686` (блок «#25 Success-driven mix») в `recommend_mix`. **Корень:** блок при непустом `success_ranking` с записью `success_score > 0 AND n_deals >= 30` (`:2667-2671`) переписывает `share_pct` top-бакета (+10%, `:2677-2678`) и rescale остальных (`:2683-2686`) + ставит `is_top_success`. Но `units_planned` / `revenue_planned_rub` / `velocity_per_month` / `months_to_sellout` уже аллоцированы выше из ИСХОДНЫХ долей (allocation-loop до `:2645`), и блок их НЕ пересчитывает. Хуже — производные агрегаты считаются ПОСЛЕ мутации, но из старых per-bucket величин: `liquidity_24mo` (`:2718-2729`) и `months_to_sellout_total` (`:2734-2743`) читают `units_planned`/`velocity_per_month` от неподнятых долей. Итог: в ответе API `share_pct` не соответствует units/revenue/sellout → «рекомендуемый микс» внутренне противоречив. **Что править:** - Применять success-boost к `share_pct` ДО allocation-loop (переместить блок `:2665-2686` выше шага аллокации units/revenue/velocity), ЛИБО - после boost заново прогнать аллокацию `units_planned`/`revenue`/`months_to_sellout`/`velocity` по новым `share_pct`, и только затем считать `liquidity_24mo` / `months_to_sellout_total` / `avg_ticket`. **Что посмотреть:** - Код: `analytics_queries.py:2602-2686` (success_ranking + boost), allocation-loop выше (`~2620-2664`), агрегаты `:2695-2746`. `_bucket_success_ranking` (`:2158`). Тест: district/class с top-success бакетом (`n_deals>=30`) → проверить, что `sum(units_planned)` и `revenue` согласованы с поднятым `share_pct`. - Vault: релевантных заметок не найдено.
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#1359
No description provided.