feat(parcels): typed AnalyzeResponse + run-history endpoints — EPIC #961 (#992,#994) #1082

Merged
bot-backend merged 1 commit from feat/analyze-response-contract-961 into main 2026-06-06 18:13:35 +00:00
Collaborator

Что

Завершает EPIC #961 (контракт API результата + версионирование).

Closes #992, Closes #994.

#992 — типизированный AnalyzeResponse + response_model

POST /{cad}/analyze теперь имеет response_model=AnalyzeResponse (был untyped dict[str,Any]).

  • Без потери ключей: model_config = ConfigDict(extra="allow") → любой ключ result_payload, не описанный в модели, ПРОХОДИТ в ответ (нет тихого drop, который сломал бы фронт). ~90 known-полей задокументированы для OpenAPI/codegen.
  • Все поля Optional → graceful 202-fetch-stub (#93) сериализуется без 500.
  • Проверено: TestClient round-trip + regression-тест ловит реальный result_payload и ассертит set(payload) ⊆ set(response) (нет drop); 202-путь возвращает stub (не 500). HTTPException (400/404/503) минуют response_model.

#994 — история прогонов (read)

  • GET /{cad}/runs → лёгкий список (без result-blob), пусто → 200 {runs:[]} (не 404).
  • GET /runs/{run_id} → полный ран (incl. result), 404 graceful.
  • repo list_runs_for/get_run (psycopg v3 CAST(:x AS type), base-таблица не view). Роуты зарегистрированы ДО /{parcel_id}/runs/{id} не затеняется.

Качество

  • code-reviewer: APPROVE — no key-drops (доказано тестом против реального payload + extra="allow"), nested-drop риск оценён (none), 202 safe, route-ordering ок, psycopg v3 чисто.
  • 15 новых тестов (108 passed), ruff clean, mypy 0 new.

Финальный гейт (мой, перед объявлением done)

Сверю live-prod /analyze key-set ДО/ПОСЛЕ деплоя (baseline = 65 top-level ключей) — если хоть один пропал, откатываю. (response_model на core-эндпоинте = высокий blast-radius.)

## Что Завершает EPIC **#961** (контракт API результата + версионирование). Closes #992, Closes #994. ## #992 — типизированный AnalyzeResponse + response_model `POST /{cad}/analyze` теперь имеет `response_model=AnalyzeResponse` (был untyped `dict[str,Any]`). - **Без потери ключей:** `model_config = ConfigDict(extra="allow")` → любой ключ `result_payload`, не описанный в модели, ПРОХОДИТ в ответ (нет тихого drop, который сломал бы фронт). ~90 known-полей задокументированы для OpenAPI/codegen. - **Все поля Optional** → graceful 202-fetch-stub (#93) сериализуется без 500. - Проверено: TestClient round-trip + regression-тест ловит реальный `result_payload` и ассертит `set(payload) ⊆ set(response)` (нет drop); 202-путь возвращает stub (не 500). HTTPException (400/404/503) минуют response_model. ## #994 — история прогонов (read) - `GET /{cad}/runs` → лёгкий список (без `result`-blob), пусто → 200 `{runs:[]}` (не 404). - `GET /runs/{run_id}` → полный ран (incl. `result`), 404 graceful. - repo `list_runs_for`/`get_run` (psycopg v3 `CAST(:x AS type)`, base-таблица не view). Роуты зарегистрированы ДО `/{parcel_id}` → `/runs/{id}` не затеняется. ## Качество - `code-reviewer`: ✅ APPROVE — no key-drops (доказано тестом против реального payload + extra="allow"), nested-drop риск оценён (none), 202 safe, route-ordering ок, psycopg v3 чисто. - 15 новых тестов (108 passed), ruff clean, mypy 0 new. ## Финальный гейт (мой, перед объявлением done) Сверю live-prod `/analyze` key-set ДО/ПОСЛЕ деплоя (baseline = 65 top-level ключей) — если хоть один пропал, откатываю. (response_model на core-эндпоинте = высокий blast-radius.)
bot-backend added the
scope/backend
GG-форсайт
site-finder
labels 2026-06-06 18:13:31 +00:00
bot-backend added 1 commit 2026-06-06 18:13:32 +00:00
feat(parcels): typed AnalyzeResponse + run-history read endpoints (#961)
All checks were successful
CI / changes (push) Successful in 8s
CI / changes (pull_request) Successful in 7s
CI / backend-tests (push) Successful in 5m51s
CI / backend-tests (pull_request) Successful in 5m49s
edf44382f8
#992: attach response_model=AnalyzeResponse to POST /{cad_num}/analyze. Model
uses extra="allow" so any result_payload key not explicitly modeled is preserved
in the 200 response (no silent drops that would break Site Finder), and ALL
fields are Optional so the #93 202 fetch-stub serializes without a 500.

#994: add GET /{cad_num}/runs (light summary list, empty 200 not 404) and
GET /runs/{run_id} (full row incl result, 404 if missing), backed by
list_runs_for/get_run in analysis_runs.repository (psycopg v3 CAST(:x AS type)).
Routes ordered before /{parcel_id} so /runs/{run_id} is not shadowed.

Closes #992. Closes #994. Refs #961.
bot-backend merged commit 22fffb9878 into main 2026-06-06 18:13:35 +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#1082
No description provided.