docs(platform): add policy configs, runbooks, ops scripts and platform documentation
Config policies (16 files): alert_routing, architecture_pressure, backlog, cost_weights, data_governance, incident_escalation, incident_intelligence, network_allowlist, nodes_registry, observability_sources, rbac_tools_matrix, release_gate, risk_attribution, risk_policy, slo_policy, tool_limits, tools_rollout Ops (22 files): Caddyfile, calendar compose, grafana voice dashboard, deployments/incidents logs, runbooks for alerts/audit/backlog/incidents/sofiia/voice, cron jobs, scripts (alert_triage, audit_cleanup, migrate_*, governance, schedule), task_registry, voice alerts/ha/latency/policy Docs (30+ files): HUMANIZED_STEPAN v2.7-v3 changelogs and runbooks, NODA1/NODA2 status and setup, audit index and traces, backlog, incident, supervisor, tools, voice, opencode, release, risk, aistalk, spacebot Made-with: Cursor
This commit is contained in:
477
docs/audit/gaps_and_recovery_plan.md
Normal file
477
docs/audit/gaps_and_recovery_plan.md
Normal file
@@ -0,0 +1,477 @@
|
||||
# Sofiia CTO Agent — Gaps & Recovery Plan (E)
|
||||
|
||||
> Generated: 2026-02-26 | P0 = блокуюче | P1 = критичне для vNext | P2 = покращення
|
||||
|
||||
---
|
||||
|
||||
## Критичне резюме
|
||||
|
||||
**Що вже готово і може йти в UI:** Chat, Voice, Projects CRUD, File upload, Sessions, Dialog Map tree, Ops actions, Node health.
|
||||
|
||||
**Що не готово і блокує vNext:** Tasks/Kanban, Meetings, Dialog Map canvas + Postgres schema, Doc versions, CTO Repo/Ops flow, Supervisor через BFF, Semantic search.
|
||||
|
||||
---
|
||||
|
||||
## Таблиця прогалин з пріоритетами
|
||||
|
||||
| # | Gap | Пріоритет | Складність | Блокує |
|
||||
|---|-----|-----------|-----------|--------|
|
||||
| G1 | `dialog_nodes`/`dialog_edges` Postgres tables + API | P0 | Medium | Dialog Map vNext |
|
||||
| G2 | `tasks` table + CRUD API + Kanban UI | P0 | Medium | Projects Board |
|
||||
| G3 | `meetings` table + CRUD API | P0 | Medium | Projects Meetings tab |
|
||||
| G4 | Supervisor не проксюється через BFF | P0 | Low | CTO workflow access |
|
||||
| G5 | `docs_versions` table + API | P1 | Low | Doc history/rollback |
|
||||
| G6 | `entity_links` table + API | P1 | Low | Cross-entity linking |
|
||||
| G7 | `repo_changesets` + `repo_patches` + PR flow | P1 | High | CTO code workflow |
|
||||
| G8 | `ops_runs` job system (not one-shot) | P1 | Medium | CTO ops audit trail |
|
||||
| G9 | Semantic search (Qdrant/Meilisearch) | P1 | Medium | Doc/Project search |
|
||||
| G10 | NATS `attachment.created` on upload | P1 | Low | Parser pipeline hook |
|
||||
| G11 | `DELETE` endpoints (projects/docs) | P1 | Low | CRUD completeness |
|
||||
| G12 | Real-time WS events for map/tasks | P1 | Medium | Live UI updates |
|
||||
| G13 | E2EE / confidential mode | P2 | Very High | Privacy |
|
||||
| G14 | 2-step Plan → Apply for dangerous actions | P2 | High | Safe ops flow |
|
||||
| G15 | `agent_id="l"` vs `"sofiia"` inconsistency | P1 | Low | Config correctness |
|
||||
| G16 | `dialog_views` saved views | P2 | Low | UX |
|
||||
| G17 | NODA3 integration | P2 | Medium | AI/ML workstation |
|
||||
| G18 | Meilisearch deployment | P2 | Low | Full-text search |
|
||||
| G19 | Privacy Gate middleware (Router) | P2 | High | Confidential mode |
|
||||
| G20 | Wiki Markdown editor UI | P2 | Medium | Docs/Wiki experience |
|
||||
| G21 | `doc_index_state` table + reindex jobs | P2 | Low | AI doc indexing |
|
||||
| G22 | Meeting reminders (push/WS) | P2 | Medium | Meetings UX |
|
||||
| G23 | `DELETE /api/nodes/{id}` | P2 | Low | Node management |
|
||||
| G24 | S3/MinIO для file storage | P2 | High | Scale (replace volume) |
|
||||
|
||||
---
|
||||
|
||||
## P0 — Блокуючі прогалини (потрібні для vNext)
|
||||
|
||||
### G1: Dialog Map — Postgres schema + API
|
||||
|
||||
**Що зроблено:** SQLite tree via `parent_msg_id`. Works for conversation branching.
|
||||
|
||||
**Чого не вистачає:**
|
||||
- Postgres tables: `dialog_nodes`, `dialog_edges`, `dialog_views`
|
||||
- API: `GET /api/projects/{id}/dialog-map`, `POST /api/links`
|
||||
- WS event: `dialog_map.updated`
|
||||
- Auto-edge creation from NATS events
|
||||
|
||||
**Recovery plan:**
|
||||
```sql
|
||||
-- Step 1: Add to sofiia-console db.py (SQLite first, Postgres later)
|
||||
CREATE TABLE IF NOT EXISTS dialog_nodes (
|
||||
node_id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
node_type TEXT NOT NULL CHECK(node_type IN ('message','task','doc','meeting','agent_run','decision','goal')),
|
||||
ref_id TEXT NOT NULL, -- FK to actual entity
|
||||
title TEXT DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
created_by TEXT DEFAULT 'system'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS dialog_edges (
|
||||
edge_id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
from_node_id TEXT NOT NULL REFERENCES dialog_nodes(node_id),
|
||||
to_node_id TEXT NOT NULL REFERENCES dialog_nodes(node_id),
|
||||
edge_type TEXT NOT NULL CHECK(edge_type IN ('references','resolves','derives_task','updates_doc','schedules','summarizes')),
|
||||
created_at TEXT NOT NULL,
|
||||
props TEXT DEFAULT '{}' -- JSON
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS dialog_views (
|
||||
view_id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
filters TEXT DEFAULT '{}',
|
||||
layout TEXT DEFAULT '{}'
|
||||
);
|
||||
```
|
||||
|
||||
```python
|
||||
# Step 2: New endpoint in docs_router.py
|
||||
@router.get("/api/projects/{project_id}/dialog-map")
|
||||
async def get_project_dialog_map(project_id: str):
|
||||
nodes = await db.get_dialog_nodes(project_id)
|
||||
edges = await db.get_dialog_edges(project_id)
|
||||
return {"nodes": nodes, "edges": edges}
|
||||
|
||||
@router.post("/api/links")
|
||||
async def create_link(body: LinkCreate):
|
||||
# Creates dialog_edge between two entities
|
||||
...
|
||||
```
|
||||
|
||||
**Оцінка:** 4–6 годин роботи.
|
||||
|
||||
---
|
||||
|
||||
### G2: Tasks + Kanban
|
||||
|
||||
**Що зроблено:** Немає.
|
||||
|
||||
**Recovery plan:**
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS tasks (
|
||||
task_id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL REFERENCES projects(project_id),
|
||||
title TEXT NOT NULL,
|
||||
description TEXT DEFAULT '',
|
||||
status TEXT DEFAULT 'backlog' CHECK(status IN ('backlog','in_progress','review','done')),
|
||||
priority TEXT DEFAULT 'medium',
|
||||
assignee_id TEXT DEFAULT '',
|
||||
labels TEXT DEFAULT '[]', -- JSON
|
||||
due_at TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
msg_id TEXT -- Optional: link to originating message
|
||||
);
|
||||
```
|
||||
|
||||
- API: `GET/POST /api/projects/{id}/tasks`, `PATCH /api/tasks/{id}`, `DELETE /api/tasks/{id}`
|
||||
- UI: Kanban board з drag-drop (можна почати з простим list + status buttons)
|
||||
- Dialog Map auto-edge: `POST /api/links` after task creation
|
||||
|
||||
**Оцінка:** 1–2 дні (backend + basic UI).
|
||||
|
||||
---
|
||||
|
||||
### G3: Meetings
|
||||
|
||||
**Recovery plan:**
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS meetings (
|
||||
meeting_id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL REFERENCES projects(project_id),
|
||||
title TEXT NOT NULL,
|
||||
starts_at TEXT NOT NULL,
|
||||
duration_min INTEGER DEFAULT 60,
|
||||
attendees TEXT DEFAULT '[]', -- JSON
|
||||
location TEXT DEFAULT '',
|
||||
agenda TEXT DEFAULT '',
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
- API: `GET/POST /api/projects/{id}/meetings`, `PATCH /api/meetings/{id}`
|
||||
- UI: simple form (title, date/time, duration, attendees)
|
||||
- Reminders: Phase 2 (WS push)
|
||||
|
||||
**Оцінка:** 1 день.
|
||||
|
||||
---
|
||||
|
||||
### G4: Supervisor → BFF proxy
|
||||
|
||||
**Що зроблено:** Supervisor API exists at `http://sofiia-supervisor:8080` (або port 9400).
|
||||
|
||||
**Recovery plan:**
|
||||
```python
|
||||
# Add to services/sofiia-console/app/main.py:
|
||||
|
||||
SUPERVISOR_URL = os.getenv("SUPERVISOR_URL", "http://sofiia-supervisor:8080")
|
||||
|
||||
@app.post("/api/supervisor/runs")
|
||||
async def run_supervisor_graph(body: dict, _auth: str = Depends(require_auth)):
|
||||
async with httpx.AsyncClient() as c:
|
||||
resp = await c.post(f"{SUPERVISOR_URL}/v1/graphs/{body['graph']}/runs",
|
||||
json=body, timeout=60)
|
||||
return resp.json()
|
||||
|
||||
@app.get("/api/supervisor/runs/{run_id}")
|
||||
async def get_supervisor_run(run_id: str, _auth: str = Depends(require_auth)):
|
||||
async with httpx.AsyncClient() as c:
|
||||
resp = await c.get(f"{SUPERVISOR_URL}/v1/runs/{run_id}", timeout=10)
|
||||
return resp.json()
|
||||
```
|
||||
|
||||
**Оцінка:** 30 хвилин.
|
||||
|
||||
---
|
||||
|
||||
## P1 — Критичні для vNext
|
||||
|
||||
### G5: Doc versions
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS doc_versions (
|
||||
version_id TEXT PRIMARY KEY,
|
||||
doc_id TEXT NOT NULL REFERENCES documents(doc_id),
|
||||
content TEXT NOT NULL, -- full text
|
||||
author_id TEXT DEFAULT 'system',
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
```python
|
||||
# New endpoints in docs_router.py:
|
||||
# GET /api/projects/{pid}/documents/{did}/versions
|
||||
# POST /api/projects/{pid}/documents/{did}/restore
|
||||
```
|
||||
|
||||
**Оцінка:** 2 години.
|
||||
|
||||
---
|
||||
|
||||
### G7: Repo Changesets (CTO Code Flow)
|
||||
|
||||
Це найскладніша частина. **Рекомендація:** почати з mock endpoints, потім реалізувати реальну логіку.
|
||||
|
||||
**Mock endpoint (30 хв):**
|
||||
```python
|
||||
@app.post("/api/repo/changesets")
|
||||
async def create_changeset_mock(body: dict, _auth=Depends(require_auth)):
|
||||
# Mock: store in SQLite, return changeset_id
|
||||
cs_id = str(uuid.uuid4())
|
||||
# await db.save_changeset(cs_id, body)
|
||||
return {"changeset_id": cs_id, "status": "draft", "mock": True}
|
||||
```
|
||||
|
||||
**Реальна реалізація (2–3 дні):**
|
||||
```sql
|
||||
CREATE TABLE repo_changesets (
|
||||
cs_id TEXT PRIMARY KEY,
|
||||
project_id TEXT,
|
||||
repo TEXT NOT NULL, -- e.g., "github.com/IvanTytar/microdao-daarion"
|
||||
base_ref TEXT NOT NULL, -- branch/commit
|
||||
intent TEXT NOT NULL,
|
||||
risk_level TEXT DEFAULT 'low',
|
||||
status TEXT DEFAULT 'draft',
|
||||
created_by TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE repo_patches (
|
||||
patch_id TEXT PRIMARY KEY,
|
||||
cs_id TEXT NOT NULL REFERENCES repo_changesets(cs_id),
|
||||
file_path TEXT NOT NULL,
|
||||
patch_text TEXT NOT NULL, -- unified diff
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE pull_requests (
|
||||
pr_id TEXT PRIMARY KEY,
|
||||
cs_id TEXT NOT NULL REFERENCES repo_changesets(cs_id),
|
||||
provider TEXT DEFAULT 'github', -- github/gitlab/gitea
|
||||
pr_url TEXT,
|
||||
pr_number INTEGER,
|
||||
status TEXT DEFAULT 'draft',
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### G8: Ops Runs (Job System)
|
||||
|
||||
Поточний `/api/ops/run` — one-shot dispatch. Потрібен job tracking.
|
||||
|
||||
```sql
|
||||
CREATE TABLE ops_runs (
|
||||
run_id TEXT PRIMARY KEY,
|
||||
project_id TEXT,
|
||||
node_id TEXT NOT NULL, -- noda1/noda2
|
||||
action TEXT NOT NULL, -- з allowlist
|
||||
params TEXT DEFAULT '{}', -- JSON
|
||||
dry_run INTEGER DEFAULT 1,
|
||||
status TEXT DEFAULT 'pending', -- pending/running/success/failed
|
||||
result TEXT DEFAULT '',
|
||||
started_at TEXT,
|
||||
finished_at TEXT,
|
||||
created_by TEXT
|
||||
);
|
||||
```
|
||||
|
||||
**API:**
|
||||
- `POST /api/ops/runs` (створити job, dry_run=true за замовч.)
|
||||
- `GET /api/ops/runs/{id}` (статус)
|
||||
- `GET /api/ops/runs?project_id=&limit=20` (список)
|
||||
|
||||
**Оцінка:** 4 години (backend) + 2 год (UI list).
|
||||
|
||||
---
|
||||
|
||||
### G10: NATS attachment.created
|
||||
|
||||
Одна зміна в `docs_router.py`:
|
||||
|
||||
```python
|
||||
# After successful file save:
|
||||
try:
|
||||
import nats
|
||||
nc = await nats.connect(NATS_URL)
|
||||
await nc.publish(f"attachment.created.{mime_category}",
|
||||
json.dumps({"file_id": file_id, "doc_id": doc_id, ...}).encode())
|
||||
await nc.close()
|
||||
except Exception:
|
||||
pass # best-effort
|
||||
```
|
||||
|
||||
**Оцінка:** 1 година.
|
||||
|
||||
---
|
||||
|
||||
### G15: agent_id "l" vs "sofiia"
|
||||
|
||||
У `services/router/router-config.yml` для NODA2:
|
||||
|
||||
```yaml
|
||||
# Check if there's "l:" entry that should be "sofiia:"
|
||||
```
|
||||
|
||||
**Action:** знайти і замінити `"l"` → `"sofiia"` у router-config відповідної ноди.
|
||||
|
||||
**Оцінка:** 15 хвилин.
|
||||
|
||||
---
|
||||
|
||||
## P2 — Покращення
|
||||
|
||||
### G13: E2EE (confidential mode)
|
||||
|
||||
**Складність:** Дуже висока. Потребує:
|
||||
1. Client-side key generation (WebCrypto API)
|
||||
2. Server-side: store only ciphertext + key_id
|
||||
3. Router Privacy Gate middleware
|
||||
4. Dialog Map: тільки user-created edges (не semantic auto-edges)
|
||||
5. Search: тільки metadata, не plaintext
|
||||
|
||||
**Рекомендація:** Не реалізовувати до завершення Projects + Dialog Map. Спочатку `mode=public` тільки.
|
||||
|
||||
---
|
||||
|
||||
### G20: Wiki Markdown Editor
|
||||
|
||||
Потрібна бібліотека (CodeMirror / Monaco / Tiptap). Для Phase 1 — textarea з preview.
|
||||
|
||||
```html
|
||||
<!-- Simple Phase 1 wiki editor -->
|
||||
<div id="wikiEditor">
|
||||
<textarea id="wikiContent" placeholder="# Сторінка wiki..."></textarea>
|
||||
<div id="wikiPreview" class="markdown-preview"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Wins (до 2 годин кожен)
|
||||
|
||||
| # | Quick Win | Час | Цінність |
|
||||
|---|-----------|-----|---------|
|
||||
| QW1 | `DELETE /api/projects/{id}` | 15 хв | CRUD completeness |
|
||||
| QW2 | `DELETE /api/projects/{id}/documents/{did}` | 15 хв | CRUD completeness |
|
||||
| QW3 | BFF proxy до Supervisor (G4) | 30 хв | CTO workflow access |
|
||||
| QW4 | Mock `/api/repo/changesets` | 30 хв | UI CTO panel development |
|
||||
| QW5 | Mock `/api/ops/runs` | 30 хв | UI CTO panel development |
|
||||
| QW6 | `docs_versions` table + API (G5) | 2 год | Doc history |
|
||||
| QW7 | `USE_EMBEDDINGS=true` + Qdrant ingest | 1 год | Semantic search |
|
||||
| QW8 | `agent_id "l"` → `"sofiia"` fix | 15 хв | Config consistency |
|
||||
| QW9 | NATS `attachment.created` on upload | 1 год | Parser pipeline |
|
||||
| QW10 | WS `dialog_map.updated` basic event | 1 год | Live map refresh |
|
||||
|
||||
---
|
||||
|
||||
## Повний план відновлення (поетапно)
|
||||
|
||||
### Тиждень 1: Stabilize & Quick Wins
|
||||
|
||||
```
|
||||
Day 1–2:
|
||||
- QW1, QW2, QW3, QW8 (CRUD + Supervisor proxy + agent_id fix)
|
||||
- Деплой на NODA2, verify через http://localhost:8002
|
||||
|
||||
Day 3–4:
|
||||
- G2: tasks table + basic API + simple list UI
|
||||
- G3: meetings table + basic form UI
|
||||
|
||||
Day 5:
|
||||
- G5: docs_versions + API
|
||||
- G10: NATS attachment.created
|
||||
- QW4, QW5: mock changeset/ops_run endpoints for UI
|
||||
```
|
||||
|
||||
### Тиждень 2: Dialog Map + CTO Panel
|
||||
|
||||
```
|
||||
Day 1–2:
|
||||
- G1: dialog_nodes/edges tables + API
|
||||
- WS event: dialog_map.updated
|
||||
|
||||
Day 3–4:
|
||||
- UI: Dialog Map canvas (D3 tree → force graph)
|
||||
- Entity links UI (drag edge between nodes)
|
||||
|
||||
Day 5:
|
||||
- G8: ops_runs job system
|
||||
- UI: CTO Ops panel (list + status)
|
||||
```
|
||||
|
||||
### Тиждень 3: Advanced Features
|
||||
|
||||
```
|
||||
- G7: Repo changesets (real implementation)
|
||||
- G9: USE_EMBEDDINGS=true + semantic search
|
||||
- G12: Full real-time WS events (tasks, docs, meetings)
|
||||
- Kanban drag-drop UI
|
||||
- Doc versions diff viewer
|
||||
```
|
||||
|
||||
### Тиждень 4+: Scale & Polish
|
||||
|
||||
```
|
||||
- G14: 2-step Plan → Apply
|
||||
- G20: Wiki Markdown editor
|
||||
- G22: Meeting reminders
|
||||
- G24: S3/MinIO for file storage
|
||||
- G13: E2EE (only when everything else is stable)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5 Найбільш Критичних Прогалин
|
||||
|
||||
1. **`dialog_nodes/edges` + project-level Dialog Map API** — без цього vNext граф неможливий
|
||||
2. **Tasks/Kanban** — Projects без задач = тільки файлосховище
|
||||
3. **Meetings** — Projects без зустрічей = неповний workflow
|
||||
4. **Supervisor не проксюється через BFF** — CTO не може запускати LangGraph runs з UI
|
||||
5. **Repo changesets / CTO code flow** — Sofiia не може "пропонувати PR" як structured artifact
|
||||
|
||||
---
|
||||
|
||||
## 5 Найбільш Готових Частин для UI
|
||||
|
||||
1. **Chat + Voice** — повністю готово, production-grade (Phase 2 streaming, HA, SLO, alerts)
|
||||
2. **Projects + Documents + File Upload** — CRUD, search, sessions — все є
|
||||
3. **Dialog Map tree** — `GET /api/sessions/{id}/map` повертає nodes/edges
|
||||
4. **Ops Actions** — risk/pressure/backlog/notion/release — все є через `/api/ops/run`
|
||||
5. **Node Health Dashboard** — multi-node, SSH, WebSocket realtime — все є
|
||||
|
||||
---
|
||||
|
||||
## 3 Рекомендації "Зробити Негайно"
|
||||
|
||||
### 1. Зберегти контекст у Dialog Map
|
||||
|
||||
Найпростіший спосіб не "загубити" поточний дизайн — додати `dialog_nodes/edges` tables у `db.py` прямо зараз (схема вже описана вище). Навіть якщо UI ще не готовий, дані почнуть накопичуватись від поточних повідомлень.
|
||||
|
||||
### 2. Proxy Supervisor через BFF
|
||||
|
||||
30 хвилин роботи, але це дасть Sofiia доступ до `alert_triage`, `incident_triage`, `postmortem_draft`, `release_check` прямо з UI Console — не тільки через Telegram.
|
||||
|
||||
### 3. Нормалізувати `agent_id`
|
||||
|
||||
Знайти і виправити `"l"` → `"sofiia"` у конфігурації NODA2. Це унеможливить silent routing failures де Router не знаходить агента і тихо fallbacks до дефолту.
|
||||
|
||||
---
|
||||
|
||||
## Next Actions for UI Team (1–2 days)
|
||||
|
||||
1. **Розгорнути і протестувати** поточний стек на NODA2 — `http://localhost:8002/` вже повністю робочий
|
||||
2. **Реалізувати QW1–QW5** (прості DELETE + Supervisor proxy + mock endpoints) — 2–3 год
|
||||
3. **Додати `tasks` і `meetings` tables** у `db.py` та відповідні endpoints у `docs_router.py`
|
||||
4. **Додати `dialog_nodes/edges`** у `db.py` (DDL вище) і endpoint `GET /api/projects/{id}/dialog-map`
|
||||
5. **Тестувати** через `tests/test_sofiia_docs.py` — всі 28 тестів мають пройти
|
||||
6. **Оновити** `docker-compose.node2-sofiia.yml` з `SUPERVISOR_URL` env var
|
||||
7. **Перевірити** що `ops/voice_ha_smoke.sh` проходить після деплою
|
||||
8. **Прочитати** `docs/architecture_inventory/` (7 файлів) для повного контексту поточного стеку
|
||||
9. **Використовувати** `ops/fabric_preflight.sh` перед кожним деплоєм (preflight-first policy)
|
||||
10. **Щотижня**: запускати `ops/fabric_snapshot.py --save` і commit результат — щоб мати baseline для drift detection
|
||||
216
docs/audit/sofiia_audit_index.md
Normal file
216
docs/audit/sofiia_audit_index.md
Normal file
@@ -0,0 +1,216 @@
|
||||
# Sofiia CTO Agent — Audit Index (A)
|
||||
|
||||
> Generated: 2026-02-26 | Scope: Full repository scan | Author: Cursor Auditor
|
||||
|
||||
---
|
||||
|
||||
## 1. Canonical Files (Топ-10 "Sources of Truth")
|
||||
|
||||
| # | File | Тип | Статус | Короткий опис |
|
||||
|---|------|-----|--------|---------------|
|
||||
| 1 | `AGENTS.md` | Identity/Capabilities | ✅ Актуальний | Головний identity файл Sofiia. CTO-агент, 3 ноди, всі можливості, toolchain |
|
||||
| 2 | `config/agent_registry.yml` | Config Registry | ✅ Актуальний | Single Source of Truth для конфігурації. Sofiia entry ~рядки 1276–1330 |
|
||||
| 3 | `services/sofiia-console/app/main.py` | BFF Implementation | ✅ Актуальний | FastAPI BFF v0.3.0. Всі endpoint-и Control Console |
|
||||
| 4 | `services/sofiia-console/static/index.html` | UI | ✅ Актуальний | 1600+ рядків SPA. Чат, Projects, Ops, Hub, Nodes, Memory |
|
||||
| 5 | `docs/ADR_ARCHITECTURE_VNEXT.md` | Architecture ADR | ✅ Актуальний (2026-01-19) | Control Plane + Data Plane архітектура, Privacy Gate, NATS standards |
|
||||
| 6 | `services/router/router-config.yml` | Router Config | ✅ Актуальний | LLM profiles, voice policies, agent routing |
|
||||
| 7 | `config/rbac_tools_matrix.yml` | Security | ✅ Актуальний | `agent_cto` роль з 39 дозволами |
|
||||
| 8 | `docs/OPENAPI_CONTRACTS.md` | API Contracts | ✅ Актуальний | Gateway→Router, Router→Memory контракти |
|
||||
| 9 | `docs/architecture_inventory/` | Inventory (7 файлів) | ✅ Актуальний (2026-02-16) | Повний каталог сервісів, інструментів, NATS, безпека |
|
||||
| 10 | `gateway-bot/sofiia_prompt.txt` | System Prompt | ✅ Актуальний | 138KB+ Telegram-промпт Sofiia як Chief AI Architect |
|
||||
|
||||
---
|
||||
|
||||
## 2. Повна Карта Файлів
|
||||
|
||||
### 2.1 Identity та промпти
|
||||
|
||||
| Файл | Опис | Розмір | Стан |
|
||||
|------|------|--------|------|
|
||||
| `AGENTS.md` | Sofiia identity: CTO-агент, NODA1/NODA2/NODA3, інструменти, стиль | ~400 рядків | ✅ Канонічний |
|
||||
| `gateway-bot/sofiia_prompt.txt` | Telegram system prompt (великий, детальний) | ~138KB | ✅ Production |
|
||||
| `services/sofiia-console/app/main.py` lines 138–177 | Console embedded system prompt (BFF) | ~1KB | ✅ Production |
|
||||
| `docs/consolidation/_node1_runtime_docs/gateway-bot/sofiia_prompt.txt` | Копія промпту (NODA1 backup) | ~138KB | ⚠️ Backup copy |
|
||||
|
||||
### 2.2 Core Implementation — sofiia-console
|
||||
|
||||
| Файл | Опис | Рядків |
|
||||
|------|------|--------|
|
||||
| `services/sofiia-console/app/main.py` | BFF FastAPI: всі endpoints, voice, telemetry, degradation SM | ~1800 |
|
||||
| `services/sofiia-console/app/docs_router.py` | Projects/Documents/Sessions/Dialog Map router | ~380 |
|
||||
| `services/sofiia-console/app/db.py` | SQLite async CRUD: projects, documents, sessions, messages, dialog map | ~320 |
|
||||
| `services/sofiia-console/app/auth.py` | API key authentication | ~50 |
|
||||
| `services/sofiia-console/app/config.py` | Node registry, URLs, feature flags | ~100 |
|
||||
| `services/sofiia-console/app/monitor.py` | Multi-node health polling | ~150 |
|
||||
| `services/sofiia-console/app/nodes.py` | Nodes dashboard | ~80 |
|
||||
| `services/sofiia-console/app/ops.py` | Ops actions dispatcher | ~200 |
|
||||
| `services/sofiia-console/app/router_client.py` | Proxy до Router (infer, tools, health) | ~100 |
|
||||
| `services/sofiia-console/app/voice_utils.py` | Voice sanitize, chunk split, think-block clean | ~150 |
|
||||
| `services/sofiia-console/app/adapters/aistalk.py` | AISTALK adapter | ~80 |
|
||||
| `services/sofiia-console/static/index.html` | SPA UI: chat, projects, ops, hub, nodes, memory | ~1600 |
|
||||
| `services/sofiia-console/requirements.txt` | aiosqlite, pypdf, python-docx, fastapi, httpx | 10 рядків |
|
||||
| `services/sofiia-console/Dockerfile` | Docker build | ~25 |
|
||||
|
||||
### 2.3 Sofiia Supervisor (LangGraph)
|
||||
|
||||
| Файл | Опис |
|
||||
|------|------|
|
||||
| `services/sofiia-supervisor/app/main.py` | FastAPI: `/v1/graphs/{name}/runs` API |
|
||||
| `services/sofiia-supervisor/app/graphs/alert_triage_graph.py` | Alert triage LangGraph |
|
||||
| `services/sofiia-supervisor/app/graphs/incident_triage_graph.py` | Incident triage LangGraph |
|
||||
| `services/sofiia-supervisor/app/graphs/postmortem_draft_graph.py` | Postmortem LangGraph |
|
||||
| `services/sofiia-supervisor/app/graphs/release_check_graph.py` | Release check LangGraph |
|
||||
| `services/sofiia-supervisor/app/alert_routing.py` | Routing policy matcher |
|
||||
| `services/sofiia-supervisor/app/gateway_client.py` | RBAC-enforced gateway client |
|
||||
| `services/sofiia-supervisor/app/models.py` | Pydantic models |
|
||||
| `services/sofiia-supervisor/app/state_backend.py` | Redis/in-memory state |
|
||||
| `docker-compose.node2-sofiia-supervisor.yml` | Supervisor Docker Compose |
|
||||
| `services/sofiia-supervisor/tests/` | 6 test files |
|
||||
|
||||
### 2.4 Router та Tools
|
||||
|
||||
| Файл | Опис |
|
||||
|------|------|
|
||||
| `services/router/main.py` | Main router: всі API endpoints, voice HA, capabilities |
|
||||
| `services/router/tool_manager.py` | 20+ інструментів: CRUD, exec, governance |
|
||||
| `services/router/agent_tools_config.py` | Per-agent tool allowlists |
|
||||
| `services/router/router-config.yml` | LLM profiles, voice policies, agent routing |
|
||||
| `services/router/fabric_metrics.py` | Prometheus metrics |
|
||||
| `services/router/offload_client.py` | NATS offload client |
|
||||
| `services/router/risk_engine.py` | Risk assessment engine |
|
||||
| `services/router/backlog_generator.py` | Backlog generation |
|
||||
| `services/router/incident_intelligence.py` | Incident correlation |
|
||||
| `services/router/cost_analyzer.py` | Cost analysis tool |
|
||||
| `services/router/data_governance.py` | Data governance |
|
||||
| `services/router/dependency_scanner.py` | Dependency scanner |
|
||||
| `services/router/drift_analyzer.py` | Infrastructure drift |
|
||||
| `services/router/architecture_pressure.py` | Architecture pressure analysis |
|
||||
|
||||
### 2.5 Memory Service
|
||||
|
||||
| Файл | Опис |
|
||||
|------|------|
|
||||
| `services/memory-service/app/main.py` | FastAPI: threads, events, memories, facts, agent memory |
|
||||
| `services/memory-service/app/vector_store.py` | Qdrant integration |
|
||||
| `services/memory-service/app/voice_endpoints.py` | STT/TTS endpoints з Prometheus metrics |
|
||||
| `services/memory-service/app/integration_endpoints.py` | Integration webhooks |
|
||||
| `services/memory-service/app/integrations.py` | External integrations |
|
||||
|
||||
### 2.6 Configuration
|
||||
|
||||
| Файл | Опис |
|
||||
|------|------|
|
||||
| `config/agent_registry.yml` | Всі 13+ агентів + sofiia entry |
|
||||
| `config/rbac_tools_matrix.yml` | RBAC ролі: `agent_cto` (39 permissions) |
|
||||
| `config/slo_policy.yml` | SLO для voice fast/quality profiles |
|
||||
| `config/risk_policy.yml` | Risk scoring policy |
|
||||
| `config/release_gate_policy.yml` | Release gate rules |
|
||||
| `config/incident_escalation_policy.yml` | Escalation policy |
|
||||
| `config/alert_routing_policy.yml` | Alert routing |
|
||||
| `config/observability_sources.yml` | Prometheus/Loki/Tempo sources |
|
||||
| `config/tool_limits.yml` | Tool rate limits |
|
||||
| `config/tools_rollout.yml` | Tools rollout configuration |
|
||||
| `config/cost_weights.yml` | Cost scoring weights |
|
||||
| `config/network_allowlist.yml` | Network access allowlist |
|
||||
| `config/nodes_registry.yml` | NODA1/NODA2 node registry |
|
||||
| `config/data_governance_policy.yml` | Data governance policy |
|
||||
| `config/backlog_policy.yml` | Backlog generation policy |
|
||||
| `services/router/router-config.yml` | Voice profiles, agent routing |
|
||||
|
||||
### 2.7 Docker Compose (NODA2 Sofiia Stack)
|
||||
|
||||
| Файл | Опис |
|
||||
|------|------|
|
||||
| `docker-compose.node2-sofiia.yml` | Main: sofiia-console + router + node-worker + memory + qdrant |
|
||||
| `docker-compose.node2-sofiia-supervisor.yml` | Sofiia Supervisor + Redis |
|
||||
| `docker-compose.memory-node2.yml` | Memory stack: Postgres + Qdrant + Neo4j + Memory Service |
|
||||
| `docker-compose.node2.yml` | Full NODA2 stack |
|
||||
|
||||
### 2.8 Документація (docs/)
|
||||
|
||||
| Файл/Dir | Опис | Стан |
|
||||
|----------|------|------|
|
||||
| `docs/ADR_ARCHITECTURE_VNEXT.md` | Основний ADR: vNext архітектура | ✅ |
|
||||
| `docs/OPENAPI_CONTRACTS.md` | API контракти Gateway↔Router↔Memory | ✅ |
|
||||
| `docs/ARCHITECTURE_DIAGRAM.md` | Діаграма архітектури | ✅ |
|
||||
| `docs/architecture_inventory/` | 7 файлів: exec summary, service catalog, tool catalog, dataflows, security, observability, open questions | ✅ 2026-02-16 |
|
||||
| `docs/fabric_contract.md` | Fabric multi-node contract, Voice HA | ✅ |
|
||||
| `docs/sofiia_ui_vnext_audit.md` | vNext UI audit | ✅ |
|
||||
| `docs/supervisor/langgraph_supervisor.md` | Supervisor архітектура | ✅ |
|
||||
| `docs/supervisor/postmortem_draft_graph.md` | Postmortem граф | ✅ |
|
||||
| `docs/runbook/sofiia-control-plane.md` | Operations runbook | ✅ |
|
||||
| `docs/NODA1-NODA2-STATUS.md` | Статус нод | ✅ |
|
||||
| `docs/MULTINODE_ARCHITECTURE.md` | Multi-node архітектура | ✅ |
|
||||
| `docs/NATS_SUBJECTS.md` | NATS subject map | ✅ |
|
||||
| `docs/voice_phase2_cutover.md` | Voice Phase 2 cutover plan | ✅ |
|
||||
| `docs/voice_streaming_phase2.md` | Voice Phase 2 spec | ✅ |
|
||||
| `docs/PRIVACY_GATE.md` | Privacy gate policy | ✅ |
|
||||
| `docs/DATA_RETENTION_POLICY.md` | Data retention | ✅ |
|
||||
| `docs/MEMORY_API_POLICY.md` | Memory API policy | ✅ |
|
||||
| `docs/AGENT_RUNTIME_POLICY.md` | Agent runtime policy | ✅ |
|
||||
| `docs/SECURITY_HARDENING_SUMMARY.md` | Security hardening | ✅ |
|
||||
| `docs/backlog/backlog.md` | Поточний беклог | ✅ |
|
||||
| `docs/incident/` | Incident tracking docs | ✅ |
|
||||
| `docs/risk/risk_index.md` | Risk index | ✅ |
|
||||
|
||||
### 2.9 Тести
|
||||
|
||||
| Файл | Що тестує |
|
||||
|------|-----------|
|
||||
| `tests/test_voice_ha.py` | Voice HA: 35 tests |
|
||||
| `tests/test_voice_policy.py` | Voice routing policy: 23 tests |
|
||||
| `tests/test_voice_stream.py` | Voice Phase 2 streaming: 22 tests |
|
||||
| `tests/test_sofiia_docs.py` | Projects/Documents/Sessions/Dialog Map: 28 tests |
|
||||
| `tests/test_tool_governance.py` | Tool RBAC (agent_cto role) |
|
||||
| `tests/test_risk_attribution.py` | Risk engine |
|
||||
| `tests/test_drift_analyzer.py` | Drift analyzer |
|
||||
| `tests/test_cost_analyzer.py` | Cost analyzer |
|
||||
| `tests/test_incident_escalation.py` | Escalation |
|
||||
| `tests/test_backlog_*.py` | Backlog generation/store |
|
||||
| `services/sofiia-supervisor/tests/` | 6 supervisor graph tests |
|
||||
|
||||
### 2.10 Ops Scripts
|
||||
|
||||
| Файл | Опис |
|
||||
|------|------|
|
||||
| `ops/fabric_preflight.sh` | Preflight checks: models, canary, voice |
|
||||
| `ops/voice_ha_smoke.sh` | Voice HA acceptance smoke test |
|
||||
| `ops/voice_latency_audit.sh` | Multi-scenario latency audit |
|
||||
| `ops/voice_policy_update.py` | Auto-update voice policy від audit results |
|
||||
| `ops/scripts/voice_canary.py` | Voice health canary (preflight + runtime) |
|
||||
| `ops/runbook-voice-incidents.md` | Voice incident runbook |
|
||||
| `ops/runbook-sofiia-docs.md` | Projects/Docs runbook |
|
||||
| `ops/grafana_voice_dashboard.json` | Grafana dashboard |
|
||||
| `ops/voice_alerts.yml` | Prometheus alerting rules |
|
||||
|
||||
---
|
||||
|
||||
## 3. Відсутні файли (NOT FOUND — очікувались)
|
||||
|
||||
| Очікуваний файл | Чому очікувався | Статус |
|
||||
|-----------------|-----------------|--------|
|
||||
| `services/projects-service/` | ADR_ARCHITECTURE_VNEXT згадує окремий projects-service | ❌ НЕ ЗНАЙДЕНО |
|
||||
| `services/docs-service/` | ADR згадує окремий docs-service з версіями | ❌ НЕ ЗНАЙДЕНО |
|
||||
| `services/dialogmap-service/` | vNext design, описаний у chat | ❌ НЕ ЗНАЙДЕНО |
|
||||
| `services/ingest-service/` | ADR 2.2 Ingest Service | ❌ НЕ ЗНАЙДЕНО (тільки stub reference) |
|
||||
| `openapi.yml` / `swagger.yml` | Формальна OpenAPI специфікація | ❌ НЕ ЗНАЙДЕНО |
|
||||
| `migrations/` (Postgres DDL для sofiia) | Versioned DB migrations | ⚠️ Є `migrations/046, 049, 052` для memory-service, але не для sofiia-console |
|
||||
| `docs/audit/` (5 аудит-файлів) | Запит цього сеансу | ✅ Створюються зараз |
|
||||
| `docs_versions` table | vNext DDL план | ❌ НЕ РЕАЛІЗОВАНО |
|
||||
| `dialog_nodes` / `dialog_edges` tables (Postgres) | vNext Dialog Map | ⚠️ SQLite-тільки, tree-based |
|
||||
| `entity_links` / `repo_changesets` / `ops_runs` | CTO DDL заготовки | ❌ НЕ ЗНАЙДЕНО |
|
||||
|
||||
---
|
||||
|
||||
## Next Actions for UI Team (1–2 days)
|
||||
|
||||
1. **Ознайомитись з `docs/architecture_inventory/` (7 файлів)** — там повний каталог поточного стеку
|
||||
2. **Перевірити `services/sofiia-console/app/docs_router.py`** — Projects/Documents/Sessions API вже є, потрібно тільки вмикати USE_EMBEDDINGS/USE_FABRIC_OCR
|
||||
3. **`config/agent_registry.yml` Sofiia entry** — перевірити `telegram_mode: whitelist` і `allowed_users: []`
|
||||
4. **Впевнитись що `docker-compose.node2-sofiia.yml`** має `sofiia-data` volume з правильним path
|
||||
5. **Протестувати UI** через `http://localhost:8002/` — відкрити вкладку "📁 Проєкти" і перевірити sidebar
|
||||
6. **Перевірити Dialog Map** через `GET /api/sessions/{sid}/map` — tree view реалізований
|
||||
7. **НОВА ПОТРЕБА**: визначити де буде Dialog Map на Postgres (`dialog_nodes/edges`) — поки SQLite tree-only
|
||||
8. **Пріоритет для UI**: mock endpoints для `repo_changesets` і `ops_runs` (CTO panel) поки не реалізовано
|
||||
9. **Додати `docs_versions` endpoint** в `docs_router.py` (колонка `extracted_text` є, потрібна таблиця версій)
|
||||
10. **Перевірити NATS subjects** в `docs/NATS_SUBJECTS.md` і зіставити з поточними з `docs/ADR_ARCHITECTURE_VNEXT.md §5`
|
||||
441
docs/audit/sofiia_intelligence_system_trace.md
Normal file
441
docs/audit/sofiia_intelligence_system_trace.md
Normal file
@@ -0,0 +1,441 @@
|
||||
# Sofiia CTO Agent — Intelligence System Trace (C)
|
||||
|
||||
> Generated: 2026-02-26 | Реконструкція "інтелектуальної системи" Sofiia
|
||||
|
||||
---
|
||||
|
||||
## Загальна схема мислення
|
||||
|
||||
```
|
||||
User Input (Telegram / Console / Voice)
|
||||
│
|
||||
▼
|
||||
[BFF: sofiia-console]
|
||||
Auth + Rate limit + Session
|
||||
│
|
||||
├─── Voice turn? ──► STT (memory-service) → sanitize_for_voice() → voice_fast_uk
|
||||
│
|
||||
└─── Text turn? ──► [Router /v1/agents/sofiia/infer]
|
||||
│
|
||||
┌────────────┴────────────┐
|
||||
│ │
|
||||
LLM selection Tool call?
|
||||
(profile-based) (tool_manager)
|
||||
│ │
|
||||
[LLM response] [Tool execution]
|
||||
│ │
|
||||
<think> strip RBAC check
|
||||
│ │
|
||||
Memory save Evidence
|
||||
│ │
|
||||
└────────┬────────────────┘
|
||||
│
|
||||
[Dialog Map update]
|
||||
(SQLite tree / future Postgres graph)
|
||||
│
|
||||
[Response to User]
|
||||
│
|
||||
[TTS if voice mode]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. Intent → Plan → Execute (Canonical CTO Flow)
|
||||
|
||||
### 1.1 Документовано
|
||||
- **Docs:** `AGENTS.md` §Example Commands, `docs/ADR_ARCHITECTURE_VNEXT.md` §3.1 CrewAI Workers
|
||||
- **Concept:** "Chat/Intent → Plan (Artifacts) → Execute as Job → Evidence → Dialog Map"
|
||||
- **vNext Design:** вся концепція описана в цьому сеансі розмови
|
||||
|
||||
### 1.2 Реалізовано
|
||||
- **Intent → Plan:** ✅ LLM inference через Router (`/v1/agents/sofiia/infer`)
|
||||
- **Plan → Execute (Ops):** ✅ `/api/ops/run` dispatches pre-defined actions
|
||||
- **Execute → Evidence:** ⚠️ частково — ops повертає result, але не зберігає як artifact
|
||||
- **Evidence → Dialog Map:** ❌ ops artifacts не зшиваються в dialog_nodes
|
||||
|
||||
### 1.3 Розриви
|
||||
- Немає загального **Job System** (тільки pre-defined ops actions)
|
||||
- Немає `repo_changesets` / `ops_runs` як артефактів у DB
|
||||
- Dialog Map не оновлюється автоматично від ops actions
|
||||
|
||||
---
|
||||
|
||||
## 2. Модулі Архітектури
|
||||
|
||||
### 2.1 BFF (sofiia-console)
|
||||
|
||||
**Документовано тут:**
|
||||
- `docs/runbook/sofiia-control-plane.md`
|
||||
- `docs/sofiia_ui_vnext_audit.md`
|
||||
- `docs/fabric_contract.md`
|
||||
|
||||
**Реалізовано тут:**
|
||||
- `services/sofiia-console/app/main.py` — FastAPI v0.3.0
|
||||
- `services/sofiia-console/app/config.py` — node registry, ENV loading
|
||||
- `docker-compose.node2-sofiia.yml` — deployment config
|
||||
|
||||
**Що BFF робить:**
|
||||
```
|
||||
1. API Gateway для UI (chat/voice/projects/ops/nodes)
|
||||
2. Session management (SQLite sofiia.db)
|
||||
3. Multi-provider LLM proxy (ollama/router/glm/grok)
|
||||
4. Voice pipeline (STT→LLM→TTS, Phase 2 streaming)
|
||||
5. Ops dispatcher (risk/pressure/backlog/notion/release)
|
||||
6. Multi-node health monitor (polling + WebSocket fan-out)
|
||||
7. Memory save (SQLite first, then Memory Service best-effort)
|
||||
```
|
||||
|
||||
**Розриви:**
|
||||
- Відсутній єдиний Job tracking (кожен ops action — one-shot, без persist)
|
||||
- Відсутній `repo_changesets` flow
|
||||
- `ops.html`, `chat.html`, `nodes.html` — fallback HTML, не окремі файли
|
||||
|
||||
---
|
||||
|
||||
### 2.2 LLM Routing
|
||||
|
||||
**Документовано тут:**
|
||||
- `services/router/router-config.yml`
|
||||
- `docs/architecture_inventory/01_SERVICE_CATALOG.md`
|
||||
- `docs/OPENAPI_CONTRACTS.md`
|
||||
|
||||
**Реалізовано тут:**
|
||||
- `services/router/main.py` — `/v1/agents/{agent_id}/infer`
|
||||
- `services/router/router-config.yml` — `sofiia:` entry
|
||||
|
||||
**Конфігурація Sofiia (router-config.yml):**
|
||||
```yaml
|
||||
sofiia:
|
||||
primary: cloud_grok # Grok API (Telegram mode)
|
||||
fallback: cloud_deepseek # DeepSeek API
|
||||
# Console mode може override через ollama
|
||||
```
|
||||
|
||||
**Voice profiles:**
|
||||
```yaml
|
||||
voice_fast_uk:
|
||||
prefer_models: [gemma3:latest, qwen3.5:35b-a3b, qwen3:14b]
|
||||
deadline_ms: 9000
|
||||
max_tokens: 256
|
||||
|
||||
voice_quality_uk:
|
||||
prefer_models: [qwen3.5:35b-a3b, qwen3:14b]
|
||||
deadline_ms: 12000
|
||||
max_tokens: 256
|
||||
```
|
||||
|
||||
**Розриви:**
|
||||
- Відсутній профіль для `repo_changeset` (long-form, structured output)
|
||||
- Відсутній профіль для `plan_generation` (CTO structured plans)
|
||||
|
||||
---
|
||||
|
||||
### 2.3 Tool System
|
||||
|
||||
**Документовано тут:**
|
||||
- `AGENTS.md` §Tool List
|
||||
- `docs/architecture_inventory/02_TOOL_CATALOG.md`
|
||||
- `config/rbac_tools_matrix.yml`
|
||||
|
||||
**Реалізовано тут:**
|
||||
- `services/router/tool_manager.py` — TOOL_DEFINITIONS + execution
|
||||
- `services/router/agent_tools_config.py` — per-agent allowlists
|
||||
|
||||
**RBAC роль `agent_cto`** (39 permissions):
|
||||
```
|
||||
docs: read ops: read/exec_safe
|
||||
repo: read jobs: smoke/drift/backup/deploy
|
||||
kb: read risk: read/write
|
||||
pr_review: use pressure: read/write
|
||||
contract: use backlog: read/write/admin
|
||||
config_lint: use deps: read/gate
|
||||
threatmodel: use cost: read/gate
|
||||
observability drift: read/gate
|
||||
incidents: write alerts: ingest/read/ack/claim
|
||||
```
|
||||
|
||||
**Sofiia спеціалізовані tools (agent_tools_config.py):**
|
||||
```python
|
||||
AGENT_SPECIALIZED_TOOLS["sofiia"] = [
|
||||
"comfy_generate_image",
|
||||
"comfy_generate_video",
|
||||
"risk_engine_tool",
|
||||
"architecture_pressure_tool",
|
||||
"backlog_tool",
|
||||
"job_orchestrator_tool",
|
||||
"dependency_scanner_tool",
|
||||
"incident_intelligence_tool",
|
||||
"cost_analyzer_tool",
|
||||
"pieces_tool",
|
||||
"notion_tool",
|
||||
]
|
||||
```
|
||||
|
||||
**FULL_STANDARD_STACK** (16 tools available to all agents):
|
||||
```
|
||||
memory_search, graph_query, web_search, web_extract, crawl4ai_scrape,
|
||||
remember_fact, image_generate, tts_speak, presentation_create/status/download,
|
||||
file_tool, repo_tool, pr_reviewer_tool, contract_tool, oncall_tool,
|
||||
observability_tool, config_linter_tool, threatmodel_tool, job_orchestrator_tool,
|
||||
kb_tool, drift_analyzer_tool, pieces_tool
|
||||
```
|
||||
|
||||
**Розриви:**
|
||||
- Відсутній `repo_changeset_tool` (create/patch/plan/pr)
|
||||
- Відсутній `ops_job_tool` (start/status/cancel з job tracking)
|
||||
- `job_orchestrator_tool` є, але не пов'язаний з Dialog Map artifact creation
|
||||
|
||||
---
|
||||
|
||||
### 2.4 Memory System
|
||||
|
||||
**Документовано тут:**
|
||||
- `docs/ADR_ARCHITECTURE_VNEXT.md` §2.5 Memory Service
|
||||
- `docs/MEMORY_API_POLICY.md`
|
||||
- `docs/AGENT-MEMORY-STANDARD.md`
|
||||
|
||||
**Реалізовано тут:**
|
||||
- `services/memory-service/app/main.py` — threads/events/memories/facts/agents
|
||||
- `services/memory-service/app/vector_store.py` — Qdrant
|
||||
- `docker-compose.memory-node2.yml` — Postgres + Qdrant + Neo4j
|
||||
|
||||
**3 рівні пам'яті (згідно ADR):**
|
||||
|
||||
| Рівень | Qdrant | Neo4j | Postgres |
|
||||
|--------|--------|-------|----------|
|
||||
| Personal | `user_{id}_*` | `:User` nodes | `user_facts`, `user_sessions` |
|
||||
| Team/DAO | `team_{id}_*` | `:Team`, `:Project` | `team_facts`, `team_quotas` |
|
||||
| Public | `public_*` | `:Public` | `indexed_content` |
|
||||
|
||||
**Реальні колекції (NODA2):**
|
||||
- `sofiia_messages` — 1183+ points
|
||||
- `sofiia_summaries`
|
||||
- Memory Service Postgres (port 5433, db `daarion_memory`)
|
||||
|
||||
**Console-рівень пам'яті (SQLite `sofiia.db`):**
|
||||
```sql
|
||||
projects, documents, sessions, messages
|
||||
```
|
||||
|
||||
**Розриви:**
|
||||
- Team/DAO namespace: описаний в ADR, реалізований лише для Personal
|
||||
- E2EE для confidential: тільки в ADR, не реалізовано
|
||||
- BFF і Memory Service "знають" одне про одного, але sync неповний
|
||||
|
||||
---
|
||||
|
||||
### 2.5 Planning System (Supervisor)
|
||||
|
||||
**Документовано тут:**
|
||||
- `docs/supervisor/langgraph_supervisor.md`
|
||||
- `docs/supervisor/postmortem_draft_graph.md`
|
||||
|
||||
**Реалізовано тут:**
|
||||
- `services/sofiia-supervisor/app/main.py`
|
||||
- `services/sofiia-supervisor/app/graphs/`
|
||||
|
||||
**Доступні LangGraph графи:**
|
||||
```
|
||||
alert_triage → класифікація/ескалація алертів
|
||||
incident_triage → тріаж інцидентів (SLO, labels, owners)
|
||||
postmortem_draft → автогенерація postmortem документа
|
||||
release_check → pre-release gate checks
|
||||
```
|
||||
|
||||
**Архітектура (загальна):**
|
||||
```
|
||||
Event/Trigger → LangGraph Node → State update → Next Node
|
||||
↓ ↓
|
||||
NATS event Tool calls (via gateway_client)
|
||||
Memory writes
|
||||
Structured output (JSON)
|
||||
```
|
||||
|
||||
**Розриви:**
|
||||
- Немає `cto_intent_graph` (intent → plan → execute)
|
||||
- Немає `repo_changeset_graph` (diff → plan → PR)
|
||||
- Немає `dialog_map_builder_graph` (events → nodes/edges)
|
||||
- Supervisor ізольований від BFF (не інтегрований у `/api/ops/run`)
|
||||
|
||||
---
|
||||
|
||||
## 3. Policies (Безпека, Дозволи, Approval)
|
||||
|
||||
### 3.1 Документовано
|
||||
- `docs/PRIVACY_GATE.md` — Privacy Gate middleware
|
||||
- `docs/ADR_ARCHITECTURE_VNEXT.md` §4 Privacy Gate
|
||||
- `docs/AGENT_RUNTIME_POLICY.md`
|
||||
- `config/rbac_tools_matrix.yml`
|
||||
- `config/data_governance_policy.yml`
|
||||
- `config/risk_policy.yml`
|
||||
|
||||
### 3.2 Реалізовано
|
||||
- RBAC tool allowlist: ✅ `agent_tools_config.py`
|
||||
- API key auth: ✅ `auth.py`
|
||||
- Rate limiting: ✅ per-endpoint
|
||||
- Upload sanitization: ✅ mime + filename + size
|
||||
- Voice guardrails: ✅ `sanitize_for_voice()`
|
||||
- Config linter (secrets detection): ✅ `tool_manager.py`
|
||||
|
||||
### 3.3 Не реалізовано
|
||||
- **Privacy Gate middleware** (перевірка `mode=confidential` в Router): 📄 описаний, не реалізований
|
||||
- **2-step Plan → Apply flow**: 📄 описаний як "dangerous actions", не реалізований
|
||||
- **E2EE client-side encryption**: 📄 тільки ADR, не реалізований
|
||||
- **Confidential doc indexing block**: 📄 тільки ADR, не реалізований
|
||||
|
||||
---
|
||||
|
||||
## 4. Event Model
|
||||
|
||||
### 4.1 Документовано
|
||||
- `docs/ADR_ARCHITECTURE_VNEXT.md` §5 NATS Standards
|
||||
- `docs/NATS_SUBJECTS.md`
|
||||
- `docs/NATS_SUBJECT_MAP.md`
|
||||
|
||||
### 4.2 NATS Subjects (ADR canonical)
|
||||
```
|
||||
message.created.{channel_id} # chat messages
|
||||
attachment.created.{type} # uploaded files
|
||||
agent.run.requested.{agent_id} # agent activation
|
||||
agent.run.completed.{agent_id}
|
||||
quota.consumed.{user_id}
|
||||
audit.{service}.{action} # append-only audit
|
||||
ops.health.{service}
|
||||
ops.alert.{severity}
|
||||
```
|
||||
|
||||
### 4.3 Fabric Subjects (реалізовані у node-worker)
|
||||
```
|
||||
node.{id}.llm.request # LLM offload
|
||||
node.{id}.tts.request # TTS offload
|
||||
node.{id}.stt.request # STT offload
|
||||
node.{id}.voice.llm.request # Voice LLM (dedicated)
|
||||
node.{id}.voice.tts.request # Voice TTS (dedicated)
|
||||
node.{id}.voice.stt.request # Voice STT (dedicated)
|
||||
node.{id}.ocr.request # OCR offload
|
||||
node.{id}.crawl.request # Crawl offload
|
||||
node.{id}.image.request # Image generation
|
||||
```
|
||||
|
||||
### 4.4 Розриви
|
||||
- `attachment.created` — реалізований частково (upload зберігає файл, але не публікує у NATS)
|
||||
- `task_create`, `doc_upsert`, `meeting_create` — не реалізовані (потрібні для Dialog Map auto-edge)
|
||||
- `agent.run.requested` → legacy flat subject ще може бути в деяких шляхах (відомий drift)
|
||||
- Dialog Map не підписаний на NATS events
|
||||
|
||||
---
|
||||
|
||||
## 5. Memory Architecture (деталізована)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ Sofiia Memory Layers │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Layer 0: Working Context (per-turn) │
|
||||
│ - history[-12:] in BFF request │
|
||||
│ - sanitize_for_voice() for voice turns │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Layer 1: Session Memory (sofiia-console SQLite) │
|
||||
│ Tables: projects, documents, sessions, messages │
|
||||
│ TTL: indefinite (volume-backed) │
|
||||
│ Fork: parent_msg_id для branching │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Layer 2: Long-term Memory (Memory Service) │
|
||||
│ Qdrant: sofiia_messages (1183+ vectors) │
|
||||
│ sofiia_summaries │
|
||||
│ Postgres: daarion_memory DB (facts, threads, events) │
|
||||
│ Neo4j: agent memory graph (infrastructure ready) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Layer 3: Factual Memory (Key-Value) │
|
||||
│ /facts/upsert, /facts/{key} │
|
||||
│ Rolling summaries via /threads/{id}/summarize │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Namespaces (implemented):**
|
||||
- `sofiia_messages` — agent-specific collection
|
||||
- Загальний: `{agent_id}_{type}` pattern
|
||||
|
||||
**Sync між Layer 1 і Layer 2:**
|
||||
- `_do_save_memory()` у `main.py`: спочатку SQLite, потім Memory Service (best-effort)
|
||||
- Немає зворотнього sync (Memory Service → SQLite)
|
||||
- Немає конфліктів (append-only обидва)
|
||||
|
||||
---
|
||||
|
||||
## 6. Dialog Map Intelligence
|
||||
|
||||
### Поточна реалізація (Phase 1)
|
||||
```
|
||||
SQLite messages table (parent_msg_id = branching)
|
||||
↓
|
||||
GET /api/sessions/{sid}/map
|
||||
↓
|
||||
Python: build_tree(messages) → nodes/edges
|
||||
↓
|
||||
UI: <details><summary> tree
|
||||
```
|
||||
|
||||
### Цільова реалізація (vNext Phase 2)
|
||||
```
|
||||
NATS events (task_create, doc_upsert, meeting_create)
|
||||
↓
|
||||
Dialog Map Builder (новий сервіс або Supervisor граф)
|
||||
↓
|
||||
Postgres: dialog_nodes + dialog_edges
|
||||
↓
|
||||
GET /projects/{id}/dialog-map
|
||||
↓
|
||||
UI: D3/Cytoscape canvas + live WS updates
|
||||
```
|
||||
|
||||
**Node types (vNext):**
|
||||
- `message` — chat message
|
||||
- `task` — задача
|
||||
- `doc` — документ/wiki
|
||||
- `meeting` — зустріч
|
||||
- `agent_run` — виклик агента
|
||||
- `decision` — ADR/рішення
|
||||
- `goal` — ціль/OKR
|
||||
|
||||
**Edge types (vNext):**
|
||||
- `references` — A посилається на B
|
||||
- `resolves` — A вирішує B
|
||||
- `derives_task` — повідомлення → задача
|
||||
- `updates_doc` — action → doc version
|
||||
- `schedules` — message → meeting
|
||||
- `summarizes` — rollup вузол
|
||||
|
||||
---
|
||||
|
||||
## 7. Preflight-First Policy
|
||||
|
||||
**Документовано тут:**
|
||||
- `ops/fabric_preflight.sh`
|
||||
- `docs/fabric_contract.md`
|
||||
|
||||
**Принцип:** "Zero assumptions" — перед будь-яким deploy/change:
|
||||
1. Запустити `ops/fabric_preflight.sh`
|
||||
2. Перевірити моделі (VOICE_REQUIRED_MODELS fail / VOICE_PREFERRED_MODELS warn)
|
||||
3. Перевірити `ops/fabric_snapshot.py --save`
|
||||
4. Тільки потім deploy
|
||||
|
||||
**Реалізовано:**
|
||||
- `ops/fabric_preflight.sh` — перевірки моделей, voice health, canary
|
||||
- `ops/scripts/voice_canary.py` — runtime canary (кожні 5–10 хв)
|
||||
- `ops/voice_latency_audit.sh` — 10-сценарний latency audit
|
||||
|
||||
---
|
||||
|
||||
## Next Actions for UI Team (1–2 days)
|
||||
|
||||
1. **Ознайомитись із Supervisor API** (`/v1/graphs/{name}/runs`) — це готовий "job runner" для CTO workflows
|
||||
2. **Розширити Supervisor**: додати `cto_intent_graph` на базі `release_check_graph` (спільна структура)
|
||||
3. **NATS attachment events**: при upload в `docs_router.py` — публікувати `attachment.created` (1 рядок коду)
|
||||
4. **Dialog Map NATS listener**: простий consumer що upsert-ить SQLite nodes при events
|
||||
5. **`docs_versions` table**: ALTER TABLE + endpoint — 1–2 год роботи
|
||||
6. **Privacy Gate stub**: додати перевірку `mode` поля в BFF, навіть якщо без шифрування
|
||||
7. **Plan → Apply pattern**: для ops actions — показувати "план" перед запуском
|
||||
8. **`agent_id` нормалізація**: замінити `"l"` на `"sofiia"` в node2 router-config.yml
|
||||
9. **Memory sync**: додати endpoint для завантаження Sofiia memory з Memory Service у SQLite
|
||||
10. **CTO Panel**: mock `/api/repo/changesets` і `/api/ops/runs` endpoints для UI розробки
|
||||
192
docs/audit/sofiia_state_of_implementation.md
Normal file
192
docs/audit/sofiia_state_of_implementation.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# Sofiia CTO Agent — State of Implementation (B)
|
||||
|
||||
> Generated: 2026-02-26 | Legend: ✅ Implemented | ⚠️ Partial | 📄 Documented Only | ❌ Not Found
|
||||
|
||||
---
|
||||
|
||||
## 1. Identity & System Prompt
|
||||
|
||||
| Feature | Status | Evidence | Risk |
|
||||
|---------|--------|----------|------|
|
||||
| Sofiia identity (AGENTS.md) | ✅ Implemented | `AGENTS.md` — CTO-агент, NODA1/2/3, capabilities | — |
|
||||
| Telegram system prompt | ✅ Implemented | `gateway-bot/sofiia_prompt.txt` (138KB) | — |
|
||||
| Control Console system prompt | ✅ Implemented | `services/sofiia-console/app/main.py` lines 138–177 | — |
|
||||
| Voice turn prompt suffix | ✅ Implemented | `main.py` `SOFIIA_VOICE_PROMPT_SUFFIX` — max 2 sentences, no markdown | — |
|
||||
| Agent ID consistency | ⚠️ Partial | `"sofiia"` у production, `"l"` у node2-конфігурації та тестах | ⚠️ Confusion risk |
|
||||
| NODA3 integration | 📄 Documented Only | `AGENTS.md` описує NODA3 (IP, GPU, models), але немає compose/config | 🔴 Blocking |
|
||||
|
||||
---
|
||||
|
||||
## 2. Control Console (BFF)
|
||||
|
||||
| Feature | Status | Evidence | Risk |
|
||||
|---------|--------|----------|------|
|
||||
| FastAPI BFF основа | ✅ Implemented | `sofiia-console/app/main.py` v0.3.0, 1800 рядків | — |
|
||||
| Chat: Ollama/Router/GLM/Grok | ✅ Implemented | `/api/chat/send`, providers: ollama, router, glm, grok | — |
|
||||
| Chat: history (client-side) | ✅ Implemented | `body.history[-12:]` передається клієнтом | — |
|
||||
| Chat: session persist (SQLite) | ✅ Implemented | `_do_save_memory` → `db.save_message`, `db.upsert_session` | — |
|
||||
| Chat: session restore on page reload | ✅ Implemented | `GET /api/chat/history`, localStorage session_id | — |
|
||||
| Ops: risk/pressure/backlog/release | ✅ Implemented | `/api/ops/run` + `ops.py` dispatcher | — |
|
||||
| Ops: Notion actions | ✅ Implemented | notion_status/create_task/create_page/create_database | — |
|
||||
| Hub: integrations status | ✅ Implemented | `/api/integrations/status` — Router, Memory, OpenWebUI, Pieces, OpenCode, Notion | — |
|
||||
| Nodes: dashboard | ✅ Implemented | `/api/nodes/dashboard` з caching, multi-node poll | — |
|
||||
| Nodes: SSH status | ✅ Implemented | `/api/nodes/ssh/status` (strict auth) | — |
|
||||
| Nodes: add node | ✅ Implemented | `/api/nodes/add` | — |
|
||||
| Nodes: remove node | ❌ Not Found | Тільки add, без delete | ⚠️ Minor gap |
|
||||
| Memory: status | ✅ Implemented | `/api/memory/status` | — |
|
||||
| Memory: context | ✅ Implemented | `/api/memory/context` | — |
|
||||
| WebSocket event bus | ✅ Implemented | `/ws/events` — nodes.status, chat.reply, voice.*, ops.run | — |
|
||||
| Rate limiting | ✅ Implemented | per-endpoint limiters: 30/min chat, 15/min stream, 30/min TTS | — |
|
||||
| API key auth | ✅ Implemented | `auth.py` + strict mode | — |
|
||||
|
||||
---
|
||||
|
||||
## 3. Voice Layer
|
||||
|
||||
| Feature | Status | Evidence | Risk |
|
||||
|---------|--------|----------|------|
|
||||
| STT proxy | ✅ Implemented | `POST /api/voice/stt` → memory-service | — |
|
||||
| TTS proxy | ✅ Implemented | `POST /api/voice/tts` (legacy + HA path) | — |
|
||||
| Voice streaming Phase 2 | ✅ Implemented | `POST /api/voice/chat/stream` — split → first TTS | — |
|
||||
| Voice policy (voice_fast_uk/quality_uk) | ✅ Implemented | `router-config.yml`, `test_voice_policy.py` 23/23 | — |
|
||||
| Voice guardrails (2 sentences) | ✅ Implemented | `SOFIIA_VOICE_PROMPT_SUFFIX`, `sanitize_for_voice()` | — |
|
||||
| `<think>` stripping | ✅ Implemented | `voice_utils.py` + Router `_clean_think_blocks` | — |
|
||||
| Degradation state machine | ✅ Implemented | `_VoiceDegradationSM` (ok/degraded_tts/degraded_llm/fast_lock/emergency) | — |
|
||||
| TTFA telemetry | ✅ Implemented | `POST /api/telemetry/voice` + Prometheus metrics | — |
|
||||
| Voice HA (multi-node routing) | ✅ Implemented | `VOICE_HA_ENABLED` flag, Router `/v1/capability/voice_*` | — |
|
||||
| Remote voice badge | ✅ Implemented | `X-Voice-Mode: remote` header → `🌐 noda1` badge | — |
|
||||
| Voice canary | ✅ Implemented | `ops/scripts/voice_canary.py` (preflight + runtime mode) | — |
|
||||
| Grafana voice dashboard | ✅ Implemented | `ops/grafana_voice_dashboard.json` | — |
|
||||
| Voice alerts (Prometheus) | ✅ Implemented | `ops/voice_alerts.yml` (6 rules) | — |
|
||||
| SLO definitions | ✅ Implemented | `config/slo_policy.yml` voice_fast_uk / voice_quality_uk | — |
|
||||
| Rate limit / DoS guard | ✅ Implemented | semaphore, per-IP limiter, `rest_chunks ≤ 8` cap | — |
|
||||
|
||||
---
|
||||
|
||||
## 4. Projects, Documents, Sessions
|
||||
|
||||
| Feature | Status | Evidence | Risk |
|
||||
|---------|--------|----------|------|
|
||||
| Projects CRUD | ✅ Implemented | `docs_router.py`: GET/POST/PATCH `/api/projects` | — |
|
||||
| Documents CRUD | ✅ Implemented | upload, list, get, keyword search | — |
|
||||
| File upload (multipart) | ✅ Implemented | `POST /api/files/upload` — sha256, mime detect, size limit | — |
|
||||
| Text extraction (PDF/DOCX/TXT) | ✅ Implemented | `_extract_text_simple()` у docs_router | — |
|
||||
| Sessions persistence | ✅ Implemented | `upsert_session`, `save_message`, SQLite `sofiia.db` | — |
|
||||
| Chat history restore | ✅ Implemented | `GET /api/chat/history?session_id=...` | — |
|
||||
| Dialog Map (tree) | ✅ Implemented | `GET /api/sessions/{sid}/map` → nodes/edges | — |
|
||||
| Dialog Map (canvas/D3) | ❌ Not Found | Поточний — `<details>` collapsible tree тільки | Phase 2 |
|
||||
| Session fork | ✅ Implemented | `POST /api/sessions/{sid}/fork` | — |
|
||||
| Projects sidebar (chat UI) | ✅ Implemented | `#sidebarProjectList` у `index.html` | — |
|
||||
| Projects section (full UI) | ✅ Implemented | `#section-projects` з tabs: docs, sessions, map | — |
|
||||
| Fabric OCR для uploaded images | ⚠️ Feature Flag Off | `USE_FABRIC_OCR=false` за замовч. | Low risk |
|
||||
| Qdrant embeddings для docs | ⚠️ Feature Flag Off | `USE_EMBEDDINGS=false` за замовч. | Low risk |
|
||||
| Docs versions (history) | ❌ Not Found | `docs_versions` таблиця відсутня | 🔴 vNext gap |
|
||||
| Docs backlinks (entity_links) | ❌ Not Found | `docs_links`/`entity_links` таблиця відсутня | 🔴 vNext gap |
|
||||
| `doc_index_state` table | ❌ Not Found | Відсутня | 🔴 vNext gap |
|
||||
| Semantic search (Meilisearch) | ❌ Not Found | Тільки SQL LIKE keyword search | 📄 ADR describes it |
|
||||
|
||||
---
|
||||
|
||||
## 5. CTO-specific Capabilities (Repo/Ops)
|
||||
|
||||
| Feature | Status | Evidence | Risk |
|
||||
|---------|--------|----------|------|
|
||||
| `repo_tool` (read-only) | ✅ Implemented | `tool_manager.py` — tree/read/search/metadata | — |
|
||||
| `pr_reviewer_tool` | ✅ Implemented | `tool_manager.py` — blocking_only/full_review | — |
|
||||
| `contract_tool` (OpenAPI) | ✅ Implemented | `tool_manager.py` — lint_openapi/diff_openapi/generate_client_stub | — |
|
||||
| `oncall_tool` | ✅ Implemented | services_list/health/runbook_search/incident_log | — |
|
||||
| `observability_tool` | ✅ Implemented | Prometheus/Loki/Tempo queries | — |
|
||||
| `config_linter_tool` | ✅ Implemented | Secrets detection, policy violations | — |
|
||||
| `threatmodel_tool` | ✅ Implemented | STRIDE-based threat modeling | — |
|
||||
| `job_orchestrator_tool` | ✅ Implemented | smoke/drift/backup/deploy tasks | — |
|
||||
| `kb_tool` | ✅ Implemented | ADR/docs search | — |
|
||||
| `drift_analyzer_tool` | ✅ Implemented | Infrastructure drift detection | — |
|
||||
| `risk_engine_tool` | ✅ Implemented | Risk scoring | — |
|
||||
| `architecture_pressure_tool` | ✅ Implemented | Architecture health analysis | — |
|
||||
| `backlog_tool` | ✅ Implemented | Backlog generation/management | — |
|
||||
| `dependency_scanner_tool` | ✅ Implemented | Dependency security scan | — |
|
||||
| `incident_intelligence_tool` | ✅ Implemented | Incident correlation | — |
|
||||
| `cost_analyzer_tool` | ✅ Implemented | Cost analysis | — |
|
||||
| `notion_tool` | ✅ Implemented | Notion pages/tasks/databases | — |
|
||||
| **`repo_changesets`** (CTO workflow) | ❌ Not Found | Тільки описано в vNext design | 🔴 Blocking |
|
||||
| **`ops_runs` API** | ❌ Not Found | Тільки `ops.py` dispatcher (не як job system) | 🔴 Blocking |
|
||||
| **`pull_requests` API** | ❌ Not Found | PR Review tool є, але PR object як артефакт — немає | 🔴 vNext gap |
|
||||
| **`entity_links`** | ❌ Not Found | Concept described, not implemented | 🔴 vNext gap |
|
||||
| Direct NODA3 integration | ❌ Not Found | Описано в AGENTS.md, відсутній docker-compose/router config | 🔴 |
|
||||
|
||||
---
|
||||
|
||||
## 6. Supervisor (LangGraph)
|
||||
|
||||
| Feature | Status | Evidence | Risk |
|
||||
|---------|--------|----------|------|
|
||||
| Alert triage graph | ✅ Implemented | `alert_triage_graph.py` + tests | — |
|
||||
| Incident triage graph | ✅ Implemented | `incident_triage_graph.py` + tests | — |
|
||||
| Postmortem draft graph | ✅ Implemented | `postmortem_draft_graph.py` + tests | — |
|
||||
| Release check graph | ✅ Implemented | `release_check_graph.py` + tests | — |
|
||||
| Supervisor API | ✅ Implemented | `/v1/graphs/{name}/runs` | — |
|
||||
| **CTO workflow graph** (intent→plan→execute) | ❌ Not Found | Описано в vNext design, немає реалізації | 🔴 vNext gap |
|
||||
| **Repo changeset graph** | ❌ Not Found | Тільки в дизайн-доці | 🔴 vNext gap |
|
||||
|
||||
---
|
||||
|
||||
## 7. Memory System
|
||||
|
||||
| Feature | Status | Evidence | Risk |
|
||||
|---------|--------|----------|------|
|
||||
| Short-term memory (threads/events) | ✅ Implemented | Memory Service `/threads`, `/events` | — |
|
||||
| Long-term memory (Qdrant) | ✅ Implemented | `/memories` + semantic search | — |
|
||||
| Facts store | ✅ Implemented | `/facts/upsert`, `/facts/{key}` | — |
|
||||
| Agent memory (Postgres + Neo4j) | ✅ Implemented | `/agents/{id}/memory` | — |
|
||||
| Rolling summaries | ✅ Implemented | `/threads/{id}/summarize` | — |
|
||||
| Neo4j graph memory | ✅ Infrastructure Ready | docker-compose.memory-node2.yml | Не тестований |
|
||||
| **Personal namespace** | ⚠️ Partial | ADR описує `user_{id}_*` collections, реалізація через `user_id` param | — |
|
||||
| **Team/DAO namespace** | 📄 Documented Only | ADR, не реалізовано в code | 🔴 vNext gap |
|
||||
| **E2EE (confidential docs)** | 📄 Documented Only | ADR + PRIVACY_GATE.md, не реалізовано | 🔴 vNext gap |
|
||||
|
||||
---
|
||||
|
||||
## 8. Infrastructure
|
||||
|
||||
| Feature | Status | Evidence | Risk |
|
||||
|---------|--------|----------|------|
|
||||
| NODA2 Docker stack | ✅ Implemented | `docker-compose.node2-sofiia.yml` | — |
|
||||
| NODA1 health + SSH | ✅ Implemented | nodes.py + SSH key auth | — |
|
||||
| Prometheus metrics | ✅ Implemented | fabric_metrics.py (router + node-worker), voice metrics | — |
|
||||
| NATS subjects | ✅ Implemented | Fabric node.{id}.*.request subjects | — |
|
||||
| Voice HA semaphores | ✅ Implemented | node-worker separate voice semaphores | — |
|
||||
| sofiia-data volume | ✅ Implemented | docker-compose.node2-sofiia.yml sofiia-data:/app/data | — |
|
||||
| Postgres для sofiia docs | ⚠️ SQLite Only | Phase 1: SQLite у sofiia-console, Postgres для Memory Service | Phase 2 needed |
|
||||
| S3/MinIO storage | ❌ Not Found | ADR описує, upload зараз у volume | 🔴 Phase 2 |
|
||||
| Meilisearch | ❌ Not Found | ADR описує для search, не розгорнутий | 🔴 vNext |
|
||||
| Control Plane service | ❌ Not Found | ADR 1.1-1.3, reference у security audit | 🔴 vNext |
|
||||
|
||||
---
|
||||
|
||||
## 9. Security
|
||||
|
||||
| Feature | Status | Evidence | Risk |
|
||||
|---------|--------|----------|------|
|
||||
| RBAC per agent | ✅ Implemented | `rbac_tools_matrix.yml` agent_cto (39 permissions) | — |
|
||||
| Tool allowlist per agent | ✅ Implemented | `agent_tools_config.py` AGENT_SPECIALIZED_TOOLS["sofiia"] | — |
|
||||
| API key auth | ✅ Implemented | `auth.py` — console + strict modes | — |
|
||||
| Upload sanitization (filename/mime) | ✅ Implemented | `_safe_filename()`, `_detect_mime()` у docs_router | — |
|
||||
| Rate limiting | ✅ Implemented | per-endpoint + semaphore + `rest_chunks ≤ 8` | — |
|
||||
| **E2EE (confidential)** | ❌ Not Found | Privacy Gate описаний в ADR, не реалізований | 🔴 |
|
||||
| **2-step approval для dangerous actions** | ❌ Not Found | ADR описує Plan → Apply flow | 🔴 vNext |
|
||||
| Audit log (append-only) | ⚠️ Partial | audit.py у agromatrix crew, `audit.{service}.{action}` NATS — частково | 🔴 |
|
||||
|
||||
---
|
||||
|
||||
## Next Actions for UI Team (1–2 days)
|
||||
|
||||
1. **Зверніть увагу**: `repo_changesets`, `ops_runs`, `entity_links` — **не існують**. UI CTO panel потребує mock endpoints
|
||||
2. **Quick win**: `docs_versions` таблиця — 30хв роботи (ALTER TABLE + endpoint у docs_router.py)
|
||||
3. **Quick win**: увімкнути `USE_EMBEDDINGS=true` в docker-compose для реального vector search
|
||||
4. **Перевірити** соfiia agent_id у тестах: `"l"` vs `"sofiia"` — потрібна нормалізація
|
||||
5. **Postgres migration**: коли sofiia-console готова до Postgres, потрібен `DATABASE_URL` env + аналогічний `init_db()`
|
||||
6. **E2EE**: перед вмиканням confidential docs — треба спроєктувати ключі (client-side only)
|
||||
7. **Dialog Map Phase 2**: canvas rendering (D3/Cytoscape) — `<details>` tree є, але не масштабується
|
||||
8. **Meilisearch**: поки `LIKE` search, але коли кількість docs зросте — потрібен реальний search index
|
||||
9. **NODA3**: додати до `nodes_registry.yml` і `docker-compose.node2-sofiia.yml` (якщо NODA3 реально доступна)
|
||||
10. **CTO workflow graph**: перший крок — alert_triage граф вже є, на його основі зробити `cto_intent_graph`
|
||||
248
docs/audit/ui_vnext_dependency_map.md
Normal file
248
docs/audit/ui_vnext_dependency_map.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# Sofiia UI vNext — Dependency Map (D)
|
||||
|
||||
> Generated: 2026-02-26 | Карта залежностей UI → Backend → DB → Events
|
||||
|
||||
---
|
||||
|
||||
## Легенда
|
||||
|
||||
| Символ | Значення |
|
||||
|--------|----------|
|
||||
| ✅ | Endpoint/Model реалізований |
|
||||
| ⚠️ | Частково реалізований або за feature flag |
|
||||
| ❌ | Відсутній, потрібна реалізація |
|
||||
| 🔧 | Потрібне виправлення/доопрацювання |
|
||||
| 📄 | Тільки документований |
|
||||
|
||||
---
|
||||
|
||||
## Таблиця 1: Chat & Voice
|
||||
|
||||
| UI Feature | Expected API/Event | Found? | Evidence | Action |
|
||||
|-----------|-------------------|--------|----------|--------|
|
||||
| Text chat | `POST /api/chat/send` | ✅ | `main.py` | — |
|
||||
| Voice STT (WebM) | `POST /api/voice/stt` | ✅ | `main.py` → memory-service | — |
|
||||
| Voice TTS | `POST /api/voice/tts` | ✅ | `main.py` (legacy + HA) | — |
|
||||
| Voice Phase 2 stream | `POST /api/voice/chat/stream` | ✅ | `main.py` | — |
|
||||
| Voice stop/abort | AbortController + `POST /api/voice/tts` cancel | ✅ | `index.html` JS | — |
|
||||
| TTFA telemetry | `POST /api/telemetry/voice` | ✅ | `main.py` | — |
|
||||
| Batch telemetry | `POST /api/telemetry/voice/batch` | ✅ | `main.py` | — |
|
||||
| Degradation badge | `GET /api/voice/degradation_status` | ✅ | `main.py` | — |
|
||||
| Remote voice badge | `X-Voice-Mode: remote` header | ✅ | `main.py` + `index.html` | — |
|
||||
| Model selector UI | inline models list | ✅ | `index.html` (hardcoded) | 🔧 Should come from `/api/models` |
|
||||
| Chat history restore | `GET /api/chat/history?session_id=` | ✅ | `docs_router.py` | — |
|
||||
| Session persistence | localStorage `session_id` | ✅ | `index.html` | — |
|
||||
| Memory status | `GET /api/memory/status` | ✅ | `main.py` | — |
|
||||
|
||||
---
|
||||
|
||||
## Таблиця 2: Projects
|
||||
|
||||
| UI Feature | Expected API/Event | Found? | Evidence | Action |
|
||||
|-----------|-------------------|--------|----------|--------|
|
||||
| Projects list | `GET /api/projects` | ✅ | `docs_router.py` | — |
|
||||
| Create project | `POST /api/projects` | ✅ | `docs_router.py` | — |
|
||||
| Get project | `GET /api/projects/{id}` | ✅ | `docs_router.py` | — |
|
||||
| Update project | `PATCH /api/projects/{id}` | ✅ | `docs_router.py` | — |
|
||||
| Delete project | `DELETE /api/projects/{id}` | ❌ | Not found | implement |
|
||||
| Projects sidebar | `GET /api/projects` (on load) | ✅ | `index.html` `loadSidebarProjects()` | — |
|
||||
| Project switcher | localStorage `project_id` | ✅ | `index.html` | — |
|
||||
| **Board (Kanban)** | `GET /api/projects/{id}/tasks` | ❌ | Not found | implement or mock |
|
||||
| **Tasks CRUD** | `/api/projects/{id}/tasks` | ❌ | Not found | implement |
|
||||
| **Meetings** | `GET /api/projects/{id}/meetings` | ❌ | Not found | implement or mock |
|
||||
| **Meeting create** | `POST /api/meetings` | ❌ | Not found | implement |
|
||||
| **Meeting reminders** | NATS `meeting.reminder.*` | ❌ | Not found | Phase 2 |
|
||||
| Project settings | `PATCH /api/projects/{id}` | ✅ | `docs_router.py` | — |
|
||||
|
||||
---
|
||||
|
||||
## Таблиця 3: Documents DB
|
||||
|
||||
| UI Feature | Expected API/Event | Found? | Evidence | Action |
|
||||
|-----------|-------------------|--------|----------|--------|
|
||||
| Upload file | `POST /api/files/upload` (multipart) | ✅ | `docs_router.py` | — |
|
||||
| List documents | `GET /api/projects/{id}/documents` | ✅ | `docs_router.py` | — |
|
||||
| Get document | `GET /api/projects/{id}/documents/{doc_id}` | ✅ | `docs_router.py` | — |
|
||||
| Download file | `GET /api/files/{file_id}/download` | ✅ | `docs_router.py` | — |
|
||||
| Search docs | `POST /api/projects/{id}/search` | ✅ | `docs_router.py` (SQL LIKE) | 🔧 Needs semantic search |
|
||||
| Delete document | `DELETE /api/projects/{id}/documents/{doc_id}` | ❌ | Not found | implement |
|
||||
| **Doc versioning** | `GET /docs/{id}/versions` | ❌ | Not found | implement (DDL needed) |
|
||||
| **Restore version** | `POST /docs/{id}/restore` | ❌ | Not found | implement |
|
||||
| **Doc diff** | `GET /docs/{id}/diff?from=&to=` | ❌ | Not found | Phase 2 |
|
||||
| **Backlinks (entity_links)** | `POST /docs/{id}/links` | ❌ | Not found | implement |
|
||||
| **"Index for AI" toggle** | `POST /docs/{id}/index` | ❌ | Not found (USE_EMBEDDINGS flag) | implement |
|
||||
| **doc_index_state** | status tracking | ❌ | Not found | implement |
|
||||
| **Wiki Markdown editor** | Frontend only | ❌ | Not in index.html | implement (Phase 2) |
|
||||
| **Docs tree navigation** | Frontend only | ❌ | Not in index.html | implement (Phase 2) |
|
||||
| Fabric OCR on upload | `POST /v1/capability/ocr` | ⚠️ | `USE_FABRIC_OCR=false` | enable flag |
|
||||
| Embeddings on upload | Qdrant ingest via Router | ⚠️ | `USE_EMBEDDINGS=false` | enable flag |
|
||||
| NATS event on upload | `attachment.created` | ❌ | Not published | add to upload handler |
|
||||
|
||||
---
|
||||
|
||||
## Таблиця 4: Sessions & Dialog Map
|
||||
|
||||
| UI Feature | Expected API/Event | Found? | Evidence | Action |
|
||||
|-----------|-------------------|--------|----------|--------|
|
||||
| Sessions list | `GET /api/sessions?project_id=` | ✅ | `docs_router.py` | — |
|
||||
| Resume session | `GET /api/chat/history?session_id=` | ✅ | `docs_router.py` | — |
|
||||
| Session title update | `PATCH /api/sessions/{id}/title` | ✅ | `docs_router.py` | — |
|
||||
| Session fork | `POST /api/sessions/{id}/fork` | ✅ | `docs_router.py` | — |
|
||||
| Dialog Map (tree) | `GET /api/sessions/{id}/map` | ✅ | `docs_router.py` | — |
|
||||
| **Dialog Map (canvas)** | D3/Cytoscape rendering | ❌ | `<details>` tree only in UI | Phase 2 |
|
||||
| **Project-level map** | `GET /api/projects/{id}/dialog-map` | ❌ | Not found | implement (Postgres needed) |
|
||||
| **Node types** (task/doc/meeting) | NATS consumers | ❌ | Not found | Phase 2 |
|
||||
| **Edge creation UI** | `POST /api/links` | ❌ | Not found | implement |
|
||||
| **Pin important node** | `PATCH /api/sessions/{id}/pin/{msg_id}` | ❌ | Not found | implement |
|
||||
| Real-time map updates | WS `dialog_map.updated` event | ❌ | Not found | implement |
|
||||
| **Saved views** | `dialog_views` table | ❌ | Not found | implement |
|
||||
|
||||
---
|
||||
|
||||
## Таблиця 5: CTO Panel (Repo + Ops)
|
||||
|
||||
| UI Feature | Expected API/Event | Found? | Evidence | Action |
|
||||
|-----------|-------------------|--------|----------|--------|
|
||||
| Ops actions (risk/backlog/etc.) | `GET /api/ops/actions` | ✅ | `main.py` | — |
|
||||
| Run ops action | `POST /api/ops/run` | ✅ | `main.py` + `ops.py` | — |
|
||||
| Node health dashboard | `GET /api/nodes/dashboard` | ✅ | `main.py` | — |
|
||||
| Node SSH status | `GET /api/nodes/ssh/status` | ✅ | `main.py` | — |
|
||||
| Add node | `POST /api/nodes/add` | ✅ | `main.py` | — |
|
||||
| Integrations status | `GET /api/integrations/status` | ✅ | `main.py` | — |
|
||||
| **Repo changesets list** | `GET /api/repo/changesets` | ❌ | Not found | implement or mock |
|
||||
| **Create changeset** | `POST /api/repo/changesets` | ❌ | Not found | implement |
|
||||
| **Add patch** | `POST /api/repo/changesets/{id}/patches` | ❌ | Not found | implement |
|
||||
| **Execution plan** | `POST /api/repo/changesets/{id}/plan` | ❌ | Not found | implement |
|
||||
| **Create PR** | `POST /api/repo/changesets/{id}/pr` | ❌ | Not found | implement |
|
||||
| **Run checks** | `POST /api/repo/pr/{id}/checks:run` | ❌ | Not found | implement |
|
||||
| **Ops runs list** | `GET /api/ops/runs` | ❌ | Not found (only one-shot dispatch) | implement |
|
||||
| **Ops run create** | `POST /api/ops/runs` (job-based) | ❌ | Not found | implement |
|
||||
| **Ops run status** | `GET /api/ops/runs/{id}` | ❌ | Not found | implement |
|
||||
| LangGraph runs | `POST /v1/graphs/{name}/runs` (Supervisor) | ✅ | `sofiia-supervisor` | 🔧 Not exposed via BFF |
|
||||
| LangGraph status | `GET /v1/runs/{id}` | ✅ | `sofiia-supervisor` | 🔧 Not exposed via BFF |
|
||||
| **repo_tool (read)** | via chat tools | ✅ | `tool_manager.py` | — |
|
||||
| **pr_reviewer_tool** | via chat tools | ✅ | `tool_manager.py` | — |
|
||||
|
||||
---
|
||||
|
||||
## Таблиця 6: Database Model Dependency
|
||||
|
||||
| UI Screen | Required DB Table | Status | Storage | Action |
|
||||
|-----------|------------------|--------|---------|--------|
|
||||
| Chat history | `messages` | ✅ | SQLite | — |
|
||||
| Projects | `projects` | ✅ | SQLite | — |
|
||||
| Documents | `documents` | ✅ | SQLite | — |
|
||||
| Sessions | `sessions` | ✅ | SQLite | — |
|
||||
| Dialog Map (messages) | `messages.parent_msg_id` | ✅ | SQLite | — |
|
||||
| **Dialog Map (graph)** | `dialog_nodes` + `dialog_edges` | ❌ | None | ADD TABLES |
|
||||
| **Saved map views** | `dialog_views` | ❌ | None | ADD TABLE |
|
||||
| **Doc versions** | `docs_versions` | ❌ | None | ADD TABLE |
|
||||
| **Entity links** | `entity_links` | ❌ | None | ADD TABLE |
|
||||
| **Tasks** | `tasks` | ❌ | None | ADD TABLE |
|
||||
| **Meetings** | `meetings` | ❌ | None | ADD TABLE |
|
||||
| **Repo changesets** | `repo_changesets` | ❌ | None | ADD TABLE |
|
||||
| **Repo patches** | `repo_patches` | ❌ | None | ADD TABLE |
|
||||
| **Pull requests** | `pull_requests` | ❌ | None | ADD TABLE |
|
||||
| **Ops runs** | `ops_runs` | ❌ | None | ADD TABLE |
|
||||
| Embeddings | Qdrant `sofiia_docs_*` | ⚠️ | Qdrant (disabled) | ENABLE FLAG |
|
||||
| Long-term memory | Qdrant `sofiia_messages` | ✅ | Qdrant | — |
|
||||
| Facts | Postgres `daarion_memory` | ✅ | Postgres | — |
|
||||
|
||||
---
|
||||
|
||||
## Таблиця 7: Real-time Events (WebSocket)
|
||||
|
||||
| Event | Direction | Status | Evidence |
|
||||
|-------|-----------|--------|----------|
|
||||
| `nodes.status` | Server → UI | ✅ | `main.py` WebSocket fan-out |
|
||||
| `chat.reply` | Server → UI | ✅ | `main.py` |
|
||||
| `voice.stt.result` | Server → UI | ✅ | `main.py` |
|
||||
| `voice.tts.ready` | Server → UI | ✅ | `main.py` |
|
||||
| `voice.stream.chunk` | Server → UI | ✅ | `main.py` |
|
||||
| `ops.run.status` | Server → UI | ✅ | `main.py` |
|
||||
| `error` | Server → UI | ✅ | `main.py` |
|
||||
| `dialog_map.updated` | Server → UI | ❌ | Not found |
|
||||
| `task.created` | Server → UI | ❌ | Not found |
|
||||
| `doc.updated` | Server → UI | ❌ | Not found |
|
||||
| `meeting.reminder` | Server → UI | ❌ | Not found |
|
||||
| `repo.pr.status` | Server → UI | ❌ | Not found |
|
||||
| `ops_run.completed` | Server → UI | ❌ | Not found |
|
||||
|
||||
---
|
||||
|
||||
## Таблиця 8: Security & Access Control
|
||||
|
||||
| Feature | Status | Evidence |
|
||||
|---------|--------|----------|
|
||||
| API key auth (console) | ✅ | `auth.py` |
|
||||
| Strict auth (SSH/admin) | ✅ | `auth.py` strict mode |
|
||||
| Rate limiting per endpoint | ✅ | `main.py` limiters |
|
||||
| Upload sanitize (filename/mime) | ✅ | `docs_router.py` |
|
||||
| Upload size limits (env-based) | ✅ | `UPLOAD_MAX_*_MB` env |
|
||||
| RBAC tool allowlist | ✅ | `agent_tools_config.py` |
|
||||
| `mode=confidential` check | ❌ | Not in BFF or Router |
|
||||
| E2EE for docs | ❌ | Not implemented |
|
||||
| Audit log for actions | ⚠️ | Partial (router audit.py) |
|
||||
| 2-step Plan → Apply for risky ops | ❌ | Not implemented |
|
||||
| CORS config | ⚠️ | Check `main.py` |
|
||||
|
||||
---
|
||||
|
||||
## Граф залежностей (логічний)
|
||||
|
||||
```
|
||||
[index.html SPA]
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
│ │ │
|
||||
[chat+voice] [projects] [ops+nodes]
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
/api/chat/send /api/projects /api/ops/run
|
||||
/api/voice/* /api/files/* /api/nodes/*
|
||||
/api/telemetry /api/sessions/* /api/integrations/*
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
[Router BFF] [SQLite sofiia.db] [nodes health poll]
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
[Router DAGI] [Memory Service] [SSH + node-worker]
|
||||
/v1/agents/ /threads /events /caps
|
||||
/v1/tools/ /memories /facts /voice/health
|
||||
│
|
||||
▼
|
||||
[LLM + Tools]
|
||||
Grok / qwen3 / DeepSeek
|
||||
+ 20+ tools (repo/pr/kb/etc.)
|
||||
```
|
||||
|
||||
**Відсутні зв'язки (vNext):**
|
||||
```
|
||||
[index.html] → [Kanban Board] ←→ /api/projects/{id}/tasks
|
||||
[index.html] → [Dialog Map canvas] ←→ /api/projects/{id}/dialog-map
|
||||
[index.html] → [CTO Repo Panel] ←→ /api/repo/changesets
|
||||
[index.html] → [CTO Ops Panel] ←→ /api/ops/runs (job-based)
|
||||
[docs_router] → NATS attachment.created
|
||||
[Supervisor] → BFF (not proxied)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Actions for UI Team (1–2 days)
|
||||
|
||||
1. **Immediate (today)**: всі фічі chat/voice/projects/sessions/dialog-tree вже працюють — deploy і тестуйте через http://localhost:8002
|
||||
2. **Quick wins (1–2 дні)**:
|
||||
- `DELETE /api/projects/{id}` — 10 рядків коду
|
||||
- `DELETE /api/projects/{id}/documents/{doc_id}` — 10 рядків
|
||||
- BFF proxy до Supervisor: `POST /api/supervisor/runs` → `sofiia-supervisor:8080/v1/graphs/{name}/runs`
|
||||
3. **Phase 2 UI (mock-first)**:
|
||||
- Kanban board: спочатку in-memory tasks → `tasks` table
|
||||
- Meetings: спочатку form → `meetings` table
|
||||
- Dialog Map canvas: `<details>` tree → D3 tree → D3 force graph
|
||||
4. **CTO Panel mock**: додати mock handlers для `/api/repo/changesets` і `/api/ops/runs`
|
||||
5. **Увімкнути USE_EMBEDDINGS=true**: після перевірки що Qdrant доступний
|
||||
6. **Expose Supervisor API через BFF**: один proxy endpoint в main.py
|
||||
7. **NATS attachment.created**: додати до upload handler у docs_router.py
|
||||
8. **`dialog_nodes/edges` tables**: DDL + API + WS events (найважливіше для vNext graph)
|
||||
9. **`docs_versions` table**: ALTER + endpoint (для wiki history)
|
||||
10. **Перевірити WebSocket**: всі voice/ops events реально приходять до UI
|
||||
Reference in New Issue
Block a user