{
  "$type": "com.whtwnd.blog.entry",
  "blobs": [
    {
      "name": "localcontent.png",
      "blobref": {
        "ref": {
          "code": 85,
          "version": 1,
          "hash": {
            "0": 18,
            "1": 32,
            "2": 229,
            "3": 213,
            "4": 14,
            "5": 244,
            "6": 35,
            "7": 20,
            "8": 10,
            "9": 54,
            "10": 122,
            "11": 177,
            "12": 40,
            "13": 233,
            "14": 32,
            "15": 207,
            "16": 84,
            "17": 168,
            "18": 41,
            "19": 203,
            "20": 213,
            "21": 150,
            "22": 174,
            "23": 248,
            "24": 231,
            "25": 18,
            "26": 173,
            "27": 1,
            "28": 56,
            "29": 19,
            "30": 88,
            "31": 238,
            "32": 166,
            "33": 254
          }
        },
        "size": 37104,
        "mimeType": "image/png",
        "original": {
          "$type": "blob",
          "ref": {
            "$link": "bafkreihf2uhpiiyubi3hvmji5eqm6vfifhf5lfvo7dtrflibhajvr3vg7y"
          },
          "mimeType": "image/png",
          "size": 37104
        }
      },
      "encoding": "image/png"
    }
  ],
  "theme": "github-light",
  "title": "atprotoモデレーション概論 実践編",
  "content": "## atprotoモデレーション概論 実践編\n\n[atprotoモデレーション概論 目次](https://whtwnd.com/did:plc:qi6xg6zplzivyu7zrylxuugk/3lb4xttmcxw2m)\n\n望まれることの多い独自モデレーションの実現案について考えてみる。\\\nあくまで一案に過ぎないし、本当に実現できるか検証したわけでもないが、何かの参考にはなるかもしれない。\n\n### 問題設定\n\natprotoのモデレーション周りで期待されることが多いのは、「日本独自のモデレーション基準を適用したい」というものだろう。\n\nlabelに関して言えば、独自モデレーションは特に難しくない。緩めるには見る側がクライアント設定で外せばいいし、強めるにはlabelerを運用すればいい。\n\n問題になるのはtakedownやアカウント削除される場合だろう。[Bluesky Socialの禁止行為](https://bsky.social/about/support/community-guidelines)には以下のように書かれており、特に抵触しやすそう。\n\n> Distribute child sexual abuse material, or any content portraying minors in a sexually explicit context\n\n似たような規約はよくあるが、日本はこの手の表現に比較的寛容と言われている。\\\n国内でのみ許されるようなコンテンツを投稿した結果、規約違反としてアカウントごとtakedownされれば、その他の問題無いコンテンツも含めてBluesky Socialから追い出されてしまう。この辺りが、(「追加の」ではなく)独自のモデレーションを望む背景にあるだろう。\n\nとはいえ、Bluesky Socialへの依存を完全に排除するのも(プロトコル的には王道だが)未だ現実的ではない。PDSはセルフホストすればいいが、appviewはそうもいかない。\\\nBluesky Social利用者の投稿も見たいなら、公式appviewのクローンを作る必要がある。つまりおよそ2000万人分(2024年時点)のデータを取り扱う必要があり、[月額4桁ドルはかかる](https://bsky.app/profile/jaz.bsky.social/post/3kuc5u2jy222t)と言われている。小規模なコミュニティで使いたいだけなら、あまりに過剰だ[^appviewcost]。\\\nそうでなくとも、Bluesky Socialから見える状態が作れるのであれば、それに越したことはないだろう。\n\n[^appviewcost]: [API利用者が少なければより安価とされる](https://bsky.app/profile/jaz.bsky.social/post/3kyi7d6icio26)が、[relayのような実験結果](https://whtwnd.com/did:plc:44ybard66vv44zksje25o7dz/3kwzl7tye6u2y)があるわけではない。[試みている人はいる](https://whtwnd.com/did:plc:by3jhwdqgbtrcc7q4tkkv3cf/3laega7icmi2q)ものの、結果が出るにはまだ時間がかかるだろう。\n\nということで、その場しのぎ感は強いが、なるべくBluesky Socialと繋がりつつ、危険コンテンツも共有できる環境を目指す。\n\n具体的には以下のような感じ。\n\n* Bluesky Socialではtakedown対象になりうるような特定のコンテンツを、一部の人には見えるように発信する\n  * 以降はこれを「危険コンテンツ」と呼ぶ\n  * 一般的には画像(blob)が対象になることが多いが、ここではrecordとblob両方を検討する\n  * 共有相手は自発的に設定等をやってくれるものとする\n* 危険コンテンツを除いて、Bluesky Social上でもBluesky Social利用者と同様にアクセスできる\n  * 相互にフォローしたりリプライしたりできて、どちらからもそれが見える\n* なるべく低コストに抑える\n  * PDS以外は基本的にBluesky Socialのインフラにフリーライドする\n\n### 解決方法\n\nやり方はいくつか考えられるが、ここでは独自仕様の改造PDSを用意し、同一PDSのアカウントとのみ危険コンテンツを共有することを考える。\n\n![](https://lionsmane.us-east.host.bsky.network/xrpc/com.atproto.sync.getBlob?did=did%3Aplc%3Aqi6xg6zplzivyu7zrylxuugk&cid=bafkreihf2uhpiiyubi3hvmji5eqm6vfifhf5lfvo7dtrflibhajvr3vg7y)\n\n危険コンテンツは普通のコンテンツと同様のrecordやblobとして扱うが、アップロードAPI(`createRecord`/`uploadBlob`)に独自のフラグパラメータを追加して、危険コンテンツだと示すことにしよう。\\\n独自のクライアントを用意したくなければ、フラグの代わりに適当なglobal labelを決めてself labelとして表せば、一部のクライアントは使えるかもしれない。\n\n外部(例えば公式relay)からデータ取得要求が来た場合、危険コンテンツのみマスクし、それ以外を渡す。ただし、危険コンテンツの存在そのものを無かったことにしてはいけない。\\\nrelayやappviewはMSTの署名を検証するため、下手に誤魔化すと整合しなくなってしまう。そのため、対外的には「PDSでtakedownされた」ということにして、存在はするが見せられないことにする。\n\nPDSからappviewのAPI(例えば`getTimeline`)が呼ばれた場合、普通のPDSと同様にappviewにプロキシする。上図だとクライアントはbsky.appに直接接続しているかのように見えるが、実際には認証の都合上、PDSが仲介している。つまり、PDSはAPIレスポンスに介在する余地がある。\\\nappviewには危険コンテンツは届いていないため、元レスポンスに危険コンテンツは当然含まれない。しかし、クライアントに返す前にPDS内部で留めていた危険コンテンツを混ぜ込んで、あたかもappviewに届いていたかのような結果を返す。\n\nPDSはかなり頑張る必要があるだろうが、like数や返信のスレッド化を省けばいくらか楽になるかもしれない。\n\nPDSでappviewのレスポンスを弄るというのは非常識に感じるかもしれないが、atproto的には案外そうでもない。公式PDSでもやっていることである。具体的には[read-after-write](https://docs.bsky.app/docs/advanced-guides/read-after-write)と呼ばれるbsky API用の機能で、直前のbsky投稿を覚えておいて、`getTimeline`等に混ぜ込むというもの。\\\n本来、PDSに投稿recordを追加してからrelayにクローリングされてappviewのDBに入るまで多少のラグがあるが、投稿者からすれば投稿した後に叩いたAPIに投稿が反映されていないのは如何にも気持ち悪い。不自然に感じて不具合を疑うこともあるだろう。そこで、read-after-writeで見かけだけ繕おうというわけだ[^readafterwrite]。\n\n[^readafterwrite]: 余談だが、公式クライアントで更新マークが出ていたのに、更新しても何も変わらない場合がある。その原因として、read-after-writeされた投稿がちゃんとappviewから返ってくるようになり、更新と判定されたことが考えられる。\n\n\n### 課題\n\nPDS内でのみ共有できるということは、PDS依存度が高いということだ。強い言い方をすれば、atprotoの長所であるアカウントポータビリティを殺す[^portability]ことになる。\n\n[^portability]: とはいっても引越しはできるし、同一機能を持つPDSなら危険コンテンツも持ち越せるので、完全に使えないわけではないが。\n\nまた、PDSがAPIにフックしてして弄るため、PDSが知っているAPIにしか危険コンテンツは乗せられない。典型的には、bsky投稿はうまくハンドリングしてくれるが、whtwnd投稿に危険コンテンツを付けたら誰からも見えなくなる、というようなことが起きるだろう。\n\nこの辺りは段階的に強化していくこともできそうだが、ここで細部詰めても仕方ないのでこんなところで。\\\n将来的には[non-public contents](https://atproto.com/specs/atp#future-work)辺りが全てをどうにかしてくれるかもしれない。",
  "createdAt": "2024-11-18T01:47:07.411Z",
  "visibility": "public"
}