Commit graph

6 commits

Author SHA1 Message Date
7e42b34a46 feat(financial): LTC 70%/equity 30% норматив МКД РФ в модели финансирования
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Successful in 59s
CI / openapi-codegen-check (pull_request) Successful in 1m55s
CI / backend-tests (pull_request) Successful in 11m44s
Заменяет 100%-кредитное покрытие разрыва реалистичной LTC-моделью:
банк покрывает 70 % каждого оттока, собственные средства — 30 %
(без начисления процентов). Итог: total_interest снижается ≈ на 30 %,
net_profit_after_financing_rub растёт соответственно.

- financial.py: добавлен _LOAN_TO_COST_RATIO=0.70, _compute_financing принимает
  ltc_ratio (default 1.0 для BC), call site передаёт константу
- ptica-adapt.ts: caveat «financing_is_simplified» уточнён (без англицизмов)
- test_financial_dcf.py: 2 новых теста (ltc_reduces_debt, uses_ltc_ratio)
- honesty.test.ts: assertion обновлён под новый текст caveat
2026-06-24 21:37:17 +05:00
5a73f1d0b6 feat(cockpit): поверхностить financial_estimate в Development Scan / Investment Clearance (#1881 rank-5) (#1894)
All checks were successful
Deploy / build-backend (push) Has been skipped
Deploy / changes (push) Successful in 7s
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m18s
Deploy / deploy (push) Successful in 1m10s
feat(cockpit): поверхностить financial_estimate в Development Scan / Investment Clearance (#1881 rank-5)
2026-06-24 16:20:19 +00:00
d350d27325 feat(finmodel): financing overlay (кредит 15%) поверх unlevered DCF (epic #1881 PR-5)
All checks were successful
CI / frontend-tests (pull_request) Successful in 59s
CI / openapi-codegen-check (pull_request) Successful in 1m53s
CI / backend-tests (pull_request) Successful in 10m1s
CI / changes (pull_request) Successful in 7s
Финансирование как ДОПОЛНИТЕЛЬНЫЙ overlay поверх готового unlevered cashflow:
кредитная линия покрывает накопительный кассовый разрыв, проценты капитализируются
(compound), ставка _CREDIT_RATE_ANNUAL=15% (норматив, ОТДЕЛЬНО от ставки
дисконтирования — разная семантика: стоимость долга vs требуемая доходность).

Backend (financial.py):
- _compute_financing(operating_cf, annual_rate) — чистая (READ-ONLY вход, не
  мутирует): процент на остаток на начало месяца ДО движений → капитализация;
  draw=-cf при оттоке, repay=min(cf,debt) при притоке (долг не уходит в минус).
  Возвращает peak_debt_rub / total_interest_rub / ending_debt_rub.
- compute_financial: вызов после DCF, net_profit_after_financing = net − interest.
- _build_monthly_cashflow и unlevered NPV/IRR/PBP НЕ ТРОНУТЫ → инвариант
  Σ unlevered cashflow == net_profit сохранён (регресс-тест).
- FinancialModel +6 полей (financing_enabled/annual_rate_used/peak_debt_rub/
  total_interest_rub/net_profit_after_financing_rub/financing_is_simplified).

Frontend: ParcelFinancialEstimate +6 полей; adaptFinanceDrawer + concept-каскад
показывают пиковый долг/проценты/чистую прибыль после финанс. (когда enabled).

MVP: только агрегаты, БЕЗ levered IRR (хрупко на хардкод-100%-долге — отдельный
PR). HEAVY caveat: проценты — реальная стоимость (net после < net до); 100%
покрытие разрыва (нет equity/LTC); compound; эскроу не моделируется; unlevered
headline не затронут. financing_is_simplified=True флаг.

mypy strict clean, +9 backend + 3 frontend тестов (compound точное значение,
no-mutation, инвариант-регресс, монотонность, net_after<net), api-types
регенерён авторитетно, deps не тронуты (hand-roll).

Refs #1881
2026-06-24 01:12:47 +05:00
67b65c8d8a feat(site-finder): bridge финмодели (DCF) в кокпит Investment Clearance (epic #1881 PR-4)
All checks were successful
CI / frontend-tests (pull_request) Successful in 57s
CI / openapi-codegen-check (pull_request) Successful in 1m49s
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Successful in 9m54s
Investment Clearance в site-finder кокпите больше не «—»: синтезируем лёгкий
ТЭП из buildability участка (площадь + предельные параметры зоны НСПД/ПЗЗ —
КСИТ/%застройки/этажность) → прогоняем через полноценную финмодель (каскад
затрат PR-1 + калибр.цена PR-2 + помесячный DCF PR-3) → GDV/Cost/Profit/ROI/
IRR/NPV/PBP в кокпите.

Backend:
- new app/services/site_finder/parcel_financial.py (ЧИСТЫЕ функции, без БД):
  synthesize_teap_from_buildability (GFA=area×max_far, degradation pct+floors;
  residential=GFA×eff; apartments/parking — нормативы teap.py, не дублируются)
  + synthesize_parcel_financial (housing_class из цены, development_type из
  этажей, land_cost=кадастровая). None когда нельзя строить МКД / нет зонинга /
  нет площади.
- parcels.py: 1 вызов в try/except (hot-path-safe → None при сбое) + ключ
  financial_estimate в /analyze. Схема не тронута (AnalyzeResponse extra=allow,
  codegen не нужен). +18 тестов.

Frontend:
- ParcelFinancialEstimate тип (site-finder.ts, hand-typed).
- adaptInvestmentClearance(financial)/adaptFinanceDrawer(financial): реальные
  числа (GDV/Cost/Profit/ROI/IRR + NPV + срок окуп.) или честный placeholder
  когда null. Локализация класса/типа (high_rise→высотная). Прокинут analysis
  через PticaBottomGrid/drawer-registry. +6 тестов, 144 passed.

HEAVY caveat везде: ОРИЕНТИРОВОЧНАЯ модель по МАКС.застройке НСПД, НЕ реальная
концепция; land=кадастровая (не рыночная); график — типовой; IRR proxy-флаг.
mypy strict clean (generative.*), ruff/tsc/lint clean.

Закрывает эпик #1881 (финмодель = полноценная DCF, видна в кокпите).
Follow-up: финансирование (кредит/займы), §22 sales-pace, гео-радиус калибровки.

Refs #1881
2026-06-23 22:44:04 +05:00
389bdd3306 test(ptica): use tracked mock fixtures instead of git-excluded __preview (CI fix)
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Successful in 54s
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m54s
CI frontend-tests упал: honesty-тест импортировал фикстуры из
src/app/%5F%5Fpreview/ptica/__fixtures__/ — эта dev-only директория в
.git/info/exclude, поэтому отсутствует в Linux CI checkout (vite:import-analysis
'Failed to resolve import'). Локально (macOS) резолвилось т.к. файлы на диске.

Переключил импорт на tracked src/lib/mocks/parcel-{forecast,analyze}.json
(NEXT_PUBLIC_USE_MOCKS source, в git) — report.exec_summary.key_numbers.
deficit_index присутствует, shape совместим. 138/138 vitest passed.

Refs #1871
2026-06-23 11:25:33 +05:00
2303207629 fix(ptica): honest isReal flags — placeholder stubs no longer marked real (audit #1871 P1.3)
Some checks failed
CI / frontend-tests (pull_request) Failing after 53s
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m52s
Adapter — единственный источник истины real-vs-placeholder; стаб с isReal:true
рисуется как живое измерение (обычная типографика «—», неотличимо от данных).
Helpers real()/placeholder()/notReal() корректны — баг в их misuse на 5 местах.

ptica-adapt.ts:
- :163 encumbrances (passport-card): {value:PLACEHOLDER, isReal:true} → notReal("источник ЕГРН")
- :272 buySignalFromForecast при deficit_index==null: {value:"наблюдать", isReal:true}
  → notReal("прогноз недоступен (Сценарии §22)") — отличает «прогноза нет» от
  «прогноз говорит наблюдать». di-present advisory-ветка (real) не тронута.
- :1942 adaptBuySignalGauge при di==null: убран synthetic gaugeValue=50 как real;
  ранний if(di==null) зеркалит no-report ветку (value:null, isReal:false, available:false).
- :681 adaptPassportDrawer registry, :1048 adaptLegalDrawer registry: те же
  «Обременения» стабы {value:DASH, isReal:true} → notReal (найдены code-review,
  recon их пропустил — drawer-зеркала card-фикса).

ptica.module.css: .kvPlaceholder += opacity:0.7 — усиленный визуальный mute стаба.

Корректные места НЕ тронуты (recon-verified): market demand-label (условный
real/placeholder), engineering utilities, InvestScore potential.

+5 unit-тестов (ptica-adapt.honesty.test.ts): encumbrances stub, buy-signal di=null,
buy-signal real di (защита от over-downgrade), gauge di=null, оба drawer-обременения.

Refs #1871
2026-06-23 11:20:48 +05:00