Andrey Epifancev 6bb111db38 chore(openspec): архив change slice-0-skeleton
Срез 0 реализован и влит (PR #3), change перенесён в openspec/changes/archive, спеки — в openspec/specs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-04 19:44:42 +04:00

6.6 KiB
Raw Blame History

Предложения по открытым вопросам и контракту (из реализации 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 не меняет.