Тип «Ошибка» и вложения: хранилище файлов, ensure_attachment, path в MCP (#43) #47

Merged
aep merged 9 commits from feat/43-bug-and-attachments into main 2026-10-16 09:10:15 +03:00
Owner

Closes #43. Закрывает R-1 из #46 (параметры в описании batch_create и в 422 закреплены в спеке). Пара — aep/jira-agent PR (агент v11, issue aep/jira-agent#31).

OpenSpec change bug-and-attachments (proposal, design — решения 1–23, дельты commands, hub-api, mcp, data-model, agent).

Что сделано

  • Тип bug в ensure_issue: настройка issue_types.bug = {name, id}; без неё — 422 «команда N: нет настройки issue_types.bug» при постановке; init берёт bug из issue_type_bug/issue_type_bug_id, только если ключи есть в конфиге.
  • Хранилище файлов files/<sha256> (новый модуль files.py): POST /files {content: base64} → {file, size}; предел 10 485 760 байт (413), пустой — 422 empty_file, не base64 — 400; атомарная запись, одна копия на содержимое, повторная загрузка обновляет mtime и лечит испорченную копию; каталог 0700 при каждом старте; уборка в tick раз в сутки — файлы старше 30 дней без ссылок команд в queued/claimed.
  • GET /agent/files/{sha256} → {file, size, content} (base64; проходит и реле папки, и HTTP), 404 no_file; id только из 64 hex нижнего регистра.
  • Команда ensure_attachment {key, file, filename}: key — ключ или new:<n>; при постановке — формат file, файл загружен, filename без /, \, " и управляющих символов; пауза 30 с; по зеркалу не подтверждается; size дописывается только при выдаче (claim, довыдача, GET /agent/commands/{id}), в базе params без него — retry проходит проверку как новая.
  • MCP batch_create: у ensure_attachment вместо file — path (локальный файл до 10 МБ); MCP читает все файлы пакета, загружает POST /files, подставляет file и filename (по умолчанию имя файла). Описание инструмента собирается из SPEC.
  • README, ARCHITECTURE.md, CLAUDE.md обновлены. Схема БД не меняется, фронт не меняется.

Проверка

  • make check: pytest 419 passed, lint и vitest 205 passed.
  • Финальное ревью ветки (opus): Critical 0, Important 0 (M-2 переоценён в Important и исправлен), Minor — ниже.

Выкатка (после merge, за владельцем)

  1. git pull на Mac mini, перезапуск хаба (launchd) и MCP; make web не нужен.
  2. settings_set issue_types = {task…, epic…, bug: {name: "Ошибка", id: null}}.
  3. Merge PR агента, jira-hub agent publish …/agent.py (v11), min_agent_version = 11.
  4. Живая проверка: «Ошибка» в бэклог + вложение с кириллическим именем, повтор пакета без дублей; тестовую задачу удаляет владелец; id типа вписать в issue_types.bug.id.

Rulings I made

  • R-1 (design #15) уборка «не чаще раза в сутки» — в пределах работы процесса, после старта на первом тике; спека уточнена. Цена: лишний проход уборки при каждом перезапуске.
  • R-2 (design #20) хаб отвергает filename с " и управляющими символами (CR, LF и др.) — они ломают multipart у агента. Цена: файл с кавычкой в имени прикладывается под другим filename.
  • R-3 (design #21) текст отчёта агента при повреждённом в пути файле не меняется («результат неизвестен (обрыв связи с хабом)…»). Цена: неточная формулировка в редком случае.
  • R-4 (design #22) агент без записи issue_types.<тип> — в том числе task/epic — отвечает failed «нет настройки…» вместо {"name": null}. Меняет поведение для старых типов; на живом хабе настройки есть.
  • R-5 (design #23) план агента исполнен параллельно фоновым исполнителем на sonnet, план хаба — в сессии; финальное ревью обеих веток — opus.
  • Решения плана без обсуждения — design.md #9–#19 (тексты 422, mkstemp, проверка sha, base64 с переносами, files_dir параметром, тексты MCP).

Findings

Маркер Суть Статус
R-1 уборка раз в сутки в пределах процесса fixed 3b4cf66, e8707d4
R-2 filename без " и управляющих символов fixed 9b21060, 87d28a9
R-3 текст отчёта при повреждённом файле rejected: общий путь повтора, в Jira ничего не записано
R-4 агент без issue_types.<тип> — failed fixed (агент)
R-5 план агента параллельно на sonnet fixed (процесс)
M-1 гонка уборки с постановкой/повторной загрузкой (окно — миллисекунды раз в сутки) deferred
M-2 испорченная копия того же размера не лечилась повторной загрузкой fixed 2e98ce6
M-3 files.size/read ловят только FileNotFoundError — PermissionError в claim даёт 500 deferred
M-4 filename по умолчанию из path без NFC — NFD и NFC пути дадут два вложения deferred
M-5 R-3…R-5 не было в design.md fixed 2e98ce6
M-6 ledger без Findings, обрезано доказательство Task 5 fixed (ledger)

Deferred

M-1, M-3, M-4 — в follow-up issue при закрытии.

🤖 Generated with Claude Code

Closes #43. Закрывает R-1 из #46 (параметры в описании `batch_create` и в 422 закреплены в спеке). Пара — aep/jira-agent PR (агент v11, issue aep/jira-agent#31). OpenSpec change `bug-and-attachments` (proposal, design — решения 1–23, дельты commands, hub-api, mcp, data-model, agent). ## Что сделано - **Тип `bug`** в `ensure_issue`: настройка `issue_types.bug = {name, id}`; без неё — 422 «команда N: нет настройки issue_types.bug» при постановке; `init` берёт `bug` из `issue_type_bug`/`issue_type_bug_id`, только если ключи есть в конфиге. - **Хранилище файлов** `files/<sha256>` (новый модуль `files.py`): `POST /files {content: base64}` → `{file, size}`; предел 10 485 760 байт (413), пустой — 422 `empty_file`, не base64 — 400; атомарная запись, одна копия на содержимое, повторная загрузка обновляет mtime и лечит испорченную копию; каталог 0700 при каждом старте; уборка в `tick` раз в сутки — файлы старше 30 дней без ссылок команд в `queued`/`claimed`. - **`GET /agent/files/{sha256}`** → `{file, size, content}` (base64; проходит и реле папки, и HTTP), 404 `no_file`; id только из 64 hex нижнего регистра. - **Команда `ensure_attachment {key, file, filename}`**: `key` — ключ или `new:<n>`; при постановке — формат `file`, файл загружен, `filename` без `/`, `\`, `"` и управляющих символов; пауза 30 с; по зеркалу не подтверждается; `size` дописывается только при выдаче (`claim`, довыдача, `GET /agent/commands/{id}`), в базе `params` без него — retry проходит проверку как новая. - **MCP `batch_create`**: у `ensure_attachment` вместо `file` — `path` (локальный файл до 10 МБ); MCP читает все файлы пакета, загружает `POST /files`, подставляет `file` и `filename` (по умолчанию имя файла). Описание инструмента собирается из `SPEC`. - README, ARCHITECTURE.md, CLAUDE.md обновлены. Схема БД не меняется, фронт не меняется. ## Проверка - `make check`: pytest 419 passed, lint и vitest 205 passed. - Финальное ревью ветки (opus): Critical 0, Important 0 (M-2 переоценён в Important и исправлен), Minor — ниже. ## Выкатка (после merge, за владельцем) 1. `git pull` на Mac mini, перезапуск хаба (launchd) и MCP; `make web` не нужен. 2. `settings_set issue_types` = `{task…, epic…, bug: {name: "Ошибка", id: null}}`. 3. Merge PR агента, `jira-hub agent publish …/agent.py` (v11), `min_agent_version = 11`. 4. Живая проверка: «Ошибка» в бэклог + вложение с кириллическим именем, повтор пакета без дублей; тестовую задачу удаляет владелец; id типа вписать в `issue_types.bug.id`. ## Rulings I made - **R-1 (design #15)** уборка «не чаще раза в сутки» — в пределах работы процесса, после старта на первом тике; спека уточнена. Цена: лишний проход уборки при каждом перезапуске. - **R-2 (design #20)** хаб отвергает `filename` с `"` и управляющими символами (CR, LF и др.) — они ломают multipart у агента. Цена: файл с кавычкой в имени прикладывается под другим `filename`. - **R-3 (design #21)** текст отчёта агента при повреждённом в пути файле не меняется («результат неизвестен (обрыв связи с хабом)…»). Цена: неточная формулировка в редком случае. - **R-4 (design #22)** агент без записи `issue_types.<тип>` — в том числе `task`/`epic` — отвечает `failed` «нет настройки…» вместо `{"name": null}`. **Меняет поведение для старых типов**; на живом хабе настройки есть. - **R-5 (design #23)** план агента исполнен параллельно фоновым исполнителем на sonnet, план хаба — в сессии; финальное ревью обеих веток — opus. - Решения плана без обсуждения — design.md #9–#19 (тексты 422, mkstemp, проверка sha, base64 с переносами, `files_dir` параметром, тексты MCP). ## Findings | Маркер | Суть | Статус | |---|---|---| | R-1 | уборка раз в сутки в пределах процесса | fixed 3b4cf66, e8707d4 | | R-2 | filename без `"` и управляющих символов | fixed 9b21060, 87d28a9 | | R-3 | текст отчёта при повреждённом файле | rejected: общий путь повтора, в Jira ничего не записано | | R-4 | агент без issue_types.<тип> — failed | fixed (агент) | | R-5 | план агента параллельно на sonnet | fixed (процесс) | | M-1 | гонка уборки с постановкой/повторной загрузкой (окно — миллисекунды раз в сутки) | deferred | | M-2 | испорченная копия того же размера не лечилась повторной загрузкой | fixed 2e98ce6 | | M-3 | `files.size`/`read` ловят только FileNotFoundError — PermissionError в claim даёт 500 | deferred | | M-4 | `filename` по умолчанию из `path` без NFC — NFD и NFC пути дадут два вложения | deferred | | M-5 | R-3…R-5 не было в design.md | fixed 2e98ce6 | | M-6 | ledger без Findings, обрезано доказательство Task 5 | fixed (ledger) | ## Deferred M-1, M-3, M-4 — в follow-up issue при закрытии. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 9 commits 2026-10-16 01:07:41 +03:00
Дельты commands, hub-api, mcp, data-model, agent: issue_type bug с настройкой
issue_types.bug, хранилище файлов хаба (POST /files, GET /agent/files/{sha256}),
команда ensure_attachment, path в MCP batch_create, агент v11; заодно R-1
(#46) и M-1/M-2 из aep/jira-agent#30.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
validate принимает task|epic|bug; queue._check_setup отвергает bug без issue_types.bug с name или id (422 «команда N: нет настройки issue_types.bug»); init берёт bug из issue_type_bug/issue_type_bug_id, только если ключи есть (решение 9). Спека hub-api: уборка файлов раз в сутки в пределах процесса (R-1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
put — атомарно (mkstemp, fsync, os.replace), одна копия на содержимое, mtime при повторе, предел 10 485 760 байт, пустой — отказ; path/exists/size/read только для sha из 64 hex; sweep — старше 30 дней без ensure_attachment в queued/claimed (решения 10–13).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Не base64 — 400 bad_request, пустой — 422 empty_file, больше 10 МБ — 413 too_large; агенту — {file, size, content} в base64, нет файла — 404 no_file; уборка отдельно от автообновления (решения 14–16).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SPEC ensure_attachment {key, file, filename}, пауза 30 с, по состоянию не подтверждается; queue._check_setup: формат file, файл загружен («файл <sha> не загружен: POST /files»), filename без / и \, без кавычек и управляющих символов (R-2); claim, довыдача и GET /agent/commands/{id} дописывают size (null без файла), в базе params без size, retry проходит (решения 17–18).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Все файлы пакета читаются до загрузки: «файл не найден: <path>», «у ensure_attachment либо path, либо file», больше 10 МБ — до POST /files; filename по умолчанию — имя файла; описание batch_create говорит про path (решение 19). design.md: решение 20 (R-2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
put сверяет sha256 копии на диске при совпадении размера и переписывает испорченную; design.md: решение 13 уточнено, рулинги R-3…R-5 — решения 21–23 (M-5 финального ревью).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aep merged commit ee1e240396 into main 2026-10-16 09:10:15 +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: aep/sdlc-hub#47
No description provided.