[Fable 5][P2] Artificial Demand (§25.5) фильтрует objective_lots по админ-району без resolve_objective_districts — индекс молча пуст для 7 из 8 районов #1205

Closed
opened 2026-06-13 04:49:43 +00:00 by bot-backend · 0 comments
Collaborator

Из армейского ревью Claude Fable 5 (2026-06-11)

Confirmed by 2/2 адверсариальных верификатора, severity P2 (correctness), confidence 0.82.

Файл

backend/app/services/forecasting/special_indices.py:821

Evidence (цитата кода)

AND (
     CAST(:district AS text) IS NULL
     OR ol.district = CAST(:district AS text)
    )

Why bug

objective_lots.district хранит микро-районы («Уралмаш», «ЖБИ»…), а §22-путь (workers/tasks/forecast.py → orchestrator) передаёт АДМИН-имя из ekb_districts («Кировский»…). Все остальные потребители objective_lots (sales_series, market_metrics, supply_layers, future_supply) разворачивают имя через resolve_objective_districts — этот единственный SQL матчит напрямую → 0 строк → n_sold=0 → индекс 'unavailable' с ложной причиной «нет проданных лотов» в каждом district-scoped отчёте (баг-класс, под который создан резолвер, ground-truthed на prod).

Suggested fix

В _query_artificial_demand развернуть district через resolve_objective_districts(db, district) и фильтровать ol.district = ANY(CAST(:districts AS text[])) с флагом has_district — зеркально _SOURCE_B_SQL в sales_series.py.

Verify notes

  • [real/P2] Трасса: forecast.py:123 берёт админ-имя из /analyze → orchestrator.py:331 → compute_special_indices:1656 → _query_artificial_demand → ol.district='Кировский' = 0 строк (objective_lots хранит 35 микро-имён; ground-truth: 131_district_vocab_map.sql «market_metrics('Кировский') → obj_count=0») → n_sold=0 → индекс 'unavailable' с ложной причиной «нет проданных лотов». resolve_objective_districts в файле не импортирован; все прочие потребители objective_lots резолвят. Advisory-индекс, не crash → P2.
  • [real/P2] forecast.py:123 берёт АДМИН-имя из ekb_districts; orchestrator.py:331 передаёт raw (контракт: «§9.x резолвят админ-имя → микро»); _query_artificial_demand матчит ol.district напрямую — единственный потребитель objective_lots без resolve_objective_districts. Админ-имя → 0 строк → n_sold=0 → unavailable с ложной причиной для 7/8 районов. P2, не P1: индекс advisory, деградация честная (None, не фабрикация чисел).

Provenance

  • Finders: forecasting
  • Confidence: 0.82
  • Originally batched at: main@d796027
## Из армейского ревью Claude Fable 5 (2026-06-11) Confirmed by 2/2 адверсариальных верификатора, severity **P2** (correctness), confidence 0.82. ## Файл [`backend/app/services/forecasting/special_indices.py:821`](backend/app/services/forecasting/special_indices.py:821) ## Evidence (цитата кода) ``` AND ( CAST(:district AS text) IS NULL OR ol.district = CAST(:district AS text) ) ``` ## Why bug objective_lots.district хранит микро-районы («Уралмаш», «ЖБИ»…), а §22-путь (workers/tasks/forecast.py → orchestrator) передаёт АДМИН-имя из ekb_districts («Кировский»…). Все остальные потребители objective_lots (sales_series, market_metrics, supply_layers, future_supply) разворачивают имя через resolve_objective_districts — этот единственный SQL матчит напрямую → 0 строк → n_sold=0 → индекс 'unavailable' с ложной причиной «нет проданных лотов» в каждом district-scoped отчёте (баг-класс, под который создан резолвер, ground-truthed на prod). ## Suggested fix В _query_artificial_demand развернуть district через resolve_objective_districts(db, district) и фильтровать ol.district = ANY(CAST(:districts AS text[])) с флагом has_district — зеркально _SOURCE_B_SQL в sales_series.py. ## Verify notes - [real/P2] Трасса: forecast.py:123 берёт админ-имя из /analyze → orchestrator.py:331 → compute_special_indices:1656 → _query_artificial_demand → ol.district='Кировский' = 0 строк (objective_lots хранит 35 микро-имён; ground-truth: 131_district_vocab_map.sql «market_metrics('Кировский') → obj_count=0») → n_sold=0 → индекс 'unavailable' с ложной причиной «нет проданных лотов». resolve_objective_districts в файле не импортирован; все прочие потребители objective_lots резолвят. Advisory-индекс, не crash → P2. - [real/P2] forecast.py:123 берёт АДМИН-имя из ekb_districts; orchestrator.py:331 передаёт raw (контракт: «§9.x резолвят админ-имя → микро»); _query_artificial_demand матчит ol.district напрямую — единственный потребитель objective_lots без resolve_objective_districts. Админ-имя → 0 строк → n_sold=0 → unavailable с ложной причиной для 7/8 районов. P2, не P1: индекс advisory, деградация честная (None, не фабрикация чисел). ## Provenance - Finders: `forecasting` - Confidence: 0.82 - Originally batched at: main@d796027
bot-backend added the
Fable 5 ревью
label 2026-06-13 04:49:43 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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#1205
No description provided.