Andrey Epifancev 71e79670c0 docs: предложение P-4 (порт tabular-parser в docs/dev/README.md)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 03:35:04 +04:00

58 lines
6.6 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.

# Предложения по открытым вопросам и контракту (из реализации `slice-0-skeleton`)
Файлы `../docs` этот репозиторий не меняет: здесь — предложения для `docs/context/07-open-questions.md` и
`docs/contracts/`; решение принимает человек / контроллер docs.
## P-1. Невалидный запрос без читаемых `job_id` / `file_id` / `attempt` (задача 4.3)
**Что видно в коде.** D-5 и spec требуют на запрос, не прошедший схему, ответить конвертом `error SCHEMA_MISMATCH`
«если `job_id` читаем». Но `recognition-result-message.schema.json` требует ещё `file_id`, а `Nats-Msg-Id` результата —
`result:<job_id>:<attempt>`. Если хоть одно из трёх не читается (тело не JSON, не объект, `job_id`/`file_id` не uuid,
`attempt` нет ни в теле, ни в заголовке запроса `Nats-Msg-Id = <job_id>:<attempt>`), валидный конверт собрать нельзя.
**Как сделано сейчас.** Значения не выдумываются: запрос логируется уровнем error (`error_category=schema_mismatch`,
причина, размер тела) и отбрасывается без ack и без результата. Ядро без ack повторит запрос `OUTBOX_MAX_REPUBLISH`
раз и переведёт задание в `dlq` — то есть «молчание» сервиса превращается в `dlq` на стороне ядра.
`attempt` при невалидном значении в теле берётся из заголовка запроса.
**Предложение.** Записать это в контракт явно (раздел «Сообщение не по схеме»): «если `job_id`, `file_id` или
`attempt` не читаемы, сервис логирует ошибку и не отвечает; ядро обнаружит задание по `dlq`/`timeout`». Альтернатива —
сделать `file_id` необязательным в конверте `error` (MINOR 1.1) — выглядит избыточной: ядро всегда шлёт корректные
идентификаторы, нечитаемое тело — это сбой транспорта, а не данных.
## P-2. Противоречие: ack при несовместимой версии запроса (`schema_version = "2.0"`)
- `docs/openspec/changes/slice-0-skeleton/specs/recognition-contract/spec.md`, сценарий «Несовместимая версия запроса»:
«публикуется результат `SCHEMA_MISMATCH`, **запрос подтверждается (ack)**, чтобы не зациклить доставку».
- `openspec/changes/slice-0-skeleton/specs/tabular-recognition-service/spec.md` (этот репозиторий), сценарий
«Несовместимая версия»: «публикуется конверт `SCHEMA_MISMATCH`, **ack не публикуется**»; D-5 — так же.
**Как сделано сейчас.** По спеке этого репозитория и брифу задачи: без ack, только результат `error SCHEMA_MISMATCH`.
Зацикливания нет: ядро (`arm-core`, `recognition_exchange`) принимает результат и в статусе `published` («потерянный
ack не блокирует результат») и закрывает задание, повторов не будет.
**Предложение.** Привести сценарий контракта в docs к «ack не публикуется; результат `SCHEMA_MISMATCH` закрывает
задание» (или наоборот — тогда правка одной ветки в `worker.py`). Нужно решение человека.
## P-3. Повторная попытка (`attempt + 1`) того же `job_id` после ошибки (задача 4.3)
**Как сделано сейчас.** Дедупликация — по `job_id` (spec: «уже обрабатывается или обработан этим процессом»), любой
итог (в том числе `error` и неудачная публикация результата) считается «обработан». Повторный запрос того же `job_id`
с другим `attempt` в этом процессе получает только ack `ack:<job_id>:<attempt нового запроса>`, без обработки, пока
`job_id` не вытеснен из LRU (`DONE_CACHE_SIZE`). Другая инстанция queue group обработает его как новый.
**Вопрос.** Если ядро (Срез 3+, replay/«переотправить») будет повторять задание тем же `job_id` с `attempt + 1`, ключ
дедупликации должен стать `(job_id, attempt)`. Предложение: зафиксировать в контракте, что новая попытка — это новый
`attempt` и сервис обрабатывает её заново; тогда в воркере ключ LRU меняется на `(job_id, attempt)` (одна строка).
Пока ядро повторяет только тем же `attempt` (повтор без ack), текущее поведение корректно.
## P-4. `docs/dev/README.md`: порт tabular-parser и копирование `.env.example` (прогон DoD, задача 5.2)
- `../docs/dev/README.md` («Запуск сервисов из venv без Nexus») называет порт `tabular-parser` в профиле `services` 8001, а сервис
по умолчанию слушает 8000 (`SERVER__PORT`, шаблон команды); там же советует `cp ../docs/dev/.env.example api/.env` —
для этого сервиса избыточно (в нём нужны только `OPENBAO__MINIO__*`, `OPENBAO__NATS__NATS_URL`, `DEBUG`; свой
`api/.env.example` лежит в репозитории).
- **Предложение.** В docs либо задавать `SERVER__PORT=8001` в профиле `services` (переменная окружения контейнера), либо
привести текст README к 8000; ожидаемые поля `/healthcheck` для `tabular-parser` — `uptime`, `version`, `nats`.
Файлы в `../docs` этот change не меняет.