39 KiB
39 KiB
Context
main eb485d7. Устройство, на которое опираются правки:
- Настройки —
src/jira_hub/settings.py:DEFAULTSсодержитbase_jql = "project = AURORA AND labels = AWPCA",project_key = "AURORA",board_id = None;AGENT_KEYSотдаёт агентуbase_jqlиboard_id. На живом хабеboard_id = 4216,settings_version = 10,schema_version = 3. Ключиlabels,comment_markerхаб и агент не читают (наследиеjira-sync), здесь не трогаются. - Полный прогон —
api(POST /refresh {full: true}) иqueue.maybe_auto_refreshставятrefresh {jql: base_jql};queue.is_full_refresh(поparams.jql == base_jql) решает, считать ли загрузку полной (authoritativeвmirror.apply_state→ пересчётneighbor).mirror.board(conn, base_jql)ищетlast_syncпоsync_run.query = base_jql. - Снимок доски и список —
mirror.boardотдаёт всё зеркало;mirror.list_issuesфильтрует поlabelчерезjson_each(i.labels); признакneighbor— колонка зеркала (вне базовой JQL). - Выдача команд —
queue.deliver_paramsдописывает параметры при выдаче (сейчасsizeуensure_attachment), в базеparamsбез них. - Агент (
jira-agent/src/agent.py, v11):sprints()читает активные и будущие спринты доскиsettings.board_id;sprint_names(keys)вrefreshсобирает имена спринтов задач по этой доске;do_ensure_sprintбезboard_id—failed. Канбан-доска наGET /board/{id}/sprintотвечает Jira ошибкой (спринтов у неё нет). - MCP —
mcp_server.py, user scope,uv run --project ~/projects/jira-bridge/jira-hub jira-hub mcp; ходит только черезclient. Описаниеbatch_createтребует меткуAWPCAвensure_issue. - Веб-приложение —
shell/Layout.tsx(шапка «Хаб Jira», вкладки «Доска», «Задачи»), доска —board/useBoardSource.ts(GET /board), список —issues/IssuesPage.tsx(GET /issues, варианты фильтров из снимка доски). Раскладка доски —board/storage.ts, ключиlocalStoragegraph-<имя>…от имени источника (у хаба — «Хаб»).fromHub.tsставитhasSprint: trueвсегда.
Goals / Non-Goals
Goals: несколько проектов-меток в одном мосте; у каждого своя доска Jira (scrum или kanban); сессия Claude и страница веб-приложения работают в разрезе одного проекта; AWPCA после выкатки работает как раньше.
Non-Goals и Anti-Goals: см. proposal.md.
Decisions
- Проект — таблица
project, схема v4. Поля:label(TEXT PK — метка Jira, она же ключ проекта),name(TEXT, непустое),board_id(INTEGER или NULL),board_type(scrum|kanban| NULL — ещё не известен),created_at. Отдельная таблица, а не ключ настроек: проект — сущность со своим жизненным циклом, а настройки уходят агенту целиком и поднимаютsettings_versionпри каждой правке. Создание проектаsettings_versionне поднимает: агенту проекты не нужны, доски он получает в параметрах команд (решение 7). - Метка проекта — непустая строка без пробельных символов, запятых, кавычек и скобок (метка Jira не может
содержать пробел; остальное исключено, чтобы метку можно было без экранирования вставить в JQL
labels in (…)), до 100 символов. Регистр сохраняется как введён; совпадение с существующей без учёта регистра — 409 (Jira сравнивает метки без учёта регистра в JQL). Название — непустое после обрезки пробелов, до 100 символов.board_id— целое > 0 или отсутствует. - Базовая JQL собирается, а не хранится.
base_jql = "project = <project_key> AND labels in (<метки по created_at, затем label>)"; функция вsettings(или новом модулеprojects), её используютPOST /refresh {full}, автообновление,is_full_refresh,mirror.boardиGET /settings(полеbase_jqlв ответе — вычисленное, только для чтения;PUT /settingsсbase_jqlилиboard_id— 422 с указанием, что JQL собирается из проектов, а доска — свойство проекта). Без проектовbase_jql = null:POST /refresh {full}— 422 «нет проектов», автообновление не ставится. Решение владельца: одна JQL на все проекты. - Миграция v3 → v4 (в одной транзакции с копией базы, как прежние): создать
projectи колонкуbatch.project; еслиbase_jqlв настройках имеет вид… labels = <M>или… labels in (<M1>, …)— завести проекты с этими метками; название проектаAWPCA— «АРМ КА», остальных — сама метка;board_idиз настроек достаётся проекту, если проект один, иначе никому (с предупреждением в лог);board_type = NULL(определит первыйrefresh). Строкамsync_runсquery= стараяbase_jqlзаписатьquery= новая вычисленная — иначе доска до первого полного прогона показывала бы «полного прогона не было»; так же переписатьparams.jqlкомандrefreshвqueuedиclaimed, равный старойbase_jql, — иначе такой прогон не признается полным. Ключиbase_jqlиboard_idвsettingмиграция не удаляет: базу открывает любой процесс новой версии (HubClient.from_homeв MCP, CLI), и это может случиться послеgit pull, но до перезапуска старого хаба, а старый хаб эти ключи читает. Новый кодbase_jqlизsettingне читает (вычисляет из проектов), аboard_idостаётся вAGENT_KEYSкак запасной для агента: по нему агент v12 выполнитensure_sprint, поставленные до миграции безboard_id. Ключи убираются отдельной задачей после выкатки (follow-up). ВDEFAULTSновой версии ключейbase_jqlиboard_idнет — на новой базе их не появляется. Еслиbase_jqlне разобрана — проектов нет, в лог — предупреждение с прежним значением.jira-hub init --configзаводит проектAWPCA«АРМ КА» сboard_idиз конфига вместо записиbase_jql/board_id. - Разрез по проекту — одна функция зеркала для доски и списка. Для проекта P: свои — задачи зеркала с меткой P;
соседи — задачи без метки P, связанные со своими связью (в любую сторону), и эпики своих (
epic_key), если они есть в зеркале.GET /board?project=Pотдаёт своих и соседей,neighbor = falseу своих иtrueу соседей;links— связи, у которых хотя бы один конец свой.GET /issues?project=P— та же выборка, фильтрneighborотносится к признаку относительно P; остальные фильтры — поверх. Безproject— прежнее поведение (всё зеркало,neighborиз колонки). Неизвестный проект — 404.last_sync— общий (прогон один на все проекты). Доска признакneighborне читает (fromHub.ts): соседи по связям из других проектов рисуются обычными карточками, как сейчас рисуются соседи зеркала; «+ соседи по связям» доска считает сама по связям. Признакneighborотносительно проекта виден в колонке «Сосед» списка задач. Владелец связей между проектами не ожидает, поэтому отдельной отрисовки соседей-из-другого-проекта нет. - Пакет проекта — проверки в хабе, не в MCP.
POST /batches {project: P, …}: неизвестный P — 422. Для каждой команды:ensure_issue— если вlabelsнет P, хаб дописывает P в конец (параметры хранятся уже с ней); метка другого проекта вlabels— 422;ensure_fields—labels_removeс P илиlabels_addс меткой другого проекта — 422;- «метка другого проекта» и «P в
labels_remove» сравниваются без учёта регистра (Jira в JQL сравнивает метки так же):awpcaв пакете STOCKS_DRRK — тоже чужая метка; - команды над существующей задачей (
ensure_fields,ensure_comment,ensure_status,ensure_sprint,ensure_attachment) —keyдолжен быть временным ключом этого пакета или задачей зеркала с меткой P, иначе 422 « не в проекте P»; ensure_link— хотя бы один изsource,targetсвой (временный ключ пакета или задача с меткой P);refresh— без ограничений. Пакет хранитbatch.project = P;GET /batches?project=P— только пакеты проекта.POST /commands/{id}/retryпринимает необязательныйproject: передан и у исходного пакета другой проект (в том числеNULL) — 422 «команда #N не из проекта P»; передан и совпадает — новый пакет с P и проверками; не передан — новый пакет получает проект исходного. MCP в привязанной сессии всегда передаёт свой P, поэтому сессия не может повторить чужую команду или команду пакета без проекта. Безproject— прежнее поведение, проверок нет,batch.project = NULL(автообновление, веб-приложение, старые клиенты). Проверки в хабе, а не в MCP: MCP по границам ходит только черезclient, а правило о метке проекта должно действовать для любого клиента, который назвал проект.
- Доски — в параметрах команд, настройки
board_idнет. Агенту не нужен список проектов, ему нужны доски:ensure_sprint— при постановке хаб определяет проект задачи (метки задачи в зеркале ∩ проекты; для временного ключа — метки еёensure_issueв пакете) и дописывает в параметрыboard_idего доски. 422 при постановке: задача ни в одном проекте; в нескольких проектах с разными досками; у проекта нет доски; доскаkanban(«у проекта P канбан-доска, спринтов нет»); тип доски ещё не известен («дождитесь обновления из Jira»).sprint: "backlog"на scrum-доске — как раньше.board_idот клиента вensure_sprint— 422 (его выставляет хаб).board_idхранится вparams(видно в истории команд, переживает довыдачу); повтор команды (retry) снимаетboard_idс параметров до проверки и вычисляет доску заново.refresh— при выдаче (deliver_params, в базе не хранится) хаб дописываетboards: [{id, type}]— все доски проектов без повторов,type— известный тип илиnull. Агент для досок сtype = nullзапрашиваетGET /rest/agile/1.0/board/{id}и возвращает в результате командыboards: {"<id>": "scrum" | "kanban" | null}(null— доска не найдена или нет доступа; причина — в лог агента); хаб записывает известные типы вproject. Имена спринтов агент собирает со всех scrum-досок (известных и только что определённых); канбан-доски пропускает. Одна задача в спринтах двух досок (или двух спринтов одной) — побеждает последнее найденное имя, как в v11 (sprint_namesперезаписывает). Агент v12 безboards/board_idв параметрах (старый хаб или команда, поставленная до миграции) берётsettings.board_id, как v11 (ключ остаётся до follow-up, решение 4).
- MCP: привязка к проекту флагом запуска.
jira-hub mcp --project <метка>. Привязка проверяется при каждом вызове (хаб может быть не запущен при старте MCP): метки нет вGET /projects— инструмент отвечает «проект <метка> не заведён в хабе: project_create или исправьте --project в .mcp.json». В привязанной сессии:issues—GET /issues?project=P;issue— любая задача по ключу (явный ключ — осознанный запрос, а карточка соседа нужна при работе со связями);notes_set— только своя задача проекта (метка P; соседи — нет), иначе отказ;batch_create,command_retry— сproject = P(проверки решения 6);batches—GET /batches?project=P;batch_status,batch_wait,batch_cancel— по id, без ограничения;refresh—full— общий полный прогон,keys— как раньше. Без привязки инструментыissues,issue,notes_set,batch_create,command_retry,refreshотвечают «сессия не привязана к проекту: …» с подсказкой про--projectиprojects; остальные (projects,project_create,agent_status,sync_log,settings_get,settings_set,batches,batch_status,batch_wait,batch_cancel) работают. Решение владельца: «только свои»; безопасное поведение без привязки — моё (см. ниже).
project_createв MCP —POST /projects {label, name, board_id?, author: "claude"}; ответ — проект, id пакета обновления и готовый фрагмент.mcp.json:{"mcpServers": {"jira-hub": {"command": "uv", "args": ["run", "--project", "<корень хаба>", "jira-hub", "mcp", "--project", "<метка>"]}}}с инструкцией: положить в корень репозитория проекта (слить с имеющимся.mcp.json) и сделать/mcp→ reconnect (одобрить project-scope сервер). Записьjira-hubв project scope перекрывает одноимённую из user scope. Корень хаба MCP вычисляет от расположения своего пакета (src/jira_hub/→ корень репозитория), не зашивая путь; путь к.venvв подсказку не попадает (uv runвосстановить изsys.argvнельзя). Если MCP запущен из worktree, в подсказке окажется путь worktree — это видно в ответе, рабочий MCP запускается из основного checkout.projects— таблица: метка, название, доска, тип доски («неизвестен», пока агент не определил), число своих задач; в привязанной сессии отмечает текущий проект.POST /projects—{label, name, board_id?, author?}→ 201{project, batch_id}; проект и пакет «Новый проект <метка>» из одного полногоrefreshставятся в одной транзакции; автор пакета —author(по умолчаниюapi). Ошибки: 422 — неверные поля (решение 2), 409 — метка уже есть.GET /projects→ список{label, name, board_id, board_type, created_at, issues_count}поcreated_at, затемlabel;issues_count— задачи зеркала с меткой проекта.- Веб-приложение — проект в адресе и в памяти браузера. Выбор проекта — выпадающий список рядом с «Хаб Jira»
(вариант A): «<метка> — <название>», текущий отмечен; в конце — «+ Новый проект…». Текущий проект — параметр
projectв адресе/app/boardи/app/issues; без него — последний выбранный (localStorage), иначе первый изGET /projects; выбранный записывается в адрес (replace). Неизвестный проект в адресе — сообщение «проект <метка> не найден» со списком проектов. Нет ни одного проекта — доска и список показывают приглашение создать проект. Переходы «Доска» / «Задачи» сохраняют проект. Карточка задачи (/app/issues/{key}) от проекта не зависит. Форма «Новый проект» — окно поверх страницы: метка, название, номер доски (необязательно); ошибка хаба (detail) — рядом с кнопкой «Создать»; после создания — переключение на новый проект. Пакет создания ставится с авторомviewer, поэтому доска подхватывает его как свойrefresh(правило «Источник данных доски») и показывает ход. - Доска в разрезе проекта.
GET /board?project=P; «Обновить из Jira» — как раньшеPOST /refresh {full: true}— обновляет все проекты (решение владельца). Состояние доски вlocalStorage— отдельно на проект. Сейчас вweb/src/board/storage.tsключи от имени источника не зависят:fileKey(n)=graph-<n>:board(pos, posdate, lanes, fold, sprint, who, colw) иpref(n)=graph-<n>(флаги neighbors, onlylinked, crit, bydate, hidekind, hideedge, snap, tbl, prob). На проект делятся оба набора: у проектаAWPCA— ровно нынешние ключи, у остальных — те же ключи с суффиксом@<метка>(graph-pos:board@STOCKS_DRRK,graph-crit@STOCKS_DRRK); общие для всего приложения настройки вне доски (если есть) не делятся. Загрузка CSV/JSON иapplyJsonSettingsпишут в ключи текущего проекта. Так раскладка AWPCA переживает выкатку, а проекты не смешиваются. Фильтр спринтов:hasSprintв модели из хаба — есть ли хотя бы одна своя задача (neighbor = false) со спринтом (даже если канбан-проект связан с задачами scrum-проекта); у канбан-проекта фильтра спринтов нет («колонки «Спринт» нет — показаны все задачи», как у CSV без спринтов). - Список задач в разрезе проекта.
GET /issues?project=P&…; варианты фильтров — из снимкаGET /board?project=P; параметрprojectв адресе — рядом с фильтрами; фильтр «Метка» остаётся. - Порядок выкатки. (1) Агент v12 опубликован и
agent_statusпоказывает v12 — он понимает иboards/board_idв параметрах, и прежнийsettings.board_id. (2) Слияние хаба,make web, перезапуск хаба (владелец) — миграция v4. (3)min_agent_version = 12. (4) Вawp-caположить.mcp.jsonс--project AWPCAи переподключить MCP — до этого сессииawp-caс задачами работать не могут (решение 8). Хаб новее агента v11 до шага (1) не выкатывать: v11 не знаетboardsиboard_idв параметрах и читает спринты только с доски из настроек — спринты задач других проектов пропадут из зеркала, аensure_sprintдля них уйдёт не на ту доску. Миграция v4 нестрашна для старого хаба, если базу откроет новый MCP/CLI раньше перезапуска (решение 4), но междуgit pullи перезапуском хаба лучше не открывать новые сессии MCP. - Агент v12 — отдельные issue, ветка, design-only change и PR в
jira-agent. Контракт (параметрыboards,board_id, результатboards) — в этом change (спекаagentживёт в хабе); у агента — решения реализации. Агент сливается и публикуется первым (решение 14).
Risks / Trade-offs
- Задача с метками двух проектов видна в обоих;
ensure_sprintдля неё при разных досках — 422. Осознанно: владелец связей между проектами не ожидает. - Задача проекта без метки проекта (метку сняли в Jira руками) выпадает из полной JQL и остаётся в зеркале со старыми данными, как сейчас.
- Без
.mcp.jsonвawp-caсессии там после выкатки не видят задач — это намеренно (анти-цель «не та метка»), но шаг выкатки легко забыть; он в чеклисте выкатки PR. refresh {keys}хвостом пакета тоже получаетboardsи тратит по одному вызовуGET /board/{id}на доску с неизвестным типом — только до первого определения.- Ошибка в номере доски при создании или доска, понадобившаяся канбан-проекту позже, интерфейсом не исправляются (правки
проекта нет). Решение владельца 19.10.2026: на первое время он правит базу сам —
UPDATE project SET board_id = <номер>, board_type = NULL WHERE label = '<метка>'; тип доски определит следующийrefresh. Агенты (Claude) базу хаба напрямую не правят. Доска, на которую агент ответил «не найдена» (null), остаётся сboard_type = NULL: каждыйrefreshснова запрашивает её тип,ensure_sprintотвечает «тип доски ещё не известен». - Создание проекта меняет базовую JQL, поэтому
last_syncдоски становитсяnull(«полного прогона не было»), пока не завершится пакет «Новый проект» — он ставится сразу, доска показывает его ход. Переписыватьsync_run.queryздесь было бы неправдой: прежний прогон новую метку не покрывал. - Сравнение меток без учёта регистра (решение 2) при создании; в разрезе проекта (решение 5) метка сравнивается точно,
как в зеркале (
json_each). Jira хранит метку так, как её записали, — расхождение возможно только при ручной правке метки в Jira другим регистром.
Decisions made without discussion
- 2026-10-19 — проект — таблица
project, а не ключ настроек. Обоснование: сущность со своим циклом; правка не должна подниматьsettings_versionи перечитывание настроек агентом. Цена ошибки: таблица и миграция; перенос в настройки — одна миграция назад. - 2026-10-19 — сессия MCP без
--projectне читает и не пишет задачи. Обоснование: анти-цель — задача с меткой не того проекта; владелец согласился с этим в обсуждении («все ок»), сам режим «только служебные инструменты» — моё уточнение. Цена ошибки:awp-caдо своего.mcp.jsonне работает с задачами; смягчить — умолчание по проекту. - 2026-10-19 — проверки метки и принадлежности задачи проекту — в хабе (
POST /batches {project}), а не в MCP. Обоснование: граница «MCP только через client», правило нужно и будущим клиентам. Цена ошибки: поле пакета и проверки вqueue; перенос в MCP — без изменения базы. - 2026-10-19 — хаб дописывает метку проекта в
ensure_issueсам (в пакете сproject). Прежнее правило «хаб метки сам не добавляет» остаётся для пакетов без проекта. Обоснование: Claude не должен помнить метку — это и есть анти-цель. Цена ошибки: одна ветка в проверках постановки. - 2026-10-19 —
issueв MCP открывает любую задачу по ключу,issues— только проект. Обоснование: явный ключ — осознанный запрос, карточка соседа нужна при работе со связями. Цена ошибки: одна проверка в MCP. - 2026-10-19 — доски передаются агенту в параметрах команд (
ensure_sprint.board_idпри постановке,refresh.boardsпри выдаче), тип доски определяет агент вrefresh. Обоснование: хаб не ходит в Jira; отдельная команда «узнать доску» потребовала бы нового типа команды. Цена ошибки: два параметра контракта. - 2026-10-19 — тип доски неизвестен →
ensure_sprint422, а не попытка на удачу. Обоснование: создание проекта само ставитrefresh, окно короткое. Цена ошибки: одна ошибка постановки сразу после создания проекта. - 2026-10-19 — разрез по проекту: свои + соседи по связям + эпики своих;
neighborотносительно проекта. Обоснование: логика доски и «+ соседи» уже построена наneighbor; эпики нужны доске для имён. Цена ошибки: функция выборки и тесты к ней. - 2026-10-19 — миграция называет проект AWPCA «АРМ КА», а
board_idиз настроек отдаёт ему. Обоснование: так называется проект в workspace; доска 4216 — его. Цена ошибки: название правится будущим «переименованием» или вручную. - 2026-10-19 — раскладка доски AWPCA остаётся на прежних ключах
localStorage, остальные проекты — на ключах с меткой. Обоснование: анти-цель «AWPCA потерял раскладку». Цена ошибки: особый случай в одном местеstorage.ts. - 2026-10-19 —
project_createотвечает готовым.mcp.jsonс командой запуска текущего процесса MCP. Обоснование: владелец хочет, чтобы Claude сам прописал проект в репозитории; путь хаба не зашивается. Цена ошибки: формат подсказки. - 2026-10-19 — метка проекта без пробелов, запятых, кавычек, скобок; уникальность без учёта регистра. Обоснование: безопасная подстановка в JQL. Цена ошибки: отказ на экзотической метке.
- 2026-10-19 —
GET /batches?project=иbatchesв привязанной сессии — только пакеты проекта;batch_status/wait/cancelпо id — без ограничения. Обоснование: список не засоряется чужими пакетами, а явный id — осознанный запрос. Цена ошибки: фильтр списка. - 2026-10-19 — миграция v4 не удаляет
base_jqlиboard_idизsetting;board_idостаётся запасной доской агента; удаление — follow-up. Обоснование: базу мигрирует любой процесс новой версии (MCP, CLI), возможно — под работающим старым хабом (находка builder check). Цена ошибки: два мёртвых ключа до follow-up. - 2026-10-19 — миграция переписывает
params.jqlуrefreshвqueued/claimedсо старой базовой JQL. Обоснование: иначе прогон из очереди не признается полным. Цена ошибки: одна строка миграции. - 2026-10-19 —
retryсprojectотказывает, если проект исходного пакета другой; хаб снимает свойboard_idпри повторе. Обоснование: сессия проекта не должна повторять чужие команды; иначе повторensure_sprintпадал бы на своей же проверке «board_id от клиента». Цена ошибки: поле телаretryи одна ветка. - 2026-10-19 — чужая метка проекта и
labels_removeP — без учёта регистра; принадлежность задачи — точно. Обоснование: Jira в JQL сравнивает метки без учёта регистра —awpcaпопала бы в общую JQL, но ни в чей разрез. Цена ошибки: сравнение в проверках. - 2026-10-19 —
notes_setв привязанной сессии — только свои задачи, без соседей. Обоснование: «только свои» владельца. Цена ошибки: одна проверка. - 2026-10-19 — фрагмент
.mcp.json—uv run --project <корень хаба от расположения пакета>. Обоснование: вызовuv runизsys.argvне восстановить, путь к.venvв чужом репозитории хрупок. Цена ошибки: формат подсказки. - 2026-10-19 — на проект делятся и раскладка (
fileKey), и флаги доски (pref); AWPCA — на нынешних ключах, остальные — с суффиксом@<метка>. Обоснование: спека требует хранить фильтры отдельно; анти-цель — потеря раскладки AWPCA. Цена ошибки: схема ключей вstorage.ts. - 2026-10-19 —
last_syncпосле создания проекта —nullдо завершения его обновления,sync_run.queryне переписывается. Обоснование: прежний прогон новую метку не покрывал. Цена ошибки: временная надпись на доске. - 2026-10-19 — пустой
authorвPOST /projects— какapi, нестрока — 422bad_project. Обоснование: как у остальных маршрутов (body.get("author") or "api"); спека требует 422 для не-строки. Цена ошибки: пустая строка пишется авторомapi, а не отвергается. - 2026-10-19 —
CommandErrorиз постановки refresh вPOST /projects— 422bad_batch, а неbad_project. Обоснование: ошибка относится к пакету, а не к полям проекта; спека называет толькоproject_existsиbad_project. Цена ошибки: код ошибки в ответе. - 2026-10-19 —
GET /batches?project=с неизвестной меткой — пустой список, а не 404; пустойproject=— как без фильтра. Обоснование: спека требует 404 только для/issuesи/board; у пакетов проект — произвольная сохранённая метка. Цена ошибки: одна ветка вh_batches_get. - 2026-10-19 — в
ensure_issueпакета проекта повторы других (не P) меток не убираются. Обоснование: спека убирает только повтор P; остальное — как прислал клиент. Цена ошибки: одна строка в_check_project. - 2026-10-19 —
projectвretry/POST /batchesне строка — 422bad_retry/bad_batch; вretry_commandсначала сверкаprojectс проектом исходного, затемcreate_batchс проверками проекта. Обоснование: «команда #N не из проекта P» точнее ошибки проверок. Цена ошибки: текст 422. - 2026-10-19 — типы досок из результата
refreshпишутся только приstatus = done; результат без ключаboardsили с мусорными значениями типы не трогает. Обоснование: у проваленной команды результат неполон, а агент v11 ключа не присылает. Цена ошибки: одно условие вreport_result. - 2026-10-19 — метки временного ключа для
ensure_sprintберутся только из егоensure_issueв пакете, без обращения к зеркалу. Обоснование:new:<n>в зеркале — не задача Jira; метки пакета (с дописанной меткой проекта) единственный надёжный источник. Цена ошибки: ветка в_assign_boards.