v1.0.178: схема Опуса — генератор + симулятор + моя оценка

This commit is contained in:
“Naeel”
2026-06-25 10:56:22 +04:00
parent 36f31c2e23
commit c022133de0
+122
View File
@@ -0,0 +1,122 @@
# Схема Опуса — генератор + симулятор (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
```