Andrey Epifancev ff0f2d1077 docs: рулинг R-1
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014Typ5sXWNMFirr2va2uL8o
2026-10-11 21:40:07 +04:00

68 lines
9.9 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.

## Context
Две машины в одной локальной сети: Mac mini (`192.168.0.106`, Python 3.13, uv, Docker не всегда запущен) и виртуалка
с macOS и системным Python 3.9.6 (`192.168.0.112`, входящих портов нет, `pip3` есть, доступ к Jira банка
`https://sdlc.go.rshbank.ru/jira` по логину/паролю из `config.json`). Общая папка гипервизора — запасной канал.
Исходный код для переноса: `admin/jira-sync/jira_sync.py` (клиент REST v2 + Agile, темп `Pacer`, карта переходов,
исправленная семантика связей: в POST `/issueLink` `inwardIssue` — источник, в GET `outwardIssue` у X — цель X),
`config.example.json` (id полей, типы, карта переходов, типы связей, доска 4216).
## Goals / Non-Goals
Goals: убрать ручной перенос файлов; один источник ключей; журнал и повторяемость изменений; безопасный повтор любой
команды; темп, при котором Jira не отвечает 429; MCP, через который сессия ставит пакеты и читает состояние.
Non-goals — см. proposal.md.
## Decisions
1. **Два репозитория, один change.** Спека и план лежат в `jira-hub`; `jira-agent` ссылается на них из CLAUDE.md.
Агент меняется редко и живёт на другой машине, поэтому отдельный репозиторий без зависимостей от хаба.
2. **Хаб — один процесс: SQLite + HTTP + MCP.** Один писатель в базу, нет зависимости от Docker, база — один файл.
Агент и интерфейсы ходят только через HTTP; виртуалке ничего не ставить, у неё нет входящих портов.
3. **Команды — желаемый результат** (`ensure_*`), каждая на одной задаче, выполняется как «прочитать из Jira → если результат
уже есть, `done` без записи → иначе записать». Повтор безопасен по построению.
4. **Хаб не повторяет команды.** Взятая команда без ответа видна как «нет ответа от агента с …»; повторяет её только сам
агент после перезапуска по своему журналу, и только через проверку. Отменить взятую команду может только человек.
5. **Истина в Jira.** После каждого пакета хаб добавляет `refresh` по затронутым ключам; команда без ответа, результат
которой виден в зеркале, помечается `confirmed_by_state`.
6. **Политика темпа в хабе, пауза на команде.** При выдаче команды хаб ставит «не раньше, чем через N с после предыдущей
операции в Jira» по типу команды и типу предыдущей. Агент помнит только время последнего вызова Jira. Нет следующей
команды — нет паузы. 429/503 — Retry-After в агенте (инструкция сервера, не политика).
7. **Пакет = одно действие пользователя.** Команды пакета — по порядку, пакеты — по порядку постановки, одна команда в полёте.
Упавшая команда не останавливает пакет; команды, ссылающиеся на её результат, — `skipped`.
8. **Временные ключи `new:<n>`** живут в хабе: `ensure_issue` с временным ключом, после `done` хаб подменяет `new:<n>`
в параметрах следующих команд пакета и в `issue_note`. У агента соответствия нет.
9. **Зеркало — JQL из настроек** (`project = AURORA AND labels = AWPCA`); задачи, на которые ведут связи, но вне JQL,
дочитываются по ключу и помечаются `neighbor`.
10. **Служебные заметки отдельно от зеркала** (`issue_note`), чтобы обновление из Jira их не затирало.
11. **Настройки агента приходят от хаба** (id полей, карта переходов, типы связей, политика темпа, версия настроек);
локально у агента — адрес хаба, токен, Jira и учётные данные.
## Risks / Trade-offs
- Чтение перед каждой записью — лишний вызов на команду. Цена мала (пауза перед чтением 2 с), а гарантия идемпотентности
стоит дороже.
- Поиск дубля при `ensure_issue` по точной теме и автору за 7 дней может не найти задачу, если тему успели поправить
в Jira руками. Остаточный риск принят: окно между ответом Jira и записью журнала — миллисекунды.
- Один агент и одна команда в полёте — медленно для сотни операций (как и сейчас: ~4,5 ч на полную актуализацию).
Это цена темпа, не архитектуры.
- Хаб должен быть запущен для MCP; если нет — инструменты возвращают понятную ошибку, не падают.
- SQLite по сети не используется; при переезде хаба на другую машину — переносится файл.
## Decisions made without discussion
| Дата | Решение | Обоснование | Цена ошибки |
|---|---|---|---|
| 2026-10-11 | Хаб: SQLite в одном процессе с HTTP, без PostgreSQL | один писатель, Docker здесь не всегда поднят, виртуалке ничего не ставить; владелец отдал плумбинг исполнителю | смена хранилища — замена одного модуля хаба, API не меняется |
| 2026-10-11 | HTTP-библиотека хаба — stdlib `http.server` + `ThreadingHTTPServer`, без FastAPI | API маленький, зависимостей ноль, тесты через `urllib`; MCP — пакет `mcp` (FastMCP) через uv | при росте API — переезд на FastAPI внутри того же репозитория |
| 2026-10-11 | Порт хаба 8790, привязка к `0.0.0.0` | свободный порт; виртуалка в LAN с другим адресом, `127.0.0.1` ей недоступен | пересечение портов — поправить настройку |
| 2026-10-11 | `claim` — долгий запрос до 30 с, затем сразу следующий | минимальная задержка выдачи без постоянного трафика | — |
| 2026-10-11 | Поиск дубля в `ensure_issue`: `project = AURORA AND reporter = currentUser() AND created >= -7d` + точное сравнение темы на клиенте | JQL `summary ~` нечёткий; точное сравнение в агенте надёжнее | дубль при смене темы руками в первые 7 дней; хаб показывает такие команды отдельно |
| 2026-10-11 | Исполнитель входит в `ensure_fields` | 11.10 исполнители ставились руками, в просмотрщике это нужная операция; владелец согласился | — |
| 2026-10-11 | Паузы по умолчанию: изменение задачи 120 с, комментарий и переход 30 с, чтение 2 с, создание связи 30 с | значения `pacing` из `config.example.json`, проверенные на Jira банка 10–11.10 | настройки, правятся без кода |
| 2026-10-11 | Резервная копия файла базы перед каждым пакетом в `backups/`, хранить последние 30 | заменяет историю версий зеркала | место на диске; число в настройках |
| 2026-10-11 | Хранение базы и настроек хаба — `~/.local/share/jira-hub/` | вне git, переживает пересоздание worktree | — |
| 2026-10-11 | Регистрация MCP — в `~/.claude.json` для проекта `awp-ca` (stdio, `uv run jira-hub mcp`) | как остальные MCP этого проекта | — |
| 2026-10-11 | Полная синхронизация по расписанию: хаб ставит `refresh` по базовой JQL раз в 60 мин, если агент на связи и очередь пуста | свежее зеркало без участия человека | лишние чтения; интервал в настройках, 0 отключает |
| 2026-10-11 | R-1: Review Focus #5 плана ссылается на Task 7, тест `test_settings_put_rejects_protected` лежит в Task 6 — тест остаётся в Task 6 | опечатка плана; спека о месте теста молчит | нулевая |