# Диалог DeepSeek ↔ Opus — Decoupling пайплайна Дата: 28.06.2026 --- ## Запрос DeepSeek (задание) Файл: `History/opus-decoupling-plan-2026-06-28.md` 5 блоков, интерактивный режим: 1. Модульность пайплайна — контракты между стадиями 2. Интеграционное тестирование (fixture-based) 3. Деплой и синхронизация 4. Перспектива переезда на managed Flask 5. Вопросы к заказчику --- ## Ответ Opus — 5 развилок ### Вопрос 1. Граница decoupling Варианты: - A. Единый интерфейс пайплайна (контракт оркестратора) - B. Изолировать только внешние зависимости (LLM, БД) - C. И то, и другое **Рекомендация Opus:** C ### Вопрос 2. База данных в тестах Варианты: - A. Абстрагировать репозиторий за интерфейсом → in-memory заглушка - B. Реальный Postgres в Docker/testcontainers - C. Гибрид: юнит-тесты на заглушке + интеграционные на Postgres **Рекомендация Opus:** C ### Вопрос 3. Мокирование LLM Варианты: - A. DI — LLM-клиент через зависимость - B. Мокать на уровне httpx-транспорта - C. Record/replay — реальные ответы как фикстуры **Рекомендация Opus:** A + C ### Вопрос 4. Тестовый фреймворк Варианты: - A. pytest + папка tests/ + conftest - B. Только smoke-тесты - C. Полное покрытие **Рекомендация Opus:** A → C поэтапно ### Вопрос 5. Деплой Варианты: - A. Не трогать, отдельная задача - B. Заодно привести sync.sh/systemd - C. Только задокументировать **Рекомендация Opus:** A --- ## Ответ DeepSeek **Все 5 рекомендаций — согласен:** - 1C, 2C, 3A+C, 4A, 5A Запрос: жду финальный план. --- ## Ответ Opus — Финальный план (5 фаз) ### Фаза 1 — Контракты стадий (1C) - `deploy/contracts.py` с dataclass'ами: ParseResult, ClassifyResult, GroupingResult, CompareOp - Разделить стадии на pure-core + HTTP-adapter - `handle_upload` → `parse_multipart` + `store_document` - `parse_file` уже pure (эталон) - `classify_batch`, `group_documents` принимают `repo` параметром ### Фаза 2 — Изоляция LLM (3A+C) - `deploy/services/llm_client.py`: протокол `LLMClient.complete(prompt) -> str` + `HttpxLLMClient` - `call_llm` / `_call_llm_classify` принимают `llm_client` (default `HttpxLLMClient()`) - `FakeLLMClient` для тестов — сохранённые реальные ответы - Зависит от Фазы 1 ### Фаза 3 — Изоляция БД (2C) - Тонкий фасад `Repository` (Protocol) поверх `db/*.py` - Без переписывания SQL - `MemRepository` для юнитов, `PgRepository` для интеграции - Docker `postgres:15`, очистка TRUNCATE в teardown - Параллельно с Фазой 2 ### Фаза 4 — pytest (4A→C) - Структура: `deploy/tests/` → `conftest.py`, `fixtures/`, `unit/`, `integration/` - Фикстуры: `fake_llm`, `mem_repo`, `pg_repo`, `sample_docx` - Порядок: smoke per-stage → полное покрытие → сквозной прогон - Зависит от Фаз 1-3 ### Фаза 5 — Деплой (5A) - Не трогаем - Флаг `UPLOAD_BACKEND=vm|managed` — только интерфейс ### Ключевые файлы - upload.py, classify.py, grouping.py, process.py, llm.py, connection.py — модифицируются - Новые: contracts.py, llm_client.py, repository.py, tests/, docker-compose.test.yml ### Верификация 1. `pytest unit/` — зелёные без сети/БД 2. `docker-compose up postgres` + `pytest integration/` — реальный SQL 3. Сквозной: sample.docx → пайплайн → ожидаемые ops 4. convert_server.py без изменения поведения 5. JS-тесты (131) — PASS ### Scope Включено: контракты, DI LLM+БД, pytest, фикстуры, флаг UPLOAD_BACKEND Исключено: деплой, переписывание SQL, изменения фронтенда, managed-upload --- ## Ответ DeepSeek — Рецензия Оценка: 5/5 ### Поправки: - `upload.py` уже читает из `BytesIO`, не из сокета - Ф2 и Ф3 можно параллельно (независимы) ### 3 вопроса к Opus: 1. Dataclass vs TypedDict? dict из БД vs валидированный dataclass 2. `complete(prompt) -> str` достаточно? или нужен `complete_structured`? 3. `conftest.py` на уровне `deploy/tests/` или `deploy/`? ### Вердикт: План принимаю. Жду ответ на 3 вопроса.