Горячая папка: запись прямо в Input, как в старом АРМ; таймаут 20 мин (#26) #27

Merged
aep merged 6 commits from feat/26-hotfolder-direct-write into main 2026-10-09 16:22:07 +03:00
Owner

Closes #26

Что сделано

Решение владельца 09.10.2026: запись в горячую папку ИС Сканирование — как в старом АРМ (reference-old-arm/api/src/core/clients.py:111).

  • put (режимы smb и local): файл <job_id>.<ext> пишется сразу в Input открытием wb; существующий файл перезаписывается. Временного Tmp/.<имя>.part, каталога Tmp и rename у шлюза больше нет.
  • Ошибка посреди записи → RECOGNITION_FAILED; недописанный файл снимается только при SCAN_CLEANUP=true. Ошибка самого открытия ничего не удаляет (I-1).
  • SCAN_TMP_DIR убран из настроек шлюза (остаётся у эмулятора; старые .env стартуют — extra="ignore").
  • SCAN_TIMEOUT_SECONDS по умолчанию 300 → 1200 (20 мин) — в паре со сроком ответа OCR в arm-core (RSHB/arm-core#87).
  • Очистка (SCAN_CLEANUP) больше не трогает Tmp. Остатки Tmp/.*.part прежних версий — убрать вручную.
  • Аутентификация SMB не менялась: OPENBAO__SMB__SMB_LOGIN/SMB_PASSWORD уже передаются в сессию и в каждый вызов.

OpenSpec change: openspec/changes/hotfolder-direct-write/ (дельта требований «Передача файла…» и «Очистка горячей папки под флагом»). План: docs/superpowers/plans/2026-10-09-hotfolder-direct-write.md.

ASSUMPTION(OQ-79): ИС не берёт файл, пока шлюз держит его открытым на запись (монопольное открытие smbclient), — так работал старый АРМ.

Связанные PR: RSHB/arm-core (#87), RSHB/arm-ka-docs (#84).

Rulings I made

Маркер Решение Цена ошибки
R-1 (design) local тоже пишет прямо в Input эмулятор теоретически может прочитать недописанный файл
R-2 (design) Input по-прежнему создаётся перед записью (терпимо к отказу в правах) лишний mkdir на задание
R-3 (design) недописанный файл удаляется только при SCAN_CLEANUP=true обрезанный файл остаётся в Input
R-4 (design) SCAN_TMP_DIR удалён у шлюза, у эмулятора остался нет
R-5 (design) правка фабрики для SMB перенесена из задачи 2 в задачу 1 (mypy) нет
R-6 (design) сверх плана: conftest.py, test_worker.py, литерал "Tmp" в roundtrip нет
R-7 (design) ошибка открытия не удаляет файл (фикс I-1) нет
R-8 (design) SHARING_VIOLATION при повторе задания в другом процессе → RECOGNITION_FAILED, как в старом АРМ (подтверждено владельцем 09.10.2026) ложный RECOGNITION_FAILED при редком повторе после потери ack

Находки

Маркер Находка Статус
I-1 ошибка открытия при SCAN_CLEANUP=true удаляла целый файл прошлой доставки fixed 7d8a506
M-1 устаревшие докстринги HotFolder.put/cleanup (Tmp, жёсткая ссылка) deferred
M-2 validate_name: «dot-фай��ы — служебные .part» deferred
M-3 SMB: сбой close() после сбоя write маскирует ошибку записи (текст конверта) deferred
M-4 текст «Горячая папка недоступна» при SHARING_VIOLATION вводит в заблуждение deferred
M-5 test_legacy_scan_tmp_dir_is_ignored проверяет env, а не .env-файл deferred
M-9 рулинги ledger не перенесены в design.md fixed 7d8a506
O-1 интеграционные тесты падают при поднятом стенде (контейнер в той же queue group; = O-3 из #21) deferred (#21)

M-6…M-8 — в PR arm-ka-docs.

Проверка

make check-full при остановленном стенде:

make check     → ruff, mypy, 1018 passed
make test-integration → 11 passed
make docker-build → ok
exit 0

🤖 Generated with Claude Code

Closes #26 ## Что сделано Решение владельца 09.10.2026: запись в горячую папку ИС Сканирование — как в старом АРМ (`reference-old-arm/api/src/core/clients.py:111`). - `put` (режимы `smb` и `local`): файл `<job_id>.<ext>` пишется сразу в `Input` открытием `wb`; существующий файл перезаписывается. Временного `Tmp/.<имя>.part`, каталога `Tmp` и rename у шлюза больше нет. - Ошибка посреди записи → `RECOGNITION_FAILED`; недописанный файл снимается только при `SCAN_CLEANUP=true`. Ошибка самого открытия ничего не удаляет (I-1). - `SCAN_TMP_DIR` убран из настроек шлюза (остаётся у эмулятора; старые `.env` стартуют — `extra="ignore"`). - `SCAN_TIMEOUT_SECONDS` по умолчанию 300 → 1200 (20 мин) — в паре со сроком ответа OCR в arm-core (RSHB/arm-core#87). - Очистка (`SCAN_CLEANUP`) больше не трогает `Tmp`. Остатки `Tmp/.*.part` прежних версий — убрать вручную. - Аутентификация SMB не менялась: `OPENBAO__SMB__SMB_LOGIN`/`SMB_PASSWORD` уже передаются в сессию и в каждый вызов. OpenSpec change: `openspec/changes/hotfolder-direct-write/` (дельта требований «Передача файла…» и «Очистка горячей папки под флагом»). План: `docs/superpowers/plans/2026-10-09-hotfolder-direct-write.md`. ASSUMPTION(OQ-79): ИС не берёт файл, пока шлюз держит его открытым на запись (монопольное открытие `smbclient`), — так работал старый АРМ. Связанные PR: RSHB/arm-core (#87), RSHB/arm-ka-docs (#84). ## Rulings I made | Маркер | Решение | Цена ошибки | |---|---|---| | R-1 (design) | `local` тоже пишет прямо в `Input` | эмулятор теоретически может прочитать недописанный файл | | R-2 (design) | `Input` по-прежнему создаётся перед записью (терпимо к отказу в правах) | лишний `mkdir` на задание | | R-3 (design) | недописанный файл удаляется только при `SCAN_CLEANUP=true` | обрезанный файл остаётся в `Input` | | R-4 (design) | `SCAN_TMP_DIR` удалён у шлюза, у эмулятора остался | нет | | R-5 (design) | правка фабрики для SMB перенесена из задачи 2 в задачу 1 (mypy) | нет | | R-6 (design) | сверх плана: `conftest.py`, `test_worker.py`, литерал `"Tmp"` в roundtrip | нет | | R-7 (design) | ошибка открытия не удаляет файл (фикс I-1) | нет | | R-8 (design) | `SHARING_VIOLATION` при повторе задания в другом процессе → `RECOGNITION_FAILED`, как в старом АРМ (**подтверждено владельцем 09.10.2026**) | ложный `RECOGNITION_FAILED` при редком повторе после потери ack | ## Находки | Маркер | Находка | Статус | |---|---|---| | I-1 | ошибка открытия при `SCAN_CLEANUP=true` удаляла целый файл прошлой доставки | fixed 7d8a506 | | M-1 | устаревшие докстринги `HotFolder.put`/`cleanup` (Tmp, жёсткая ссылка) | deferred | | M-2 | `validate_name`: «dot-фай��ы — служебные `.part`» | deferred | | M-3 | SMB: сбой `close()` после сбоя `write` маскирует ошибку записи (текст конверта) | deferred | | M-4 | текст «Горячая папка недоступна» при `SHARING_VIOLATION` вводит в заблуждение | deferred | | M-5 | `test_legacy_scan_tmp_dir_is_ignored` проверяет env, а не `.env`-файл | deferred | | M-9 | рулинги ledger не перенесены в design.md | fixed 7d8a506 | | O-1 | интеграционные тесты падают при поднятом стенде (контейнер в той же queue group; = O-3 из #21) | deferred (#21) | M-6…M-8 — в PR arm-ka-docs. ## Проверка `make check-full` при остановленном стенде: ``` make check → ruff, mypy, 1018 passed make test-integration → 11 passed make docker-build → ok exit 0 ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 6 commits 2026-10-09 16:18:40 +03:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Открытие вынесено из блока снятия недописанного файла: при SCAN_CLEANUP=true
удаляется только файл, сбойнувший после открытия. Решения R-5…R-8 — в design.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aep merged commit f37a3cd706 into main 2026-10-09 16:22:07 +03:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/arm-scan-gateway#27
No description provided.