チケットのライフサイクル
チケットのステータス
「チケットのステータス」というセクション| ステータス | 保存文字列 | 説明 |
|---|---|---|
backlog |
backlog |
記録済みだが、まだアクティブなキューへトリアージされていない |
open |
open |
トリアージ済みで作業可能だが、未着手 |
inProgress |
inProgress |
現在作業中 |
blocked |
blocked |
着手済みだが、外部要因でブロックされている |
inReview |
inReview |
作業は完了し、レビュー待ち |
done |
done |
正常に完了(終端) |
failed |
failed |
エラーで終了(終端) |
cancelled |
cancelled |
放棄(終端) |
ステータス値は camelCase(inProgress、inReview)で保存され、in_progress になることはありません。保存値が null の場合は open としてパースされ、不明な値は強制変換されずに例外をスローします。
tryParseLoose はエージェントが指定した別名を受け付け、大文字小文字と - / _ / スペースを無視します:
| ステータス | 受け付ける別名 |
|---|---|
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このグラフが縛るのはエージェントと自動化だけです。 TicketWorkflowService.transitionStatus は force が false のときにこれをチェックします — MCP ツールとリコンサイラーです。そこで不正な遷移が行われるとログに記録されて無視されます。UI でのユーザー操作によるステータス変更はすべて force: true を渡してグラフを完全に迂回するため、人間はピッカーに並ぶ任意のステータス(failed を除くすべてのステータス)へチケットを移動でき、終端状態のチケットを再び開くこともできます。エージェントは fail_ticket で failed にします。
ステータスは常にそれ自身へ遷移できます。終端状態には外向きのエッジがありません。
| 遷移元 | 許可される遷移先 |
|---|---|
backlog |
open, cancelled |
open |
inProgress, blocked, cancelled |
inProgress |
blocked, inReview, done, failed, cancelled |
blocked |
inProgress, cancelled |
inReview |
inProgress, done, failed, cancelled |
done |
—(終端) |
failed |
—(終端) |
cancelled |
—(終端) |
チケットの優先度
「チケットの優先度」というセクション整数として Linear のネイティブな 0〜4 スケールで保存されます。不明な値は none にパースされます。
| 優先度 | 保存値 |
|---|---|
none |
0 |
urgent |
1 |
high |
2 |
medium |
3 |
low |
4 |
チケットのプロバイダー
「チケットのプロバイダー」というセクション保存値が不明または null の場合は local にパースされます。
| プロバイダー | ステータス |
|---|---|
local |
ワークスペースデータベースに完全に保存される。既定 |
linear |
リモートが所有し、ローカルにミラーリングされる |
同期アダプターは packages/cc_infra/lib/src/tickets/sync/ 配下にあり、Linear、
GitHub Issues、Jira Cloud、ClickUp に対応します。GitHub Issues はあくまで同期
アダプターのベンダー(vendorId: github)であり、TicketProvider の値ではあり
ません。そのため、プルされた GitHub イシューは originKind: externalSync と
既定の provider: local で保存されます。ベンダーのマッピングは
ticket_sync_links にあります。
チケットのオリジン
「チケットのオリジン」というセクションcreateTicket は manual を書き込みます。ベンダーからのプルは externalSync を
書き込みます。委任された子チケットは manual のままです。
| 値 | 意味 |
|---|---|
manual |
createTicket の既定(人間、エージェント、委任された行) |
externalSync |
ベンダーからのプル時に TicketSyncEngine が設定 |
チケットのフィールド
「チケットのフィールド」というセクションこの集約は 1 つの行に 2 つの関心事をまたがって持ちます。ミラー(プロバイダー、キー、タイトル、説明、優先度、ラベル、ステータス、タイムスタンプ)はリモートプロバイダーのキャッシュであり、リフレッシュによって丸ごと書き換えられます。オーバーレイ(割り当て、委任、スペース、親、プロジェクト、リンクされた PR)は Control Center だけのものであり、リフレッシュが触れることはありません。
| フィールド | 型 | 説明 |
|---|---|---|
id |
String |
UUID v4 |
workspaceId |
String |
所有するワークスペース |
provider |
TicketProvider |
正規データを所有するバックエンド(既定は local) |
externalKey |
String? |
プロバイダー固有のキー(例: LIN-123)。ローカルの createTicket はここに別の UUID を書き込み、行の id は書き込みません |
url |
String? |
リモートプロバイダー上の Web URL |
title |
String |
短い要約。空にできません |
description |
String? |
長めの Markdown 本文 |
priority |
TicketPriority |
既定は none |
labels |
List<String> |
自由形式のラベル |
status |
TicketStatus |
正規化された正規のステータス |
rawStatus |
String? |
リモートプロバイダーのネイティブな状態名。ロスレス表示のために保持される |
externalSyncedAt |
DateTime? |
最後のマルチベンダー同期。初回までは null。ベンダーごとのマッピングは ticket_sync_links にあります |
parentTicketId |
String? |
委任/分解ツリーの親 |
projectId |
String? |
所有するプロジェクト。リモートへプッシュされることはありません |
assignedAgentId |
String? |
割り当てられたプリンシパルの id(メタデータのみ — 割り当てても何もディスパッチされません) |
assigneeType |
PrincipalType |
assignedAgentId が指すプリンシパルの種類 — user または agent(既定は agent) |
createdByType |
PrincipalType? |
チケットを作成したプリンシパルの種類(user または agent)。レガシー/システム行では null |
createdById |
String? |
作成したプリンシパルの id |
assignedTeamId |
String? |
割り当てられたチーム(メタデータのみ) |
delegatedByAgentId |
String? |
このチケットを委任したエージェント |
delegationDepth |
int |
委任チェーン内の深さ。ルートは 0 で、最大深度の上限と照合される |
delegationRootTicketId |
String? |
委任チェーンのルート。ルートチケットでは null |
spaceId |
String? |
チケットの元になった会話、または委任したエージェントのスペース |
errorMessage |
String? |
status が failed のときに設定される |
linkedPrIds |
List<String> |
このチケットがリンクされている PR ノード id |
metadata |
Map<String, dynamic> |
自由形式のバッグ |
createdAt |
DateTime |
作成日時 |
startedAt |
DateTime? |
作業を開始した日時 |
blockedAt |
DateTime? |
チケットがブロックされた日時 |
cancelledAt |
DateTime? |
チケットがキャンセルされた日時 |
completedAt |
DateTime? |
チケットが正常に完了した日時 |
finishedAt |
DateTime? |
チケットが任意の終端状態に達した日時 |
updatedAt |
DateTime |
最後の変更(ミラーのリフレッシュまたはオーバーレイの変更) |
version |
int |
楽観的同時実行のカウンター。変更のたびにインクリメントされる |
originKind |
TicketOriginKind |
チケットがどのように作成されたか(既定は manual) |
collaborators |
List<TicketCollaborator> |
リポジトリによってオンデマンドでハイドレートされる |
派生: isTerminal、isRemote(provider != local)、isAssignedToUser、displayKey(externalKey ?? id — そのためローカルチケットは、行の id ではなく、作成時に付与された別の UUID を表示します)。
チケットの関連
「チケットの関連」というセクション保存されるエッジは ticket_links 内の方向性を持つ行です:
| 種類 | 保存文字列 | 意味 |
|---|---|---|
blocks |
blocks |
ソースがターゲットをブロックする |
relatesTo |
relates_to |
対称な関連 |
duplicateOf |
duplicate_of |
ソースはターゲットの重複 |
UI と ticket_relation が扱う語彙は TicketRelationKind で、保存されたエッジと、対象がどちらの端点に位置するかから導出されます:
| 種類 | 導出元 |
|---|---|
blockedBy |
対象がターゲットである blocks 行 |
blocking |
対象がソースである blocks 行 |
relatedTo |
relates_to 行(対称) |
duplicateOf |
対象がソースである duplicate_of 行 |
duplicatedBy |
対象がターゲットである duplicate_of 行 |
subIssueOf |
対象側の tickets.parent_ticket_id |
parentOf |
もう一方のチケット側の tickets.parent_ticket_id |
親とサブイシューのリンクは ticket_links の行ではありません — これらは tickets.parent_ticket_id にあります。
ドメインイベント
「ドメインイベント」というセクションこれら 8 つのクラスは packages/cc_domain/lib/core/domain/events/ticketing_events.dart にあります。TicketStarted、TicketDelegated、TicketCollaboratorAdded、ExternalTicketWebhookReceived は存在しません。
| イベント | 発行されるタイミング |
|---|---|
TicketCreated |
チケットが作成されたとき |
TicketAssigned |
チケットがプリンシパルまたはチームに割り当てられたとき |
TicketCompleted |
作業が正常に完了したとき |
TicketFailed |
作業が失敗したとき |
TicketCancelled |
チケットがキャンセルされたとき |
TicketStatusChanged |
ステータスが変更されたとき |
TicketReassigned |
チケットが再割り当てされたとき |
TicketDetailsUpdated |
タイトル、説明、優先度、またはラベルが変更されたとき |
TicketAssigned は監査と通知のシグナルであり、パイプラインのトリガーでもあります。エージェントへの割り当ては実行を開始しません — assignedAgentId を監視するチケットディスパッチャーは存在しません。例外はチームへの割り当てです: TeamRoutingService がチームリーダーをディスパッチします。コラボレーターの追加は行を書き込むだけで、何も発行しません。ベンダーの Webhook は TicketSyncEngine を通じて適用され、ドメインイベントは伴いません。
変更操作のチョークポイント
「変更操作のチョークポイント」というセクションTicketWorkflowService がすべての変更操作を所有します。
| 仕組み | 詳細 |
|---|---|
| 単一のチョークポイント | すべての変更は _mutate を経由し、_mutate は行をロードして適用前に _assertWorkspace を呼び出す |
| ワークスペース分離 | ロードした行の workspaceId が呼び出し元のものと一致しない場合、_assertWorkspace は WorkspaceMismatchException をスローする |
| 楽観的同時実行 | _mutate は、読み取ったばかりの version を expectedVersion に設定して書き込み、ConcurrencyConflictException では最新の状態を再読み取りして再試行する |
| 排他的なチェックアウト | tryCheckout / releaseCheckout。チェックアウト済みのチケットを別のエージェントが要求すると CheckoutConflictException を受け取る |
| 遷移ガード | canTransitionTo。force が false のときにのみ適用される |