Hoppa till innehåll

Ärendelivscykel

Status Lagringssträng Beskrivning
backlog backlog Fångat, ännu inte triageat in i den aktiva kön
open open Triagerat och redo att arbetas med, inte påbörjat
inProgress inProgress Arbetas aktivt med
blocked blocked Påbörjat men blockerat av något externt
inReview inReview Arbetet klart, väntar på granskning
done done Slutfört utan fel (terminalt)
failed failed Slutfört med ett fel (terminalt)
cancelled cancelled Övergivet (terminalt)

Statusvärden lagras i camelCase (inProgress, inReview), aldrig in_progress. Ett lagrat nullvärde tolkas som open; ett okänt värde kastar ett fel i stället för att tvinga fram ett värde.

tryParseLoose tar emot alias som agenter anger och struntar i skiftläge samt - / _ / blanksteg:

Status Accepterade alias
open todo, ready, pending, new
inProgress doing, started, active, wip
blocked stuck
inReview review, reviewing
done closed, complete, completed, finished
failed error, errored
cancelled canceled, abandoned, dropped
backlog ──→ open ──→ inProgress ──→ inReview ──→ done
│ │ │
│ └──→ failed ┘
└──→ blocked ──→ inProgress
Any non-terminal status ──→ cancelled; inReview ──→ failed

Den här grafen binder bara agenter och automatisering. TicketWorkflowService.transitionStatus kontrollerar den när force är false – MCP-verktygen och avstämmarna. En otillåten övergång där loggas och ignoreras. Varje användarstyrd statusändring i gränssnittet skickar force: true och kringgår grafen helt, så en människa kan flytta ett ärende till vilken status som helst som väljaren listar (alla statusar utom failed), inklusive att återöppna ett terminalt sådant. Agenter markerar failed med fail_ticket.

En status får alltid övergå till sig själv. Terminala tillstånd har inga utgående kanter.

Från Tillåtna mål
backlog open, cancelled
open inProgress, blocked, cancelled
inProgress blocked, inReview, done, failed, cancelled
blocked inProgress, cancelled
inReview inProgress, done, failed, cancelled
done — (terminalt)
failed — (terminalt)
cancelled — (terminalt)

Lagras som ett heltal på Linears inbyggda skala 0–4. Ett okänt värde tolkas som none.

Prioritet Lagras som
none 0
urgent 1
high 2
medium 3
low 4

Ett okänt lagrat värde eller null tolkas som local.

Leverantör Status
local Lagras helt i arbetsytans databas; standardvärdet
linear Fjärrågt, speglas lokalt

Synkadaptrar finns under packages/cc_infra/lib/src/tickets/sync/ för Linear, GitHub Issues, Jira Cloud och ClickUp. GitHub Issues är bara en leverantör för synkadaptrar (vendorId: github) – det är inte ett värde för TicketProvider, så ett hämtat GitHub-ärende lagras med originKind: externalSync och standardvärdet provider: local. Leverantörsmappningen ligger i ticket_sync_links.

createTicket skriver manual. En hämtning från leverantören skriver externalSync. Delegerade barn förblir manual.

Värde Betydelse
manual Standard i createTicket (rader för människor, agenter och delegerade ärenden)
externalSync Sätts av TicketSyncEngine vid en hämtning från leverantören

Aggregatet spänner över två angelägenheter på en och samma rad. Speglingen (leverantör, nycklar, titel, beskrivning, prioritet, etiketter, statusar, tidsstämplar) är en cache för en fjärrleverantör och skrivs om i sin helhet vid en uppdatering. Överlägget (tilldelning, delegering, yta, förälder, projekt, länkade PR:er) finns bara i Control Center och en uppdatering rör det aldrig.

