fix(sf-21): mv_layout_velocity weighted AVG (P0 data corruption) #290
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#290
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/sf-21-mv-weighted-avg"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
🔴 P0 — CRITICAL data corruption
mv_layout_velocityиспользует unweightedAVG()наobjective_corpus_room_month.deals_total_avg_area_m2/price. Источник имеет per-month rows включая месяцы с 0 сделок (count=0, area=0, price=0) — нули тянут среднее в 2-14× вниз.Все UI значения площади и цены в Top layouts + Recommendation TZ ИСКАЖЕНЫ (например studio = 11.5 м² когда реально 28 м², 3-к = 21.8 м² когда реально 81.7 м²).
Полный context: vault
fixes/Bug_MvLayoutVelocity_UnweightedAvg_May17.md.Verified bug examples (prod DB pre-migration)
Fix
data/sql/100_fix_mv_layout_velocity_weighted_avg.sql— DROP + CREATE MV с:Plus UNIQUE INDEX
(obj_id, room_bucket)для futureREFRESH CONCURRENTLY.Dependency check: нет дочерних views/MV. DROP без CASCADE issues.
Deploy: auto-applied через
_schema_migrationsmechanism. REFRESH включён в migration — manual step не нужен.⚠️ Phase 2 follow-up (НЕ в этом PR)
backend/app/services/site_finder/best_layouts.py:121-122(_INLINE_VELOCITY_SQL) использует тот же broken pattern напрямую наobjective_corpus_room_month— тот же bug, тот же source table. Будет fix отдельным PR. Без него inline-path всё равно покажет broken numbers.Verify after deploy
UI:
https://gendsgn.ru/site-finder?cad=66:41:0204016:10→ "Рассчитать" в BestLayouts → studio ~28 м² (не 12), 3-к ~81 м² (не 22).Related: NEW P0 item #21 в epic #271 (вне Wave 1-3 списка, вставлен в начало по severity)
Deep Code Review — verdict ✅ APPROVE (P0 critical fix)
Severity: P0 — data corruption fix, мержим.
Math correctness ✅
SUM(avg_x * count) / NULLIF(SUM(count), 0)математически эквивалентноSUM(total_x) / SUM(count)(т.к. per-monthavg_x = total_x / count, произведение восстанавливаетtotal_x). Месяцы сcount=0дают0в numerator и0в denominator sum — корректно не contributes. Edge case (все месяцы пустые) → NULL черезNULLIF. Verified.SQL structure ✅
BEGIN; ... COMMIT;обёртка — соответствуетsql.mdDROP MV IF EXISTS ... CASCADE— idempotent, безопасно (нет зависимых VIEW/MV — confirmed)WITH NO DATA→CREATE UNIQUE INDEX→REFRESH MATERIALIZED VIEW(non-concurrent) — правильный порядок для initial populateUNIQUE (obj_id, room_bucket)+(obj_id)индексы — schema идентична94_mv_layout_velocity.sql, downstream consumers (admin_etl.py,parcels.py,layout_velocity_refresh.py,test_phantom_columns.py) не сломаютсяCross-file impact ✅
avg_area_m2,avg_price_thousand_rub_per_m2), которые сохранены_schema_migrationstracks by full filename → DROP+CREATE применится один разREFRESH CONCURRENTLYвlayout_velocity_refresh.pyбудет работать (UNIQUE index сохранён)best_layouts.py:121-122_INLINE_VELOCITY_SQL) — отдельный PR #291, корректно вынесено за scope🟡 MINOR: migration numbering conflict
100_fix_mv_layout_velocity_weighted_avg.sqlколлизит по prefix с уже applied100_user_weight_profiles_default_seed.sql. Deploy НЕ упадёт —_schema_migrationstracks по full filename, не по NN-prefix;sortпоставит100_fix_*перед100_user_*(lex: 'f' < 'u'), оба применятся. Ноsql.mdправило:NN — следующий sequential номер(ls data/sql/ | sort | tail -5→ следовало бы106_*).Не блокирующее: deploy безопасен. Rename можно отдельным cleanup PR (или оставить — historical context).
Post-deploy verify (обязательно)
UI:
https://gendsgn.ru/site-finder?cad=66:41:0204016:10→ BestLayouts → studio ~28 м² (не 12), 3-к ~81 м² (не 22).Followup: PR #291 (inline
_INLINE_VELOCITY_SQLfix) — merge сразу после этого, иначе inline-path всё ещё будет broken.Мержу.