Événements de domaine
Bus d’événements
Section intitulée « Bus d’événements »Le DomainEventBus est un bus de publication/abonnement en diffusion, interne au processus. Les éditeurs appellent publish(event) ; les abonnés consomment un flux typé on<T>(). Chaque événement implémente DomainEvent et porte un occurredAt.
Le bus s’exécute à l’intérieur de cc_server. Chaque éditeur et chaque abonné actif y résident. Aucun client ne voit ce bus — le serveur réémet un sous-ensemble sélectionné sous forme de trames JSON-RPC notifications/*, filtrées par abonné selon l’appartenance à l’espace de travail.
| Mesure | Nombre |
|---|---|
| Classes d’événements concrètes | 54 |
Fichiers sources (packages/cc_domain/lib/core/domain/events/) |
14 (plus domain_event_bus.dart) |
| Classes de base abstraites jamais publiées directement | 1 (TaskLifecycleEvent, une hiérarchie scellée) |
Chaque événement du catalogue ci-dessous vit dans ce seul répertoire ; aucun événement de domaine n’est déclaré ailleurs.
Événements d’espace de travail, d’agent et de dépôt
Section intitulée « Événements d’espace de travail, d’agent et de dépôt »| Événement | Charge utile | Déclenché quand |
|---|---|---|
WorkspaceCreated |
workspaceId |
L’espace de travail est créé |
AgentRunCompleted |
agentId, runId?, workspaceId?, conversationId? |
Un agent termine une exécution (succès ou échec) |
AgentAwaitingInput |
workspaceId, kind, summary, spaceId?, conversationId?, agentId?, agentName? |
Un agent commence à attendre une personne : une approbation, une question ask_user ou une exécution bloquée sur des identifiants (kind vaut approval, question ou credential) |
RepoAdded |
repoId, path, workspaceId |
Un dépôt est enregistré ; déclenche l’indexation du code en arrière-plan |
SkillUpdated |
workspaceId, slug, origin, computedHash, scanVerdict? |
Un skill est installé ou mis à jour, avec son verdict d’analyse de chaîne d’approvisionnement |
Événements de PR et de revue
Section intitulée « Événements de PR et de revue »Le premier bloc est le cycle de vie propre de la PR. Le second est la veille des PR rédigées : des signaux concernant une PR que vous avez ouverte, chacun portant forUserId afin que la boucle d’interrogation les achemine vers la personne concernée plutôt que de les diffuser à tout le monde.
| Événement | Charge utile | Déclenché quand |
|---|---|---|
PullRequestPublished |
prId, workspaceId, repoOwner, repoName |
Un agent ouvre une PR |
PullRequestStatusChanged |
status, workspaceId, prId?, repoFullName?, prNumber? |
PR fusionnée/fermée/ouverte/rouverte/approuvée |
PrMerged |
prId, workspaceId, agentId |
La PR est fusionnée — un signal étroit limité à la fusion, conservé pour l’analytique et les notifications |
PrReviewRequested |
workspaceId, repoOwner, repoName, prNumber, prTitle |
GitHub demande une revue de la part de l’utilisateur du serveur (interrogation des notifications, review_requested) |
PrMentioned |
workspaceId, repoOwner, repoName, prNumber, prTitle |
L’utilisateur du serveur est mentionné sur une PR (interrogation des notifications, mention) |
ExternalPrMerged |
workspaceId, repoOwner, repoName, prNumber, prTitle, mergedByLogin? |
Une PR suivie de l’extérieur (hors agent) a été fusionnée, détectée par l’interrogation des notifications GitHub ; correspond à la catégorie de notification prMerged |
ExternalPrDetected |
repoOwner, repoName, prNumber, prTitle, author, workspaceId? |
PR hors agent trouvée par interrogation — réservée aux pipelines (alimente external_pr_welcome), ne lève aucune notification |
PrHeadChanged |
repoOwner, repoName, prNumber, prTitle, previousHeadSha, headSha, workspaceId |
Le SHA de tête de la PR a changé — l’auteur a poussé |
ReviewBecameStale |
workspaceId, spaceId, repoOwner, repoName, prNumber, prTitle, reviewedHeadSha, headSha |
Une revue IA terminée ne décrit plus la PR qu’elle a examinée. Ne se déclenche que si une revue existe pour le commit remplacé, ce qui en fait un signal plutôt qu’une alerte à chaque push |
La veille des PR rédigées
Section intitulée « La veille des PR rédigées »Les six portent workspaceId, repoOwner, repoName, prNumber, prTitle et un forUserId facultatif.
| Événement | Charge utile supplémentaire | Déclenché quand |
|---|---|---|
PrMergeReadinessChanged |
ready, reason |
Une PR que vous avez rédigée est devenue fusionnable, ou a cessé de l’être |
PrReviewDecisionChanged |
decision, reviewersRemaining, approverLogin? |
Un relecteur a approuvé, demandé des modifications, ou une approbation a été rejetée |
PrChecksStatusChanged |
failing, failingCheckName?, failingCheckUrl? |
La CI est passée au rouge, ou s’est rétablie |
PrCommentMentioned |
commentId, authorLogin, bodyPreview, isReviewComment, threadId?, path?, line? |
Quelqu’un vous a mentionné dans un commentaire de PR ou de revue |
PrThreadReplied |
commentId, authorLogin, bodyPreview, threadId?, path?, line? |
Quelqu’un a répondu dans un fil de revue auquel vous participez |
PrThreadResolved |
threadId, commentId?, path?, line? |
Quelqu’un a résolu un fil de revue auquel vous participez |
Événements de messagerie
Section intitulée « Événements de messagerie »| Événement | Charge utile | Déclenché quand |
|---|---|---|
MessageReceived |
spaceId, messageId, senderName, contentPreview, isAgentMessage, workspaceId?, mentions, requestedByUserId?, senderUserId? |
Un nouveau message arrive |
SpaceCreated |
spaceId, workspaceId |
L’espace est créé |
SpaceDeleted |
spaceId, workspaceId |
L’espace est supprimé |
SpaceProvisioningChanged |
workspaceId, spaceId, status, step? |
L’espace de travail associé entre en provisionnement, atteint une étape (clonage d’un dépôt, extraction d’une PR, configuration d’un agent) ou bascule à prêt/échec — la passerelle de chat le relate sur sa carte de tâche |
Événements de billetterie
Section intitulée « Événements de billetterie »| Événement | Charge utile | Déclenché quand |
|---|---|---|
TicketCreated |
ticketId, workspaceId |
Le ticket est créé |
TicketAssigned |
ticketId, ticketTitle, ticketBody?, ticketUrl?, assignedAgentId?, assigneeType, assignedTeamId?, workspaceId |
Ticket assigné à un principal ou à une équipe |
TicketCompleted |
ticketId |
Le travail se termine (terminal) |
TicketFailed |
ticketId, errorMessage |
L’agent échoue (terminal) |
TicketCancelled |
ticketId |
Le ticket est annulé (terminal) |
TicketStatusChanged |
ticketId, workspaceId, from, to |
Tout changement de statut |
TicketReassigned |
ticketId, workspaceId, fromAgentId?, toAgentId? |
Le ticket est réassigné |
TicketDetailsUpdated |
ticketId, workspaceId |
Le titre, la description ou la priorité changent |
Événements de cycle de vie des tâches
Section intitulée « Événements de cycle de vie des tâches »Le flux unifié du cycle de vie des tâches — une exécution d’agent lancée, identifiée par l’id de son journal d’exécution. Chaque événement porte taskId, un seq monotone propre à la tâche, workspaceId?, agentId? et une phase ; les lignes ci-dessous ne listent que les champs supplémentaires.
| Événement | Charge utile | Déclenché quand |
|---|---|---|
TaskDispatched |
— | Tâche remise à un backend pour exécution |
TaskRunning |
— | La tâche a commencé à produire de la sortie |
TaskWaitingLocalDirectory |
lockedPath, holderTaskId? |
Tâche parquée — une autre tâche détient le verrou de chemin sur disque dont elle a besoin |
TaskProgress |
note? |
Point de contrôle de progression en cours d’exécution |
TaskMessage |
messageType, content |
Message diffusé en flux (text/thinking/tool_use/tool_result/error) ; rapporté sous la phase progress |
TaskCompleted |
summary? |
La tâche s’est terminée avec succès |
TaskFailed |
errorMessage |
La tâche s’est terminée par une erreur |
TaskCancelled |
— | Tâche annulée avant son achèvement |
L’énumération TaskPhase possède aussi un membre queued, mais rien ne publie d’événement pour celui-ci — il n’existe pas de classe TaskQueued. La première trame observable d’une tâche est TaskDispatched.
Événements de pipeline
Section intitulée « Événements de pipeline »| Événement | Charge utile | Déclenché quand |
|---|---|---|
PipelineRunCompleted |
workspaceId, pipelineRunId, templateId |
L’exécution se termine |
PipelineRunCancelled |
workspaceId, pipelineRunId, templateId |
Exécution annulée (par l’utilisateur ou le système) — un arrêt délibéré, pas une erreur |
PipelineRunFailed |
workspaceId, pipelineRunId, templateId, errorMessage |
L’exécution échoue |
Seules les transitions terminales sont publiées. Il n’existe ni PipelineRunStarted ni événement par étape : la progression d’une étape parvient aux clients par les lignes de l’exécution elle-même et par le flux de cycle de vie des tâches de l’agent qu’elle a lancé, et non par le bus.
Événements d’observabilité
Section intitulée « Événements d’observabilité »| Événement | Charge utile | Déclenché quand |
|---|---|---|
ActivityLogged |
id, actorType, actorId?, action, entityType, entityId?, details?, workspaceId?, runId? |
Entrée de piste d’audit créée |
BudgetThresholdCrossed |
scopeType, scopeId, spentCents, budgetCents, isHardStop |
Les dépenses dépassent le seuil |
Événements d’identité et d’appartenance
Section intitulée « Événements d’identité et d’appartenance »| Événement | Charge utile | Déclenché quand |
|---|---|---|
WorkspaceMemberAdded |
workspaceId, userId, role |
Un utilisateur rejoint un espace de travail (utilisation d’une invitation ou ajout par un administrateur) |
WorkspaceMemberRemoved |
workspaceId, userId |
Un membre est retiré — les sessions actives de cet utilisateur limitées à l’espace de travail doivent revérifier l’accès immédiatement |
WorkspaceMemberRoleChanged |
workspaceId, userId, role |
Le rôle d’un membre change |
L’appartenance constitue toute la surface d’identité sur le bus. La création d’utilisateurs et la révocation d’appareils ont lieu, mais elles ne sont pas publiées comme événements de domaine — la révocation est appliquée directement sur les sessions actives plutôt que routée par le bus.
Événements de calendrier et de réunion
Section intitulée « Événements de calendrier et de réunion »| Événement | Charge utile | Déclenché quand |
|---|---|---|
CalendarAuthExpired |
workspaceId, accountEmail |
Le jeton de rafraîchissement OAuth d’un compte connecté est définitivement invalide (publié une fois par épisode de déconnexion) |
MeetingStartingSoon |
workspaceId, eventId, title, startTime, meetingUrl? |
Un événement de calendrier commence dans la fenêtre d’avance configurée |
MeetingRecordingStopped |
workspaceId, meetingId, title, userNotes, transcript, summaryInstructions? |
Un enregistrement de réunion se termine et déclenche le pipeline intégré meeting_summary |
Événements de rig
Section intitulée « Événements de rig »| Événement | Charge utile | Déclenché quand |
|---|---|---|
RigClosedEvent |
workspaceId, rigId, reason |
Un rig a disparu, avec sa raison de fermeture ; les consommateurs n’agissent que sur backendFailure — toute autre raison est demandée ou accompagnée d’un RigReaped |
RigControlChanged |
workspaceId, rigId, controller? |
Un humain a pris le contrôle exclusif d’un rig ou l’a rendu (controller vaut null à la restitution — l’événement n’enregistre pas qui a rendu la main) |
RigReaped |
workspaceId, rigId, reason, agentId? |
Le système a récupéré une machine : inactivité, TTL ou éviction sous pression mémoire (rapportée comme idleTimeout), avec l’agent aux commandes |
L’ouverture d’un rig n’est pas un événement. Le démarrage s’achève et la ligne du rig bascule à prêt ; rien n’est publié, il n’y a donc pas de RigOpened auquel s’abonner.
Sous-domaines sans aucun événement
Section intitulée « Sous-domaines sans aucun événement »Plusieurs sous-systèmes qui semblent pilotés par événements vus de l’extérieur ne le sont pas. Ils sont listés ici parce que leur absence est une décision de conception qu’il vaut la peine de connaître avant de chercher un point d’accroche :
| Sous-domaine | Comment l’état progresse à la place |
|---|---|
| Mémoire | record_memory_fact et ses semblables écrivent et renvoient ; le rappel lit. Rien ne publie sur un fait ou un conflit |
| Orchestration | La proposition, son approbation et l’exécution de pipeline générée sont des lignes et des appels RPC |
| Documents de plan | submit_plan écrit une révision ; l’approbation matérialise une orchestration. Ni l’un ni l’autre n’est annoncé |
| Artefacts | publish_artifact / revise_artifact écrivent des révisions directement |
| Approbations | L’escalade est gérée à l’intérieur du service de flux de travail des approbations |
| Synchronisation des tickets | Le coordinateur de fournisseurs s’abonne aux événements de tickets ci-dessus ; les webhooks entrants sont appliqués directement |
| Rafraîchissement du calendrier | Une synchronisation insère ou met à jour des événements et le client relit ; il n’existe aucune diffusion de rafraîchissement |
| Fusions d’arbres de travail | Consignées dans worktree_merge_log et lues depuis là |
Chaque abonné ci-dessous est construit à l’intérieur de runCcServer (ou d’un service qu’il construit). Il n’existe aucun abonné côté client.
| Abonné | Événements qu’il consomme |
|---|---|
WorkspaceSeeder |
WorkspaceCreated |
| Amorçage de la suite d’évaluation de démarrage (en ligne) | WorkspaceCreated |
| Provisionnement de l’espace de chat (en ligne) | SpaceCreated |
PipelineTriggerDispatcher |
Chaque DomainEvent ; chaque déclencheur activé filtre sur son propre type |
SubPipelineResumeListener |
PipelineRunCompleted, PipelineRunFailed |
PipelineCostRollupListener |
AgentRunCompleted |
BudgetEvaluationListener |
AgentRunCompleted |
MeetingSummaryReconciler |
PipelineRunCompleted, PipelineRunFailed, PipelineRunCancelled (uniquement les exécutions 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 — injecte un avis en langage clair dans la voie de pilotage de l’agent aux commandes |
StaleReviewWatcher |
PrHeadChanged — publie ReviewBecameStale uniquement lorsqu’une revue terminée existe pour le commit remplacé |
GitHubPrConversationBridge |
AgentRunCompleted — réponses sortantes de conversation de PR |
NotificationFeedRecorder |
Les vingt-deux événements de classe notification ci-dessous |
RemoteEventForwarder |
Ces vingt-deux, plus TicketReassigned et chaque TaskLifecycleEvent. Les trois événements d’appartenance ne font qu’invalider son cache d’appartenance par espace de travail ; ils ne sont pas transmis sous forme de trames |
LocalRpcServer / RemoteRelayHost |
WorkspaceMemberRemoved — abandonne les abonnements d’espace de travail rattachés à cet utilisateur ; la socket reste ouverte |
TicketAssigned est un signal d’audit et de notification, ainsi qu’un déclencheur de pipeline. L’assignation à un agent enregistre la propriété et ne démarre aucune exécution — il n’existe aucun répartiteur de tickets. L’assignation à une équipe (assignedTeamId défini) fait exception : TeamRoutingService lance le chef d’équipe.
TicketRemoteSyncHandler est déclaré mais jamais construit dans le code de production, il ne s’abonne donc à rien aujourd’hui. Le NotificationEventMapper côté client n’est construit que dans son propre test — c’est le vestige du chemin interne au processus d’avant la séparation client/serveur. Les notifications éphémères en direct proviennent des trames ci-dessous.
Mappage des notifications
Section intitulée « Mappage des notifications »Côté serveur, NotificationFeedRecorder et RemoteEventForwarder transforment ces événements en trames notifications/* (notification_wire.dart). Côté client, RpcNotificationMapper → mapNotificationFrame transforme une trame en AppNotification.
Il existe exactement dix-sept catégories de notification. Plusieurs événements correspondent à plus d’une méthode de trame, car la trame porte la transition (échec ou rétablissement) tandis que la catégorie porte la question (« que fait la CI ? »).
| Catégorie | Événement source | Méthode de trame |
|---|---|---|
newMessage |
MessageReceived |
notifications/message_received (vous mentionne) |
agentRunCompleted |
MessageReceived |
notifications/message_received (is_agent_message, sans mention de vous) |
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 |
La trame de prise de contrôle d’un rig n’est pas renvoyée à celui qui a pris le volant, une restitution n’est pas filtrée (l’événement n’enregistre pas qui a rendu la main), et seule une fermeture backendFailure produit une trame rig_closed — les autres raisons sont soit demandées, soit déjà couvertes par la trame de récupération.
AgentAwaitingInput est publié par AgentAwaitingInputPublisher, qui surveille l’apparition de nouvelles entrées dans les registres des approbations et des identifiants bloqués, et que AgentQuestionService prévient de chaque question ask_user. Une attente produit un seul événement, et rien n’est publié lorsqu’elle prend fin.
Les cinq catégories de PR rédigées portent forUserId, si bien qu’elles atteignent l’auteur plutôt que tout le monde dans l’espace de travail.
RemoteEventForwarder transmet en outre TicketReassigned sous la forme notifications/ticket_reassigned et chaque TaskLifecycleEvent sous la forme notifications/task_<phase>. Ni l’un ni l’autre ne correspond à une catégorie de notification — ils pilotent l’interface en direct, et non le centre de notifications. Les événements d’appartenance ne sont pas transmis sous forme de trames : ils invalident le cache du redirecteur, et les hôtes de session abandonnent les abonnements d’espace de travail du membre retiré.