Přeskočit na obsah

Doménové události

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

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á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á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á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á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á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

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.

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.