docs: код-ревью (2026-08-26) + задания Sonnet по архитектуре (v2.0.16)
Deploy contracts-flask / validate (push) Canceled after 0s

This commit is contained in:
“Naeel”
2026-08-26 16:29:41 +03:00
parent 021c925e3c
commit 87524c54a4
3 changed files with 278 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
# Sonnet: код-ревью contracts-flask (2026-08-26)
## Контекст
- Написан промпт для Sonnet: `contracts-flask/docs/prompt-sonnet-architecture.md`
(задача — прочитать файлы текущего сервиса сверки и дать описание/архитектуру).
- Sonnet прочитал все указанные файлы и вместо описания выдал **код-ревью** с 10 находками
(2 критические, 3 средних, 2 XSS, 3 мелких). Архитектурное описание — отдельным документом (не выдано).
## Находки Sonnet
### 🔴 Критические
1. **`process.py` + `spec_events.py` — UPDATE/DELETE никогда не применяются (сломана частичная сверка).**
LLM возвращает `target_id: "r1"` (индекс строки), а `apply_ops()` читает `op.get("target_hash", "")`.
Поля `target_hash` в ответе LLM нет → все UPDATE/DELETE из `mode=partial` молча уходят в `UNRESOLVED`.
Трассировка: `_build_spec_text()` показывает строки `[id: r1]` → LLM возвращает `target_id: "r1"`
`process.py` передаёт ops без трансляции r1→hash → `spec_events.py` `th = op.get("target_hash","")` = "" → UNRESOLVED.
Работает только `mode=full_replace` (все ADD) и первый документ (extract, только ADD).
2. **`Dockerfile` — образ не запустится: `upload/` не скопирован.**
`COPY site /app/site` — только site/, `upload/` отсутствует.
При старте `routes/__init__.py` делает `from upload.backend.upload_refs import ...`, `app.py` добавляет `/app` в sys.path.
В образе `/app/upload/` нет → `ModuleNotFoundError`.
### 🟠 Средние
3. **`db/prompts.py``list_by_role()` запрашивает несуществующий столбец `created_by`.**
В схеме `prompts` нет `created_by``sqlite3.OperationalError``/api/prompts/list` всегда 500.
4. **`routes/prompts_bp.py` — вызов несуществующих функций:**
- `db_prompts.insert(...)` — нет (есть `save_new_version()`);
- `db_prompts.delete(...)` — нет (есть `delete_prompt()`).
`/api/prompts/save` и `/api/prompts/delete` падают с `AttributeError`.
5. **`services/llm.py`, `services/classify.py` — захардкожены `LLM_URL/LLM_KEY/LLM_MODEL` в обход `config.py`.**
`config.py` читает из `LLM_API_URL`, а compare/classify игнорируют его. Конфигурация расщеплена на 3 блока.
### 🟡 XSS (frontend)
6. **`compare.js``nr.name` в таблице операций не экранирован** (`escHtml()` отсутствует).
Имя услуги из договора (текст LLM) вставляется в innerHTML → XSS.
7. **`compare.js``sec.filename` в заголовке секции не экранирован.** Имя файла от пользователя → XSS.
### ⚪ Мелкие
8. **`llm_prompt.py`** — устаревший комментарий «Lucee API» (читает напрямую из SQLite).
9. **`db/connection.py`** — `_pg_to_sqlite`: `gen_random_uuid()` добавляет `?` в SQL, но не добавляет значение в params (мёртвый код, но при исполнении сломает запрос).
10. **`services/classify.py`** — комментарий «re-classify after file changes» вводит в заблуждение: `reset_classify_status()` сбрасывает только `processing``pending`, уже классифицированные не трогает.
## Итоговая таблица
| # | Файл | Проблема | Критичность |
|---|---|---|---|
| 1 | process.py, spec_events.py | UPDATE/DELETE → UNRESOLVED, частичная сверка сломана | 🔴 критический |
| 2 | Dockerfile | upload/ не скопирован → образ не стартует | 🔴 критический |
| 3 | db/prompts.py | created_by отсутствует → 500 на /api/prompts/list | 🟠 средний |
| 4 | prompts_bp.py | insert()/delete() — не те имена функций → 500 | 🟠 средний |
| 5 | llm.py, classify.py | захардкожены LLM_URL/KEY/MODEL в обход config.py | 🟠 средний |
| 6 | compare.js | nr.name не экранирован → XSS | 🟡 XSS |
| 7 | compare.js | sec.filename не экранирован → XSS | 🟡 XSS |
| 8 | llm_prompt.py | устаревший комментарий | ⚪ мелкое |
| 9 | connection.py | gen_random_uuid() мёртвый код с ошибкой | ⚪ мелкое |
| 10 | classify.py | комментарий re-classify вводит в заблуждение | ⚪ мелкое |
## Статус
- ✅ Все 10 находок исправлены (v2.0.15, commit `e3f5581`, запушено).
- #1 (критично) — сам: `process.py` трансляция `target_id``target_hash`.
- #2#10 (механика) — Флаш-субагент: Dockerfile, prompts CRUD, XSS, конфиг LLM, комментарии.
- Верифицировано: `py_compile`, `node -c`, `import app` — OK.
- Архитектурное описание от Sonnet — так и не получено (вместо него — ревью). Если нужно — отдельным запросом.