Andrey Epifancev 7738221b5a docs: README/CLAUDE.md Среза 2a, tasks.md, спека-дельты
- README: парсер по модулям, статусы и коды, словари и добавление синонима, лимиты, golden-процесс, настройки PARSE_*
- CLAUDE.md: раздел «Добавлено в Срезе 2a» (модули, правила расширения, линтер, R-21); api/rules/README.md: ключи словарей
- openspec: tasks.md (5.1), design.md (D-1…D-7, O-7/O-8), спека-дельты osv-parsing (R-12…R-22) и tabular-recognition-service («Результат по контракту»)
- tests: check_snapshot в golden_helpers + тесты «нет снимка»/«регрессия»; locator в property-тесте; пример needs_check синхронизирован с docs

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-05 15:53:11 +04:00

4.5 KiB
Raw Blame History

Spec Delta: tabular-recognition-service

MODIFIED Requirements

Requirement: Результат по контракту

После подтверждения сервис SHALL прочитать объект s3.key из бакета s3.bucket, вызвать парсер, записать файл результата (по recognition-result.schema.json) в results/{file_id}/{job_id}/result.json и опубликовать конверт результата (по recognition-result-message.schema.json) с заголовком Nats-Msg-Id = result:<job_id>:<attempt>. При неудаче публикации сервис SHALL повторить её до трёх раз с паузой, затем залогировать ошибку.

Scenario: Запрос с заглушкой парсера (Срез 0)

  • WHEN воркеру явно передана заглушка NullParser (только тесты воркера; реализация по умолчанию — реальный парсер), запрос подтверждён и объект существует в uploads/
  • THEN в recognition.result появляется конверт status = error, error.code = NOT_IMPLEMENTED, job_id/file_id из запроса, metrics.duration_ms ≥ 0; файл результата может отсутствовать

Scenario: Запрос с реальным парсером

  • WHEN запрос подтверждён и объект в uploads/ существует, но не является книгой Excel (сигнатура не XLS/XLSX/XLSB)
  • THEN в recognition.result появляется конверт status = error, error.code = UNSUPPORTED_FORMAT (повреждённая книга — UNREADABLE), job_id/file_id из запроса, metrics.duration_ms ≥ 0; файл результата может отсутствовать; корректная ОСВ в том же потоке даёт done (см. «Парсер — заменяемый интерфейс»)

Scenario: Повтор публикации

  • WHEN первая публикация конверта результата завершается ошибкой соединения, вторая — успешно
  • THEN конверт опубликован один раз с тем же Nats-Msg-Id, обработка не повторяется

Requirement: Парсер — заменяемый интерфейс

Разбор файла SHALL выполняться через единый интерфейс «байты + тип файла → документы/метрики/ошибка», не знающий о NATS и S3; воркер MUST NOT зависеть от конкретной реализации. Реализация по умолчанию (get_parser()) SHALL разбирать ОСВ по спеке osv-parsing и писать файл результата с schema_version = "1.1"; листы с признаками ББ/ОФР SHALL пропускаться с предупреждением до подсреза 2b. Заглушка NullParser (error NOT_IMPLEMENTED) SHALL использоваться только в тестах воркера и MUST NOT быть реализацией по умолчанию. Реализация по умолчанию SHALL создаваться один раз при старте приложения (словари читаются и проверяются там же). Каталог api/rules/ SHALL содержать словари ОСВ (osv_headers, osv_groups, periods, data_types) и README.

Scenario: Подмена реализации в тесте

  • WHEN в тесте воркеру передан парсер, возвращающий один osvDocument
  • THEN файл результата с этим документом записан в S3, конверт имеет status = done и result_s3 на этот файл

Scenario: Реальная ОСВ через воркер

  • WHEN в интеграционном тесте в S3 лежит rb/2024-FY/ОСВ_66 за 2024.xls и опубликован запрос file_type = XLS
  • THEN после ack публикуется конверт done с result_schema_version = "1.1", файл результата проходит схему v1.1 и содержит один osvDocument с account_code_raw = "66"