feat(freshness): zero-output check + kn_flats source — catch "ran but produced nothing" (#1945) #1947

Merged
lekss361 merged 1 commit from feat/freshness-zero-output-check into main 2026-06-27 07:02:51 +00:00
Collaborator

Зачем

Превентивно к #1945: domrf_kn FLATS loader работал status=done, но извлекал 0 flats ~5 недель — и монитор не алёртил, потому что (а) классифицировал по recency прогона, не по выхлопу, и (б) kn-источник смотрел objects_count (здоров ~1548), а не flats_count (сломан =0). «Прогнался успешно, но ничего не произвёл» проскакивал тихо.

Что

Opt-in zero-output check: otherwise-fresh run-ledger источник (свежий success по возрасту), который произвёл 0 work-rows за 7d-окно, понижается до status="failed"scrape_freshness_check шлёт GlitchTip-алёрт. Аддитивное поле reason.

Гарды (все 4): alert_on_zero_output флаг · run-ledger only (timestamp_col is None) · status=="ok" (age-stale/failed уже покрыт возрастом, не дублируем) · upd_7d==0 (SUM собственного work_col источника по done-прогонам).

Реестр: новый kn_flats (kn_scrape_runs, work_col=flats_count, critical, флаг ON) — смотрит ИМЕННО сломанную колонку; существующий kn (objects_count) не тронут. Флаг также на objective (rows_lots, critical). nspd/nspd_geo/cadastre — без флага (легитимные 0 / data-table).

Безопасность

  • JSON аддитивно: новый nullable reason + поле alert_on_zero_output (default False). Эндпоинт dict[str,Any] (permissive), фронт его не консьюмит типизированно → codegen не нужен. Существующие ключи/shape целы.
  • Гард status=="ok" + last_success is Nonefailed раньше → no-successful-runs не проскочит как ложный ok.
  • 4 новых теста (downgrade, no-false-positive, age-precedence, registry). ruff , 17 freshness/admin_scrape passed.
  • code-reviewer: APPROVE, 0 critical (4 гарда, work_col-агрегация kn_flats=flats_count, no-false-positive, beat-alert path, frontend-tolerance — все проверены).

Поймал бы #1945 за ~8-14 дней вместо 5 недель. Migration не нужна (чистый код).

## Зачем Превентивно к #1945: domrf_kn FLATS loader работал `status=done`, но извлекал **0 flats ~5 недель** — и монитор не алёртил, потому что (а) классифицировал по **recency прогона**, не по выхлопу, и (б) `kn`-источник смотрел `objects_count` (здоров ~1548), а не `flats_count` (сломан =0). «Прогнался успешно, но ничего не произвёл» проскакивал тихо. ## Что Opt-in **zero-output check**: otherwise-fresh run-ledger источник (свежий success по возрасту), который произвёл **0 work-rows за 7d-окно**, понижается до `status="failed"` → `scrape_freshness_check` шлёт GlitchTip-алёрт. Аддитивное поле `reason`. Гарды (все 4): `alert_on_zero_output` флаг · run-ledger only (`timestamp_col is None`) · `status=="ok"` (age-stale/failed уже покрыт возрастом, не дублируем) · `upd_7d==0` (SUM собственного `work_col` источника по done-прогонам). **Реестр:** новый `kn_flats` (kn_scrape_runs, `work_col=flats_count`, critical, флаг ON) — смотрит ИМЕННО сломанную колонку; существующий `kn` (objects_count) не тронут. Флаг также на `objective` (rows_lots, critical). nspd/nspd_geo/cadastre — без флага (легитимные 0 / data-table). ## Безопасность - **JSON аддитивно**: новый nullable `reason` + поле `alert_on_zero_output` (default False). Эндпоинт `dict[str,Any]` (permissive), фронт его не консьюмит типизированно → codegen не нужен. Существующие ключи/shape целы. - Гард `status=="ok"` + `last_success is None`→`failed` раньше → no-successful-runs не проскочит как ложный ok. - 4 новых теста (downgrade, no-false-positive, age-precedence, registry). ruff ✅, 17 freshness/admin_scrape passed. - **code-reviewer: ✅ APPROVE**, 0 critical (4 гарда, work_col-агрегация kn_flats=flats_count, no-false-positive, beat-alert path, frontend-tolerance — все проверены). Поймал бы #1945 за ~8-14 дней вместо 5 недель. Migration не нужна (чистый код).
bot-backend added 1 commit 2026-06-27 06:52:57 +00:00
feat(freshness): zero-output check + kn_flats source (#1945)
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m53s
CI / backend-tests (pull_request) Successful in 12m5s
bd1adc1f59
The data-freshness monitor classified by run RECENCY only, so the domrf_kn
FLATS loader running status=done but extracting 0 flats for ~5 weeks went
undetected — and the kn source watched objects_count (healthy ~1548), not
flats_count (the broken =0 metric).

Add an opt-in zero-output check: an otherwise-fresh run-ledger source (recent
success, would-be fresh by age) that produced 0 work-rows in the 7d window is
downgraded to status="failed" (so scrape_freshness_check alerts), with an
additive "reason". Guards: alert_on_zero_output flag, run-ledger only
(timestamp_col is None), status=="ok" (age-stale/failed already covered), and
upd_7d==0 (SUM of the source's own work_col over done-runs).

Registry: new kn_flats source (kn_scrape_runs, work_col=flats_count, critical,
flag on) — watches the column that was broken; existing kn (objects_count)
unchanged. Flag also enabled on objective (rows_lots, critical). nspd/nspd_geo/
cadastre left unflagged (legitimate-0 / data-table).

JSON additive only (new nullable "reason" key; endpoint is dict[str,Any], no
frontend consumer / no codegen needed). 4 new tests (downgrade, no-false-
positive, age-precedence, registry). code-reviewer APPROVE.

Would have caught #1945 within ~8-14d instead of 5 weeks.
lekss361 merged commit 9c9b50ceca into main 2026-06-27 07:02:51 +00:00
lekss361 deleted branch feat/freshness-zero-output-check 2026-06-27 07:02:51 +00:00
Sign in to join this conversation.
No reviewers
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#1947
No description provided.