24 KiB
MAESTRO タスク実行アーキテクチャ
この文書は、MAESTROでタスク依頼を受け付けてから、Worker、Piece、Movement、LLM、ツール、承認、再試行、通知、UI反映を経て完了するまでの現行処理を示す。機能追加やリファクタリング時の影響確認に使用する。
文書の扱い
- 実装を正とし、処理経路を変更したPRではこの文書も更新する。
- 通常経路だけでなく、ASK、承認待ち、サブタスク待ち、再試行、キャンセル、失敗を維持する。
- 図中の名称は主要なファイル、関数、状態名に対応させる。
- 特定機能の将来設計は含めず、現行コードの動作だけを記載する。
調査対象コミット
- 基準ブランチ:
origin/main - PR #935実装コミット:
a86fea5523d9f8245cd42c53e3c1c167ccb26388 - 最終照合HEAD:
2ba26737742464f9ef7ccfd4459012e00175fd88 - 対象変更: PR #935「systemプロンプト静的化 + 動的コンテキスト末尾注入」
- 調査日: 2026-07-24
主要な実装境界
| 境界 | 主なファイル・関数 |
|---|---|
| タスク作成 | src/bridge/local-tasks-crud-api.ts |
| コメント・interjection・ASK再開 | src/bridge/local-tasks-comments-api.ts |
| 継続・キャンセル | src/bridge/local-tasks-control-api.ts |
| Tool承認 | src/bridge/local-tasks-tool-requests-api.ts |
| Package承認 | src/bridge/local-tasks-package-requests-api.ts |
| Job永続化・claim・再開 | src/db/repositories/jobs.ts |
| Worker実行・終了処理 | src/worker.ts |
| Piece・Movement制御 | src/engine/piece-runner.ts |
| Agent iteration | src/engine/agent-loop.ts |
| LLM stream | src/engine/agent-loop/llm-iteration.ts、src/engine/llm-stream.ts |
| Tool dispatch | src/engine/agent-loop/tool-dispatcher.ts、tool-execution.ts |
| チャット表示 | ui/src/components/chat/ChatPane.tsx、ChatMessageFeed.tsx |
| 承認UI | ui/src/components/chat/ToolRequestApproval.tsx、PackageRequestApproval.tsx |
| 通知・監査 | src/notifications/、src/progress/、ui/src/components/activity/* |
1. タスク依頼から完了までの全体フロー
flowchart TD
U[ユーザー / 外部クライアント]
UI[React UI<br/>CreateTaskDialog / ChatComposer]
API_CREATE[POST /api/local/tasks]
API_COMMENT[POST /api/local/tasks/:id/comments]
API_CONTINUE[POST /api/local/tasks/:id/continue]
OTHER[Scheduler / A2A / Reflection / Subtask]
U --> UI
UI --> API_CREATE
UI --> API_COMMENT
UI --> API_CONTINUE
API_CREATE --> VALIDATE[入力・可視性・Space・LLM選択・添付検証]
VALIDATE --> CLASSIFY[Piece選択 / Grounded固定 / LLM Router]
CLASSIFY --> TASKDB[(local_tasks / comments)]
CLASSIFY --> WORKSPACE[Space解決<br/>persistent/ephemeral workspace・runtime dir]
WORKSPACE --> JOBDB[(jobs: queued)]
API_COMMENT --> WRITE_GATE[Task write gate]
WRITE_GATE --> PREV{最新Job状態}
PREV -->|running / dispatching / waiting_subtasks| INTERJECT[interjection comment保存<br/>既存Jobへ次iterationで投入]
PREV -->|tool/package approval待ち| CONFLICT[409: 承認を先に要求]
PREV -->|queued / retry| REUSE[既存pending Jobを再利用]
PREV -->|ASK待ち・終端・Jobなし| FOLLOWUP[resumeMovement/askCount継承<br/>Job作成]
REUSE --> JOBDB
FOLLOWUP --> JOBDB
API_CONTINUE --> CONTINUE_GATE[所有権・Piece存在・前Job終端確認]
CONTINUE_GATE --> HANDOFF[continuedFromJobIdとhandoff comment<br/>新Jobは transcript replay で前会話を引き継ぐ]
HANDOFF --> JOBDB
OTHER --> JOBDB
JOBDB --> POLL[Worker.processNext polling]
POLL --> CLAIM[retry期限優先→queued<br/>worker/model/profile適合<br/>issue lockなし]
CLAIM --> RUNNING[原子的にstatus=running<br/>worker_id設定]
RUNNING --> EXEC[Worker.executeJob]
EXEC --> PREP[workspace / reporter / Space / Piece / model / MCP / browser / context準備]
PREP --> RUNPIECE[runPiece]
RUNPIECE --> MOVEMENT[Movement loop]
MOVEMENT --> RESULT{PieceRunResult}
RESULT -->|completed| SUCCESS[succeeded<br/>workspace commit・最終結果]
RESULT -->|waiting_human: ASK| ASKWAIT[waiting_human<br/>回答コメントで再開]
RESULT -->|waiting_human: tool_request| TOOLWAIT[waiting_human<br/>承認APIで再開]
RESULT -->|waiting_human: package_request| PKGWAIT[waiting_human<br/>承認・install後に再開]
RESULT -->|waiting_subtasks| SUBWAIT[子Job完了待ち<br/>全完了で親queued]
RESULT -->|cancelled| CANCELLED[cancelled<br/>子Job取消]
RESULT -->|error / aborted| RETRY{再試行可能か}
RETRY -->|yes| RETRYDB[retry + next_retry_at]
RETRY -->|fatal / 上限| FAILED[failed]
ASKWAIT --> API_COMMENT
TOOLWAIT --> APPROVE_TOOL[tool request decide API]
APPROVE_TOOL -->|approve/deny| JOBDB
PKGWAIT --> APPROVE_PKG[package request decide API]
APPROVE_PKG -->|approve/deny| JOBDB
SUBWAIT --> JOBDB
RETRYDB --> POLL
SUCCESS --> EVENTS[Audit / events.jsonl / activity / metrics]
ASKWAIT --> EVENTS
TOOLWAIT --> EVENTS
PKGWAIT --> EVENTS
SUBWAIT --> EVENTS
CANCELLED --> EVENTS
FAILED --> EVENTS
EVENTS --> NOTIFY[Push / Webhook / Notification projection]
EVENTS --> UIREFRESH[REST polling + SSE stream]
UIREFRESH --> UI
2. WorkerとPiece実行
flowchart TD
A[Worker.processNext]
A --> B[claimNextRetryJob または claimNextJob]
B --> C[runJobTracked]
C --> D[executeJob]
D --> E[issue lock取得 / running監査 / Push]
E --> F{Reflection Jobか}
F -->|yes| FR[Reflection専用経路]
F -->|no| G[prepareJobWorkspace]
G --> H[Space・folderContext・runtimeDir解決]
H --> I[Piece読込・定義検証]
I --> J{worker/model適合}
J -->|不一致| JQ[queuedへ戻す]
J -->|適合| K{required MCP tokenあり}
K -->|不足| KH[waiting_human: mcp_auth_required]
K -->|OK| L[LLM client生成]
L --> M[Tool Policy・SSH・grant・package解決]
M --> N[Mission / conversation / provenance / browser / skill context]
N --> O[runPiece]
O --> P[EventLogger・Conversation・ContextManager初期化]
P --> P2{continuedFromJobIdあり<br/>= Continue経由}
P2 -->|yes| REPLAY[transcript.jsonl を loadFrom → allReplayableThreads<br/>全スレッドを古い順に連結(system行が境界)<br/>掃除はスレッド毎・重複call_idは付け替え<br/>transition保持は最終スレッドかつ同一pieceのときだけ<br/>seedContinuation で新会話の頭に再生]
P2 -->|no| Q
REPLAY --> Q[開始Movement選択<br/>resume > override > piece start]
Q --> R[loop/revisit/cancel guard]
R --> S[prepareMovementContext]
S --> T[executeMovement]
T --> U[MovementResult mapping]
U --> V{next}
V -->|別Movement| Q
V -->|COMPLETE / ASK / WAIT / ABORT| W[PieceRunResult]
W --> X[handlePieceResult]
X --> Y[DB状態・コメント・監査・通知・親子Job処理]
Y --> Z[heartbeat/guard停止・metrics・unlock]
prepareMovementContextでは、Workspace Tool Policyを唯一のtool/edit/SSH権限源とし、タスク内承認済みtoolをunionする。task instructionへ、Movement feedback、follow-up notice、subtask resume notice、checklist、lessonsを加える。
transcript(runs/{taskId}/transcript.jsonl)はタスクのruntime directoryに置く正規化された会話記録で、通常はturnを追記し、Continuation seedやprompt guardによる整形時には全体を再構築する。transcript replayが走るのはContinue経由(continuedFromJobIdあり)のみ。コメントやASK回答による新Jobではreplayせず、コメント文脈をtask instructionへ含める。この場合に再利用可能なのは条件が一致する静的接頭辞までで、実際の再利用量は保証しない。replayの整形規則はConversation.replayableTurnsを参照。
3. Movement・LLM・ツール内部
flowchart TD
M0[executeMovement] --> M1[prepareMovement]
M1 --> TOOLS[getToolDefs + complete<br/>遷移先があるPieceではtransitionも追加]
M1 --> STATIC[static preamble構築<br/>AGENTS・Memory・Skills・tool説明]
M1 --> DYNAMIC[dynamic context構築<br/>時刻・files・Mission・handoff・console]
M1 --> GUIDE[Movement guidance + task instruction]
M1 --> SEED[プロンプト要素をConversationへ順序どおり配置]
STATIC --> SEED
DYNAMIC --> SEED
GUIDE --> SEED
SEED --> DCFG{delegate許可かつ<br/>再帰深度上限未満}
DCFG -->|yes| DINJECT[runDelegateをtoolCtxへ注入]
DCFG -->|no| LOOP[iteration loop]
DINJECT --> LOOP
TOOLS --> REQUEST[LLM request入力<br/>toolsはConversationの外で保持]
LOOP --> CANCEL{cancel/deadline signal}
CANCEL -->|yes| MCANCEL[cancel result]
CANCEL -->|no| INJECT[未処理interjectionをuser messageへ追加]
INJECT --> WATCH[watchdog / loop guard]
WATCH --> PGUARD[prompt guard<br/>estimate・dedup・compact・summarize]
PGUARD -->|overflow復旧不能| ABORT[context overflow result]
PGUARD -->|変更あり| REWRITE[Conversation.rewrite<br/>正規化後transcriptを再構築]
PGUARD -->|変更なし| LLM[runLlmIteration]
REWRITE --> LLM
REQUEST --> LLM
LLM --> CLIENT_GUARD[LLM client側の<br/>最終token上限検査]
CLIENT_GUARD --> STREAM[OpenAI-compatible streaming<br/>text/tool deltas/usage/retry/thinking/backend]
STREAM --> ERR{LLM error}
ERR -->|recoverable| LOOP
ERR -->|terminal| LERR[llm error result]
ERR -->|no error| CALLS{tool callsあり}
CALLS -->|なし| TEXT[text-only warning/retry]
TEXT --> LOOP
CALLS -->|あり| SPLIT[regular と transition/completeを分類]
SPLIT --> TLOOP[重複tool loop判定]
TLOOP -->|上限| TABORT[tool loop abort]
TLOOP --> DISPATCH[dispatchRegularToolCalls]
DISPATCH --> PAR{read-only parallel可能か}
PAR -->|yes| PEXEC[Promise.all]
PAR -->|no| SEXEC[sequential]
PEXEC --> TOOL[executeRegularToolCallCached]
SEXEC --> TOOL
TOOL --> AUTH[tool存在・引数・権限・sandbox・cache]
AUTH --> TOOL_KIND{delegateか}
TOOL_KIND -->|yes| DELEGATE[runDelegateSubAgent<br/>隔離した子ConversationでexecuteMovement]
TOOL_KIND -->|no| IMPL[各tool execute]
DELEGATE --> TResult[tool_resultをconversation・UI・eventへ記録]
IMPL --> TResult
TResult --> WAIT{待機フラグ}
WAIT -->|browser| WB[waiting_human]
WAIT -->|tool request| WT[waiting_human tool_request]
WAIT -->|package request| WP[waiting_human package_request]
WAIT -->|subtask| WS[waiting_subtasks]
WAIT -->|なし| TERM{complete / transition winner}
TERM -->|complete success + pending child| WS
TERM -->|complete| COMPLETE[completed / needs_user_input / abort mapping]
TERM -->|transition valid| TRANS[next Movement]
TERM -->|invalid| RET[tool_result errorを追加してiteration再試行]
TERM -->|none| LOOP
toolsはConversationへ格納されない。prepareMovementがmessagesと並ぶ別の戻り値として返し、runLlmIterationへ渡す。delegateは通常tool dispatchの一種だが、実行前にrunDelegateをtoolCtxへ注入し、呼び出された場合は隔離した子Conversationで再帰的にexecuteMovementを実行する。
3.1 LLMリクエストのキャッシュ境界
PR #935以降は、単にプロンプトの内容を分割するだけでなく、LLMへ渡すtoolsとmessagesの順序を次の形に固定する。図中の「キャッシュ再利用可能」は、同一モデル・同一チャットテンプレート・同一Pieceなど、先行要素がバイト一致し、バックエンド側に対象キャッシュが残っている場合を表す。再利用量そのものを保証するものではない。
flowchart TD
REGULAR[Workspace Tool Policyで解決した<br/>regular tools] --> TOOLS[tools配列を構築]
TRANSITION[transition<br/>遷移先がある場合のみ<br/>enumはPiece全体の和集合] --> TOOLS
COMPLETE[complete] --> TOOLS
TOOLS --> TOOLS_STABLE[同一Piece内でtools配列を<br/>バイト単位で安定化]
STATIC[static preamble<br/>共通ルール・tool概要・AGENTS・Memory Index<br/>Skills Index・Working Directory] --> SYSTEM[先頭の単一system message]
FIRST_GUIDANCE[開始Movement guidance] --> SYSTEM
SYSTEM --> REPLAY{Continueかつ<br/>再生可能transcriptあり}
REPLAY -->|yes| PRIOR[過去の非system turnを順番に再生]
REPLAY -->|no| NO_PRIOR[過去turnなし]
PRIOR --> USER[末尾の単一user message]
NO_PRIOR --> USER
DYNAMIC[dynamic context<br/>日時・Mission・files・console<br/>handoffは再生可能turnがないContinue時のみ] --> USER
INSTRUCTION[task instruction] --> USER
USER --> MESSAGES[messages配列完成]
TOOLS_STABLE --> REQUEST[LLM request]
MESSAGES --> REQUEST
TOOLS_STABLE -. キャッシュの先行条件 .-> SYSTEM
SYSTEM -. 同一なら静的接頭辞を再利用 .-> PRIOR
PRIOR -. 過去requestと一致する範囲を再利用 .-> USER
USER -. ここから新規評価 .-> GENERATE[生成開始]
実際のメッセージ列は次の形になる。dynamic contextとtask instructionは、厳密なrole交互制約を持つモデルでも扱えるよう、別々のuser messageではなく一つに結合する。
tools = [regular tools..., transition(遷移先がある場合), complete]
messages = [
system(static preamble + 開始Movement guidance),
...replayable prior turns, // Continue時のみ
user(dynamic context + task instruction),
]
Movement 2以降のguidance、interjection、watchdog警告などは、既存会話の末尾へuser messageとして追加する。先頭へ挿入しないため、そこまでのキャッシュ済み接頭辞を壊さない。
3.2 初回・遷移・再開経路ごとのプロンプト構築
flowchart TD
START[Job開始] --> KIND{開始・再開の種類}
KIND -->|新規Job| NEW[Conversation.seed]
NEW --> NEW_MESSAGES["system: static + 開始guidance<br/>user: dynamic + instruction"]
NEW_MESSAGES --> NEW_CACHE[過去turnの再利用なし]
KIND -->|同一Job内のMovement遷移| MOVE[Conversation.enterMovement]
MOVE --> MOVE_MESSAGES["既存messages末尾へ<br/>user: 次Movement guidance"]
MOVE_MESSAGES --> MOVE_CACHE["toolsはPiece内で安定<br/>既存prefixをそのまま再利用可能"]
KIND -->|同一PieceをContinue| SAME[loadFrom → replayableTurns<br/>keepTransitions=true]
SAME --> SAME_MESSAGES["systemを新しく構築<br/>過去の非system turnを再生<br/>Error回答でないcompleteを除去<br/>handoffを省略して末尾へdynamic + instruction"]
SAME_MESSAGES --> SAME_CACHE["static・tools・再生turnが一致する範囲を再利用可能"]
KIND -->|別PieceをContinue| CROSS[loadFrom → replayableTurns<br/>keepTransitions=false]
CROSS --> CROSS_MESSAGES["旧Pieceのtransitionを除去<br/>新Pieceのsystem・toolsを使用<br/>再生turnがあればhandoffを省略"]
CROSS_MESSAGES --> CROSS_CACHE["Piece固有のguidance/toolsが変わるため<br/>同一Piece相当の再利用は保証しない"]
KIND -->|コメント・ASK回答による新Job| COMMENT[transcript replayなし]
COMMENT --> COMMENT_MESSAGES["system: static + 開始guidance<br/>user: dynamic + コメント文脈を含むinstruction"]
COMMENT_MESSAGES --> COMMENT_CACHE["条件が一致する静的接頭辞のみ再利用可能<br/>再利用量は保証せず、過去turnも再生しない"]
3.3 transcript replayの整形
flowchart TD
LOAD[transcript.jsonlをloadFrom] --> THREAD[system行を境界にスレッド分割<br/>全スレッドを古い順に連結<br/>掃除はスレッド毎・重複call_idは付け替え]
THREAD --> DROP_SYSTEM[スレッド先頭のsystemを除外]
DROP_SYSTEM --> COMPLETE_CHECK{assistantにcompleteがあるか}
COMPLETE_CHECK -->|Errorで始まる結果あり| KEEP_COMPLETE[拒否された中間completeを保持]
COMPLETE_CHECK -->|結果なし、またはError以外| DROP_COMPLETE[completeを除外]
DROP_COMPLETE --> DROP_COEMITTED[同じassistant messageで<br/>同時出力されたtransitionも除外]
COMPLETE_CHECK -->|completeなし| TRANSITION_CHECK{transitionか}
KEEP_COMPLETE --> TRANSITION_CHECK
DROP_COEMITTED --> VALIDATE
TRANSITION_CHECK -->|回答済みtransition かつ keepTransitions=true<br/>(最終スレッドかつ同一PieceのContinue)| KEEP_TRANSITION[call/resultペアを保持]
TRANSITION_CHECK -->|keepTransitions=false<br/>(別PieceのContinue、および古いスレッドでは一括除去)| DROP_TRANSITION[除外]
TRANSITION_CHECK -->|通常tool call| KEEP_REGULAR[call/resultペアを保持]
KEEP_TRANSITION --> VALIDATE[未回答call・孤立result・空assistantを除外]
DROP_TRANSITION --> VALIDATE
KEEP_REGULAR --> VALIDATE
VALIDATE --> SEED_CONTINUATION[seedContinuation]
判定基準は厳密には「成功済みか」ではなく、対応するtool resultがErrorで始まるかである。Error回答されたcompleteは、その後も会話が続いた中間履歴として保持する。結果がない、またはError以外のcompleteは除外し、同じassistant messageで同時出力されたtransitionも一緒に除外する。
transcriptはタスクのruntime directoryに置く会話記録で、コメント追いメッセージのJobは新しいスレッド(先頭はsystem)を追記するため複数スレッドが蓄積し得る。replayは蓄積された全スレッドを古い順に連結して使う(Conversation.allReplayableThreads。issue #1343。以前は最後の再生可能スレッドだけを採っていたが、質問への回答で前の話が落ちる形で表に出たため既定から外した。経緯は docs/design/2026-07-26-transcript-last-thread-replay.html の冒頭の注記)。掃除(replayableTurns)はスレッド毎にかける——まとめてかけると、別スレッドが同じtool_callのidを使い回したときに対応付けが狂い、終了済みのcompleteが生き残る。連結後にスレッドをまたいで重なったidは決定的に付け替える(gen_call_{n}はジョブ毎に1番から振り直されるため実際に重なる)。keepTransitionsは最終スレッドにだけ当てる——その値の元になるsamePieceContinuationは直前のジョブ1件から決まる判断で、古いスレッドがどのpieceで走ったかは記録に無いため。最終スレッドが空でない限り、この形でも連結前より再生量は増える(古いスレッドは以前は捨てていた)。例外は最終スレッドが空のとき——クラッシュや書き込み途中で切れてsystem行しか無いジョブがそれで、以前のlastReplayableThreadは空スレッドを飛ばして1つ前を採っていたため、そこにkeepTransitionsが当たっていた。いまは1つ前が「古いスレッド」扱いになり遷移が落ちるので、この形では再生量が減る。遷移を落とす向きは安全側なので意図してそのままにしている。通常のturn追加では追記するが、seedContinuationと、prompt guardのdedup・compact・summarizeによってmessagesが変わった場合は、Conversation.rewrite()でファイル全体を再構築する。
3.4 キャッシュを維持するための変更時ルール
| 対象 | 維持すべき条件 | 変更時の影響 |
|---|---|---|
tools配列 |
Workspace Tool Policy、task内grant、動的tool module条件が不変なら、同一Piece内で名前、順序、schema、descriptionを安定させる | 1バイトでも変わるとllama.cppで全prompt cache missになり得る |
| transition | 遷移先があるPieceだけ追加し、enumはPiece全体の和集合にする | Movementごとの差分がtools配列に入ると全prompt cache missになり得る |
| static preamble | 日時、Mission、files、handoff、consoleを入れない | Jobごとの差分が先頭に入り、継続時の共有prefixを失う |
| system message | index 0の一つだけにする | 厳格なchat templateで拒否される可能性がある |
| dynamic context | task instructionと一つの末尾user messageに結合する |
連続したuser roleに対応しないモデルで失敗し得る |
| Movement guidance | 2番目以降は会話末尾へuserとして追記する |
先頭を書き換えると既存prefixを無効化する |
| 同一Piece transition | replay時に回答済みcall/resultを保持する | 中間履歴を削ると、その位置以降のcacheが分岐する |
| Error以外のcomplete | replayから除外し、同時出力transitionも除外する | 再生すると継続Jobが即時完了を模倣する可能性がある |
キャッシュ再利用量はllm-streamのprompt_cache reused=... prompt=... pct=...ログと、LLMイベントのcachedPromptTokensで確認する。構造を変更した場合は、単体テストだけでなく実バックエンドでMovement遷移直後とContinue直後の再利用率を測定する。
4. 待機・再開・通知・UI
sequenceDiagram
participant Agent as Agent Loop
participant Worker
participant DB
participant API
participant UI as Chat UI
participant Notify as Push/Webhook/Inbox
Agent->>Worker: PieceRunResult(waiting_human)
Worker->>DB: status=waiting_human, waitReason, resumeMovement
Worker->>Notify: waiting_human event
UI->>API: task/tool/package request polling
API->>DB: pending request取得
API-->>UI: 承認カード / ASK表示
alt ASK
UI->>API: POST comment
API->>DB: resumeMovementとaskCountを継承したJob作成
else Tool Request
UI->>API: approve / deny
API->>DB: grantまたはdeny + parked Jobをqueuedへ戻す
else Package Request
UI->>API: approve / deny
API->>DB: CAS決定、必要なら隔離install、parked Jobをqueuedへ戻す
end
DB-->>Worker: 次回pollでclaim
Worker->>Agent: 同一Movementから再実行
Agent->>Worker: completed / failed / cancelled
Worker->>DB: 終端status・comment・audit・event
Worker->>Notify: succeeded / failed
DB-->>UI: task/comments/activity更新
チャットUIでは ChatPane → ChatMessageFeed → ChatMessage が永続コメントを表示し、ChatComposerPanelがTool RequestとPackage Requestの承認カードを表示する。useJobStreamは生成中text、tool call、LLM状態、delegate streamを反映する。ActivityはActivityTimeline、短期通知はToast、要対応通知はNotification Bell/Centerが担う。
4.1 Auto Prompterの透明性境界
Auto Prompterが有効なJobでは、ツール実行前に固定済みPolicy Snapshotを評価し、追加指示、拒否、引数に結び付いた一回限りの承認を行う。発火結果は許可リスト形式のPolicy Eventとして記録し、チャットへ通知する。無効なJobではこの経路を短絡し、従来のツール実行経路を変えない。
Policy Eventは追跡可能性を支援するbest-effort監査であり、hidden chain-of-thought、生のツール引数、認証情報、prompt全文を保存しない。記録失敗だけを理由にエージェント処理を停止する保証型台帳でもない。
この機構はEU AI Actその他の法令への準拠を自己宣言しない。Article 50だけでchain-of-thought保存や一律5年保持が要求されるとは解釈せず、適用範囲、事業者の役割、保持期間は法務確認の対象とする。保持期間の設定は将来のCompliance Phaseで扱う。詳細は EU AI Act透明性対応 設計付録 を参照する。