Doménové události
Sběrnice událostí
Sekce “Sběrnice událostí”DomainEventBus je broadcastová sběrnice publish/subscribe uvnitř procesu. Publikující volají publish(event), odběratelé konzumují typovaný proud on<T>(). Každá událost implementuje DomainEvent a nese occurredAt.
Sběrnice běží uvnitř cc_server. Každý publikující i každý živý odběratel žije tam. Žádný klient tuhle sběrnici nevidí. Server předává vybranou podmnožinu jako JSON-RPC rámce notifications/*, filtrované pro každého odběratele podle členství v pracovním prostoru.
| Míra | Počet |
|---|---|
| Konkrétní třídy událostí | 54 |
Zdrojové soubory (packages/cc_domain/lib/core/domain/events/) |
14 (plus domain_event_bus.dart) |
| Abstraktní báze, které se nikdy nepublikují přímo | 1 (TaskLifecycleEvent, sealed hierarchie) |
Každá událost v katalogu níže žije v tom jednom adresáři. Jinde se doménové události nedeklarují.
Události pracovního prostoru, agenta a repozitáře
Sekce “Události pracovního prostoru, agenta a repozitáře”| Událost | Payload | Kdy se spustí |
|---|---|---|
WorkspaceCreated |
workspaceId |
Vytvoří se pracovní prostor |
AgentRunCompleted |
agentId, runId?, workspaceId?, conversationId? |
Agent dokončí běh (úspěch i selhání) |
AgentAwaitingInput |
workspaceId, kind, summary, spaceId?, conversationId?, agentId?, agentName? |
Agent začne čekat na člověka: na schválení, na odpověď na otázku ask_user, nebo na přihlašovací údaje, kvůli kterým stojí běh (kind je approval, question nebo credential) |
RepoAdded |
repoId, path, workspaceId |
Zaregistruje se repozitář a spustí se indexace kódu na pozadí |
SkillUpdated |
workspaceId, slug, origin, computedHash, scanVerdict? |
Nainstaluje se nebo aktualizuje skill a nese verdikt skenu dodavatelského řetězce |
Události PR a kontroly
Sekce “Události PR a kontroly”První blok je vlastní životní cyklus PR. Druhý je sledování vlastních PR: signály o PR, který jsi otevřel. Každý nese forUserId, aby je dotazování směrovalo k člověku, kterého se týkají, místo aby je rozesílalo všem.
| Událost | Payload | Kdy se spustí |
|---|---|---|
PullRequestPublished |
prId, workspaceId, repoOwner, repoName |
Agent otevře PR |
PullRequestStatusChanged |
status, workspaceId, prId?, repoFullName?, prNumber? |
PR se sloučí, zavře, otevře, znovu otevře nebo schválí |
PrMerged |
prId, workspaceId, agentId |
PR se sloučí. Úzký signál jen pro sloučení, ponechaný pro analytiku a oznámení |
PrReviewRequested |
workspaceId, repoOwner, repoName, prNumber, prTitle |
GitHub žádá o kontrolu uživatele serveru (dotazování na oznámení, review_requested) |
PrMentioned |
workspaceId, repoOwner, repoName, prNumber, prTitle |
Uživatel serveru je zmíněn na PR (dotazování na oznámení, mention) |
ExternalPrMerged |
workspaceId, repoOwner, repoName, prNumber, prTitle, mergedByLogin? |
Sloučí se externě sledovaný PR (ne od agenta), zjištěný dotazováním na oznámení GitHubu; mapuje se na kategorii oznámení prMerged |
ExternalPrDetected |
repoOwner, repoName, prNumber, prTitle, author, workspaceId? |
PR bez agenta nalezený dotazováním. Jen pro pipeline (pohání external_pr_welcome), oznámení nezvedne |
PrHeadChanged |
repoOwner, repoName, prNumber, prTitle, previousHeadSha, headSha, workspaceId |
Head SHA pull requestu se posunul. Autor pushnul |
ReviewBecameStale |
workspaceId, spaceId, repoOwner, repoName, prNumber, prTitle, reviewedHeadSha, headSha |
Hotová AI kontrola už nepopisuje PR, který kontrolovala. Spustí se jen tehdy, když pro nahrazený commit kontrola existuje, takže zůstane signálem, ne pingem na každý push |
Sledování vlastních PR
Sekce “Sledování vlastních PR”Všech šest nese workspaceId, repoOwner, repoName, prNumber, prTitle a volitelné forUserId.
| Událost | Další payload | Kdy se spustí |
|---|---|---|
PrMergeReadinessChanged |
ready, reason |
PR, který jsi napsal, se stal sloučitelným, nebo jím být přestal |
PrReviewDecisionChanged |
decision, reviewersRemaining, approverLogin? |
Recenzent schválil, požádal o změny, nebo mu schválení někdo zrušil |
PrChecksStatusChanged |
failing, failingCheckName?, failingCheckUrl? |
CI přešlo do červené, nebo se zotavilo |
PrCommentMentioned |
commentId, authorLogin, bodyPreview, isReviewComment, threadId?, path?, line? |
Někdo tě zmínil v komentáři k PR nebo v komentáři kontroly |
PrThreadReplied |
commentId, authorLogin, bodyPreview, threadId?, path?, line? |
Někdo odpověděl ve vlákně kontroly, ve kterém jsi |
PrThreadResolved |
threadId, commentId?, path?, line? |
Někdo vyřešil vlákno kontroly, ve kterém jsi |
Události zpráv
Sekce “Události zpráv”| Událost | Payload | Kdy se spustí |
|---|---|---|
MessageReceived |
spaceId, messageId, senderName, contentPreview, isAgentMessage, workspaceId?, mentions, requestedByUserId?, senderUserId? |
Přijde nová zpráva |
SpaceCreated |
spaceId, workspaceId |
Vytvoří se prostor |
SpaceDeleted |
spaceId, workspaceId |
Prostor se smaže |
SpaceProvisioningChanged |
workspaceId, spaceId, status, step? |
Pracovní prostor daného prostoru vstoupí do zřizování, dosáhne kroku (klonování repozitáře, checkout PR, nastavení agenta), nebo přepne na ready/failed. Chatový most to vypráví na kartě úkolu |
Události ticketů
Sekce “Události ticketů”| Událost | Payload | Kdy se spustí |
|---|---|---|
TicketCreated |
ticketId, workspaceId |
Vytvoří se ticket |
TicketAssigned |
ticketId, ticketTitle, ticketBody?, ticketUrl?, assignedAgentId?, assigneeType, assignedTeamId?, workspaceId |
Ticket se přiřadí principálovi nebo týmu |
TicketCompleted |
ticketId |
Práce skončí (konečný stav) |
TicketFailed |
ticketId, errorMessage |
Agent selže (konečný stav) |
TicketCancelled |
ticketId |
Ticket se zruší (konečný stav) |
TicketStatusChanged |
ticketId, workspaceId, from, to |
Jakákoli změna stavu |
TicketReassigned |
ticketId, workspaceId, fromAgentId?, toAgentId? |
Ticket se přeřadí |
TicketDetailsUpdated |
ticketId, workspaceId |
Změní se název, popis nebo priorita |
Události životního cyklu úkolu
Sekce “Události životního cyklu úkolu”Jednotný proud životního cyklu úkolu: jeden odeslaný běh agenta, klíčovaný id svého run logu. Každá událost nese taskId, monotónní seq v rámci úkolu, workspaceId?, agentId? a phase. Řádky níže uvádějí jen další pole.
| Událost | Payload | Kdy se spustí |
|---|---|---|
TaskDispatched |
— | Úkol se předá backendu k provedení |
TaskRunning |
— | Úkol začne produkovat výstup |
TaskWaitingLocalDirectory |
lockedPath, holderTaskId? |
Úkol je odstavený. Jiný úkol drží zámek cesty na disku, který potřebuje |
TaskProgress |
note? |
Kontrolní bod průběhu uprostřed běhu |
TaskMessage |
messageType, content |
Streamovaná zpráva (text/thinking/tool_use/tool_result/error); hlásí se ve fázi progress |
TaskCompleted |
summary? |
Úkol úspěšně skončí |
TaskFailed |
errorMessage |
Úkol skončí chybou |
TaskCancelled |
— | Úkol se zruší před dokončením |
Enum TaskPhase má i člen queued, ale nic nepublikuje událost ve frontě. Třída TaskQueued neexistuje. První pozorovatelný rámec úkolu je TaskDispatched.
Události pipeline
Sekce “Události pipeline”| Událost | Payload | Kdy se spustí |
|---|---|---|
PipelineRunCompleted |
workspaceId, pipelineRunId, templateId |
Běh skončí |
PipelineRunCancelled |
workspaceId, pipelineRunId, templateId |
Běh se zruší (uživatelem nebo systémem). Záměrné zastavení, ne chyba |
PipelineRunFailed |
workspaceId, pipelineRunId, templateId, errorMessage |
Běh selže |
Publikují se jen konečné přechody. PipelineRunStarted neexistuje a neexistuje ani událost na krok. Průběh kroku se ke klientům dostane přes vlastní řádky běhu a přes proud životního cyklu úkolu agenta, kterého krok odeslal, ne přes sběrnici.
Události observabilty
Sekce “Události observabilty”| Událost | Payload | Kdy se spustí |
|---|---|---|
ActivityLogged |
id, actorType, actorId?, action, entityType, entityId?, details?, workspaceId?, runId? |
Vytvoří se záznam auditní stopy |
BudgetThresholdCrossed |
scopeType, scopeId, spentCents, budgetCents, isHardStop |
Útrata překročí práh |
Události identity a členství
Sekce “Události identity a členství”| Událost | Payload | Kdy se spustí |
|---|---|---|
WorkspaceMemberAdded |
workspaceId, userId, role |
Uživatel vstoupí do pracovního prostoru (uplatnění pozvánky nebo přidání správcem) |
WorkspaceMemberRemoved |
workspaceId, userId |
Člen se odebere. Živé relace toho uživatele vázané na pracovní prostor musí hned znovu ověřit přístup |
WorkspaceMemberRoleChanged |
workspaceId, userId, role |
Změní se role člena |
Členství je celá identitní plocha na sběrnici. Vytvoření uživatele a odvolání zařízení se dějí, ale jako doménové události se nepublikují. Odvolání se vynucuje přímo proti živým relacím, ne přes sběrnici.
Události kalendáře a schůzek
Sekce “Události kalendáře a schůzek”| Událost | Payload | Kdy se spustí |
|---|---|---|
CalendarAuthExpired |
workspaceId, accountEmail |
Obnovovací token OAuth připojeného účtu je trvale neplatný (publikuje se jednou na epizodu odpojení) |
MeetingStartingSoon |
workspaceId, eventId, title, startTime, meetingUrl? |
Událost kalendáře začíná uvnitř nastaveného okna předstihu |
MeetingRecordingStopped |
workspaceId, meetingId, title, userNotes, transcript, summaryInstructions? |
Nahrávka schůzky skončí a spustí vestavěnou pipeline meeting_summary |
Události stanic
Sekce “Události stanic”| Událost | Payload | Kdy se spustí |
|---|---|---|
RigClosedEvent |
workspaceId, rigId, reason |
Stanice zmizela a nese důvod zavření. Konzumenti reagují jen na backendFailure. Každý jiný důvod je vyžádaný, nebo ho doprovází RigReaped |
RigControlChanged |
workspaceId, rigId, controller? |
Člověk převzal výhradní řízení stanice, nebo ho vrátil (controller je při uvolnění null. Událost nezaznamenává, kdo pustil) |
RigReaped |
workspaceId, rigId, reason, agentId? |
Systém stroj vzal zpět: nečinnost, TTL, nebo vyklizení kvůli tlaku na paměť (hlášené jako idleTimeout), spolu s řídícím agentem |
Samotné otevření stanice není událost. Boot doběhne a řádek stanice přepne na ready. Nic se nepublikuje, takže neexistuje RigOpened, na které by šlo se přihlásit.
Subdomény zcela bez událostí
Sekce “Subdomény zcela bez událostí”Několik subsystémů vypadá zvenku jako řízených událostmi. Nejsou. Jsou tu proto, že jejich absence je rozhodnutí návrhu, které stojí za to znát, než půjdeš hledat hook:
| Subdoména | Jak se stav hýbe místo toho |
|---|---|
| Paměť | record_memory_fact a spol. zapíšou a vrátí se. Vyvolání jen čte. Na fakt ani na konflikt se nic nepublikuje |
| Orchestrace | Návrh, jeho schválení a vygenerovaný běh pipeline jsou řádky a volání RPC |
| Dokumenty plánu | submit_plan zapíše revizi. Schválení zhmotní orchestraci. Ani jedno se neoznamuje |
| Artefakty | publish_artifact / revise_artifact zapisují revize přímo |
| Schválení | Eskalaci řeší služba workflow schválení |
| Synchronizace ticketů | Koordinátor dodavatele se přihlásí k událostem ticketu výše. Příchozí webhooky se aplikují přímo |
| Obnovení kalendáře | Synchronizace události upsertuje a klient si je znovu přečte. Broadcast obnovení neexistuje |
| Sloučení worktree | Zapisuje se do worktree_merge_log a čte se odtud |
Odběratelé
Sekce “Odběratelé”Každý odběratel níže se konstruuje uvnitř runCcServer (nebo ve službě, kterou sestaví). Odběratel na straně klienta neexistuje.
| Odběratel | Události, které konzumuje |
|---|---|
WorkspaceSeeder |
WorkspaceCreated |
| Osazení startovní sady evalů (přímo v kódu) | WorkspaceCreated |
| Zřizování chatového prostoru (přímo v kódu) | SpaceCreated |
PipelineTriggerDispatcher |
Každá DomainEvent. Každý zapnutý spouštěč filtruje na svůj vlastní typ |
SubPipelineResumeListener |
PipelineRunCompleted, PipelineRunFailed |
PipelineCostRollupListener |
AgentRunCompleted |
BudgetEvaluationListener |
AgentRunCompleted |
MeetingSummaryReconciler |
PipelineRunCompleted, PipelineRunFailed, PipelineRunCancelled (jen běhy 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. Vloží srozumitelnou zprávu do kanálu usměrnění řídícího agenta |
StaleReviewWatcher |
PrHeadChanged. Publikuje ReviewBecameStale jen tehdy, když pro nahrazený commit existuje hotová kontrola |
GitHubPrConversationBridge |
AgentRunCompleted. Odchozí odpovědi v konverzaci PR |
NotificationFeedRecorder |
Dvaadvacet událostí třídy oznámení níže |
RemoteEventForwarder |
Těch dvaadvacet plus TicketReassigned a každá TaskLifecycleEvent. Tři události členství jen zneplatní jeho cache členství po pracovních prostorech. Jako rámce se nepřeposílají |
LocalRpcServer / RemoteRelayHost |
WorkspaceMemberRemoved. Zahodí připojené odběry pracovního prostoru toho uživatele. Soket zůstane otevřený |
TicketAssigned je signál auditu i oznámení a zároveň spouštěč pipeline. Přiřazení agentovi zapíše vlastnictví a nespustí běh. Dispečer ticketů neexistuje. Výjimka je přiřazení týmu (nastavené assignedTeamId): TeamRoutingService odešle vedoucího týmu.
TicketRemoteSyncHandler je deklarovaný, ale v produkčním kódu se nikdy nekonstruuje, takže dnes neodebírá nic. Klientský NotificationEventMapper se konstruuje jen ve vlastním testu. Je to zbytek cesty uvnitř procesu z doby před rozdělením klienta a serveru. Živé toasty přicházejí z rámců na drátě níže.
Mapování oznámení
Sekce “Mapování oznámení”Na serveru z těchto událostí NotificationFeedRecorder a RemoteEventForwarder udělají rámce na drátě notifications/* (notification_wire.dart). Na klientovi z rámce RpcNotificationMapper → mapNotificationFrame udělá AppNotification.
Kategorií oznámení je přesně sedmnáct. Několik událostí se mapuje na víc než jednu metodu na drátě, protože rámec nese hranu (selhání, nebo zotavení) a kategorie nese otázku („co dělá CI?“).
| Kategorie | Zdrojová událost | Metoda na drátě |
|---|---|---|
newMessage |
MessageReceived |
notifications/message_received (zmiňuje tě) |
agentRunCompleted |
MessageReceived |
notifications/message_received (is_agent_message, bez tvé zmínky) |
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 |
Rámec převzetí stanice se nevrací tomu, kdo řízení převzal. Uvolnění se nefiltruje (událost nezaznamenává, kdo pustil) a jen zavření backendFailure vyrobí rámec rig_closed. Ostatní důvody jsou buď vyžádané, nebo je už pokrývá rámec reap.
AgentAwaitingInput publikuje AgentAwaitingInputPublisher. Sleduje nové záznamy v registrech schválení a blokací přihlašovacích údajů a o každé otázce ask_user mu dá vědět AgentQuestionService. Jedno čekání je jedna událost. Když čekání skončí, nepublikuje se nic.
Pět kategorií vlastních PR nese forUserId, takže dorazí k autorovi, ne ke všem v pracovním prostoru.
RemoteEventForwarder navíc přeposílá TicketReassigned jako notifications/ticket_reassigned a každou TaskLifecycleEvent jako notifications/task_<phase>. Ani jedno se nemapuje na kategorii oznámení. Pohánějí živé rozhraní, ne centrum oznámení. Události členství se jako rámce nepřeposílají: zneplatní cache přeposílače a hostitelé relací zahodí odběry pracovního prostoru odebraného člena.