要約

  • RFC 9610 の ContactCard は存続中、少なくとも一つの AddressBook に属するが、複数に属することができる。一つの所属を外すことは、カードの破棄とは異なる。
  • グループはメンバーの UID を保存する。対応するカードへのアクセスを一時的に失うと表示から消えるが、未解決 UID は保持され、アクセス回復後に再び解決できる。
  • 削除を立証するには、Account、サーバーオブジェクト ID、UID、変更前の所属集合、正確な /set 引数、応答、その後の権威ある照会が必要である。

画面は空になったが、オブジェクトの運命は決まっていなかった

プロジェクト終了時に共有アドレス帳を削除し、クライアントが空の画面を返したとする。監査担当者は「連絡先削除済み」と記録する。ところが後日、同じ取引先が障害対応用のアドレス帳に現れる。復元が起きたと考える前に、最初の操作が何を削除したのかを確かめる必要がある。

RFC 9610 で AddressBook は名前付きのコレクションである。一つの ContactCard は複数のコレクションに所属できる。onDestroyRemoveContents:true でプロジェクト用 AddressBook を破棄すると、その所属はカードから外れる。しかし別の AddressBook にも属しているカードは破棄されない。最後の所属を失ったカードだけが破棄される。

従って、空の一覧、成功した要求、存続するカードは矛盾しない。表示、所属関係、オブジェクト寿命を一つの「削除」に畳み込むと、ローカルな観測が全体的な消去証明へ変質する。

AddressBook は分類するが、排他的に所有しない

連絡先データモデルを持つ Account は複数の AddressBook を含み、それぞれが ContactCard をまとめる。生きているカードの addressBookIds は空であってはならない。この設計により、一枚のカードを「調達」「当番」「更新」の各用途で共有できる。

「更新」から外す操作は一つの関係を変えるだけで、「調達」と「当番」の事実を取り消さない。重複コピーを減らす利点と引き換えに、実装は所属変更と破棄を区別する責任を負う。

プロトコルは相互運用に必要な最小状態を決める。製品はそれをフォルダー、ラベル、ワークスペースとして描けるが、表示上の比喩が操作権限を拡張することはない。

onDestroyRemoveContents は状態に依存する分岐である

既定値 false のまま、内容のある AddressBook を破棄しようとすると、サーバーは addressBookHasContents で拒否する。これは当該引数によるコレクション破棄が行われなかった証拠であり、あらゆる場所でカードが永久に保存される証拠ではない。

true の場合、サーバーは対象 AddressBook を各カードの所属集合から除く。その後、他の所属が一つもないカードだけを破棄する。同じ要求の中で、コレクションの破棄、複数所属カードの存続、孤立カードの破棄が同時に起こり得る。

監査ログに「cascade=true」だけを残しても、結果を決めた条件は失われる。各カードの変更前 addressBookIds と、応答の destroyed、notDestroyed、updated、エラーを保存しなければならない。破壊的な名前のオプションは、普遍的な消去命令ではない。

サーバー id と uid は異なる範囲を識別する

ContactCard にはサーバーが設定する不変の id がある。さらに JSContact の uid があり、RFC 9610 は両者が異なってよいと明記する。同じ Account 内では、同一 UID を持つ ContactCard は一つまでである。

サーバー ID は JMAP の /get、/set、/changes が扱うオブジェクトを指す。UID は連絡先表現の連続性を担い、グループの members が保存する値でもある。表示名しか残さなければ両方を失う。UID だけでは、どの Account のどのサーバーオブジェクトが変わったか分からない。ID だけでは、グループや別のアクセス可能な Account が表す連続性を見失う。

両者を保存しても、現実の人物そのものを識別したことにはならない。一つの ContactCard の破棄は、メール、エクスポート、端末、CRM、バックアップ、本人の消去を意味しない。

グループは、いま見えない参照を捨てない

グループ型 ContactCard の members は UID の集合である。クライアントは、現在アクセス可能で JMAP Contacts を支える Account から一致するカードを探す。見つからない UID は表示上無視してよいが、保存し続けるべきである。

RFC 9610 自身が例を示す。共有アドレス帳の連絡先を私的グループに加えた利用者が、その共有帳へのアクセスを一時的に失う。UID が解決できないためメンバーは消える。アクセスが戻ると、保持された UID が再びカードを見つけ、メンバーが現れる。

復元書き込みは必要ない。連続性は中断中も残っていた。中断時のスクリーンショットが証明するのは、その主体がその瞬間に解決できなかったことだけである。カードの破棄、UID の削除、他主体からの不可視性までは証明しない。

フィルターの不一致は存在否定ではない

inAddressBook は指定 AddressBook に属するカードを選ぶ。結果にないカードは、そのコレクションにいないと分かるだけで、別の AddressBook や別の可視範囲に存在し得る。

JMAP の状態文字列と /changes は遷移を追跡できる。ただしクライアントは旧状態を保持し、created、updated、destroyed の ID を検査し、不確かなときは正しい Account で /get を行う必要がある。一覧から一行消えたという事実は、この連鎖の代わりにならない。

サーバーが ContactCard の破棄を確認しても、結論はその JMAP Account 内のオブジェクトに限られる。他 Account、複製、バックアップ、メール履歴、外部システム、法的消去までは覆わない。

既定帳の要求も、意図と結果の差を示す

onSuccessSetIsDefault は他の変更が成功した後、指定した AddressBook を既定にしようとする。しかし ID が見つからない場合やサーバーポリシーが許さない場合、この変更はエラーなしで無視され、従来の既定帳が残る。

要求の送信は試行の証拠であり、状態変更の証拠ではない。クライアントは返されたサーバー設定値を読むか、現在状態を再取得してから成功を表示すべきである。この原則は削除にもそのまま当てはまる。

削除証跡を構成するもの

まず Account、ContactCard のサーバー id、UID を特定する。次に操作前の完全な addressBookIds と、グループに残る関連 UID を保存する。AddressBook を破棄したのか ContactCard を直接破棄したのか、onDestroyRemoveContents の値は何かを記録する。

さらに応答、新状態、後続照会を保存する。結論は「この AddressBook から除外」「この主体には現在解決不能」「この Account で ContactCard を破棄」「未確定」のいずれかに限定する。RFC 9610 は「その人物があらゆる場所から消去された」という判定を発行しない。

表示、関係、オブジェクト、外部世界を分けることは、監査を弱くしない。各決定が必要とする本当の証拠を見えるようにする。

情報源