Skip to content

パイプラインライフサイクル契約

ステータス: 実装済み — すべてのギャップが解消された。pipeline_next_actionsm.PhaseStart() を呼び出し phase-start イベントを発行する。pipeline_report_resultphase-complete イベントを発行する。チェックポイントイベントは awaiting_human 設定時に発行される。

目的

このドキュメントは、パイプラインフェーズの必須状態遷移契約を定義する。すべてのフェーズは対称的な PhaseStart / PhaseComplete ライフサイクルに従わなければならない。どのコンポーネントもこの契約を迂回してはならない。

この契約が解決する問題

パイプラインには2つの実行パスがある:

  1. スタンドアロンハンドラ (phase_start, phase_complete MCPツール) — 適切な状態更新とイベント発行を伴い sm.PhaseStart()sm.PhaseComplete() を呼び出す
  2. パイプラインエンジン (pipeline_next_action + pipeline_report_result) — メインループを駆動するが、歴史的に sm.PhaseStart() を迂回していたため、以下の問題が発生:
    • CurrentPhaseStatus"in_progress" ではなく "pending" のまま
    • Timestamps.PhaseStarted が設定されない
    • phase-start イベントが発行されない(ダッシュボードに完了まで何も表示されない)
    • phase-complete イベントが pipeline_report_result から発行されない

この契約は、すべてのパスが同一のライフサイクルに従うことで不整合を排除する。

フェーズライフサイクル

すべてのフェーズ遷移はこのシーケンスに従う。どのステップもスキップしてはならない。

pending ──[PhaseStart]──> in_progress ──[PhaseComplete]──> (次フェーズ: pending)
   |                           |
   |                           |──[PhaseFail]──> failed
   |                           └──[Checkpoint]──> awaiting_human
   |
   └──[PhaseCompleteSkipped]──> (次フェーズ: pending)

状態変更

遷移メソッドCurrentPhaseStatusTimestamps.PhaseStartedイベント
開始sm.PhaseStart(workspace, phase)"in_progress"nowISO()phase-start
完了sm.PhaseComplete(workspace, phase)"pending" (次) or "completed"nilphase-complete
失敗sm.PhaseFail(workspace, msg)"failed"(変更なし)phase-fail
チェックポイントsm.Checkpoint(workspace, phase, ...)"awaiting_human"(変更なし)checkpoint
スキップsm.PhaseCompleteSkipped(workspace, phase)"pending" (次)nil(なし)

イベント発行に関する注記: sm.PhaseStart()sm.PhaseComplete() は純粋な状態変更であり、イベント自体は発行しない。呼び出し元が状態変更成功後に publishEvent() を呼ぶ責任を持つ。これにより StateManagerEventBus への依存を持たない(設計判断参照)。

不変条件

  1. 対称的な開始/完了: すべての PhaseStart の後には、必ず1回の PhaseCompletePhaseFail、または Abandon が続く。開始されていないフェーズを完了してはならない。
  2. 単一書き込み者: 1つのコンポーネントのみが特定のフェーズを遷移する。パイプラインループでは、pipeline_next_actionPhaseStart を、pipeline_report_resultPhaseComplete を所有する。
  3. イベントと状態の整合性: イベントは対応する状態変更が成功した後に発行される。変更が失敗した場合、イベントは発行されない。
  4. 冪等性: Engine.NextAction() は読み取り専用 — 状態を変更しない。シグナルを返し、呼び出し元 (pipeline_next_action) が状態遷移を担当する。

実行パス

パス 1: パイプラインエンジン(主要)

メイン実行ループ。/forge を介したすべての自動パイプライン実行で使用。

pipeline_next_action
  |-- eng.NextAction() -> Action        [読み取り専用の判断]
  |-- sm.PhaseStart(workspace, phase)   [状態: pending -> in_progress]
  |-- publishEvent("phase-start")       [ダッシュボード通知]
  └-- return Action to orchestrator     [オーケストレーターが実行]

[オーケストレーターがアクションを実行: Agent, exec, write_file]

pipeline_report_result
  |-- sm.PhaseLog(...)                  [メトリクス記録]
  |-- determineTransition()
  |   └-- sm.PhaseComplete(...)         [状態: in_progress -> pending (次)]
  |-- publishEvent("phase-complete")    [ダッシュボード通知]
  └-- return next_action_hint

アクションタイプごとの動作:

アクションタイプphase-start 発行?agent-dispatch 発行?報告方法
spawn_agentYesYes (エージェント名付き)pipeline_report_result
execYesNopipeline_report_result (P5 埋め込みパス)
write_fileYesNopipeline_report_result (P5 埋め込みパス)
checkpointNo (パス3参照)Noチェックポイントフロー
done (skip)NoNoP1 スキップループ (内部)

