パース確定(アセンブルのキュー投入)
メソッド
このAPIはRESTメソッドを採用しています。
HTTPメソッド
POST: 対話型生成ランのパースチェックポイントを確定し、アセンブルフェーズをキューに投入します(または、拒否パスの場合はパースを却下します)。
このエンドポイントは対話型フロー(autoConfirm = false)にのみ適用されます。自動確定ランはパースからアセンブルへ単一のワーカー呼び出しで直接連鎖し、確定チェックポイントには到達しません。
命名規則
一貫性と可読性を確保するため、リクエストとレスポンス内のJSONノードにはcamelCaseを使用します。SQSペイロードのノードにはsnake_caseを使用します。
リクエストとレスポンス
ヘッダー
メタ情報はレスポンスボディではなく、HTTPヘッダーに設定されます。
リクエストヘッダー
AuthorizationContent-TypeAcceptAccept-language
レスポンスヘッダー
Content-Type
パース確定
URI
パスパラメータ
| Name | Type | Required | Description |
|---|---|---|---|
| organization_id | integer | Required | 組織ID |
| project_id | integer | Required | プロジェクトID |
| wf2des_id | string | Required | wf2des ID |
リクエストボディ
リクエストボディはJSONです。
リクエストパラメータ
| Name | Type | Required | Description |
|---|---|---|---|
| attempt | integer | Required | プラグインがプレビューした試行回数。行のattemptに対してcompare-and-setを行う。不一致は、レビュー対象のパースがより新しいパースに置き換えられたことを意味する(409)。 |
| parseArtifactHash | string | Required | プラグインがプレビューしたparse.jsonアーティファクトのコンテンツハッシュ。キュー投入前に現在のパースアーティファクトと比較される。不一致は409。 |
レスポンス
レスポンスはJSONです(HTTPステータス: 200 OK)。
レスポンスフィールド
| Name | Type | Description |
|---|---|---|
| wf2desId | string | wf2des ID |
| status | string | 確定後の行ステータス。確定時は'0'処理中(アセンブルがキュー投入済み)。拒否時は'3'拒否済み。 |
| phase | string | null | status '0'内の生成フェーズ。確定後は'2'アセンブル。拒否後はnull(クリア済み)。 |
| attempt | integer | 確定された試行回数(エコー)。 |
このエンドポイントは冪等です。すでにphase '2'アセンブルへ進行済みのラン(同一attempt)に対する確定の繰り返しは、同一のボディで200を返し、何もキュー投入しません。アセンブルメッセージは最初の呼び出しですでに送信済みです。すでにstatus '3'にあるランに対する拒否の繰り返しも同様に、拒否形式のボディで200を返します。
パース拒否
拒否は同じチェックポイントの代替的な結果です。デザイナーがパースを確定する代わりに却下します。これは失敗ではありません。status '2'失敗とは区別される、終端のstatus '3'拒否済みです。
拒否は詳細を先に・フラグを後に(detail-first-flag-last)の2ステップシーケンスです。
- 詳細を先に。 プラグインは拒否詳細を内部
wf2des-apiデータプレーンに書き込み、これがdesign_generation_resultドキュメントのparse.rejectedブロックへ永続化されます。
| Name | Type | Required | Description |
|---|---|---|---|
| reasonCode | string (enum) | Required | wrong_roles、wrong_memos、wrong_sections、otherのいずれか。 |
| note | string | Optional | 自由記述の説明。reasonCode = otherの場合に推奨。 |
- フラグを後に。 このエンドポイント(拒否バリアントとして呼び出す。リクエストボディ
{ "attempt": 1, "reject": true })は、同じ(attempt, phase awaiting_confirm)のcompare-and-setのもとで行をstatus '3'拒否済みに切り替えます。フラグを切り替える前に詳細を書き込むことで、status '3'の行が常にparse.rejectedブロックを持つことが保証されます。拒否パスではアセンブルメッセージはキュー投入されません。
拒否されたparse.rejected詳細は、後の再トリガーが消費するものです。新しいパース(attempt + 1)がキュー投入され、拒否理由がそれとともに伝わるため、ワーカーはパースキャッシュをスキップします(新しいパースを行うことが目的です)。
認証
認証はAmazon Cognitoが発行するJSON Web Token(JWT)を使用して行われます。
例外処理
エラーに対して以下のステータスコードが返却されます。
| Description | Status Code | Status Name |
|---|---|---|
リクエストボディの欠落または無効(確定時にattempt欠落/parseArtifactHash欠落、拒否時に未知のreasonCode) |
400 | Bad Request |
| 認証情報の欠落 | 401 | Unauthorized |
| 権限不足 | 403 | Forbidden |
| wf2des、プロジェクト、または組織が見つからない | 404 | Not Found |
compare-and-setの不一致: attemptが一致しない、または行がphase '1' awaiting_confirmにない(アセンブル済み、終端、または自動確定) |
409 | Conflict |
| 内部サーバーエラー | 500 | Internal Server Error |
すでに適用済みの状態に一致する確定/拒否の繰り返し(同一attempt、対象のphase/statusがすでに設定済み)では、エンドポイントは409ではなく200(冪等エコー)を返します。409は、置き換えられたランまたは誤ったフェーズのランという、真のattempt/phase不一致のために予約されています。
処理フロー
確定パス
- パスパラメータから組織ID、プロジェクトID、
wf2des_idを抽出し、リクエストボディからattemptとparseArtifactHashを抽出する。 - ユーザーがプロジェクトへのWriteアクセス権を持つことを確認する。
wf2des行をロードする。存在しない場合(またはそのproject_idが一致しない場合)、404を返す。- 冪等エコーチェック: 行がすでに同一
attemptでphase '2'アセンブルにある場合、キュー投入せずに確定ボディで200を返す。 - compare-and-set:
status = '0'処理中、phase = '1'awaiting_confirm、および行のattemptがリクエストのattemptと等しいことを要求する。不一致の場合、409を返す。 parseArtifactHashを当該ランの現在のparse.jsonアーティファクトハッシュに対して検証する。不一致の場合、409を返す。- 同じ
(attempt, phase '1')条件でガードして、アトミックにphase = '2'アセンブルを設定する(行はstatus '0'のまま)。 - アセンブルメッセージをSQS生成キューへ送信する(
snake_caseペイロード。下記参照)。 - 更新された行(
status '0'、phase '2')を返す。
拒否パス
- パスパラメータと拒否ボディ(
attempt、reject = true)を抽出する。 - ユーザーがプロジェクトへのWriteアクセス権を持つことを確認する。
wf2des行をロードする。存在しないかプロジェクトが一致しない場合は404。- 冪等エコーチェック: 行がすでに
status '3'拒否済みにある場合、拒否ボディで200を返す。 - 拒否詳細が
wf2des-api経由でdesign_generation_resultドキュメントのparse.rejectedブロックへすでに書き込まれていることを確認する(detail-first-flag-last)。欠落している場合、400を返す。 - compare-and-set:
status = '0'、phase = '1'awaiting_confirm、およびattemptの一致を要求する。不一致の場合は409。 - アトミックに
status = '3'拒否済みに切り替え、phaseをクリアする(NULL)。SQSメッセージは送信されない。 - 更新された行(
status '3'、phase null)を返す。
詳細フローチャート
flowchart TD
Start([POST /confirm]) --> Auth[Auth & Parameter Extraction]
Auth --> Service[Service Layer]
Service --> AccessCheck[Access Check]
AccessCheck --> HasAccess{Write Access?}
HasAccess -->|No| Err403[403 Forbidden]
HasAccess -->|Yes| LoadRow[Load wf2des Row]
LoadRow --> RowExists{Exists &<br/>project matches?}
RowExists -->|No| Err404[404 Not Found]
RowExists -->|Yes| Branch{Reject flag?}
Branch -->|No confirm| EchoC{Already phase '2'<br/>assemble, same attempt?}
EchoC -->|Yes| Ok200[200 OK<br/>idempotent echo]
EchoC -->|No| CASConfirm{status '0' &<br/>phase '1' awaiting_confirm &<br/>attempt matches?}
CASConfirm -->|No| Err409[409 Conflict]
CASConfirm -->|Yes| HashCheck{parseArtifactHash<br/>matches parse.json?}
HashCheck -->|No| Err409
HashCheck -->|Yes| SetAssemble[CAS set phase '2' assemble<br/>row stays status '0']
SetAssemble --> SendSQS[Send assemble message<br/>to SQS generation queue]
SendSQS --> SQSResult{Success?}
SQSResult -->|No| Err500[500 Internal Server Error]
SQSResult -->|Yes| SuccessC[200 OK<br/>status '0' / phase '2']
Branch -->|Yes reject| EchoR{Already status '3'<br/>rejected?}
EchoR -->|Yes| Ok200
EchoR -->|No| DetailCheck{parse.rejected detail<br/>written via wf2des-api?}
DetailCheck -->|No| Err400[400 Bad Request]
DetailCheck -->|Yes| CASReject{status '0' &<br/>phase '1' awaiting_confirm &<br/>attempt matches?}
CASReject -->|No| Err409
CASReject -->|Yes| SetRejected[CAS flip status '3' rejected<br/>clear phase NULL<br/>no SQS]
SetRejected --> SuccessR[200 OK<br/>status '3' / phase null]
非同期処理
確定パスでは、アセンブルフェーズはSQSワーカー上で非同期に実行されます。ワーカーはdesign_generation_resultドキュメントのinputsブロックから入力ピンをリハイドレートし、終端のspec/selection/validator_report/confidenceブロックを書き込みます。ワーカーは決してPostgreSQLに書き込みません。完了はバックエンド側でai-status webhookハンドラーによって適用され、行を切り替えます。
status '0'(処理中)/phase '2'(アセンブル)→status '1'(完了、phaseクリア)またはstatus '2'(失敗、phaseクリア)
拒否パスはこのエンドポイントで終端です。ワーカーは実行されず、webhookも発火しません。
SQSペイロード
確定パスでSQS生成キューへ送信されるアセンブルメッセージです。アセンブルワーカーが必要とするその他すべてはdesign_generation_resultドキュメントのinputsブロックからリハイドレートされます。メッセージはランのアイデンティティ、フェンシングペア、確定判断のみを運びます。
{
"wf2des_id": "wf2des-001",
"attempt": 1,
"nonce": "b1946ac92492d2347c6235b4d2611184",
"confirm": {
"attempt": 1,
"parse_artifact_hash": "8f14e45fceea167a5a36dedd4bea2543"
}
}
SQSペイロードフィールド
| Name | Type | Required | Description |
|---|---|---|---|
| wf2des_id | string | Required | wf2des ID(= PG行ID。完了webhookではjob_idとしてエコーされる)。 |
| attempt | integer | Required | フェンシングカウンター。DocumentDBの結果ドキュメント書き込みをフェンスする((_id, attempt)のCAS)。 |
| nonce | string | Required | キュー投入ごとに新規生成。(job_id, attempt, nonce) webhook重複排除キーの一部。 |
| confirm.attempt | integer | Required | 確定された試行回数(このエンドポイントがキュー投入前にCASで一致させた値)。 |
| confirm.parse_artifact_hash | string | Required | 確定されたparse.jsonアーティファクトハッシュ(このエンドポイントがキュー投入前に検証した値)。 |
拒否パスではSQSメッセージは送信されません。