fix(ptica): «0 мм осадков» перестаёт означать «данных нет» (#2464) #2947

Merged
bot-backend merged 1 commit from fix/2464-precipitation-unknown-not-zero into main 2026-08-20 07:00:04 +00:00
Collaborator

Ноль, означавший «не знаем»

weather_cache отдавал 0, когда open-meteo не прислал ряд осадков:

"precipitation_total_mm": round(sum(precip), 1) if precip else 0
"total_precip_mm":        round(sum(precip), 0) if precip else 0   # сезонные нормали

Ноль здесь — утверждение о погоде («сухо»), а пустой ряд значит, что мы не знаем. Разница доходит до пользователя: ptica-adapt заворачивал значение в real(...) безусловно, то есть подавал его как измеренную величину.

Непоследовательность внутри одного литерала

Шесть соседних агрегатов при пустых данных дают None: min_c, max_c, avg_max_c, avg_min_c, uv_index_max, max_speed_m_s. Осадки были единственным исключением.

В сезонном блоке ещё нагляднее — эти две строки идут подряд и считаются из одного списка:

"avg_precip_per_day_mm": round(sum(precip) / len(precip), 1) if precip else None,
"total_precip_mm":       round(sum(precip), 0)               if precip else 0,

Класс уже был решён в этом же файле

Раздел 7 тестов weather_cache:

«wind_d all-None → dominant_direction_deg = None, а не 0.0° (= север)»

То же рассуждение, тот же файл, только про ветер. Новые тесты зеркалят его структуру, включая заголовок раздела — чтобы следующий читатель увидел, что это одна и та же мысль, а не два разных случая.

Фронт: типы нашли потребителей сами

Сделал оба поля number | null — и tsc выдал четыре ошибки в двух файлах, плюс нашёлся сезонный блок. Ровно для этого смена типа и нужна.

Везде теперь «нет данных» вместо числа. В ptica-adapt применён образец соседней строки avg_min_c: есть значение → real(), нет → notReal().

Проверка

тест origin/main
все precipitation_sum = null красный: AssertionError: ожидался None, получено 0 — ноль здесь читается как «осадков не будет»
ключа precipitation_sum нет красный: assert 0 is None
контроль: настоящая сухая неделя [0,0,0] зелёный

Контроль существенен: без него правку можно было бы «сделать» так, что осадки всегда None — и оба первых теста стали бы зелёными по неверной причине, а продукт перестал бы показывать законный измеренный ноль.

pytest tests/services: 3089 passed, 14 skipped, rc=0 (перепрогнано после хуков)
tsc --noEmit: rc=0 · vitest: 36 файлов, 279 тестов, rc=0

Refs #2464

## Ноль, означавший «не знаем» `weather_cache` отдавал `0`, когда open-meteo не прислал ряд осадков: ```python "precipitation_total_mm": round(sum(precip), 1) if precip else 0 "total_precip_mm": round(sum(precip), 0) if precip else 0 # сезонные нормали ``` Ноль здесь — утверждение о погоде («сухо»), а пустой ряд значит, что мы **не знаем**. Разница доходит до пользователя: `ptica-adapt` заворачивал значение в `real(...)` **безусловно**, то есть подавал его как измеренную величину. ## Непоследовательность внутри одного литерала Шесть соседних агрегатов при пустых данных дают `None`: `min_c`, `max_c`, `avg_max_c`, `avg_min_c`, `uv_index_max`, `max_speed_m_s`. Осадки были единственным исключением. В сезонном блоке ещё нагляднее — эти две строки идут **подряд** и считаются из **одного** списка: ```python "avg_precip_per_day_mm": round(sum(precip) / len(precip), 1) if precip else None, "total_precip_mm": round(sum(precip), 0) if precip else 0, ``` ## Класс уже был решён в этом же файле Раздел 7 тестов `weather_cache`: > «wind_d all-None → `dominant_direction_deg` = None, а **не 0.0°** (= север)» То же рассуждение, тот же файл, только про ветер. Новые тесты зеркалят его структуру, включая заголовок раздела — чтобы следующий читатель увидел, что это одна и та же мысль, а не два разных случая. ## Фронт: типы нашли потребителей сами Сделал оба поля `number | null` — и `tsc` выдал четыре ошибки в двух файлах, плюс нашёлся сезонный блок. Ровно для этого смена типа и нужна. Везде теперь «нет данных» вместо числа. В `ptica-adapt` применён образец **соседней строки** `avg_min_c`: есть значение → `real()`, нет → `notReal()`. ## Проверка | тест | `origin/main` | |---|---| | все `precipitation_sum` = null | **красный**: `AssertionError: ожидался None, получено 0 — ноль здесь читается как «осадков не будет»` | | ключа `precipitation_sum` нет | **красный**: `assert 0 is None` | | **контроль**: настоящая сухая неделя `[0,0,0]` | **зелёный** | Контроль существенен: без него правку можно было бы «сделать» так, что осадки всегда `None` — и оба первых теста стали бы зелёными по неверной причине, а продукт перестал бы показывать законный измеренный ноль. `pytest tests/services`: **3089 passed, 14 skipped, rc=0** (перепрогнано после хуков) `tsc --noEmit`: rc=0 · `vitest`: 36 файлов, 279 тестов, rc=0 Refs #2464
bot-backend added 1 commit 2026-08-20 06:11:01 +00:00
fix(ptica): «0 мм осадков» перестаёт означать «данных нет» (#2464)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 1m11s
CI / openapi-codegen-check (pull_request) Successful in 2m3s
CI / backend-tests (pull_request) Successful in 17m10s
9ae7af5753
weather_cache отдавал 0, когда open-meteo не прислал ряд осадков:

    "precipitation_total_mm": round(sum(precip), 1) if precip else 0
    "total_precip_mm":        round(sum(precip), 0) if precip else 0   (сезонные)

Ноль здесь — утверждение о погоде («сухо»), а пустой ряд значит, что мы не знаем.
Разница видна пользователю: ptica-adapt заворачивал значение в real(...)
БЕЗУСЛОВНО, то есть подавал его как измеренную величину.

Непоследовательность внутри одного литерала: шесть соседних агрегатов при пустых
данных дают None (min_c / max_c / avg_max_c / avg_min_c / uv_index_max /
max_speed_m_s). В сезонном блоке ещё нагляднее — avg_precip_per_day_mm и
total_precip_mm считаются из ОДНОГО списка соседними строками, первый даёт None,
второй давал 0.

В репозитории уже был решён ровно этот класс: раздел 7 тестов weather_cache —
«wind_d all-None → dominant_direction_deg = None, а не 0.0° (= север)». Новые
тесты зеркалят его структуру, включая заголовок раздела.

Фронт: оба поля стали nullable, и TypeScript сам нашёл всех потребителей —
четыре ошибки в двух файлах плюс сезонный блок. Везде «нет данных» вместо числа.
В ptica-adapt применён образец соседней строки avg_min_c: есть значение → real(),
нет → notReal().

Тесты: 2 красных на origin/main —
«AssertionError: ожидался None, получено 0 — ноль здесь читается как
«осадков не будет»». Контроль отдельный: настоящая сухая неделя (precip=[0,0,0])
обязана давать ИЗМЕРЕННЫЙ 0.0, а не None — без него правку можно было бы «сделать»
так, что осадки всегда None, и оба теста стали бы зелёными по неверной причине.

pytest tests/services: 3089 passed, 14 skipped, rc=0 (перепрогнано после хуков)
tsc --noEmit rc=0 · vitest 36 файлов / 279 тестов rc=0
bot-backend merged commit 6bca4f7ead into main 2026-08-20 07:00:04 +00:00
bot-backend deleted branch fix/2464-precipitation-unknown-not-zero 2026-08-20 07:00:05 +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#2947
No description provided.