Přeskočit na obsah

Tickety a delegování

Ticket je jednotka práce, kterou Control Center sleduje. Schválně toho umí málo: název, tělo, stav, vlastník a místo ve stromu. Není to plocha, na které agenti pracují. Práce agentů žije v konverzacích a strukturovaný výstup běhu leží na záznamu běhu.

Přiřazení zapisuje vlastnictví a nic neodesílá

Sekce “Přiřazení zapisuje vlastnictví a nic neodesílá”

Tohle je na ticketech to nejdůležitější, co je potřeba mít správně.

Nastavení assignedAgentId zapíše pole a publikuje doménovou událost TicketAssigned. Ta událost je signál pro audit a pro oznámení a zároveň spouštěč pipeline. Přiřazení agentovi nespustí žádný běh. Žádný dispečer ticketů nesleduje assignedAgentId a toho agenta neprobudí.

Výjimka je tým. Když je nastavené assignedTeamId, TeamRoutingService odešle vedoucího týmu s provozním protokolem a sestavou.

Má-li na ticketu pracovat konkrétní agent, požádáš ho v konverzaci, odešle ho krok pipeline, nebo mu práci deleguje jiný agent. Přiřadit ticket agentovi a čekat je to jediné, z čeho práce nikdy nevznikne.

Ticket může být čistě místní, nebo ho kryje externí tracker. Obojí nese jeden řádek.

Zrcadlo (poskytovatel, externí klíč, URL, název, popis, priorita, štítky, surový a normalizovaný stav, časová razítka) je u vzdáleného ticketu cache. Zdroj pravdy je tam vzdálená strana a obnovení zrcadlo přepíše celé.

Překryv (přiřazení, delegování, vazba na prostor, rodič, projekt, propojené PR) patří jen Control Center. Tracker o něm neví a obnovení se ho nedotkne.

Právě tohle rozdělení dělá synchronizaci bezpečnou. Stažení od dodavatele smí zrcadlo přepsat i destruktivně a orchestrační metadata navršená nad ním se neztratí.

Graf životního cyklu váže agenty, ne tebe

Sekce “Graf životního cyklu váže agenty, ne tebe”

Stavy jdou backlog → open → inProgress → inReview → done. blocked je vedlejší smyčka a failed / cancelled jsou další koncové stavy.

Graf přechodů se vynucuje jen na cestě agenta a automatizace, tedy u nástrojů MCP a rekoncilerů. Nepovolený přechod se tam zapíše do logu a ignoruje, takže zmatený agent ticket z koncového stavu nevrátí zpátky.

Každá změna, kterou člověk udělá v rozhraní, posílá force: true a graf úplně obejde. Člověk smí ticket přesunout na jakýkoli stav, který výběr nabízí, včetně znovuotevření koncového. Výběr failed nenabízí. Ten nastavují agenti přes fail_ticket. Graf je pojistka pro automatizaci, ne pravidlo o tom, jak smí práce postupovat.

TicketWorkflowService vlastní každou mutaci přes jediný průchod. Načte řádek, ověří, že patří do pracovního prostoru volajícího, a zapíše s očekávanou version, takže dvě souběžné úpravy se navzájem tiše nepřepíšou.

Úplnou tabulku stavů, přechody, seznam polí a druhy vazeb najdeš v Životním cyklu ticketu.

Původ: jak ticket vznikl

Sekce “Původ: jak ticket vznikl”

Každý ticket má originKind. Enum má pět hodnot (manual, pipelineStep, agentDelegation, externalSync, recovery), ale dnes se zapisují jen dvě: manual (výchozí hodnota u createTicket, včetně delegovaných potomků) a externalSync (synchronizační engine při stažení od dodavatele). TicketWorkflowService.createTicket argument původu nepřijímá, takže pipelineStep, agentDelegation a recovery se na řádek nikdy nedostanou.

Delegování je místo, kde agent zakládá práci pro jiného agenta, a právě tady by mohlo uniknout oprávnění. Pojistky proto sedí na serveru v jednom průchodu, ne v pokynech promptu.

delegate_task jde přes TicketWorkflowService.delegateGuarded. Ten z rodičovského řetězce spočítá hloubku a kořen potomka a pak spustí všechny čtyři kontroly DelegationGuards: skok, který by překročil strop hloubky 3, skok zpět k agentovi, který už v řetězci je (detekce cyklu), strop autonomie (účinná úroveň delegáta v prostoru nesmí přesáhnout úroveň toho, kdo deleguje) a obálku rozpočtu (delegování se účtuje ze zbývajícího rozpočtu do tvrdého zastavení toho, kdo deleguje, a další rozpočet nevyrobí). Produkční zapojení dodá oba porty resolverů. Autonomie a rozpočet se přeskočí, když chybí from_agent_id (projde i neomezený rozpočet a rozpočet bez politiky). Odmítnutí se vyhodí jako DelegationRefusedException a jeho zpráva dojde delegujícímu agentovi doslova. Je to hlasité ne, ne tiché nic.

delegate_ticket je starší sourozenec bez pojistek: volá přímo createTicket a všechny pojistky přeskočí. Používej delegate_task.

Nepleť strop hloubky delegování (3, na řetězcích delegate_task) se stropem zanoření podagentů ve vestavěném harnessu (2). Jsou to různé limity na různých mechanismech.

Hierarchie, vazby a projekty

Sekce “Hierarchie, vazby a projekty”

Vztah rodiče a podticketu žije na tickets.parent_ticket_id a vlastní ho setParent / clearParent. Nejsou to řádky ticket_links, takže cokoli, co čte vazby ticketu, musí oba zdroje sloučit.

ticket_links drží orientované hrany mezi tickety, které jinak spolu nesouvisejí:

Typ vazby Význam
blocks Zdroj blokuje cíl
relatesTo Oba tickety spolu souvisejí (symetricky)
duplicateOf Zdroj je duplikát cíle

Projekt je seskupení ticketů v rámci jednoho pracovního prostoru ke společnému cíli. Projekty patří jen Control Center a k externímu poskytovateli se nikdy nesynchronizují.

Řádky TicketCollaborator připojují k ticketu víc než jednoho principála, v roli assignee, collaborator nebo reviewer. Lidé a agenti jsou rovnocenné řádky: principalId a collaboratorType. Není tu sentinelová hodnota pro „uživatele“ ani cizí klíč do jedné nebo druhé tabulky.

Primární je ticket v Control Center. Smazání ticketu je jen místní, takže ticket krytý dodavatelem, který smažeš, se na trackeru nesmaže a při další synchronizaci se může vrátit. Spolupracovníci a podtickety se mažou kaskádou.

Přihlašovací údaje adaptéru se berou z úložišť přihlašovacích údajů na serveru (klíč Linear nebo token GitHub vložený v Nastavení se vezme při dalším požadavku; prostředí ta úložiště jen naplní).

Žádný uzel pipeline ticket nevytvoří, nedokončí ani nezruší. Paleta takový krok nemá a engine nevolá TicketWorkflowService. Spouštěč pipeline se přesto může spustit na TicketAssigned, TicketCompleted, TicketFailed nebo TicketCancelled (ty čtyři ticketové události EventPayloadMapper skutečně mapuje). Sloupec pipelineRunId na ticketu není. Vazba na pipeline žije na záznamu běhu agenta.