gendesign/backend/app/services/exporters
Light1YT dcccebf2c2
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / frontend-tests (pull_request) Successful in 1m17s
CI / openapi-codegen-check (pull_request) Successful in 2m11s
CI / backend-tests (pull_request) Successful in 10m19s
fix(forecasting): honest scenarios collapse when β rate-sensitivity gate fails (audit #1871 P1)
Когда demand_normalization honesty-gate отбивает β rate-sensitivity
(`sensitivity.confidence=='low'`, ЕКБ-регрессия не проходит n≥30/R²≥0.1/slope<0),
все 393 прод-отчёта получают coefficient=1.0 для всех трёх сценариев
conservative/base/aggressive. По дизайну backend честно деградирует, но фронт
рисует 3 разноцветные карточки/линии одинаковых чисел без caveat.

Backend (scenarios.py, report.py, report_assembler.py, orchestrator.py):
- compute_scenarios теперь возвращает (list, collapsed: bool, reason: str|None)
- _detect_collapsed(): math.isclose(rel_tol=1e-9, abs_tol=1e-6) сравнивает
  projected_demand_units И deficit_index на всех горизонтах между
  conservative и aggressive — расхождение в любой метрике на любом h → False
- _COLLAPSE_REASON_LOW_BETA — единственный источник истины каноничного
  русского предложения
- ReportScenarios получает поля scenarios_collapsed + scenarios_collapse_reason
- demand_normalization.py НЕ ТРОНУТ — поведение корректно по контракту

Backend экспортёры (report_pdf.py, excel.py):
- PDF: при collapse — тёмная плашка-параграф вместо таблицы трёх столбцов
- Excel: ОДНА строка «base» + caveat-ячейка вместо трёх идентичных столбцов

Frontend (forecast.ts, ScenariosBlock, ScenarioCards, ScenarioCompareTable,
ForecastChart, Section6Forecast, ptica.module.css):
- Тип ReportScenarios расширен двумя optional-полями
- ScenariosBlock (light): headline-bar + одна grid-карточка base + caveat
- ScenarioCards (ptica dark): sub-component ScenarioBaseCard, одна карточка
  + collapse-note, ScenarioCompareTable return null
- ForecastChart: effectiveScenarios filter — одна линия viz-1 «Базовый»
  вместо трёх перекрывающихся
- Section6Forecast: caveat выше графика, читается ТОЛЬКО из
  scenarios_collapse_reason (источник истины — backend constant)

Тесты: +18 новых (TestMetricsEqual×6, TestDetectCollapsed×7,
TestComputeScenariosCollapseDetection×4 + 1 проверка graceful + corner).
102 forecasting passed, 88 cross-module passed.

Refs #1871
2026-06-22 19:06:22 +05:00
..
__init__.py init 2026-04-25 13:45:19 +03:00
dxf.py init 2026-04-25 13:45:19 +03:00
excel.py fix(forecasting): honest scenarios collapse when β rate-sensitivity gate fails (audit #1871 P1) 2026-06-22 19:06:22 +05:00
layout_tz_pdf.py fix(analyze): district KeyError 500 in #994 persist + revive by-bbox tests 2026-06-03 18:04:37 +05:00
pdf.py init 2026-04-25 13:45:19 +03:00
report_docx.py fix(exporters): annotate scenario deficit horizon in docx/pptx (#1590 follow-up) 2026-06-17 14:35:48 +05:00
report_md.py merge: resolve conflicts with main (#1660) into week-review-finish 2026-06-17 20:21:06 +03:00
report_pdf.py fix(forecasting): honest scenarios collapse when β rate-sensitivity gate fails (audit #1871 P1) 2026-06-22 19:06:22 +05:00
report_pptx.py fix(exporters): annotate scenario deficit horizon in docx/pptx (#1590 follow-up) 2026-06-17 14:35:48 +05:00
snapshot_pdf.py Merge remote-tracking branch 'forgejo-backend/main' into fix/sf-feedback-batch 2026-06-18 10:01:43 +03:00
trade_in_pdf.py fix(week-review): backend-аудит v2 — 82 фиксов (#1660) 2026-06-17 17:13:38 +00:00