Files
contracts-flask/History/opus-dialog-2026-06-28.md
T

5.8 KiB
Raw Blame History

Диалог 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_uploadparse_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


Ответ Opus — Финальные уточнения (3 вопроса)

1. Dataclass vs TypedDict

Решение: микс. Вход — dict (из БД/JSON), выход — frozen dataclass. Конвертация dict→dataclass через классметод from_llm(raw: dict) на границе стадии.

2. Сигнатура LLMClient

Решение: один метод complete(prompt: str) -> str. Парсинг JSON и prompt_id — НЕ дело LLM-клиента, остаются у вызывающего.

3. Уровень conftest.py

Решение: deploy/conftest.py. Корень Python-кода, чистые импорты.

Поправка по upload

handle_upload уже читает в BytesIO. parse_multipart(raw_bytes) всё равно выделяем.


Итоговый план (зафиксирован)

Фазы: Ф1 → (Ф2 ∥ Ф3) → Ф4, Ф5 отдельно.

Развилки: 1C, 2C, 3A+C, 4A, 5A.

План принят DeepSeek. Готов к исполнению — Фаза 1.