# 永続操作と再試行 永続操作には、同じ依頼を識別する情報と、安全な再試行に必要な事実を保存する。Rustの関数呼出しや待機位置を、そのまま永続状態として記録しない。再読取りで分かる情報や安全に繰り返せる処理は、再構成または再実行する。 ## 記録の分類 | 種類 | 保存する理由 | | --- | --- | | 原子的な冪等性記録 | 正本の更新と結果が一つのDBトランザクションで確定する。同一依頼の再送には保存済み結果を返し、異なる依頼による操作IDの再利用は拒否する。途中状態は不要。 | | 予約 | 後続の結付けに先立ち、資源IDや排他的な権利を確保する。予約先、依頼、権限、確定した結付けを記録する。 | | 外部副作用を伴う操作 | DB外で起きた効果を再試行で重複させないため、安定した依頼ID、必要なチェックポイント、結果を残す。 | | 親ワークフロー | 複数の操作を調整する。親の依頼、権限、安定した子操作ID、最終結果を持ち、子の状態は子の正本から読む。 | 同じDB内で原子的に確定できる処理を、永続操作を設けるためだけに分割しない。補償にも独立した副作用や再試行がある場合は、暗黙的な後始末ではなく、識別可能な子操作として扱う。 ## 操作の識別 操作IDは所有するWorkspaceなどの権限範囲で識別する。依頼のfingerprintには、変わると別の依頼になる入力を含める。Serverが採番した結果ID、時刻、試行回数、変動する観測値、秘密の値は含めない。 厳密な再送で固定する権限・設定と、実行時に再検証する制約を分ける。固定した入力があっても、現在の割当、所有、接続、削除制約の検証を省略しない。子の作成も安定したIDまたは原子的な結付けで冪等にし、再送で別の子を増やさない。 ## チェックポイントの条件 チェックポイントは、再試行の方法が変わる事実を記録する。次の条件をすべて満たす場合だけ追加する。 1. 現在のトランザクション外で副作用が発生し得る。 2. その事実を十分確実に再観測できない、または安全に繰り返せない。 3. 記録の前後で再試行の処理が変わる。 4. 記録の前後それぞれの挙動をテストできる。 「検証中」「終了処理中」などコード位置を表す段階名ではなく、削除確認、子操作との結付け、確定結果の識別子などの事実を保存する。要求を送信した事実と、副作用の完了を確認した事実は区別する。 ## 状態・失敗・処置 操作が未完か完了か、直近の失敗、現在の阻害条件、保持・削除などの処置結果は別の情報である。阻害条件は実行前に現在の正本から再判定する。過去の失敗から再試行可能性を推測せず、所有するdomainの規則に従う。 外部providerには、利用できる冪等性キー、期待する内容、安定した資源IDを渡し、権威ある応答または観測で結果を確認する。応答喪失を失敗と決めつけて、新しい操作IDで副作用を繰り返さない。確認できなければ最後に確定した事実を保持し、結果不明または要確認として扱う。 ## 保証の限界 対象は重複要求、返却エラー、timeout、既知の部分成功、最後に確定した記録からの再起動復旧である。任意の命令位置でのpanic、強制終了、マシン喪失、電源断に対して、一度だけ実行されることを一般的には保証しない。すべての`await`の前後に状態を書いて、その保証を装わない。 破壊的・機密性の高い操作に強い耐障害性が必要なら、providerの契約、記録順、再送規則、照合根拠を個別に定義する。診断には調査と再試行に必要な識別子・分類だけを残し、秘密、生のプロンプト、セッション全文、内部パスを複製しない。