Срез 0 (issue #1): раздел «Соглашения шаблона» (что оставлено от шаблона команды, что вырезается, что добавляется); change openspec/changes/slice-0-skeleton — proposal, design с таблицей «Decisions made without discussion», спеки и tasks; в openspec/config.yaml строки с двоеточием взяты в кавычки (YAML разбирал их как словари). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
3.4 KiB
Spec Delta: scan-emulator
Purpose
Эмулятор ИС Сканирование для разработки и тестов: воспроизводит протокол горячих папок и формат ответов Content AI,
отдавая реальные ответы из ../fixtures/ocr по имени файла, чтобы конвейер scan-gateway проверялся без доступа к
банковской системе.
ADDED Requirements
Requirement: Эмулятор отвечает по протоколу горячих папок
Процесс python -m src.scan_emulator SHALL опрашивать входящий каталог каждую секунду; для нового файла
<uuid>_<name>.<ext> через SCAN_EMULATOR_DELAY секунд (по умолчанию 2) SHALL создать <output>/<uuid>/<uuid>.json;
после обработки входящий файл SHALL быть переименован в <uuid>_<name>.<ext>.done, чтобы не обрабатываться повторно.
Scenario: Один файл
- WHEN во входящем каталоге появляется
3f1c…_aep_5.pdf - THEN через ≤ 5 с существует
Output/3f1c…/3f1c….json, а входящий файл переименован в…pdf.done
Requirement: Ответ берётся из фикстур по имени
Эмулятор SHALL искать в SCAN_FIXTURES_DIR файл <name>.json, затем <name>*.json (первый по алфавиту), где <name> —
имя входящего файла без префикса <uuid>_ и расширения; содержимое SHALL быть записано в ответ с file_uid = <uuid>.
Scenario: Точное имя
- WHEN входящий файл —
…_aep_5.pdf, в фикстурах естьaep_5.json - THEN ответ равен
aep_5.jsonс заменённымfile_uid
Scenario: Префикс
- WHEN входящий файл —
…_aep_8.pdf, в фикстурах естьaep_8_form4.json - THEN ответ равен
aep_8_form4.jsonс заменённымfile_uid
Requirement: Неизвестный файл — ошибка в формате Content AI
Если пара не найдена, эмулятор SHALL записать ответ {"file_uid": "<uuid>", "error": {"code": "INVALID_DOCUMENT", "message": "<имя>: нет эталонного ответа в фикстурах"}, "data_ocr": []}.
Scenario: Нет пары
- WHEN входящий файл —
…_unknown.pdf - THEN ответ содержит
error.code = INVALID_DOCUMENTи пустойdata_ocr;scan-gatewayпубликует конверт с тем же кодом
Requirement: Эмулятор запускается из того же образа
В docs/dev/docker-compose.yml сервис scan-emulator SHALL использовать образ scan-gateway с командой
python -m src.scan_emulator, общий том hotfolder и ../../fixtures/ocr, смонтированный только для чтения.
Scenario: Compose
- WHEN выполнен
docker compose --profile services up -d - THEN контейнер
scan-emulatorработает, его лог сообщает каталоги и число найденных пар фикстур