Code-review #1927 found 2 MAJOR bugs in the initial fix:
1. JOIN fan-out: objective_complex_mapping UNIQUE is (objective_complex_name,
objective_group), NOT domrf_obj_id (68_schema:321) — one obj_id can map to
multiple rows (same name, different group), so COUNT(*) over cm JOIN ol
double-counts lots (GROUP BY collapses output rows but not dups inside the
aggregate). Fixed with COUNT(DISTINCT ol.objective_lot_id).
2. Missing premise_kind: MarketMetrics._STOCK_SQL filters premise_kind='квартира';
the new SQL did not, so sold parking/storage/non-residential lots counted as
sold flats (over-count). Added AND ol.premise_kind = :premise_kind.
3. Aligned the sold predicate to MarketMetrics exactly:
is_sold IS TRUE OR contract_date IS NOT NULL OR LOWER(status)='продан'
(Objective populates these inconsistently — OR mirrors _STOCK_SQL:285-289),
not contract_date alone.
Tests: added static SQL-structure guards (fan-out-safe COUNT(DISTINCT),
premise_kind filter, full predicate) since mock-based API tests bypass real SQL
and cannot detect fan-out; the live-DB fan-out/EXPLAIN check lives in
test_phantom_columns (skipped without TEST_DATABASE_URL). Updated phantom EXPLAIN
to the new SQL.
Full suite: 3530 passed, 51 skipped, 0 failed. Ruff clean.
Audit #1871/#1926: competitor block computed flats_sold from
domrf_kn_flats.status (LIKE '%прод%'/'sold'), populated in only ~0.2% of
rows (99.8% NULL) -> massive undercount (~1600 units in reported case) and
divergence from MarketMetrics, which counts sold via objective_lots.contract_date
(100% populated for sold lots).
Fix: new _SOLD_COUNT_SQL counts sold lots from objective_lots.contract_date
IS NOT NULL, bridged domrf obj_id -> objective_complex_mapping.domrf_obj_id ->
objective_complex_mapping.objective_complex_name == objective_lots.project_name
(same 1:1 mapping pattern as _OBJECTIVE_PRICE_FALLBACK_SQL primary_price CTE).
This is the exact source MarketMetrics._STOCK_SQL uses, so the two paths agree.
Dropped the domrf_kn_flats.status count from _AVG_PRICE_SQL (price-only now).
No schema/Pydantic field change (flats_sold/sold_pct already existed) ->
codegen not needed. psycopg v3 CAST style preserved.
Tests: updated mock DB ordering (+ sold-count execute), added
test_competitors_flats_sold_from_contract_date (120/200 -> 60% sold) and
phantom-column EXPLAIN check for _SOLD_COUNT_SQL.