P1 スキップループ: Engine.NextAction()SkipSummaryPrefix 付きの ActionDone を返した場合、pipeline_next_action は内部で吸収する — sm.PhaseCompleteSkipped() を呼び、上限20回のループ内で eng.NextAction() を再呼び出しする。スキップされたフェーズには phase-startphase-complete イベントは発行されない。

パス 2: スタンドアロンハンドラ(デバッグ / 手動)

個別の phase_start / phase_complete MCPツール。手動での状態操作やデバッグに使用。

PhaseStartHandler
  |-- ガードチェック (例: phase-5 でタスクが空でないこと)
  |-- sm.PhaseStart(workspace, phase)
  └-- publishEvent("phase-start")

PhaseCompleteHandler
  |-- ガードチェック (アーティファクト存在、awaiting_human でない、pending revision なし)
  |-- sm.PhaseComplete(workspace, phase)
  └-- publishEvent("phase-complete")

パス 3: チェックポイントフロー

ヒューマンレビューゲート。pipeline_next_action はチェックポイントフェーズを検出し、sm.Update() を介して awaiting_human を設定する(sm.Checkpoint() ではない — スタンドアロンチェックポイントハンドラは別の MCP ツール)。オーケストレーターがユーザーにチェックポイントを提示し、レスポンスを返す。

pipeline_next_action (チェックポイントアクション検出)
  |-- sm.Update(): CurrentPhaseStatus = "awaiting_human"
  └-- return Action{type: "checkpoint"} to orchestrator

[ユーザーがレビューして応答]

pipeline_next_action (user_response 付き)
  |-- "proceed" -> sm.PhaseComplete(workspace, phase)
  |-- "revise"  -> sm.Update() で状態を巻き戻し
  └-- "abandon" -> sm.Abandon()

注記: スタンドアロンの CheckpointHandler (handlers.go) は sm.Checkpoint() を呼び checkpoint イベントを発行する。パイプラインエンジンパスは sm.Update() を直接使用する。両方とも CurrentPhaseStatus = "awaiting_human" となるが、異なるコードパスを通る。

イベント分類

イベント発行者タイミング結果
pipeline-initpipeline_init_with_contextワークスペース作成時in_progress
phase-startpipeline_next_action or PhaseStartHandlerフェーズ開始時in_progress
agent-dispatchpipeline_next_actionエージェント起動時dispatched
action-completepipeline_next_action (P5 埋め込みレポートパス)エージェント/exec完了時completed
phase-completepipeline_next_action (P5パス), pipeline_report_result, or PhaseCompleteHandlerフェーズ完了時completed
phase-failPhaseFailHandlerフェーズ失敗時failed
checkpointpipeline_next_action or CheckpointHandlerヒューマン待機時awaiting_human
revision-requiredpipeline_next_actionレビューREVISE判定時failed
pipeline-completepipeline_next_action全フェーズ完了時completed
abandonAbandonHandlerパイプライン放棄時abandoned

フェーズごとの期待イベントシーケンス

通常の spawn_agent フェーズは以下を生成する:

phase-start (in_progress)
  -> agent-dispatch (dispatched)
  -> action-complete (completed)
  -> phase-complete (completed)

exec または write_file フェーズは以下を生成する:

phase-start (in_progress)
  -> action-complete (completed)
  -> phase-complete (completed)

設計判断

PhaseStart が pipeline_next_action に置かれる理由

pipeline_next_action はパイプラインループにおけるフェーズ遷移の単一エントリポイントである。ここに PhaseStart を配置することで:

  • 局所性: 開始遷移がディスパッチ判断の隣にあり、コードの監査が容易
  • 対称性: pipeline_next_action がフェーズを開始し、pipeline_report_result が完了する
  • エンジンの純粋性: Engine.NextAction() は状態の純粋関数のまま — 副作用なし
  • レイヤー準拠: tools -> orchestrator -> state のインポート方向が保持される

スタンドアロンハンドラが残される理由

phase_startphase_complete MCPツールは以下の用途で利用可能:

  • 中断後の手動状態復旧
  • 開発中のパイプライン状態デバッグ
  • パイプラインループ外で動作する将来のCLIツール

同一の契約に従い、パイプラインエンジンパスと競合してはならない。

イベントがハンドラレベルで発行される理由

StateManager は外部依存のない純粋な状態永続化レイヤーである。EventBus を追加すると tools -> orchestrator -> state レイヤリングに違反する:

tools (publishEvent + sm.PhaseStart)
  -> orchestrator (Engine — 読み取り専用)
    -> state (StateManager — 永続化のみ)

イベントはプレゼンテーション関心事(ダッシュボード、Slack)であり、バスが利用可能なハンドラレベルに属する。

Released under the MIT License.