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

123 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Схема Опуса — генератор + симулятор (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 | 1–3 на договор |
| Битые/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
```