콘텐츠로 이동

티켓과 위임

티켓은 Control Center가 추적하는 작업 단위입니다. 티켓은 의도적으로 단순한 산출물입니다. 제목, 본문, 상태, 담당자, 그리고 트리 안에서의 위치만 담습니다. 티켓은 에이전트가 실행하는 대상이 아닙니다. 에이전트의 작업은 대화에 있고, 실행의 구조화된 출력은 실행 로그에 있습니다.

배정은 소유권을 기록할 뿐, 아무것도 디스패치하지 않습니다

섹션 제목: “배정은 소유권을 기록할 뿐, 아무것도 디스패치하지 않습니다”

티켓에 관해 가장 중요하게 바로 이해해야 할 점입니다.

assignedAgentId를 설정하면 필드 하나를 기록하고 TicketAssigned 도메인 이벤트를 발행합니다. 이 이벤트는 감사 및 알림 신호이자 파이프라인 트리거입니다. 에이전트에 배정해도 실행은 시작되지 않습니다. assignedAgentId를 지켜보다가 그 에이전트를 깨우는 티켓 디스패처는 없습니다.

예외는 팀입니다. assignedTeamId가 설정되면 TeamRoutingService가 운영 프로토콜과 팀 구성원 명단을 갖춘 팀 리더를 디스패치합니다.

특정 에이전트가 티켓을 처리하게 하려면 대화에서 요청하거나, 파이프라인 단계가 그 에이전트를 디스패치하거나, 다른 에이전트가 그 에이전트에 위임해야 합니다. 티켓을 에이전트에 배정해 놓고 기다리는 것은 결코 작업을 만들어 내지 못하는 유일한 방법입니다.

티켓은 순전히 로컬일 수도 있고 외부 트래커를 기반으로 할 수도 있으며, 두 경우 모두 하나의 행에 담깁니다.

미러(공급자, 외부 키, URL, 제목, 설명, 우선순위, 레이블, 원시 및 정규화 상태, 타임스탬프)는 티켓이 원격일 때 캐시 역할을 합니다. 그 경우 원격이 진실의 원천이고, 새로 고침은 미러를 통째로 다시 씁니다.

오버레이(배정, 위임, 스페이스 연결, 상위 티켓, 프로젝트, 연결된 PR)는 Control Center에만 있습니다. 트래커는 이에 대해 아무것도 모르며, 새로 고침이 이를 건드리는 일도 없습니다.

이러한 분리가 동기화를 애초에 안전하게 만듭니다. 공급업체에서 데이터를 가져와도 미러만 덮어쓸 뿐, 그 위에 얹힌 오케스트레이션 메타데이터를 잃지 않습니다.

수명주기 그래프는 사용자가 아니라 에이전트를 구속합니다

섹션 제목: “수명주기 그래프는 사용자가 아니라 에이전트를 구속합니다”

상태는 backlog → open → inProgress → inReview → done 순으로 흐르고, blocked는 곁가지 루프이며 failed / cancelled는 나머지 종료 상태입니다.

전이 그래프는 에이전트와 자동화 경로, 즉 MCP 도구와 조정기에만 강제됩니다. 이 경로에서 허용되지 않는 전이는 로그에 기록되고 무시되므로, 혼란에 빠진 에이전트가 티켓을 거꾸로 되돌려 종료 상태에서 빼내는 일은 없습니다.

UI에서 사용자가 일으키는 모든 변경은 force: true를 전달해 그래프를 완전히 우회합니다. 사람은 선택기에 나열된 어떤 상태로든 티켓을 옮길 수 있으며, 종료된 상태를 다시 여는 것도 가능합니다. 선택기는 failed를 제공하지 않으며, 에이전트는 fail_ticket을 통해 이를 설정합니다. 그래프는 자동화를 위한 가드레일이지, 작업이 어떻게 진행되어야 하는지에 대한 규칙이 아닙니다.

TicketWorkflowService는 모든 변경을 단일 병목 지점에서 처리합니다. 이 지점은 행을 로드하고, 호출자의 워크스페이스에 속하는지 확인한 뒤 기대하는 version과 함께 기록하므로, 동시에 일어난 두 편집이 서로를 조용히 덮어쓰는 일이 없습니다.

전체 상태 표, 전이, 필드 목록, 관계 종류는 티켓 수명주기를 참고하세요.

출처: 티켓은 어떻게 생겨났는가

섹션 제목: “출처: 티켓은 어떻게 생겨났는가”

