Files
contracts/History/opus-generator-schema.md
T

8.3 KiB
Raw Blame History

Схема Опуса — генератор + симулятор (v1.0)

Ответ Опуса от 25.06.2026 на запрос History/opus-generator-request.md.


Оценка схемы

Сильные стороны

  1. v1→v2 diff-пары — ключевая идея. Генератор закладывает конкретные изменения между версиями спецификаций (цена, объём, ADD/DELETE/UPDATE), и верификатор проверяет что compare нашёл именно их. Это даёт детерминированную проверку самой важной функции сервиса.

  2. manifest.json как ground truth — каждая проверка сверяется с эталоном, а не с «примерно ожидаемым». Никакой неоднозначности.

  3. Пул услуг из реальных данных — стойко-место, PDU, L2-канал, cross-connect, Cloud, IPv4. Не выдуманные, а те что в реальных файлах.

  4. 17 ошибочных кейсов — покрытие крайне широкое: от битого XML до сиротских спецификаций.

  5. Структура папокtestgen/ + sim/ с чётким разделением генерации и симуляции.

Что нужно уточнить/доработать

  1. Симулятор: API или браузер? Опус описывает «реальное приложение (API/UI)». Два варианта:

    • curl-симулятор (только API): дёргаем /upload, /api/classify-batch, /api/groups, /process-v2. Быстро, дёшево, но не проверяет фронтенд (duplicate confirm, renderFiles, SSE в UI).
    • Playwright (полный UI): открывает браузер, кликает кнопки, читает DOM. Медленно, но проверяет ВСЁ включая confirm-диалоги.
    • Рекомендация: curl для генерации/классификации/групп + выборочно Playwright для UI-специфичных сценариев (дубликаты, confirm, удаление).
  2. .doc файлы — парсинг допник-1-XXX002-01200_3.doc не удался (старый формат). Нужен LibreOffice для конвертации, либо исключить .doc из генерации и использовать только .docx.

  3. Стресс-сценарий F — rapid-fire загрузки во время classify. Это может быть сложно воспроизвести и проверить. Вероятно, отложить на потом.

  4. Количество файлов — раскладка даёт ~92 файла + edge cases. Можно докрутить до ровно 100 добавив ещё дубликатов или мусора.


Исходная схема Опуса

Часть 1 — Генерация ~100 файлов

Базовая структура: 10 компаний × 10 договоров × (спецификация v1 + v2 + 1-3 допника)

Раскладка:

Категория Кол-во Зачем
Договоры (валидные) 10 по 1 на компанию
Спецификации v1 10 базовая версия
Спецификации v2 (ревизия) 10 diff для сравнения
Допники 18 13 на договор
Битые/edge .docx 15 ошибки парсинга/классификации
Форматы .doc/.pdf 12 ветка конвертера
ZIP-архивы 5 внутри — наборы файлов
Дубликаты (имя/контент) 10 upload-логика
Мусор (не договор) 10 негативная классификация
Итого ~100

Оси вариативности:

  • Компания: ЗАО/ООО/АО/ПАО/ИП, латиница/кириллица
  • Номер: 5 цифр, опц. суффикс _N, edge — буквы/длинный/пустой
  • Дата: 12.202506.2026, форматы 01.02.2026 и «01 февраля 2026»
  • Цены: базовые ±20%, разрядность с пробелом
  • Услуги (пул): стойко-место, PDU, L2-канал, IPv4 /30 и /32, cross-connect ВОЛС/UTP, Cloud Intel/AMD, Интернет, порт, подсеть
  • Таблица: 3–12 строк, 6 или 7 колонок

Различия v1→v2 (для компаратора): изменение цены, изменение объёма, добавленная услуга, удалённая услуга, переименование, сдвиг даты, пересчёт итога.

Ошибочные кейсы (17 шт): нет номера, нестандартный заголовок, битый XML, пустой файл, только таблицы, только текст, .doc формат, битый PDF, дубликат имени, дубликат контента, гигант (500 строк), не-договор, сирота (спека без договора), рассинхрон (имя файла ≠ номер в тексте).

Parent-child: ключ — НОМЕР. Генератор связывает договор→спеку/допник по НОМЕРу.

Шаблоны python-docx:

  • Билдеры: build_contract(ctx), build_spec(ctx), build_addendum(ctx)
  • ctx = {company, number, date, parties, services[], totals}
  • Хелперы: add_title, add_section, add_services_table
  • Битый XML: валидный docx → распаковать zip → испортить document.xml → запаковать
  • .doc: docx → libreoffice --convert-to doc
  • Битый PDF: docx → pdf → обрезать байты

Часть 2 — Симулятор

Словарь действий: upload, delete, classify, groups, compare (SSE), confirm/cancel, reset.

Сценарии:

  • A. Хэппи-путь: договор + спека v1 + v2 → classify → группа → compare → diff совпал
  • B. Зигзаг: загрузил 3 → удалил 1 → добавил 2 → classify → проверить консистентность
  • C. Bulk: все ~100 разом → classify → число групп, битые ✗
  • D. Тупые действия: дубликат (OK/Отмена), удалить всё, смешать форматы, classify на нуле, compare с одной версией
  • E. ZIP: валидный, с дубликатами, с битым файлом внутри
  • F. Стресс: случайные паузы, rapid-fire, загрузка во время classify

Тайминги: think-time (random 0.1-3с), classify — поллинг, compare — SSE до done/таймаут.

Часть 3 — Верификация

После каждого шага:

  • state.files count == ожидаемого
  • Статусы ✓/✗ соответствуют (битые → ✗)
  • После classify: группы есть, состав по НОМЕРу верный
  • Сироты без краша
  • Compare: diff == заложенному (ground truth из manifest.json)
  • Дубликаты: счётчик после OK ≠ после Отмена
  • Нет 500-х, нет необработанных исключений
  • Идемпотентность classify

Ground truth: manifest.json — что сгенерировано + ожидаемые группы и diff-ы.

Структура папок

testgen/
  pools.py        # услуги, компании, цены
  templates.py    # build_contract / build_spec / build_addendum
  corrupt.py      # порча docx/pdf, конвертация .doc
  generate.py     # оркестратор → out/ + manifest.json
  out/{valid,errors,formats,zips,duplicates}/
  manifest.json   # ground truth

sim/
  actions.py      # обёртки над API
  scenarios.py    # A..F
  verify.py       # чек-лист
  run.py