EMISS-парсер: годовой агрегат (PERIOD='год') и I квартал коллидируют по obs_date=date(year,1,1) — последний Series молча затирает первый #1606

Closed
opened 2026-06-16 17:18:58 +00:00 by bot-backend · 0 comments
Collaborator

Severity: medium · Категория: data-loss / silent-overwrite · Файл: backend/app/services/scrapers/rosstat_emiss.py:702-704, 790-799

Файл: backend/app/services/scrapers/rosstat_emiss.py:688-704 (_emiss_period_to_month) + 762-799 (parse_emiss_sdmx dedup).

ПОДТВЕРЖДЕНО. Ключ дедупа by_key = (target.region, obs_date), где obs_date = date(int(yr), month, 1) (стр.790-791). _emiss_period_to_month маппит и 'i квартал' → 1 (через _QUARTER_START_MONTH, стр.605), и годовой под-период 'год'/'значение показателя за год'/'за год' → 1 (стр.702-703, _YEAR_PERIODS). Год берётся из

ИМПАКТ: если дефолт-экспорт fedstat data.do по id=57039 содержит годовую строку наряду с поквартальными (типично для SDMX-экспортов Росстата), значение income_per_capita за Q1 в macro_indicator может быть тихо подменено годовым средним (или наоборот), кормя неверными данными forecasting/scoring. Текущая фикстура tests/fixtures/emiss_income_57039.xml содержит ТОЛЬКО квартальные PERIOD (I..IV квартал) — годовой строки нет, поэтому тест зелёный и регрессия не ловится.

ФИКС: включить под-период/frequency в ключ дедупа — например by_key = (region, obs_date, period_kind), где period_kind различает 'quarter' vs 'year'; либо при frequency='quarterly' игнорировать (skip) Series с PERIOD ∈ _YEAR_PERIODS (стр.770-778, рядом с уже существующим month is None → continue).

Почему баг: obs_date нормализует и Q1, и годовой под-период к 1 января, а ключ дедупа не различает frequency/под-период. Текущая фикстура (emiss_income_57039.xml) содержит только кварталы, поэтому тест зелёный, но реальный дефолт-экспорт ЕМИСС часто включает годовую строку. Импакт: неверное значение income_per_capita за Q1 в macro_indicator, которое затем кормит forecasting/scoring.

Как чинить: Либо включить под-период/frequency в ключ дедупа (например (region, obs_date, is_yearly)), либо явно пропускать годовые Series для quarterly-спеков (если spec.frequency=='quarterly' и _emiss_period_to_month вернул месяц из _YEAR_PERIODS — skip), либо маппить годовой под-период не на месяц 1, а отбрасывать. Сейчас _YEAR_PERIODS→1 создаёт коллизию именно с Q1.


deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.78 · unit B32

**Severity:** medium · **Категория:** data-loss / silent-overwrite · **Файл:** `backend/app/services/scrapers/rosstat_emiss.py:702-704, 790-799` Файл: backend/app/services/scrapers/rosstat_emiss.py:688-704 (_emiss_period_to_month) + 762-799 (parse_emiss_sdmx dedup). ПОДТВЕРЖДЕНО. Ключ дедупа by_key = (target.region, obs_date), где obs_date = date(int(yr), month, 1) (стр.790-791). _emiss_period_to_month маппит и 'i квартал' → 1 (через _QUARTER_START_MONTH, стр.605), и годовой под-период 'год'/'значение показателя за год'/'за год' → 1 (стр.702-703, _YEAR_PERIODS). Год берётся из <Obs><Time>[:4]. Поэтому для одного региона/года квартальная Series (PERIOD='I квартал') и годовая агрегатная Series (PERIOD='год') обе дают obs_date=date(year,1,1) и пишутся в один и тот же ключ by_key — 'последний выигрывает' (стр.791). frequency при этом фиксирован spec.frequency='quarterly' (INCOME_PER_CAPITA_SPEC, стр.660), так что семантика (квартал vs год) теряется без следа. ИМПАКТ: если дефолт-экспорт fedstat data.do по id=57039 содержит годовую строку наряду с поквартальными (типично для SDMX-экспортов Росстата), значение income_per_capita за Q1 в macro_indicator может быть тихо подменено годовым средним (или наоборот), кормя неверными данными forecasting/scoring. Текущая фикстура tests/fixtures/emiss_income_57039.xml содержит ТОЛЬКО квартальные PERIOD (I..IV квартал) — годовой строки нет, поэтому тест зелёный и регрессия не ловится. ФИКС: включить под-период/frequency в ключ дедупа — например by_key = (region, obs_date, period_kind), где period_kind различает 'quarter' vs 'year'; либо при frequency='quarterly' игнорировать (skip) Series с PERIOD ∈ _YEAR_PERIODS (стр.770-778, рядом с уже существующим month is None → continue). **Почему баг:** obs_date нормализует и Q1, и годовой под-период к 1 января, а ключ дедупа не различает frequency/под-период. Текущая фикстура (emiss_income_57039.xml) содержит только кварталы, поэтому тест зелёный, но реальный дефолт-экспорт ЕМИСС часто включает годовую строку. Импакт: неверное значение income_per_capita за Q1 в macro_indicator, которое затем кормит forecasting/scoring. **Как чинить:** Либо включить под-период/frequency в ключ дедупа (например (region, obs_date, is_yearly)), либо явно пропускать годовые Series для quarterly-спеков (если spec.frequency=='quarterly' и _emiss_period_to_month вернул месяц из _YEAR_PERIODS — skip), либо маппить годовой под-период не на месяц 1, а отбрасывать. Сейчас _YEAR_PERIODS→1 создаёт коллизию именно с Q1. --- <sub>deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.78 · unit B32</sub>
bot-backend added the
week ревью 1
label 2026-06-16 17:18:58 +00:00
bot-backend added the
needs-human
label 2026-06-16 20:44:20 +00:00
Sign in to join this conversation.
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#1606
No description provided.