Тікети та делегування
Тікет — це одиниця роботи, яку відстежує Control Center. Він навмисно примітивний артефакт: заголовок, тіло, стан, власник і місце в дереві. Це не те, з чим працюють агенти — робота агентів живе в розмовах, а структурований вивід запуску живе в журналі запусків.
Призначення фіксує власність; воно нічого не запускає
Розділ із назвою «Призначення фіксує власність; воно нічого не запускає»Це найважливіше, що треба правильно зрозуміти про тікети.
Встановлення assignedAgentId записує поле й публікує
доменну подію TicketAssigned. Ця подія —
сигнал аудиту й сповіщення та тригер конвеєра. Призначення агенту не
запускає жодного запуску. Немає диспетчера тікетів, який стежив би за
assignedAgentId і будив би цього агента.
Виняток — команда: коли встановлено assignedTeamId, TeamRoutingService
запускає лідера команди з робочим протоколом і реєстром.
Якщо ви хочете, щоб над тікетом працював конкретний агент, попросіть його в розмові, або його запускає крок конвеєра, або йому делегує інший агент. Призначити тікет агенту й чекати — це єдине, що ніколи не дасть роботи.
Дзеркало й оверлей
Розділ із назвою «Дзеркало й оверлей»Тікет може бути цілком локальним або підкріпленим зовнішнім трекером, і він несе обидва аспекти в одному рядку.
Дзеркало — постачальник, зовнішній ключ, URL, заголовок, опис, пріоритет, мітки, сирий і нормалізований стан, часові мітки — це кеш, коли тікет віддалений. Там джерело істини — віддалена система, і оновлення повністю перезаписує дзеркало.
Оверлей — призначення, делегування, зв’язок із простором, батьківський тікет, проєкт, пов’язані PR — існує лише в Control Center. Трекер нічого про нього не знає, і оновлення ніколи його не торкається.
Саме цей поділ і робить синхронізацію безпечною: витяг даних від постачальника може руйнівно вплинути на дзеркало й при цьому ніколи не втратить метадані оркестрації, накладені зверху.
Граф життєвого циклу зв’язує агентів, а не вас
Розділ із назвою «Граф життєвого циклу зв’язує агентів, а не вас»Стани йдуть backlog → open → inProgress → inReview → done, де blocked —
бічна петля, а failed / cancelled — інші термінальні стани.
Граф переходів застосовується лише на шляху агентів і автоматизації — інструменти MCP та узгоджувачі. Неприпустимий перехід там записується в журнал і ігнорується, тож розгублений агент не може провести тікет назад із термінального стану.
Кожна зміна з боку користувача в інтерфейсі передає force: true і повністю
обминає граф. Людина може перевести тікет у будь-який стан зі списку вибору —
зокрема відкрити термінальний заново. Вибір не пропонує failed; агенти
встановлюють його через fail_ticket. Граф — це запобіжник для автоматизації,
а не правило про те, як має відбуватися робота.
TicketWorkflowService володіє кожною зміною через єдину контрольну точку, яка
завантажує рядок, перевіряє, що він належить робочому простору того, хто
викликає, і записує з очікуваним version, щоб два одночасні редагування не
перезаписали одне одного мовчки.
Повну таблицю станів, переходи, список полів і види зв’язків дивіть у розділі Життєвий цикл тікета.
Походження: як тікет з’явився
Розділ із назвою «Походження: як тікет з’явився»Кожен тікет має originKind. Перелік налічує п’ять значень — manual,
pipelineStep, agentDelegation, externalSync, recovery — але сьогодні
записуються лише два: manual (типове для createTicket, зокрема для
делегованих дочірніх тікетів) і externalSync (рушій синхронізації, під час
витягу від постачальника). TicketWorkflowService.createTicket не приймає
аргументу походження, тож pipelineStep, agentDelegation і recovery ніколи
не потрапляють у рядок.
Захищене делегування
Розділ із назвою «Захищене делегування»Делегування — це коли агент створює роботу для іншого агента, і саме тут могли б просочуватися привілеї, тож запобіжники живуть на сервері в єдиній контрольній точці, а не в інструкціях промпту.
delegate_task проходить через TicketWorkflowService.delegateGuarded, який
обчислює глибину й корінь дочірнього тікета з ланцюга батьків, а потім виконує
всі чотири перевірки DelegationGuards: крок, що перевищив би обмеження
глибини у 3, крок назад до агента, який уже є в ланцюзі (виявлення
циклів), стеля автономії (дієвий рівень делегата в просторі не повинен
перевищувати рівень делегатора) і бюджетна рамка (делегування списується із
залишку жорсткого бюджету делегатора і не може створити нового). Виробниче
компонування надає обидва порти розв’язувача. Перевірки автономії та бюджету
пропускаються, коли from_agent_id не вказано (необмежений бюджет або бюджет
без політики також проходить). Відмова викидається як
DelegationRefusedException, чиє повідомлення доходить до агента-делегатора
дослівно — гучна відмова, а не тиха бездіяльність.
delegate_ticket — старіший незахищений побратим: він викликає
createTicket напряму й пропускає всі запобіжники. Надавайте перевагу
delegate_task.
Не плутайте обмеження глибини делегування (3, для ланцюгів delegate_task) з
обмеженням вкладеності субагентів у вбудованому харнесі (2). Це різні межі для
різних механізмів.
Ієрархія, зв’язки та проєкти
Розділ із назвою «Ієрархія, зв’язки та проєкти»Зв’язки «батько — підзадача» живуть у tickets.parent_ticket_id і належать
setParent / clearParent. Вони не є рядками ticket_links, тож усе, що
читає зв’язки тікета, має об’єднувати обидва джерела.
ticket_links зберігає напрямлені ребра між інакше не пов’язаними тікетами:
| Тип зв’язку | Значення |
|---|---|
blocks |
Джерело блокує ціль |
relatesTo |
Два тікети пов’язані (симетрично) |
duplicateOf |
Джерело — дублікат цілі |
Проєкт — це групування тікетів у межах робочого простору заради спільної мети. Проєкти існують лише в Control Center і ніколи не синхронізуються із зовнішнім постачальником.
Учасники
Розділ із назвою «Учасники»Рядки TicketCollaborator — це те, як до тікета прикріплюється більш ніж один
принципал, у ролі assignee, collaborator або reviewer. Люди й агенти —
рівноправні рядки: principalId плюс collaboratorType, без сторожового
значення для «користувача» і без зовнішнього ключа до жодної з таблиць.
Зовнішня синхронізація
Розділ із назвою «Зовнішня синхронізація»Тікет у Control Center — первинний. Видалення тікета — лише локальне, тож тікет, підкріплений зовнішнім трекером, який ви видалили, не видаляється на трекері й може з’явитися знову під час наступної синхронізації. Учасники та дочірні тікети каскадують.
Облікові дані адаптера беруться зі сховищ облікових даних сервера (ключ Linear або токен GitHub, вставлений у Налаштуваннях, підхоплюється під час наступного запиту; середовище лише наповнює ці сховища початковими значеннями).
Тікети та конвеєри
Розділ із назвою «Тікети та конвеєри»Жоден вузол конвеєра не створює, не завершує й не скасовує тікети — у палітрі
немає такого кроку, і рушій не викликає TicketWorkflowService. Тригер
конвеєра все ж може спрацьовувати на TicketAssigned, TicketCompleted,
TicketFailed або TicketCancelled (ці чотири — ті події тікета, які
EventPayloadMapper справді зіставляє). На тікеті немає стовпця
pipelineRunId; зв’язок із конвеєром живе в журналі запусків агента.
Дивіться також
Розділ із назвою «Дивіться також»- Конвеєри та автоматизація: події тікета можуть запускати конвеєр
- Оркестрація: звідки береться DAG підлеглих тікетів
- Модель агента: кому призначено тікет
- Доменні події: події життєвого циклу тікета
- Життєвий цикл тікета: стани, поля, переходи, зв’язки
- Створювати й керувати тікетами
- Делегувати роботу агентам
- Організувати роботу через проєкти