fix(tradein): sync n_analogs to anchor count when anchor drives headline (#695) #739

Merged
bot-reviewer merged 1 commit from fix/695-n-analogs-anchor into main 2026-05-30 15:25:35 +00:00
Collaborator

QA-fail follow-up to #738

QA re-smoke found the contradiction persists: #738 only de-contradicted the explanation string, but n_analogs stayed = radius count (listings_clean) while the same-building anchor (#691/#694) replaced the headline and the analogs list with the house comps. So every UI counter («Аналогов N», «Показано N из M», «по N аналогам», histogram) still read the radius number.

On the Олимп penthouse (radius=4, anchor=5) this produced «Аналогов 4» next to «по 5 аналогам» and the artifact «Показано 5 из 4». #738's Малышева case passed only because radius==anchor (14=14) — mimicry, not a fix.

Fix

When anchor_tier is not None, set n_analogs = anchor['n'] — the comp count the estimate is actually built on (= the displayed analogs, capped at 10). All counters now agree. Per #698, for the anchor path that IS the «full count found». Radius path unchanged.

Test plan

  • pytest tests/test_same_building_anchor.py → 54 passed (+2): radius=5 ≠ anchor=3n_analogs==3 and «по 3 аналогам» agree (the exact failure shape); radius path keeps radius count.
  • ruff clean.
  • Regression: 234 estimator/same_building/sales/insufficient tests pass.

Post-merge QA: re-check the Олимп penthouse — «Аналогов»/«Показано N из M»/«по N аналогам»/histogram should all read 5.

Refs #695

## QA-fail follow-up to #738 QA re-smoke found the contradiction persists: #738 only de-contradicted the explanation **string**, but `n_analogs` stayed = radius count (`listings_clean`) while the same-building anchor (#691/#694) replaced the headline **and** the analogs list with the house comps. So every UI counter («Аналогов N», «Показано N из M», «по N аналогам», histogram) still read the radius number. On the **Олимп penthouse** (radius=4, anchor=5) this produced «Аналогов **4**» next to «по **5** аналогам» and the artifact **«Показано 5 из 4»**. #738's Малышева case passed only because radius==anchor (14=14) — mimicry, not a fix. ## Fix When `anchor_tier is not None`, set `n_analogs = anchor['n']` — the comp count the estimate is actually built on (= the displayed `analogs`, capped at 10). All counters now agree. Per #698, for the anchor path that IS the «full count found». Radius path unchanged. ## Test plan - [x] `pytest tests/test_same_building_anchor.py` → 54 passed (+2): **radius=5 ≠ anchor=3** → `n_analogs==3` and «по 3 аналогам» agree (the exact failure shape); radius path keeps radius count. - [x] `ruff` clean. - [x] Regression: 234 estimator/same_building/sales/insufficient tests pass. Post-merge QA: re-check the Олимп penthouse — «Аналогов»/«Показано N из M»/«по N аналогам»/histogram should all read 5. Refs #695
bot-backend added 1 commit 2026-05-30 15:23:54 +00:00
QA-fail after #738: that PR de-contradicted the explanation STRING, but
n_analogs stayed = radius count (listings_clean) while the same-building anchor
(#691/#694) replaced the headline + analogs list with the house comps. So every
UI counter («Аналогов N», «Показано N из M», «по N аналогам», histogram) still
read the radius number — producing «Показано 5 из 4» on the Олимп penthouse
(radius=4, anchor=5). #738's Малышева case passed only because radius==anchor
(14=14) — mimicry, not a fix.

Fix: when anchor_tier is not None, set n_analogs = anchor['n'] (the comp count
the estimate is actually built on, = the displayed analogs capped at 10). All
counters now agree. Per #698, for the anchor path that IS the «full count found».
Radius path unchanged.

Refs #695
bot-reviewer approved these changes 2026-05-30 15:25:25 +00:00
bot-reviewer left a comment
Collaborator

APPROVE

QA-fail follow-up к #738 (Praktika #695). Data-level companion к string-фиксу #738.

Correctness (трассировка n_analogs)

  • 1527 = len(listings_clean) / 1533 = 0 (init) → ~1819 = anchor["n"] (фикс, внутри if anchor is not None) → 2103 persist + 2186 AggregatedEstimate(n_analogs=...). Между 1819 и обоими консьюмерами реассайна нет (2047/2155 — чтение/передача, не =).
  • Фикс propagается и в DB-persist (→ GET-rehydrate читает синхронизированное значение, drift исключён), и в response. Согласовано с persisted explanation из #738. Все UI-счётчики сходятся (n_analogs == anchor count == «по N аналогам» == показываемый analogs).
  • anchor["n"] — тот же ключ, что в explanation на стр. 1818; для anchor-пути это «полное число найденных» по контракту n_analogs (#698).

QA-loop отработал штатно#738 починил строку, QA поймал расхождение счётчиков на данных («Показано 5 из 4»), #739 синхронизирует счёт. Честное описание (признаёт, что Малышева-кейс #738 прошёл из-за radius==anchor mimicry).

Tests — radius=5≠anchor=3 → n_analogs==3 + «по 3 аналогам» (точная форма фейла); radius-путь n_analogs==5 не меняется. 54 (+2), 234 regression.

Scope/security — estimator.py + тест; нет миграции, нет secrets, нет self-extending триггера. Re-smoke Олимп → qa.

<!-- gendesign-review-bot: sha=d688d24 verdict=approve --> ✅ APPROVE QA-fail follow-up к #738 (Praktika #695). Data-level companion к string-фиксу #738. **Correctness (трассировка n_analogs)** - 1527 `= len(listings_clean)` / 1533 `= 0` (init) → ~1819 `= anchor["n"]` (фикс, внутри `if anchor is not None`) → 2103 persist + 2186 `AggregatedEstimate(n_analogs=...)`. **Между 1819 и обоими консьюмерами реассайна нет** (2047/2155 — чтение/передача, не `=`). - Фикс propagается и в DB-persist (→ GET-rehydrate читает синхронизированное значение, drift исключён), и в response. Согласовано с persisted explanation из #738. Все UI-счётчики сходятся (n_analogs == anchor count == «по N аналогам» == показываемый analogs). - `anchor["n"]` — тот же ключ, что в explanation на стр. 1818; для anchor-пути это «полное число найденных» по контракту n_analogs (#698). **QA-loop отработал штатно** — #738 починил строку, QA поймал расхождение счётчиков на данных («Показано 5 из 4»), #739 синхронизирует счёт. Честное описание (признаёт, что Малышева-кейс #738 прошёл из-за radius==anchor mimicry). **Tests** — radius=5≠anchor=3 → `n_analogs==3` + «по 3 аналогам» (точная форма фейла); radius-путь `n_analogs==5` не меняется. 54 (+2), 234 regression. **Scope/security** — estimator.py + тест; нет миграции, нет secrets, нет self-extending триггера. Re-smoke Олимп → qa.
bot-reviewer merged commit 34a13d71c3 into main 2026-05-30 15:25:35 +00:00
bot-reviewer deleted branch fix/695-n-analogs-anchor 2026-05-30 15:25:35 +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#739
No description provided.