docs: спека — когда SCHEMA_MISMATCH не публикуется; nats = off в proposal (I-2, M-2)

Требование «Ошибки транспорта превращаются в результат» приведено к коду:
SCHEMA_MISMATCH публикуется, если читаемы job_id, file_id и attempt и job_id
ещё не известен; иначе — лог (error/warning) без ack и результата. Добавлены
два сценария (их покрывают test_unreadable_request_is_logged_and_dropped и
test_malformed_request_for_{job_in_progress,done_job}_is_dropped).
В proposal.md поле healthcheck nats — ok/down/off.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-04 03:45:03 +04:00
parent 30c3e8281a
commit c9cdf7592d
2 changed files with 24 additions and 4 deletions

View File

@ -33,9 +33,11 @@
- **Парсер как интерфейс**: `src/parser/` — протокол `Parser` и `NullParser`, возвращающий `status = error`,
`error.code = NOT_IMPLEMENTED` для любого файла (Срез 2 заменяет реализацией §1/§12); `api/rules/README.md` —
место словарей синонимов.
- **Ошибки транспорта** всегда превращаются в результат: запрос не по схеме → `SCHEMA_MISMATCH`; файл не читается из
- **Ошибки транспорта** превращаются в результат: запрос не по схеме → `SCHEMA_MISMATCH`
(если читаемы `job_id`, `file_id`, `attempt`, иначе — лог ошибки без ответа); файл не читается из
S3 → `FILE_READ_ERROR`; неожиданное исключение → `UNKNOWN_ERROR`. Ядро не ждёт таймаута, если сервис жив.
- **Healthcheck** `/healthcheck` шаблона дополняется полем `nats` (`ok`/`down`).
- **Healthcheck** `/healthcheck` шаблона дополняется полем `nats` (`ok`/`down`; `off` — NATS выключен флагом
`NATS_ENABLED=false`).
- **Проверки качества** вместо CI: `make check` (ruff, mypy, pytest без Docker, идентичность контракта) и
`make check-full` (+ интеграционный тест против compose, `docker build`) — по `../docs/dev/checks.md`.

View File

@ -49,8 +49,15 @@ Stateless-сервис разбора табличных файлов (XLS/XLSX/
### Requirement: Ошибки транспорта превращаются в результат
Сервис SHALL отвечать конвертом `status = error` в случаях: тело не проходит схему или `MAJOR` версии ≠ 1 →
`SCHEMA_MISMATCH` (если `job_id` читаем); объект S3 не читается → `FILE_READ_ERROR`; исключение парсера →
`UNKNOWN_ERROR` (сообщение без трассировки). Сервис MUST NOT падать и MUST NOT молчать по этим причинам.
`SCHEMA_MISMATCH`; объект S3 не читается → `FILE_READ_ERROR`; исключение парсера → `UNKNOWN_ERROR` (сообщение без
трассировки). Сервис MUST NOT падать по этим причинам. `SCHEMA_MISMATCH` SHALL публиковаться (без ack), когда из тела
читаемы `job_id` и `file_id` (uuid), а `attempt` — из тела или из заголовка запроса `Nats-Msg-Id = <job_id>:<attempt>`,
и этот `job_id` сервису ещё не известен (не в работе и не среди обработанных). Иначе валидный конверт собрать нельзя
либо он ушёл бы под тем же `Nats-Msg-Id`, что и настоящий результат: сервис SHALL записать в лог ошибку
(`error_category=schema_mismatch`, причина) — уровнем error, если идентификаторы не читаемы, уровнем warning, если
`job_id` уже известен, — и MUST NOT публиковать ни ack, ни результат; ядро обнаружит такое задание по `dlq`/`timeout`
(явная запись в контракт — открытый вопрос «невалидный запрос без читаемых `job_id`/`file_id`/`attempt`» в
`open-questions-proposal.md`). FILE_READ_ERROR и UNKNOWN_ERROR публикуются всегда: сервис MUST NOT молчать по ним.
#### Scenario: Нет объекта в S3
- **WHEN** `s3.key` запроса указывает на несуществующий объект
@ -60,6 +67,17 @@ Stateless-сервис разбора табличных файлов (XLS/XLSX/
- **WHEN** запрос содержит `schema_version = "2.0"`
- **THEN** публикуется конверт `error.code = SCHEMA_MISMATCH`, ack не публикуется
#### Scenario: Невалидный запрос без читаемых идентификаторов
- **WHEN** тело запроса не JSON либо в нём не читаются `job_id` или `file_id`, либо `attempt` нет ни в теле, ни в
заголовке `Nats-Msg-Id`
- **THEN** в лог пишется ошибка `error_category=schema_mismatch`, ни ack, ни результат не публикуются, процесс
продолжает работу
#### Scenario: Невалидный запрос с уже известным `job_id`
- **WHEN** запрос не проходит схему, а его `job_id` уже в работе или среди обработанных
- **THEN** в лог пишется предупреждение `error_category=schema_mismatch`, ни ack, ни результат не публикуются;
обработка или результат задания с этим `job_id` не меняются
### Requirement: Парсер — заменяемый интерфейс
Разбор файла SHALL выполняться через единый интерфейс «байты + тип файла → документы/метрики/ошибка», не знающий о
NATS и S3; воркер MUST NOT зависеть от конкретной реализации. В Срезе 0 реализация SHALL возвращать `NOT_IMPLEMENTED`