모든 티켓에는 originKind가 있습니다. 이 열거형은 manual, pipelineStep, agentDelegation, externalSync, recovery라는 다섯 값을 가지지만, 오늘날 실제로 기록되는 값은 두 개뿐입니다. manual(createTicket의 기본값이며 위임된 하위 티켓도 포함)과 externalSync(공급업체에서 데이터를 가져올 때 동기화 엔진이 기록)입니다. TicketWorkflowService.createTicket은 출처 인자를 받지 않으므로 pipelineStep, agentDelegation, recovery는 행에 기록되지 않습니다.

위임은 한 에이전트가 다른 에이전트를 위해 작업을 만드는 지점이며, 권한이 새어 나갈 수 있는 곳입니다. 그래서 가드는 프롬프트 지시문이 아니라 서버 측 병목 지점에 있습니다.

delegate_task는 TicketWorkflowService.delegateGuarded를 거치며, 이 메서드는 상위 체인에서 하위 티켓의 깊이와 루트를 계산한 다음 네 가지 DelegationGuards 검사를 모두 실행합니다. 깊이 상한 3을 넘어서는 홉, 이미 체인에 있는 에이전트로 되돌아가는 홉(순환 감지), 자율성 상한(스페이스에서 위임받는 에이전트의 실효 레벨이 위임하는 쪽을 넘을 수 없음), 예산 한도(위임은 위임하는 쪽의 남은 강제 중단 예산을 청구하며 그 이상을 만들어 낼 수 없음)입니다. 프로덕션 배선은 두 리졸버 포트를 모두 제공합니다. from_agent_id를 생략하면 자율성과 예산 검사는 건너뜁니다(예산이 무제한이거나 정책이 없는 경우도 통과합니다). 거부는 DelegationRefusedException으로 던져지며, 그 메시지는 위임한 에이전트에 그대로 전달됩니다. 조용한 무시가 아니라 소리 내어 거부하는 것입니다.

delegate_ticket은 더 오래된, 보호되지 않는 형제 도구입니다. createTicket을 직접 호출하고 모든 가드를 건너뜁니다. delegate_task를 사용하세요.

위임 깊이 상한(delegate_task 체인에서 3)과 내장 하네스의 서브에이전트 중첩 상한(2)을 혼동하지 마세요. 서로 다른 메커니즘에 걸린 서로 다른 한도입니다.

상위 및 하위 이슈 관계는 tickets.parent_ticket_id에 있으며 setParent / clearParent가 관리합니다. 이들은 ticket_links 행이 아니므로, 티켓의 관계를 읽는 모든 코드는 두 출처를 병합해야 합니다.

ticket_links는 서로 관련 없는 티켓 사이의 방향성 간선을 담습니다.

링크 유형 의미
blocks 소스가 대상을 차단합니다
relatesTo 두 티켓이 관련되어 있습니다(대칭)
duplicateOf 소스가 대상의 중복입니다

프로젝트는 공동 목표를 향한 티켓을 워크스페이스 범위로 묶은 그룹입니다. 프로젝트는 Control Center에만 있으며 외부 공급자와 동기화되지 않습니다.

TicketCollaborator 행은 하나의 티켓에 둘 이상의 주체를 연결하는 방식이며, 역할은 assignee, collaborator, reviewer 중 하나입니다. 사람과 에이전트는 principalId와 collaboratorType으로 이루어진 동등한 행이며, “사용자”를 나타내는 센티널 값도, 어느 테이블로 향하는 외래 키도 없습니다.

Control Center의 티켓이 원본입니다. 티켓 삭제는 로컬에서만 일어나므로, 공급업체 기반 티켓을 삭제해도 트래커에서는 삭제되지 않고 다음 동기화 때 다시 나타날 수 있습니다. 협업자와 하위 티켓은 함께 삭제됩니다.

어댑터 자격 증명은 서버의 자격 증명 저장소에서 해석됩니다(설정에 붙여 넣은 Linear 키나 GitHub 토큰은 다음 요청에서 반영되며, 환경 변수는 이 저장소를 초기값으로 채울 뿐입니다).

어떤 파이프라인 노드도 티켓을 생성, 완료, 취소하지 않습니다. 팔레트에 그런 단계가 없고 엔진도 TicketWorkflowService를 호출하지 않습니다. 그래도 파이프라인 트리거는 TicketAssigned, TicketCompleted, TicketFailed, TicketCancelled에서 여전히 발동할 수 있습니다(EventPayloadMapper가 실제로 매핑하는 티켓 이벤트는 이 네 가지입니다). 티켓에는 pipelineRunId 열이 없으며, 파이프라인과의 결합은 에이전트 실행 로그에 있습니다.