feat(generative): POST /concepts/recompute — live финрасчёт по massing-program (#1965 Stage 2a) #2024

Merged
bot-backend merged 3 commits from feat/concept-recompute-1965-stage2a into main 2026-06-27 19:53:54 +00:00
Collaborator

#1965 Stage 2a (эпик #1953) — backend для живого пересчёта экономики от интерактивного 3D. code-reviewer APPROVE. Бэкенд-онли, без миграций, аддитивно.

Что

  • synthesize_teap_from_program(total_footprint_sqm, floors, site_area_sqm, housing_class, sections=1) (teap.py) — чистая: built=footprint, GFA=footprint×floors, те же константы share/efficiency что у synthesize_teap_from_buildability/compute_teap (drift невозможен; parity-тест = byte-equal TEAP с compute_teap на эквивалентном прямоугольнике).
  • Схемы MassingProgram + MassingRecomputeOutput (Literal-наборы точно как у ConceptInput/compute_financial).
  • POST /api/v1/concepts/recompute → synthesize_teap_from_program → существующий compute_financial → TEAP+FinancialModel.
  • Резолв цены (приоритет): body market_price_per_sqm (FAST, без БД) → _lookup_market_price (threadpool, если есть parcel_centroid_wkt) → class_norm. price_source пробрасывается (честный флаг происхождения цены — не мислейблит).

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

  • mypy-strict (generative) чисто; ruff ; no :name::type; 125 passed (+ 12 новых: gfa-математика, parity, class-efficiency, price passthrough/fallback, bounds 1-40/1-6, exploding-session доказывает no-DB на fast-path).
  • compute_financial НЕ тронут (чистая функция, in-loop — без БД/IO). Аддитивный endpoint+схемы → консьюмеров нет (Stage 2b — следующий).

Stage 2b (следующий PR): 3D MassingScene в секцию «7. Концепция» + debounced-хук на этот endpoint → живой пересчёт NPV/IRR при кручении этажности/секций. Refs #1965.

#1965 Stage 2a (эпик #1953) — backend для живого пересчёта экономики от интерактивного 3D. code-reviewer ✅ APPROVE. Бэкенд-онли, без миграций, аддитивно. ## Что - `synthesize_teap_from_program(total_footprint_sqm, floors, site_area_sqm, housing_class, sections=1)` (teap.py) — чистая: built=footprint, GFA=footprint×floors, **те же** константы share/efficiency что у `synthesize_teap_from_buildability`/`compute_teap` (drift невозможен; parity-тест = byte-equal TEAP с compute_teap на эквивалентном прямоугольнике). - Схемы `MassingProgram` + `MassingRecomputeOutput` (Literal-наборы точно как у ConceptInput/compute_financial). - `POST /api/v1/concepts/recompute` → synthesize_teap_from_program → **существующий `compute_financial`** → TEAP+FinancialModel. - **Резолв цены (приоритет):** body `market_price_per_sqm` (FAST, без БД) → `_lookup_market_price` (threadpool, если есть `parcel_centroid_wkt`) → class_norm. `price_source` пробрасывается (честный флаг происхождения цены — не мислейблит). ## Безопасность - mypy-strict (generative) чисто; ruff ✅; no `:name::type`; **125 passed** (+ 12 новых: gfa-математика, parity, class-efficiency, price passthrough/fallback, bounds 1-40/1-6, exploding-session доказывает no-DB на fast-path). - compute_financial НЕ тронут (чистая функция, in-loop — без БД/IO). Аддитивный endpoint+схемы → консьюмеров нет (Stage 2b — следующий). Stage 2b (следующий PR): 3D `MassingScene` в секцию «7. Концепция» + debounced-хук на этот endpoint → живой пересчёт NPV/IRR при кручении этажности/секций. Refs #1965.
bot-backend added 2 commits 2026-06-27 19:34:52 +00:00
Stage 2a of epic #1953: backend service + endpoint for live economic recompute
driven by the interactive 3D massing (Stage 2b debounced sliders).

- teap.py: add pure synthesize_teap_from_program(total_footprint_sqm, floors,
  site_area_sqm, housing_class, sections) — builds a TEAP from the SCALAR
  aggregate footprint × floors, mirroring synthesize_teap_from_buildability and
  reusing the same shared norm constants (_OFFICE_SHARE_OF_GFA / _EFFICIENCY_BY_CLASS
  / _AVG_APARTMENT_SQM / _PARKING_PER_APARTMENT) — single source of truth.
- schemas/concept.py: add MassingProgram (program contract, optional pre-resolved
  market_price_per_sqm + parcel_centroid_wkt) and MassingRecomputeOutput (teap + financial).
- api/v1/concepts.py: add POST /api/v1/concepts/recompute — synthesize TEAP → run
  the existing pure compute_financial. FAST path uses body market_price_per_sqm
  (no DB); else _lookup_market_price by centroid via run_in_threadpool; else class norm.
- tests: synthesize_teap_from_program (gfa math, parity with compute_teap, class
  efficiency, sections no-op) + endpoint (200, coherent output, price passthrough
  skips DB, DB fallback, class-norm default, floors validation).
fix(generative): forward genuine price_source through /recompute (#1965 Stage 2a)
Some checks failed
CI / frontend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 7s
CI / openapi-codegen-check (pull_request) Failing after 1m49s
CI / backend-tests (pull_request) Successful in 13m49s
18d012da1b
Code-review follow-up: /recompute hardcoded price_source="objective_district_median"
for any body-supplied market_price_per_sqm, mislabeling the honesty-flag once
Stage 2b forwards a price whose genuine source differs (objective_geo_radius /
district_reference / class_norm from financial_estimate).

- schemas/concept.py: add optional price_source: str | None to MassingProgram.
- api/v1/concepts.py: on FAST path use payload.price_source if provided, else the
  default label (now a module-level constant _DEFAULT_PRERESOLVED_SOURCE). DB-fallback
  and class-norm paths keep their own resolved source unchanged.
- tests: assert body-provided price_source echoes through to financial.price_source
  (not overwritten), and the default label applies when the front omits it.
Light1YT added 1 commit 2026-06-27 19:39:07 +00:00
chore(frontend): regenerate api-types.ts for /concepts/recompute (#1965 Stage 2a)
All checks were successful
CI / changes (pull_request) Successful in 8s
CI / frontend-tests (pull_request) Successful in 1m17s
CI / openapi-codegen-check (pull_request) Successful in 2m11s
CI / backend-tests (pull_request) Successful in 14m1s
7e824ce6e4
The new POST /api/v1/concepts/recompute endpoint + MassingProgram /
MassingRecomputeOutput schemas changed the backend OpenAPI; the generated
frontend/src/lib/api-types.ts was out of sync, failing the CI
openapi-codegen-check gate. Regenerated via the exact CI sequence
(openapi-typescript + prettier 3.9.0). Byte-stable on 2nd regen; tsc --noEmit clean.
bot-backend merged commit 01b0dc74de into main 2026-06-27 19:53:54 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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#2024
No description provided.