実装はあんまり見ずに、ATPの雰囲気を把握するためのメモ
要素としては以下のような感覚。
- Repository: 署名つきRDB
- データ構造がRDB(というか表)という話で、SQL-likeな操作が規定されてるわけではない
- 他サーバやクライアントが複製する形で通信(兼バックアップする)
- 1行(Record)はJSON互換のCBORで表される
- テーブルはCollection、主キーはTID(タイムスタンプ)、スキーマはLexiconに対応
- 署名はRepository全体(のMST)に対して、更新される毎に行う
- DID: ユーザID→Repository置場マッピング
- ユーザIDが直接Repositoryの在処を示さないため、IDそのままで引越せる
- 公開鍵もあるので、Repositoryの検証ができる
- 当面は(おそらく唯一の)サーバで運用するdid:plcを用いる
- XRPC: サーバAPI形式
- HTTP GET/POST上で定義され、型取得方法やURL決定方法を規定する
- 具体的なメソッドはLexicon形式のJSONが定める
- Repository同期のような基本的な操作もやるし、タイムライン取得のようなapp固有の操作も可
- 普通はクライアントは(特に他人の)Repository全体を持ちたくはないので、固有APIが期待される
- Lexicon: Repositoryスキーマ・XRPCメソッド定義
- 逆ドメイン名で名前空間を切って、RecordやXRPCの型をJSONで定義する
- Lexicon名に対応するドメインからLexiconが取得できることが期待されるが、必須ではない
Activitypubの主体がメッセージであるのに対し、ATPはデータが主体。APでいうなら、所有者のみPOST可なCollectionだけがある感じか?二者間の関係ではなく、誰かが持つ情報を別の誰かが見る形。アクセス制御は無いと考えた方がよさそう(PDS単位でのブロックくらいはできるとは思うが)。
サーバ間通信は現状Repository同期のみ。サーバ間で使えるかはわからないが、一応特定Collectionのみの取得も可。app.bsky.graph.followを元にfetchするようにPDSを実装する必要がありそう。Indexerの話も出ていないし、そもそも現状は単独PDSを主に考えていそうなので、この辺りは今後新要素の登場に期待。
そもそもこの名前が何を指すのかも不明瞭だが、一旦app.bsky.*を一通り使いこなすクライアントと想定し、どのようなサービスになるか考える。
プリミティブなTwitterという感じ。ホームTLが見れてリプライやいいねやrepost(RT)ができる。RTどころか画像投稿もスレッド表示もできるので、初期Twitterより多機能っぽいが。DM、非公開アカウント等のアクセス制限する要素は無い。リスト・ハッシュタグ・検索もおそらく無いが、これらは将来的にはClientやIndexerが解決するかも。
最初はPDS固定になる気がする。単独サーバ内のサービスとして始めて、federation可能にして、もしかしたら汎用クライアントになるかも、程度のつもりでいた方が気楽か。
- CollectionはRepository内の同じ型のRecordをまとめたもの
- Lexiconによって決まるもので、ユーザが定義するものではない点に注意
- DIDは不変、usernameは(name serverを確保していれば)変更可
- DIDメソッド固定と考えるとそこそこ強い制約の気もする
- DIDとusenameは相互変換可
- 推定Repository構成はMST(履歴&署名付き)+KVS(TID-Record)
- MSTについては原論文の図を見るのが手っ取り早い
- 記載されていないが、keyはTID(Lexicon依存?)、valueはRecordのCID(≒ハッシュ)だと思われる
- MSTノードもCBORになっており、参照をCIDで表すため、Record操作は常に根まで波及する
- MSTの根のCIDに署名する(commit)ことで、全てのRecordの改竄が検証可能
- MST Entryが葉と右隣のサブツリーをセットで表しているのが少しややこしい
- Record本体の管理方法はおそらく自由で、普通にDBに突っ込むとかになりそう
- PDSが知らない型のRecordも保持してほしいので若干注意が必要
- 一度作ったRecordを無かったことにする等は普通にできそうだが、MSTが魚拓になる
- MSTについては原論文の図を見るのが手っ取り早い
- s2sは何も決まってない
- Bluesky Socialは当面1PDSのみで運用するつもり?
- 最低限Repository同期APIだけはあるので全く出来ないわけではないが……
- イベントベースの通信もしたいという話はあったが予定は不明
形式定義だけなので特に見所は無い
これも形式定義のみなので、意味はGuideの方を見ろということか
defsは何?
- HTTP GET/PUTとして働く
- 入力としてParameterとInputの2つがある
- Lexicon Schemaは必ずしも公開する必要は無い
- 公開しないとPDSはRecordの検証できない場合が出るので公開しててほしい
- サーバが特定のmethodを実装しているか、権限的に呼べるかは実際に呼んでみるしかない?
- 本当にドメインを持っている人だけがそのNSID使おうと言っている?
- 一度Lexicon作ったら保持し続けないといけないの少し厳しそう
- 全ATPユーザが同じ(少なくとも一貫した内容の)PLCサーバを参照する
- PLCサーバはDIDをDIDドキュメント(公開鍵・username・PDSアドレス)に解決する
- PDSやPLCサーバはsigningKeyの秘密鍵を受け取るが、recoveryKeyは持たないのでまあまあ安全、という思想?
- usernameはalsoKnownAsで指定
- 以下の節については現状対応する仕様が無いので注意
- Federation
- Achieving scale
- Algorithmic choice
- Speech, reach, and moderation
- "Authenticated Transfer Protocol a.k.a ATP"と言ったそのページ中で別名持ち出すのどうなの?
- AT Protocolに至っては同じ段落
- @-protocolはATPのコア部分のみ指すようにも読めなくはないが、多分違う
- ドメインやリポジトリがatprotoなのはわかるが、URIスキームがatなのは嫌い
- クライアントはRepositoryを手元にコピーしておくことが推奨される
- PDSが急に使えなくなっても移行できるバックアップとして働く
- 逆に言えば、Repositoryにそのユーザの全てが記録されているべき
- "These IDs should rarely change"ということはDID変更可能にすることも想定している?
- 良いDIDメソッドが無いので中央集権的だけどdid:plcを使う、とのこと
- usernameとPDSアドレスは全く異なっていてよい
TIDの定義以外はATPで言ってる内容
- LexiconはJSONで定義される
- XRPCメソッド(query/procedure)、Recordの型、定数(token)を定める
- Recordの
$ext
フィールドはLexiconに無いフィールドの追加を許す?- 別で定義したものを付け足すとかでもなさそう
- かなり気持ち悪い使い方されそう
- Lexiconは互換性を保つ更新(オプションフィールド追加)のみ可能
- 追加機能だけ別Lexiconで、とかになる?
- サーバがどのLexiconを知っている(≒どのメソッドを実装している)べきかは自己判断?
簡単なサンプルコード
- ブロックチェーンと関係無いと断言するのちょっと安心感ある
- 現状ちゃんとDIDしようとすると関わる可能性高そうだが、別アプローチに期待している?
- APに対するATPの強みとしてアカウントの可搬性を挙げている
- 例えばPDS(Mastodon等でいうインスタンス)を変えてもフォロワーも投稿も維持できる
あまり具体的な記載は無いので推測交えて気になったとこだけ
- XRPCメソッドの想定権限くらいほしい
- アカウント作成にemail必須・パスワード認証強制なの微妙に納得いかない
- せっかく公開鍵あるしそれ使ってもいいのでは、と思ってよく見たらsigningKeyはPDSしか知らないっぽい?
- invite概念があるらしいがよくわからない
- com.atproto.syncはサーバ間想定のようだが、クライアントが使う場合もあるはず
- フォロワーやlike数を正確に把握するの無理では?
- app.bsky.system.declarationわかってないが、人間/グループ/botみたいな区別に使うものっぽく見える
- Lexicon間の依存関係はあり?
- app.bskyの拡張とかしたくなりそう
- →普通に許されそうだが、依存関係を示す仕組みは無いので注意
- Collectionの部分公開とかあり?
- 例えばDM的なものを実装するにあたって、特定ユーザしか見れないRecordを作りたい
- 公開対象をRecord内で指定しても、複数ユーザを抱えるPDSがそのLexiconの扱いを知らない場合に漏れたりしそう
- →現状できないが、DMは暗号化によって実現しようとしている 参考
- Clientが担当のPDSを介さず直接他PDSに問い合わせることは想定している?
- 例えば、あるユーザのいいね一覧(app.bsky.feed.like)を取得しようと思った時、誰に聞く?
- PLCサーバに問い合わせられるのは誰か、どんなタイミングでRepository同期が発生するかにも関わる
- →基本的にはしない想定だと思われるが、それはそれとして認証無しで叩けるAPIもあるので可能ではある 参考
- PDSはどのように通信先を定める?
- 現状、あるPDSが取得すべき別PDSのRepositoryを特定できるのはapp.bsky.graph.followだけに見える
- 同期すべき相手を決めるのは各Lexiconというのはわかるが、それはPDSに全Lexiconのロジック実装を要求するのでは?
- 基本的なs2sというか、適当な相手とのfetch/push程度はATPのレベルでできてほしい
- →small-worldの同期はPDSにロジック実装、big-worldは汎用の仕組みを作ってこっちをメインにしたがっているように見える 参考
- フォーラムを実現するらしい
- 認証周り割と不安
- OpenID的な仕組みほしい(Lexicon作ればよさそう)
- signingKeyを(場合によってはrecoveryKeyも)PDSだけが持ってる片手落ち感
- com.atproto.account.create使う限り既存DIDは使えない
- →将来的にどうにかしようと考えているらしいので期待……だが、createSession使ってる限りパスワード排除はできなそう
ウェブサイトのものから構造が変わっているので注意
big-worldは現状想像だけどおそらく大体こんな感じ。かつこっちがメイン?
Twitterは中身分からんけどfanoutとか考えればこの書き方でも間違ってはいないはず。Zotはまともなドキュメント無いので雰囲気で書いている。
アカウントがサーバに依存しない=引っ越せるというのは自己アピールしている魅力だけど、それとは別にサービスがサーバに依存しない=サービスロジックをクライアントだけで実装できる(ので独立した複数サービスに同じアカウントを使いやすい)のも魅力になりうるので、その辺りが思い込みでないことを願う。
とはいえ仮に仕様上は可能であったとしても、WebUIを主とする人が大多数なら結局PDS依存ということにもなりそうだが。クライアントサイドで処理するのがどれだけ現実的かはわからないし。例えばapp.bsky.feed.getTimelineを使えないPDSを想定したBlueskyクライアントを作るかという話なので。
これについてはアカウントも同じで、1アカウントに複数サービス抱え込めばクライアントがRepository丸ごと持つのが現実的かは怪しくなるかもしれないし、そもそもクライアント使わず外部サービス使わずでバックアップが存在しないユーザは一定数出そう。