Tickets e delegação
Um ticket é a unidade de trabalho que o Control Center acompanha. Ele é, de propósito, um artefato burro: um título, um corpo, um status, um responsável e um lugar em uma árvore. Ele não é aquilo contra o que os agentes executam — o trabalho dos agentes vive nas conversas, e a saída estruturada de uma execução fica no log de execução.
A atribuição registra a propriedade; ela não despacha nada
Seção intitulada “A atribuição registra a propriedade; ela não despacha nada”De todos os pontos sobre tickets, este é o mais importante de acertar.
Definir assignedAgentId grava um campo e publica um TicketAssigned
evento de domínio. Esse evento é
um sinal de auditoria e de notificação e um gatilho de pipeline. Atribuir um
ticket a um agente não inicia nenhuma execução. Não existe um despachante de
tickets que observe assignedAgentId e acorde esse agente.
A exceção é uma equipe: quando assignedTeamId está definido, o
TeamRoutingService despacha o líder da equipe com o protocolo de operação e a
lista de integrantes.
Se você quer que um agente específico trabalhe em um ticket, você pede a ele em uma conversa, ou uma etapa de pipeline o despacha, ou outro agente delega a ele. Atribuir um ticket a um agente e esperar é a única coisa que nunca vai produzir trabalho.
Espelho e sobreposição
Seção intitulada “Espelho e sobreposição”Um ticket pode ser puramente local ou respaldado por um rastreador externo, e ele carrega os dois na mesma linha.
O espelho — provedor, chave externa, URL, título, descrição, prioridade, rótulos, status bruto e normalizado, carimbos de data e hora — é um cache quando o ticket é remoto. O sistema remoto é a fonte da verdade nesse caso, e uma atualização reescreve o espelho por inteiro.
A sobreposição — atribuição, delegação, vínculo com espaço, pai, projeto, PRs vinculadas — existe só no Control Center. O rastreador não sabe nada a respeito dela, e uma atualização nunca a toca.
É essa separação que torna seguro sincronizar: uma importação do fornecedor pode ser destrutiva para o espelho sem nunca perder os metadados de orquestração sobrepostos.
O grafo de ciclo de vida vincula os agentes, não você
Seção intitulada “O grafo de ciclo de vida vincula os agentes, não você”Os status seguem backlog → open → inProgress → inReview → done, com blocked
como um ramo lateral e failed / cancelled como os demais estados
terminais.
O grafo de transições é aplicado apenas no caminho do agente e da automação — ferramentas MCP e reconciliadores. Uma transição ilegal por ali é registrada em log e ignorada, de modo que um agente confuso não consegue fazer um ticket voltar para trás e sair de um estado terminal.
Toda mudança feita por um usuário na interface passa force: true e ignora o
grafo por completo. Uma pessoa pode mover um ticket para qualquer status que o
seletor liste — inclusive reabrir um estado terminal. O seletor não oferece
failed; os agentes definem esse status por meio de fail_ticket. O grafo é
uma barreira de proteção para a automação, não uma regra sobre como o trabalho
pode andar.
O TicketWorkflowService concentra toda mutação em um único ponto de passagem,
que carrega a linha, verifica se ela pertence ao espaço de trabalho de quem
chama e grava com um version esperado, de modo que duas edições simultâneas
não possam se sobrescrever em silêncio.
Para a tabela completa de status, as transições, a lista de campos e os tipos de relação, consulte Ciclo de vida de tickets.
Procedência: como um ticket passou a existir
Seção intitulada “Procedência: como um ticket passou a existir”Todo ticket tem um originKind. O enum tem cinco valores — manual,
pipelineStep, agentDelegation, externalSync, recovery — mas hoje só
dois são gravados: manual (o padrão em createTicket, incluindo filhos
delegados) e externalSync (o motor de sincronização, em uma importação do
fornecedor). TicketWorkflowService.createTicket não recebe um argumento de
origem, então pipelineStep, agentDelegation e recovery nunca chegam a uma
linha.
Delegação protegida
Seção intitulada “Delegação protegida”A delegação é onde um agente cria trabalho para outro agente e é o ponto por onde privilégios poderiam vazar, então as verificações ficam do lado do servidor, em um ponto único de passagem, e não nas instruções do prompt.
O delegate_task passa pelo TicketWorkflowService.delegateGuarded, que
calcula a profundidade e a raiz do filho a partir da cadeia de pais e então
executa as quatro verificações de DelegationGuards: um salto que
ultrapassaria um limite de profundidade de 3, um salto de volta a um agente
que já está na cadeia (detecção de ciclo), um teto de autonomia (o
nível efetivo do delegado no espaço não pode exceder o do delegador) e um
envelope de orçamento (a delegação debita o orçamento de parada rígida
restante do delegador e não pode criar mais). A montagem de produção fornece
ambas as portas de resolução. Autonomia e orçamento são ignorados quando
from_agent_id é omitido (orçamento ilimitado / sem política também passa).
Uma recusa é lançada como uma DelegationRefusedException cuja mensagem chega
ao agente delegador literalmente — uma negação ruidosa, nunca uma operação
silenciosa sem efeito.
O delegate_ticket é o irmão mais antigo e sem verificações: ele chama
createTicket diretamente e pula todas as verificações. Prefira o
delegate_task.
Não confunda o limite de profundidade da delegação (3, nas cadeias de
delegate_task) com o limite de aninhamento de subagentes do harness integrado
(2). São limites diferentes, em mecanismos diferentes.
Hierarquia, vínculos e projetos
Seção intitulada “Hierarquia, vínculos e projetos”As relações de pai e de subitem ficam em tickets.parent_ticket_id,
controladas por setParent / clearParent. Elas não são linhas de
ticket_links, então qualquer coisa que leia as relações de um ticket precisa
combinar as duas fontes.
ticket_links guarda as arestas direcionais entre tickets que, fora isso, não
têm relação entre si:
| Tipo de vínculo | Significado |
|---|---|
blocks |
A origem bloqueia o destino |
relatesTo |
Os dois tickets estão relacionados (simétrico) |
duplicateOf |
A origem é uma duplicata do destino |
Um projeto é um agrupamento de tickets com escopo de espaço de trabalho em direção a um objetivo comum. Projetos existem só no Control Center e nunca sincronizam com um provedor externo.
Colaboradores
Seção intitulada “Colaboradores”As linhas de TicketCollaborator são como mais de um principal é anexado a um
ticket, em um papel de assignee, collaborator ou reviewer. Pessoas e
agentes são linhas equivalentes — um principalId mais um collaboratorType —
sem valor sentinela para “o usuário” e sem chave estrangeira para qualquer uma
das tabelas.
Sincronização externa
Seção intitulada “Sincronização externa”No Control Center, o ticket é o principal. Excluir um ticket é somente local, então um ticket respaldado por um fornecedor que você exclui não é excluído no rastreador e pode reaparecer na próxima sincronização. Colaboradores e tickets filhos são excluídos em cascata.
As credenciais dos adaptadores são resolvidas nos armazenamentos de credenciais do servidor (uma chave do Linear ou um token do GitHub colado em Configurações é reconhecido na próxima requisição; o ambiente apenas semeia esses armazenamentos).
Tickets e pipelines
Seção intitulada “Tickets e pipelines”Nenhum nó de pipeline cria, conclui ou cancela tickets — a paleta não tem essa
etapa e o motor não chama o TicketWorkflowService. Um gatilho de pipeline
ainda pode disparar em TicketAssigned, TicketCompleted, TicketFailed ou
TicketCancelled (esses quatro são os eventos de ticket que o
EventPayloadMapper de fato mapeia). Não existe uma coluna pipelineRunId no
ticket; o acoplamento com pipelines vive no log de execução do agente.
Veja também
Seção intitulada “Veja também”- Pipelines e automação: eventos de ticket podem disparar um pipeline
- Orquestração: de onde vem um DAG de subtickets
- O modelo de agentes: a quem um ticket é atribuído
- Eventos de domínio: os eventos do ciclo de vida do ticket
- Ciclo de vida de tickets: status, campos, transições, relações
- Criar e gerenciar tickets
- Delegar trabalho a agentes
- Organizar o trabalho com projetos