Fält Typ Beskrivning
id String UUID v4
workspaceId String Ägande arbetsyta
provider TicketProvider Backend som äger den kanoniska datan (standard local)
externalKey String? Leverantörens egen nyckel (t.ex. LIN-123). Lokala anrop till createTicket skriver ett separat UUID här, inte radens id
url String? Webbadress hos fjärrleverantören
title String Kort sammanfattning; får inte vara tom
description String? Längre brödtext i Markdown
priority TicketPriority Standard none
labels List<String> Fria etiketter
status TicketStatus Kanonisk normaliserad status
rawStatus String? Fjärrleverantörens eget tillståndsnamn, sparat för förlustfri visning
externalSyncedAt DateTime? Senaste synkning över flera leverantörer; null till den första. Mappningen per leverantör ligger i ticket_sync_links
parentTicketId String? Förälder i delegerings- och nedbrytningsträdet
projectId String? Ägande projekt; skickas aldrig till en fjärr
assignedAgentId String? Den tilldelade principalens id (endast metadata – en tilldelning skickar inte ut något)
assigneeType PrincipalType Vilken sorts principal assignedAgentId pekar ut – user eller agent (standard agent)
createdByType PrincipalType? Sorten av principal som skapade ärendet (user eller agent); null för äldre rader och systemrader
createdById String? Den skapande principalens id
assignedTeamId String? Tilldelat team (endast metadata)
delegatedByAgentId String? Agenten som delegerade det här ärendet
delegationDepth int Djup i delegeringskedjan; roten är 0, kontrolleras mot taket för maxdjup
delegationRootTicketId String? Roten i delegeringskedjan; null för ett rotärende
spaceId String? Samtalet som ärendet bröts ut ur, eller den delegerande agentens yta
errorMessage String? Sätts när status är failed
linkedPrIds List<String> Nod-id:n för de PR:er som ärendet är länkat till
metadata Map<String, dynamic> Fri påse
createdAt DateTime Tidpunkten då ärendet skapades
startedAt DateTime? När arbetet startade
blockedAt DateTime? När ärendet blockerades
cancelledAt DateTime? När ärendet avbröts
completedAt DateTime? När ärendet slutfördes utan fel
finishedAt DateTime? När ärendet nådde ett terminalt tillstånd
updatedAt DateTime Senaste mutation (speglingen uppdaterad eller överlägget ändrat)
version int Räknare för optimistisk samtidighetskontroll, ökas vid varje mutation
originKind TicketOriginKind Hur ärendet skapades (standard manual)
collaborators List<TicketCollaborator> Fylls på av repositoryt vid behov

Härlett: isTerminal, isRemote (provider != local), isAssignedToUser och displayKey (externalKey ?? id – lokala ärenden visar alltså det separata UUID:t från skapandet, inte radens id).

Lagrade kanter är riktade rader i ticket_links:

Typ Lagringssträng Betydelse
blocks blocks Källan blockerar målet
relatesTo relates_to Symmetrisk relation
duplicateOf duplicate_of Källan är en dubblett av målet

Vokabulären som gränssnittet och ticket_relation talar är TicketRelationKind, härledd från en lagrad kant plus vilken ändpunkt subjektet sitter på:

Sort Härleds från
blockedBy En blocks-rad där subjektet är målet
blocking En blocks-rad där subjektet är källan
relatedTo En relates_to-rad (symmetrisk)
duplicateOf En duplicate_of-rad där subjektet är källan
duplicatedBy En duplicate_of-rad där subjektet är målet
subIssueOf tickets.parent_ticket_id på subjektet
parentOf tickets.parent_ticket_id på det andra ärendet

Länkar mellan förälder och underärende är inte rader i ticket_links – de ligger i tickets.parent_ticket_id.

De här åtta klasserna ligger i packages/cc_domain/lib/core/domain/events/ticketing_events.dart. Det finns ingen TicketStarted, TicketDelegated, TicketCollaboratorAdded eller ExternalTicketWebhookReceived.

Händelse Utlöses när
TicketCreated Ett ärende skapas
TicketAssigned Ett ärende tilldelas en principal eller ett team
TicketCompleted Arbetet slutförs utan fel
TicketFailed Arbetet misslyckas
TicketCancelled Ett ärende avbryts
TicketStatusChanged Varje statusändring
TicketReassigned Ett ärende tilldelas på nytt
TicketDetailsUpdated Titel, beskrivning, prioritet eller etiketter ändras

TicketAssigned är en revisions- och aviseringssignal och en pipelinetrigger. Tilldelning till en agent startar ingen körning – det finns ingen ärendedispatcher som bevakar assignedAgentId. Undantaget är tilldelning till ett team: TeamRoutingService skickar ut teamledaren. Att lägga till en medarbetare skriver en rad och publicerar ingenting. En leverantörswebhook tillämpas genom TicketSyncEngine utan någon domänhändelse.

TicketWorkflowService äger varje mutation.

Mekanism Detalj
En enda flaskhals Alla mutationer går genom _mutate, som läser in raden och anropar _assertWorkspace innan den tillämpar
Arbetsyteisolering _assertWorkspace kastar WorkspaceMismatchException när den inlästa radens workspaceId inte matchar anroparens
Optimistisk samtidighetskontroll _mutate skriver med expectedVersion satt till den version den just läste och försöker igen vid ConcurrencyConflictException genom att läsa in färskt tillstånd på nytt
Exklusivt anspråk tryCheckout / releaseCheckout; en andra agent som gör anspråk på ett utcheckat ärende får en CheckoutConflictException
Övergångsspärr canTransitionTo, tillämpas bara när force är false