Eventos de domínio
O que é um evento de domínio
Seção intitulada “O que é um evento de domínio”Eventos de domínio são o mecanismo de desacoplamento que permite às features se comunicarem sem dependências diretas. Em vez de a feature A chamar a feature B, a feature A publica um evento e a feature B o assina.
O DomainEventBus é um barramento de publicação/assinatura por difusão que roda
em processo. Os publicadores chamam publish(event); os assinantes consomem um
stream tipado on<T>(). Todo evento implementa DomainEvent e carrega
occurredAt.
O barramento roda dentro do cc_server. Todo publicador e todo assinante
ativo ficam lá. Nenhum cliente vê este barramento. O que um cliente vê é um
subconjunto curado que o servidor reemite como frames JSON-RPC notifications/*.
Por que um barramento, afinal
Seção intitulada “Por que um barramento, afinal”Sem eventos, toda reação entre features é um import. O caminho das notificações teria de importar a feature de agentes, a feature de pull requests, a de tickets e a de reuniões só para saber quando exibir um toast — e cada uma dessas teria então de saber que as notificações existem. A parte de tickets importaria os pipelines para que um ticket concluído pudesse avançar uma execução. O grafo de dependências fecha um nó, e o kernel compartilhado deixa de ser compartilhado.
Publicar um evento rompe isso. O caminho das notificações assina vinte e uma classes de evento e não importa nenhuma das features que os emitem. O dispatcher de gatilhos de pipeline assina o barramento inteiro e não sabe nada sobre pull requests, tickets ou reuniões. A observabilidade agrega resultados de execução sem alcançar o despacho.
O custo é o de sempre: um publicador não consegue saber se alguém está
escutando, e um ouvinte que nunca é construído fica silenciosamente inerte. O
TicketRemoteSyncHandler é o exemplo permanente: ele é declarado, coberto por
testes e nunca é conectado em produção.
O que o barramento não é
Seção intitulada “O que o barramento não é”Vale ser preciso sobre uma coisa que o barramento não possui.
O registro de auditoria não é uma projeção do fluxo de eventos. Toda
operação RPC que modifica algo é auditada por padrão — RepoOp.audited tem como
padrão true, e uma operação só abre mão disso ao declarar audited: false, um
ato deliberado e visível na própria operação. O dispatcher acrescenta a linha
“quem fez o quê, de onde” logo depois de uma chamada bem-sucedida. Não existe
DomainEventAuditBridge. O ActivityLogPersister grava linhas em activity_log
a partir de eventos ActivityLogged; esse é um feed separado da auditoria RPC.
O barramento de eventos é o transporte das notificações e da automação. Ele não é o sistema de registro contábil.
O que o barramento impulsiona
Seção intitulada “O que o barramento impulsiona”- Notificações. Vinte e uma classes de evento são transformadas em frames
notifications/*pelo servidor, gravadas em um feed durável por espaço de trabalho e transmitidas às sessões conectadas. Um frame cujoworkspace_idnomeia um espaço de trabalho do qual o usuário da sessão não é membro é descartado no servidor; o cliente então filtra o restante para o espaço de trabalho que está exibindo. - Automação orientada a eventos. Os gatilhos de pipeline assinam o barramento e iniciam automaticamente os pipelines correspondentes (veja abaixo).
- Reações de ciclo de vida. Criar um espaço de trabalho semeia seus agentes CEO e especialistas, os modelos de pipeline integrados e as suítes de avaliação iniciais. Uma execução de agente concluída retoma uma etapa de pipeline suspensa, fecha uma tarefa, alimenta o supervisor de metas, pode acordar um verificador nomeado e pode disparar novamente um líder de equipe. Uma PR mesclada ou um espaço excluído dispara a coleta de lixo do worktree.
- Sincronização entre fornecedores. As mudanças locais de tickets são enviadas aos fornecedores configurados por um coordenador que escuta cinco eventos de ticket.
Categorias de eventos
Seção intitulada “Categorias de eventos”Os eventos cobrem toda a superfície do produto. Em linhas gerais:
- Espaços de trabalho, agentes e repos — criação de espaço de trabalho, conclusão de execução, registro de repo, atualizações de skill
- Pull requests — publicação, mudanças de status, merges, pedidos de revisão, menções, acompanhamento de PRs de autoria própria, PRs detectadas externamente
- Mensagens — mensagens, espaços e o progresso de provisionamento de espaços
- Tickets — criação, atribuição, reatribuição, detalhes, status e os três desfechos terminais
- Tarefas — frames de ciclo de vida sequenciados para uma execução despachada, para que os clientes possam ordená-los e desduplicá-los
- Pipelines — apenas eventos terminais de execução (concluída, cancelada, com falha)
- Observabilidade — entradas do log de atividades e limites de orçamento
- Identidade e associação — membro adicionado, removido, papel alterado
- Calendário e reuniões — expiração de autenticação, início de reuniões e conclusão de gravações
- Rigs — tomada de controle, reap e fechamento inesperado
Memória, orquestração, documentos de plano, artefatos, aprovações, ingestão de sincronização de tickets, atualização de calendário, merges de worktree, criação de usuários, convites e revogação de dispositivos não são eventos de domínio; consulte a referência.
Para o catálogo completo — todas as 53 classes de evento concretas, seus payloads e os 24 assinantes que as consomem — veja a Referência de eventos de domínio. Aquela página é o inventário; esta é o modelo.
O controle de acesso ao vivo usa dois mecanismos diferentes
Seção intitulada “O controle de acesso ao vivo usa dois mecanismos diferentes”Os eventos de associação e de dispositivo parecem simétricos e não são, o que importa se você estiver raciocinando sobre a rapidez com que uma revogação faz efeito.
Revogar um dispositivo de fato encerra as sessões dele. O servidor observa a tabela de dispositivos emparelhados e derruba qualquer sessão ativa cujo dispositivo saiu do conjunto ativo, em questão de segundos.
Remover um membro não fecha o socket. O WorkspaceMemberRemoved é
consumido: o LocalRpcServer e o RemoteRelayHost derrubam as assinaturas de
espaço de trabalho anexadas àquele usuário, e o RemoteEventForwarder invalida
seu cache de associação para que novos frames daquele espaço de trabalho não
sejam enviados. O que nega a próxima RPC ainda é o portão de papel, que resolve
a associação novamente a cada chamada — então a próxima solicitação deles é
recusada com “Not a member of this workspace”. O efeito é imediato para qualquer
coisa que eles tentem fazer; só não é obtido desligando a conexão deles.
Gatilhos de pipeline
Seção intitulada “Gatilhos de pipeline”Os gatilhos de pipeline assinam eventos de domínio e iniciam automaticamente os
pipelines correspondentes. O PipelineTriggerDispatcher escuta o barramento
inteiro e então:
- Faz um curto-circuito, a menos que o tipo de evento seja um que ele saiba mapear para um payload
- Localiza os gatilhos habilitados que correspondem a esse tipo de evento, em todos os espaços de trabalho
- Filtra cada um para o próprio espaço de trabalho e aplica seu filtro de correspondência de payload
- Inicia uma execução para cada gatilho que sobrevive
A restrição importante é a etapa 1. O barramento carrega 53 tipos de evento; o
seletor de adicionar gatilho inicia uma execução para estes catorze (EventPayloadMapper
ramos de payload):
ExternalPrDetected, PullRequestPublished, PullRequestStatusChanged,
PrMerged, MessageReceived, TicketAssigned,
TicketCompleted, TicketFailed, TicketCancelled,
BudgetThresholdCrossed, RepoAdded, MeetingRecordingStopped, SkillUpdated
e SpaceDeleted. Nada mais pode iniciar um pipeline.
Como um cliente vê tudo isso
Seção intitulada “Como um cliente vê tudo isso”O RemoteEventForwarder traduz os eventos da classe de notificação em frames e
os envia por RPC às sessões conectadas, onde um mapeador de frames os transforma
em notificações dentro do app. Um cliente fino, portanto, vê uma projeção do
fluxo de eventos do servidor sem ser dono de nenhuma execução — que é justamente
o ponto da divisão de cliente fino.
Nem todo frame enviado é uma notificação, porém. O fluxo de ciclo de vida de tarefas e a reatribuição de tickets são encaminhados ao vivo para movimentar a interface, mas não são gravados no feed de notificações nem exibem toast.
Veja também
Seção intitulada “Veja também”- Pipelines e automação: o que um gatilho inicia
- Tickets e delegação: atribuição a um agente versus a uma equipe
- Arquitetura: como os eventos se encaixam na regra de dependências
- Referência de eventos de domínio: o catálogo completo e seus assinantes
- Configurar gatilhos de pipeline
- Configurar notificações