Événements de domaine
Bus d’événements
Section intitulée “Bus d’événements”Le DomainEventBus est un bus de publication/abonnement par diffusion à l’intérieur du processus. Les éditeurs appellent publish(event); les abonnés consomment un flux typé on<T>(). Chaque événement implémente DomainEvent et porte occurredAt.
Le bus s’exécute à l’intérieur de cc_server. Chaque éditeur et chaque abonné actif y réside. Aucun client ne voit ce bus — le serveur réémet un sous-ensemble choisi 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) |
| Bases abstraites jamais publiées directement | 1 (TaskLifecycleEvent, une hiérarchie scellée) |
Chaque événement du catalogue ci-dessous réside 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 | Se déclenche quand |
|---|---|---|
WorkspaceCreated |
workspaceId |
L’espace de travail est créé |
AgentRunCompleted |
agentId, runId?, workspaceId?, conversationId? |
Un agent termine une exécution (réussie ou échouée) |
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 le verdict de son analyse de chaîne d’approvisionnement |
Événements de PR et de révision
Section intitulée “Événements de PR et de révision”Le premier bloc est le cycle de vie propre à la PR. Le second est la surveillance des PR dont vous êtes l’auteur : des signaux au sujet d’une PR que vous avez ouverte, chacun portant forUserId afin que le sondage puisse les acheminer vers la personne concernée plutôt que de les diffuser.
| Événement | Charge utile | Se déclenche quand |
|---|---|---|
PullRequestPublished |
prId, workspaceId, repoOwner, repoName |
Un agent ouvre une PR |
PullRequestStatusChanged |
status, workspaceId, prId?, repoFullName?, prNumber? |
La PR est fusionnée/fermée/ouverte/rouverte/approuvée |
PrMerged |
prId, workspaceId, agentId |
La PR est fusionnée — un signal étroit de fusion seule conservé pour l’analytique et les notifications |
PrReviewRequested |
workspaceId, repoOwner, repoName, prNumber, prTitle |
GitHub demande la revue de l’utilisateur du serveur (sondage des notifications, review_requested) |
PrMentioned |
workspaceId, repoOwner, repoName, prNumber, prTitle |
L’utilisateur du serveur est mentionné sur une PR (sondage des notifications, mention) |
ExternalPrMerged |
workspaceId, repoOwner, repoName, prNumber, prTitle, mergedByLogin? |
Une PR suivie de l’extérieur (hors agent) est fusionnée, détectée par le sondage des notifications de GitHub; correspond à la catégorie de notification prMerged |
ExternalPrDetected |
repoOwner, repoName, prNumber, prTitle, author, workspaceId? |
Une PR hors agent est trouvée par sondage — réservé 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 révision par IA terminée ne décrit plus la PR qu’elle a révisée. Ne se déclenche que lorsqu’une révision existe pour le commit remplacé, ce qui en fait un signal plutôt qu’un ping à chaque poussée |
La surveillance des PR dont vous êtes l’auteur
Section intitulée “La surveillance des PR dont vous êtes l’auteur”Tous les six portent workspaceId, repoOwner, repoName, prNumber, prTitle et un forUserId facultatif.
| Événement | Charge utile supplémentaire | Se déclenche quand |
|---|---|---|
PrMergeReadinessChanged |
ready, reason |
Une PR dont vous êtes l’auteur est devenue fusionnable, ou a cessé de l’être |
PrReviewDecisionChanged |
decision, reviewersRemaining, approverLogin? |
Un réviseur a approuvé, demandé des changements, ou a vu une approbation 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 | Se déclenche 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 de l’espace entre en provisionnement, atteint une étape (clonage d’un dépôt, extraction d’une PR, configuration d’un agent) ou bascule vers prêt/échoué — la passerelle de clavardage le raconte sur sa carte de tâche |
Événements de billetterie
Section intitulée “Événements de billetterie”| Événement | Charge utile | Se déclenche quand |
|---|---|---|
TicketCreated |
ticketId, workspaceId |
Le ticket est créé |
TicketAssigned |
ticketId, ticketTitle, ticketBody?, ticketUrl?, assignedAgentId?, assigneeType, assignedTeamId?, workspaceId |
Le ticket est 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é change |
É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, indexée par l’identifiant de son journal d’exécution. Chaque événement porte taskId, un seq monotone par tâche, workspaceId?, agentId? et une phase; les lignes ci-dessous n’énumèrent que les champs supplémentaires.
| Événement | Charge utile | Se déclenche quand |
|---|---|---|
TaskDispatched |
— | La tâche est confiée à un backend pour exécution |
TaskRunning |
— | La tâche a commencé à produire de la sortie |
TaskWaitingLocalDirectory |
lockedPath, holderTaskId? |
La tâche est mise en attente — 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 continu (text/thinking/tool_use/tool_result/error); signalé 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 |
— | La tâche est annulée avant la fin |
L’énumération TaskPhase comporte aussi un membre queued, mais rien ne publie d’événement de mise en file — 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 | Se déclenche quand |
|---|---|---|
PipelineRunCompleted |
workspaceId, pipelineRunId, templateId |
L’exécution se termine |
PipelineRunCancelled |
workspaceId, pipelineRunId, templateId |
L’exécution est 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 aucun PipelineRunStarted ni aucun é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 | Se déclenche quand |
|---|---|---|
ActivityLogged |
id, actorType, actorId?, action, entityType, entityId?, details?, workspaceId?, runId? |
Une entrée de la piste d’audit est 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 | Se déclenche quand |
|---|---|---|
WorkspaceMemberAdded |
workspaceId, userId, role |
Un utilisateur rejoint un espace de travail (acceptation d’une invitation ou ajout par un administrateur) |
WorkspaceMemberRemoved |
workspaceId, userId |
Un membre est retiré — les sessions actives de cet utilisateur rattaché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 est toute la surface d’identité sur le bus. La création d’utilisateur et la révocation d’appareil ont lieu, mais elles ne sont pas publiées comme événements de domaine — la révocation est appliquée directement aux sessions actives plutôt que d’être acheminé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 | Se déclenche quand |
|---|---|---|
CalendarAuthExpired |
workspaceId, accountEmail |
Le jeton de rafraîchissement OAuth d’un compte connecté est définitivement invalide (publié une seule fois par épisode de déconnexion) |
MeetingStartingSoon |
workspaceId, eventId, title, startTime, meetingUrl? |
Un événement du calendrier commence dans la fenêtre d’anticipation configurée |
MeetingRecordingStopped |
workspaceId, meetingId, title, userNotes, transcript, summaryInstructions? |
L’enregistrement d’une 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 | Se déclenche 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 remise — l’événement ne consigne pas qui a lâché) |
RigReaped |
workspaceId, rigId, reason, agentId? |
Le système a récupéré une machine : inactivité, TTL ou éviction pour pression mémoire (signalée comme idleTimeout), avec l’agent qui la pilotait |
L’ouverture d’un rig n’est pas un événement. L’amorçage se termine et la ligne du rig bascule vers prêt; rien n’est publié, il n’y a donc aucun RigOpened auquel s’abonner.
Sous-domaines sans aucun événement
Section intitulée “Sous-domaines sans aucun événement”Plusieurs sous-systèmes qui, de l’extérieur, semblent pilotés par les événements ne le sont pas. Ils figurent ici parce que leur absence est une décision de conception qu’il vaut la peine de connaître avant d’aller chercher un point d’accroche :
| Sous-domaine | Comment l’état progresse à la place |
|---|---|
| Mémoire | record_memory_fact et ses acolytes écrivent et retournent; 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é |
| Artéfacts | publish_artifact / revise_artifact écrivent les révisions directement |
| Approbations | L’escalade est traitée à l’intérieur du service de flux d’approbation |
| Synchronisation des tickets | Le coordinateur de fournisseurs s’abonne aux événements de ticket ci-dessus; les webhooks entrants sont appliqués directement |
| Actualisation du calendrier | Une synchronisation insère ou met à jour les événements et le client les relit; il n’y a aucune diffusion d’actualisation |
| Fusions d’arbres de travail | Consignées dans worktree_merge_log et lues à partir de là |
Abonnés
Section intitulée “Abonnés”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 des suites d’évaluation de départ (en ligne) | WorkspaceCreated |
| Provisionnement de l’espace de clavardage (en ligne) | SpaceCreated |
PipelineTriggerDispatcher |
Tout DomainEvent; chaque déclencheur activé filtre selon 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 qui pilote |
StaleReviewWatcher |
PrHeadChanged — ne publie ReviewBecameStale que lorsqu’une révision 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 réémis 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, et un déclencheur de pipeline. L’assignation à un agent consigne la propriété et ne démarre aucune exécution — il n’existe pas de répartiteur de tickets. L’assignation à une équipe (assignedTeamId défini) est l’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 intra-processus d’avant la séparation client/serveur. Les toasts en direct proviennent des trames ci-dessous.
Mappage des notifications
Section intitulée “Mappage des notifications”Sur le serveur, NotificationFeedRecorder et RemoteEventForwarder transforment ces événements en trames notifications/* (notification_wire.dart). Sur le client, RpcNotificationMapper → mapNotificationFrame transforme une trame en AppNotification.
Il y a exactement dix-sept catégories de notification. Plusieurs événements correspondent à plus d’une méthode de trame, parce que la trame porte le changement (échoué ou rétabli) 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 livrée à la personne qui a pris
le volant, une remise n’est pas filtrée (l’événement ne consigne pas qui a
lâché), 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 dont vous êtes l’auteur portent forUserId, de sorte qu’elles atteignent l’auteur plutôt que tout le monde dans l’espace de travail.
RemoteEventForwarder réémet en plus TicketReassigned sous notifications/ticket_reassigned et chaque TaskLifecycleEvent sous notifications/task_<phase>. Ni l’un ni l’autre ne correspond à une catégorie de notification — ils pilotent l’interface en direct, pas le centre de notifications. Les événements d’appartenance ne sont pas réémis sous forme de trames : ils invalident le cache du réémetteur, et les hôtes de session abandonnent les abonnements d’espace de travail du membre retiré.