「送ったかどうか」はproviderの申告ではなくhostが観測する
createが失敗したとき、「何も作られていない」と「作られたかもしれない」を分ける一番強い手がかりは、リクエストが実際にネットワークへ出たかどうかである。出ていなければ、クラウドに何かが起きた可能性は無い。createの失敗は「外部世界について何が分かっているか」で分ける
この事実をproviderの自己申告に任せると、providerのバグや手抜きがそのまま「作られていない」という誤った帳簿になり、孤立したリソースが残る。Carinaはこれをprovider(WASMのguest)から取り上げ、HTTPを実際に送り出すhostが観測する。
仕組み
- hostはguestの呼び出し1回ごとに
CallEgressRecorderを用意する。複製しても「どの呼び出しの記録係か」は保たれるので、遅れて出たリクエストが後の呼び出しの記録を汚すことはない - 送信の直前に
begin_request()でガードを取り、HTTPトランスポートに渡す直前にdispatched()で消費する。ポリシーでの拒否、DNSの失敗、タスクのキャンセルでガードが捨てられた場合は「送っていない」になる - 呼び出しが終わると、記録係は
CallEgress::None(NoEgress)かCallEgress::Sent(EgressSent)のどちらかを返す - 失敗の分類はこれで分岐する。
Noneならattempt.not_created(error)、Sentならattempt.outcome_unknown(sent, error)
要点はNoEgressとEgressSentのフィールドがprivateなことである。hostの記録係しかこの証拠を作れない。outcome_unknownはEgressSentを引数に要求するので、観測なしに「届いたかもしれない」を作ることもできない。
信頼境界の置き方として
これは信頼境界を越えるデータは境界で再検証するの一例だが、向きが少し違う。境界を越えてきた値を検証し直すのではなく、境界の外の主体に申告させること自体をやめ、境界の内側で観測できる事実で置き換えている。providerがどう書かれていても、「出ていないのに出たことにする」も「出たのに出ていないことにする」もできない。
観測できるのは「出たか」までで、「クラウドで何が起きたか」ではない。だからSentは成功ではなくOutcomeUnknownに落ちる。観測した事実より強いことを主張しない、という線の引き方である。planは予測であり、真実はapplyが確立する
根拠の確度
CallEgressRecorder / PendingCallEgress / CallEgress / NoEgress / EgressSentの定義とコメント、GuestCallFailure::classifyの分岐、CreateAttempt::outcome_unknownの引数はcarina main 273a2520で確認した。キャンセル時にmay_have_dispatched()で報告する経路があることも見たが、その後のstateの扱いまでは追っていない(要確認)。「申告をやめて観測に置き換える」という整理は解釈である。