feat(chat): deterministic §22 chat foundation /api/v1/chat/ask (#957 Step1) #1172

Merged
bot-backend merged 1 commit from feat/chat-957-foundation into main 2026-06-08 12:29:24 +00:00
Collaborator

Summary

Step 1 of #957 (chat over the engine) — the deterministic foundation, NO LLM. POST /api/v1/chat/ask answers parcel questions by reading the already-persisted §22 SiteFinderReport (latest_run_for, schema "1.0", read-only — no recompute) and returning templated Russian answers with the engine's numbers verbatim (§16 traceability; never fabricated).

  • Intent routing (explicit enum or RU keyword match) → per-section renderers: summary→exec_summary, what_to_build→product_tz, why_forecast→future_market+reasons+confidence, risks→§25 special_indices+confidence, scenarios→scenarios, unknown→menu.
  • Graceful: no run / DB error → report_status="pending" (200, no 500, no recompute); missing/partial sections → honest "нет данных", never KeyError; uncomputed §25 indices skipped (not fabricated).
  • Works at llm_enabled=False (prod default) — llm_used always False. LLM prose composition is Step 2 (this PR doesn't import services/llm).
  • RBAC: mounted off /api/v1/chatrbac_guard auto-requires an authenticated known user (401 no-header, 403 unknown-user tested).
  • Every answer carries an advisory caveat (report is advisory).

Test plan

  • uv run pytest tests/api/v1/test_chat.py tests/services/chat/ -q44 passed
  • ruff check + mypy → clean
  • Tests: each intent's templated answer, pending (no run / DB error), partial-report-never-raises, numbers-not-fabricated-on-empty (marker fixtures asserted absent), 401/403 RBAC, history-accepted-but-unused
  • code-reviewer APPROVE (no blockers; numbers integrity, graceful degradation, RBAC, no-LLM, scope all verified)
  • staging smoke: POST /chat/ask for a cad with a real §22 run (each intent) + one without (pending)

Scope

New chat files + 2-line main.py router only. parcels.py / special_indices.py / own_portfolio.py / services/llm/ untouched; no pyproject/uv.lock changes.

Next

Step 2: LLM tool-loop (section dict-slicer tools + composition, gated by llm_enabled, fallback to this deterministic path). Step 3: §19 redaction wiring. Frontend chat UI: separate track.

Refs #957

## Summary Step 1 of #957 (chat over the engine) — the **deterministic** foundation, NO LLM. `POST /api/v1/chat/ask` answers parcel questions by reading the **already-persisted** §22 `SiteFinderReport` (`latest_run_for`, schema "1.0", read-only — no recompute) and returning templated Russian answers with the engine's numbers **verbatim** (§16 traceability; never fabricated). - **Intent routing** (explicit enum or RU keyword match) → per-section renderers: `summary`→exec_summary, `what_to_build`→product_tz, `why_forecast`→future_market+reasons+confidence, `risks`→§25 special_indices+confidence, `scenarios`→scenarios, `unknown`→menu. - **Graceful**: no run / DB error → `report_status="pending"` (200, no 500, no recompute); missing/partial sections → honest "нет данных", never KeyError; uncomputed §25 indices skipped (not fabricated). - **Works at `llm_enabled=False`** (prod default) — `llm_used` always False. LLM prose composition is Step 2 (this PR doesn't import `services/llm`). - **RBAC**: mounted off `/api/v1/chat` → `rbac_guard` auto-requires an authenticated known user (401 no-header, 403 unknown-user tested). - Every answer carries an advisory caveat (report is advisory). ## Test plan - [x] `uv run pytest tests/api/v1/test_chat.py tests/services/chat/ -q` → **44 passed** - [x] `ruff check` + `mypy` → clean - [x] Tests: each intent's templated answer, pending (no run / DB error), partial-report-never-raises, **numbers-not-fabricated-on-empty** (marker fixtures asserted absent), 401/403 RBAC, history-accepted-but-unused - [x] code-reviewer ✅ APPROVE (no blockers; numbers integrity, graceful degradation, RBAC, no-LLM, scope all verified) - [ ] staging smoke: `POST /chat/ask` for a cad with a real §22 run (each intent) + one without (pending) ## Scope New chat files + 2-line main.py router only. `parcels.py` / `special_indices.py` / `own_portfolio.py` / `services/llm/` untouched; no pyproject/uv.lock changes. ## Next Step 2: LLM tool-loop (section dict-slicer tools + composition, gated by `llm_enabled`, fallback to this deterministic path). Step 3: §19 redaction wiring. Frontend chat UI: separate track. Refs #957
bot-backend added 1 commit 2026-06-08 12:22:15 +00:00
feat(chat): deterministic §22 chat foundation — POST /api/v1/chat/ask (no LLM)
All checks were successful
CI / changes (push) Successful in 6s
CI / frontend-tests (push) Has been skipped
CI / backend-tests (pull_request) Successful in 6m23s
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Successful in 6m25s
Deploy / changes (push) Successful in 5s
Deploy / build-frontend (push) Has been skipped
Deploy / build-backend (push) Successful in 1m43s
Deploy / deploy (push) Successful in 1m38s
Deploy / build-worker (push) Successful in 7m39s
4847a2eb01
Step 1 of #957. Answers parcel questions by reading the already-persisted
§22 SiteFinderReport (latest_run_for, schema "1.0", read-only) and returning
templated RU answers with engine numbers verbatim (§16, never fabricated).
Intent routing (explicit or RU keyword match) -> per-section renderers;
graceful on partial/missing sections and pending (no run / DB error) without
500s. Works with llm_enabled=False (llm_used always False); LLM composition
is Step 2. Mounted off /api/v1/chat so rbac_guard auto-requires an authed
known user.

Refs #957
bot-backend merged commit 4847a2eb01 into main 2026-06-08 12:29:24 +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#1172
No description provided.