Eventos de domínio
Barramento de eventos
Seção intitulada “Barramento de eventos”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 servidor encaminha um subconjunto curado como frames JSON-RPC notifications/*, filtrados por assinante conforme a associação ao espaço de trabalho.
| Medida | Quantidade |
|---|---|
| Classes de evento concretas | 54 |
Arquivos-fonte (packages/cc_domain/lib/core/domain/events/) |
14 (mais domain_event_bus.dart) |
| Bases abstratas que nunca são publicadas diretamente | 1 (TaskLifecycleEvent, uma hierarquia selada) |
Todo evento do catálogo abaixo fica nesse único diretório; não há eventos de domínio declarados em nenhum outro lugar.
Eventos de espaço de trabalho, agente e repo
Seção intitulada “Eventos de espaço de trabalho, agente e repo”| Evento | Payload | Dispara quando |
|---|---|---|
WorkspaceCreated |
workspaceId |
O espaço de trabalho é criado |
AgentRunCompleted |
agentId, runId?, workspaceId?, conversationId? |
O agente termina uma execução (com sucesso ou com falha) |
AgentAwaitingInput |
workspaceId, kind, summary, spaceId?, conversationId?, agentId?, agentName? |
Um agente começa a esperar por uma pessoa: uma aprovação, uma pergunta ask_user ou uma execução parada em uma credencial (kind é approval, question ou credential) |
RepoAdded |
repoId, path, workspaceId |
Um repo é registrado; dispara a indexação de código em segundo plano |
SkillUpdated |
workspaceId, slug, origin, computedHash, scanVerdict? |
Uma skill é instalada ou atualizada, carregando o veredito da análise da cadeia de suprimentos |
Eventos de PR e revisão
Seção intitulada “Eventos de PR e revisão”O primeiro bloco é o ciclo de vida da própria PR. O segundo é o acompanhamento de PRs de autoria própria: sinais sobre uma PR que você abriu, cada um carregando forUserId para que a consulta periódica possa encaminhá-los à pessoa a quem dizem respeito em vez de difundi-los.
| Evento | Payload | Dispara quando |
|---|---|---|
PullRequestPublished |
prId, workspaceId, repoOwner, repoName |
O agente abre uma PR |
PullRequestStatusChanged |
status, workspaceId, prId?, repoFullName?, prNumber? |
PR mesclada/fechada/aberta/reaberta/aprovada |
PrMerged |
prId, workspaceId, agentId |
A PR é mesclada — um sinal estreito, apenas de merge, mantido para análises e notificações |
PrReviewRequested |
workspaceId, repoOwner, repoName, prNumber, prTitle |
O GitHub pede a revisão do usuário do servidor (consulta periódica de notificações, review_requested) |
PrMentioned |
workspaceId, repoOwner, repoName, prNumber, prTitle |
O usuário do servidor é mencionado em uma PR (consulta periódica de notificações, mention) |
ExternalPrMerged |
workspaceId, repoOwner, repoName, prNumber, prTitle, mergedByLogin? |
Uma PR acompanhada externamente (não de agente) foi mesclada, detectada pela consulta periódica de notificações do GitHub; mapeia para a categoria de notificação prMerged |
ExternalPrDetected |
repoOwner, repoName, prNumber, prTitle, author, workspaceId? |
PR não de agente encontrada por consulta periódica — apenas para pipelines (alimenta external_pr_welcome), não gera notificação |
PrHeadChanged |
repoOwner, repoName, prNumber, prTitle, previousHeadSha, headSha, workspaceId |
O SHA de cabeça da PR mudou — o autor fez push |
ReviewBecameStale |
workspaceId, spaceId, repoOwner, repoName, prNumber, prTitle, reviewedHeadSha, headSha |
Uma revisão de IA concluída não descreve mais a PR que revisou. Só dispara quando existe uma revisão para o commit substituído, então continua sendo um sinal e não um ping a cada push |
O acompanhamento de PRs de autoria própria
Seção intitulada “O acompanhamento de PRs de autoria própria”Todos os seis carregam workspaceId, repoOwner, repoName, prNumber, prTitle e um forUserId opcional.
| Evento | Payload adicional | Dispara quando |
|---|---|---|
PrMergeReadinessChanged |
ready, reason |
Uma PR de sua autoria se tornou mesclável, ou deixou de ser |
PrReviewDecisionChanged |
decision, reviewersRemaining, approverLogin? |
Um revisor aprovou, pediu alterações ou teve uma aprovação descartada |
PrChecksStatusChanged |
failing, failingCheckName?, failingCheckUrl? |
A CI ficou vermelha, ou se recuperou |
PrCommentMentioned |
commentId, authorLogin, bodyPreview, isReviewComment, threadId?, path?, line? |
Alguém mencionou você em um comentário de PR ou de revisão |
PrThreadReplied |
commentId, authorLogin, bodyPreview, threadId?, path?, line? |
Alguém respondeu em uma thread de revisão da qual você participa |
PrThreadResolved |
threadId, commentId?, path?, line? |
Alguém resolveu uma thread de revisão da qual você participa |
Eventos de mensagens
Seção intitulada “Eventos de mensagens”| Evento | Payload | Dispara quando |
|---|---|---|
MessageReceived |
spaceId, messageId, senderName, contentPreview, isAgentMessage, workspaceId?, mentions, requestedByUserId?, senderUserId? |
Uma nova mensagem chega |
SpaceCreated |
spaceId, workspaceId |
O espaço é criado |
SpaceDeleted |
spaceId, workspaceId |
O espaço é excluído |
SpaceProvisioningChanged |
workspaceId, spaceId, status, step? |
O espaço de trabalho do espaço entra em provisionamento, chega a uma etapa (clonar um repo, fazer checkout de uma PR, configurar um agente) ou muda para pronto/falhou — a ponte de chat narra isso no cartão de tarefa dela |
Eventos de tickets
Seção intitulada “Eventos de tickets”| Evento | Payload | Dispara quando |
|---|---|---|
TicketCreated |
ticketId, workspaceId |
O ticket é criado |
TicketAssigned |
ticketId, ticketTitle, ticketBody?, ticketUrl?, assignedAgentId?, assigneeType, assignedTeamId?, workspaceId |
Ticket atribuído a um principal ou a uma equipe |
TicketCompleted |
ticketId |
O trabalho termina (terminal) |
TicketFailed |
ticketId, errorMessage |
O agente falha (terminal) |
TicketCancelled |
ticketId |
Ticket cancelado (terminal) |
TicketStatusChanged |
ticketId, workspaceId, from, to |
Qualquer mudança de status |
TicketReassigned |
ticketId, workspaceId, fromAgentId?, toAgentId? |
Ticket reatribuído |
TicketDetailsUpdated |
ticketId, workspaceId |
Título, descrição ou prioridade mudam |
Eventos de ciclo de vida de tarefa
Seção intitulada “Eventos de ciclo de vida de tarefa”O fluxo unificado de ciclo de vida de tarefas — uma execução de agente despachada, identificada pelo id do log de execução. Todo evento carrega taskId, um seq monotônico por tarefa, workspaceId?, agentId? e uma phase; as linhas abaixo listam apenas os campos adicionais.
| Evento | Payload | Dispara quando |
|---|---|---|
TaskDispatched |
— | Tarefa entregue a um backend para execução |
TaskRunning |
— | A tarefa começou a produzir saída |
TaskWaitingLocalDirectory |
lockedPath, holderTaskId? |
Tarefa estacionada — outra tarefa detém o bloqueio do caminho em disco de que ela precisa |
TaskProgress |
note? |
Checkpoint de progresso no meio da execução |
TaskMessage |
messageType, content |
Mensagem transmitida em stream (text/thinking/tool_use/tool_result/error); reportada sob a fase progress |
TaskCompleted |
summary? |
A tarefa terminou com sucesso |
TaskFailed |
errorMessage |
A tarefa terminou com um erro |
TaskCancelled |
— | Tarefa cancelada antes da conclusão |
A enum TaskPhase também tem um membro queued, mas nada publica um evento de fila — não existe uma classe TaskQueued. O primeiro frame observável de uma tarefa é TaskDispatched.
Eventos de pipeline
Seção intitulada “Eventos de pipeline”| Evento | Payload | Dispara quando |
|---|---|---|
PipelineRunCompleted |
workspaceId, pipelineRunId, templateId |
A execução termina |
PipelineRunCancelled |
workspaceId, pipelineRunId, templateId |
Execução cancelada (pelo usuário ou pelo sistema) — uma parada deliberada, não um erro |
PipelineRunFailed |
workspaceId, pipelineRunId, templateId, errorMessage |
A execução falha |
Somente transições terminais são publicadas. Não existe PipelineRunStarted nem evento por etapa: o progresso de uma etapa chega aos clientes pelas próprias linhas da execução e pelo fluxo de ciclo de vida de tarefa do agente que ela despachou, não pelo barramento.
Eventos de observabilidade
Seção intitulada “Eventos de observabilidade”| Evento | Payload | Dispara quando |
|---|---|---|
ActivityLogged |
id, actorType, actorId?, action, entityType, entityId?, details?, workspaceId?, runId? |
Entrada de trilha de auditoria criada |
BudgetThresholdCrossed |
scopeType, scopeId, spentCents, budgetCents, isHardStop |
O gasto ultrapassa o limite |
Eventos de identidade e associação
Seção intitulada “Eventos de identidade e associação”| Evento | Payload | Dispara quando |
|---|---|---|
WorkspaceMemberAdded |
workspaceId, userId, role |
Um usuário entra em um espaço de trabalho (resgate de convite ou adição por um administrador) |
WorkspaceMemberRemoved |
workspaceId, userId |
Um membro é removido — as sessões ativas desse usuário no escopo do espaço de trabalho devem verificar o acesso novamente de imediato |
WorkspaceMemberRoleChanged |
workspaceId, userId, role |
O papel de um membro muda |
A associação é toda a superfície de identidade no barramento. A criação de usuários e a revogação de dispositivos acontecem, mas não são publicadas como eventos de domínio — a revogação é aplicada diretamente às sessões ativas em vez de passar pelo barramento.
Eventos de calendário e reuniões
Seção intitulada “Eventos de calendário e reuniões”| Evento | Payload | Dispara quando |
|---|---|---|
CalendarAuthExpired |
workspaceId, accountEmail |
O token de atualização OAuth de uma conta conectada fica inválido em definitivo (publicado uma vez por episódio de desconexão) |
MeetingStartingSoon |
workspaceId, eventId, title, startTime, meetingUrl? |
Um evento de calendário vai começar dentro da janela de antecedência configurada |
MeetingRecordingStopped |
workspaceId, meetingId, title, userNotes, transcript, summaryInstructions? |
A gravação de uma reunião termina e dispara o pipeline integrado meeting_summary |
Eventos de rig
Seção intitulada “Eventos de rig”| Evento | Payload | Dispara quando |
|---|---|---|
RigClosedEvent |
workspaceId, rigId, reason |
Um rig desapareceu, com o motivo do fechamento; os consumidores só agem em backendFailure — qualquer outro motivo foi solicitado ou vem acompanhado de um RigReaped |
RigControlChanged |
workspaceId, rigId, controller? |
Uma pessoa assumiu o controle exclusivo de um rig ou o devolveu (controller nulo ao liberar — o evento não registra quem soltou) |
RigReaped |
workspaceId, rigId, reason, agentId? |
O sistema recuperou uma máquina: ociosidade, TTL ou despejo por pressão de memória (reportado como idleTimeout), com o agente que a conduzia |
A abertura de um rig não é um evento. O boot termina e a linha do rig passa para pronto; nada é publicado, então não há um RigOpened para assinar.
Subdomínios sem nenhum evento
Seção intitulada “Subdomínios sem nenhum evento”Vários subsistemas que parecem orientados a eventos quando vistos de fora não são. Eles estão listados aqui porque a ausência deles é uma decisão de projeto que vale conhecer antes de sair procurando um hook:
| Subdomínio | Como o estado avança em vez disso |
|---|---|
| Memória | record_memory_fact e companhia escrevem e retornam; a recuperação lê. Nada publica sobre um fato ou conflito |
| Orquestração | A proposta, sua aprovação e a execução de pipeline gerada são linhas e chamadas RPC |
| Documentos de plano | submit_plan grava uma revisão; a aprovação materializa uma orquestração. Nenhum dos dois é anunciado |
| Artefatos | publish_artifact / revise_artifact gravam revisões diretamente |
| Aprovações | A escalada é tratada dentro do serviço de fluxo de aprovação |
| Sincronização de tickets | O coordenador de fornecedores assina os eventos de ticket acima; os webhooks de entrada são aplicados diretamente |
| Atualização de calendário | Uma sincronização faz upsert dos eventos e o cliente os relê; não há difusão de atualização |
| Merges de worktree | Registrados em worktree_merge_log e lidos de lá |
Assinantes
Seção intitulada “Assinantes”Todos os assinantes abaixo são construídos dentro de runCcServer (ou de um serviço que ele monta). Não existe assinante do lado do cliente.
| Assinante | Eventos que consome |
|---|---|
WorkspaceSeeder |
WorkspaceCreated |
| Semeadura inicial de suítes de avaliação (inline) | WorkspaceCreated |
| Provisionamento do espaço de chat (inline) | SpaceCreated |
PipelineTriggerDispatcher |
Todo DomainEvent; cada gatilho habilitado filtra pelo próprio tipo |
SubPipelineResumeListener |
PipelineRunCompleted, PipelineRunFailed |
PipelineCostRollupListener |
AgentRunCompleted |
BudgetEvaluationListener |
AgentRunCompleted |
MeetingSummaryReconciler |
PipelineRunCompleted, PipelineRunFailed, PipelineRunCancelled (apenas execuções de meeting_summary) |
PipelineStepResumeListener |
AgentRunCompleted |
AgentRunTaskCompleter |
AgentRunCompleted |
GoalSupervisor |
AgentRunCompleted |
CheckerDispatchListener |
AgentRunCompleted |
TeamRoutingService |
AgentRunCompleted, TicketAssigned |
OrchestrationRunListener |
PipelineRunCancelled, PipelineRunFailed |
MultiVendorTicketSyncCoordinator |
TicketCreated, TicketAssigned, TicketReassigned, TicketStatusChanged, TicketDetailsUpdated |
WorktreeGcListener |
TicketCompleted, TicketCancelled, SpaceDeleted, PrMerged, PullRequestStatusChanged |
ChatBridgeService |
MessageReceived, SpaceProvisioningChanged |
ActivityLogPersister |
ActivityLogged |
RigEventListener |
RigControlChanged, RigReaped, RigClosedEvent — injeta um aviso em linguagem simples na pista de orientação do agente que conduz |
StaleReviewWatcher |
PrHeadChanged — publica ReviewBecameStale apenas quando existe uma revisão concluída para o commit substituído |
GitHubPrConversationBridge |
AgentRunCompleted — respostas de saída em conversas de PR |
NotificationFeedRecorder |
Os vinte e dois eventos da classe de notificação abaixo |
RemoteEventForwarder |
Aqueles vinte e dois mais TicketReassigned e todo TaskLifecycleEvent. Os três eventos de associação apenas invalidam seu cache de associação por espaço de trabalho; eles não são encaminhados como frames |
LocalRpcServer / RemoteRelayHost |
WorkspaceMemberRemoved — descarta as assinaturas de espaço de trabalho anexadas daquele usuário; o socket permanece aberto |
TicketAssigned é um sinal de auditoria e de notificação e um gatilho de pipeline. A atribuição a um agente registra a propriedade e não inicia nenhuma execução — não existe um dispatcher de tickets. A atribuição a uma equipe (assignedTeamId definido) é a exceção: o TeamRoutingService despacha o líder da equipe.
O TicketRemoteSyncHandler é declarado, mas nunca é construído no código de produção, então hoje não assina nada. O NotificationEventMapper do lado do cliente é construído apenas em seu próprio teste — é o resquício do caminho em processo de antes da separação entre cliente e servidor. Os toasts ao vivo vêm dos frames de transmissão abaixo.
Mapeamento de notificações
Seção intitulada “Mapeamento de notificações”No servidor, NotificationFeedRecorder e RemoteEventForwarder transformam esses eventos em frames de transmissão notifications/* (notification_wire.dart). No cliente, RpcNotificationMapper → mapNotificationFrame transforma um frame em uma AppNotification.
Há exatamente dezessete categorias de notificação. Vários eventos mapeiam para mais de um método de transmissão, porque o frame carrega a transição (falhou versus recuperou) enquanto a categoria carrega a pergunta (“o que a CI está fazendo?”).
| Categoria | Evento de origem | Método de transmissão |
|---|---|---|
newMessage |
MessageReceived |
notifications/message_received (menciona você) |
agentRunCompleted |
MessageReceived |
notifications/message_received (is_agent_message, sem mencionar você) |
agentAwaitingInput |
AgentAwaitingInput |
notifications/agent_awaiting_input |
ticketAssigned |
TicketAssigned |
notifications/ticket_assigned |
ticketStatusChanged |
TicketStatusChanged |
notifications/ticket_status_changed |
pullRequestPublished |
PullRequestPublished |
notifications/pr_published |
prMerged |
PrMerged |
notifications/pr_merged |
prMerged |
ExternalPrMerged |
notifications/external_pr_merged |
prMentioned |
PrMentioned |
notifications/pr_mentioned |
prMentioned |
PrCommentMentioned |
notifications/pr_comment_mentioned |
reviewRequested |
PrReviewRequested |
notifications/pr_review_requested |
reviewStale |
ReviewBecameStale |
notifications/review_stale |
prMergeReadiness |
PrMergeReadinessChanged |
notifications/pr_ready_to_merge / pr_merge_blocked |
prReviewDecision |
PrReviewDecisionChanged |
notifications/pr_approved / pr_changes_requested / pr_review_dismissed |
prChecksStatus |
PrChecksStatusChanged |
notifications/pr_checks_failed / pr_checks_recovered |
prThreadActivity |
PrThreadReplied |
notifications/pr_thread_replied |
prThreadActivity |
PrThreadResolved |
notifications/pr_thread_resolved |
meetingStartsSoon |
MeetingStartingSoon |
notifications/meeting_starting_soon |
calendarAuthExpired |
CalendarAuthExpired |
notifications/calendar_auth_expired |
rigStatusChanged |
RigControlChanged |
notifications/rig_control_changed |
rigStatusChanged |
RigReaped |
notifications/rig_reaped |
rigStatusChanged |
RigClosedEvent |
notifications/rig_closed |
O frame de tomada de controle do rig não é entregue de volta a quem assumiu o volante, uma liberação não é filtrada (o evento não registra quem soltou) e apenas um fechamento por backendFailure produz um frame rig_closed — os outros motivos foram solicitados ou já estão cobertos pelo frame de reap.
AgentAwaitingInput é publicado pelo AgentAwaitingInputPublisher, que observa os registros de aprovações e de bloqueios de credencial em busca de novas entradas e é avisado de cada pergunta ask_user pelo AgentQuestionService. Uma espera é um evento; nada é publicado quando a espera termina.
As cinco categorias de PR de autoria própria carregam forUserId, então chegam ao autor em vez de a todos no espaço de trabalho.
O RemoteEventForwarder ainda encaminha TicketReassigned como notifications/ticket_reassigned e todo TaskLifecycleEvent como notifications/task_<phase>. Nenhum dos dois mapeia para uma categoria de notificação — eles movimentam a interface ao vivo, não a central de notificações. Os eventos de associação não são encaminhados como frames: eles invalidam o cache do encaminhador, e os hosts de sessão descartam as assinaturas de espaço de trabalho do membro removido.