{
  "$type": "com.whtwnd.blog.entry",
  "blobs": [
    {
      "name": "network.png",
      "blobref": {
        "ref": {
          "code": 85,
          "version": 1,
          "hash": {
            "0": 18,
            "1": 32,
            "2": 105,
            "3": 183,
            "4": 183,
            "5": 35,
            "6": 254,
            "7": 92,
            "8": 128,
            "9": 201,
            "10": 190,
            "11": 72,
            "12": 234,
            "13": 200,
            "14": 164,
            "15": 213,
            "16": 83,
            "17": 5,
            "18": 149,
            "19": 107,
            "20": 3,
            "21": 231,
            "22": 31,
            "23": 78,
            "24": 27,
            "25": 176,
            "26": 108,
            "27": 15,
            "28": 181,
            "29": 82,
            "30": 248,
            "31": 110,
            "32": 12,
            "33": 65
          }
        },
        "size": 30797,
        "mimeType": "image/png",
        "original": {
          "$type": "blob",
          "ref": {
            "$link": "bafkreidjw63sh7s4qde34shkzcsnkuyfsvvqhzy7jyn3a3apwvjpq3qmie"
          },
          "mimeType": "image/png",
          "size": 30797
        }
      },
      "encoding": "image/png"
    }
  ],
  "theme": "github-light",
  "title": "atprotoモデレーション概論 基礎編",
  "content": "## atprotoモデレーション概論 基礎編\n\n[atprotoモデレーション概論 目次](https://whtwnd.com/did:plc:qi6xg6zplzivyu7zrylxuugk/3lb4xttmcxw2m)\n\nここでは、atproto仕様上モデレーションがどのような形で表れるかについて説明する。基本的には[公式ドキュメント](https://atproto.com/specs/label)にある内容。\n\nbsky固有の仕様やlabelについては別記事。\n\n### atprotoの構造とモデレーション\n\nまず前提として、atprotoにおけるデータフローは以下のようになっている。[^network]\n\n[^network]: relayもappviewも単一である必要は無いが、現状はほぼ単一で、かつ増やしても説明上はあまり意味が無いため、ここではこれくらいにしておく。\n\n![](https://lionsmane.us-east.host.bsky.network/xrpc/com.atproto.sync.getBlob?did=did%3Aplc%3Aqi6xg6zplzivyu7zrylxuugk&cid=bafkreidjw63sh7s4qde34shkzcsnkuyfsvvqhzy7jyn3a3apwvjpq3qmie)\n\natprotoのモデレーションは基本的に、この中のどれかが出力をマスキングするという形で実現される。\n\nただし実のところ、この文脈においてappviewとrelayを区別する必要はあまり無いので、以降はrelayを省略する。[^relayapp]\\\n今のところrelayにおけるモデレーションらしき例も([アカウント数制限](https://docs.bsky.app/docs/advanced-guides/rate-limits#relay-limits)くらいしか)聞かない。\n\n[^relayapp]: relayは必須の存在ではなく、appviewが直接クロールしてもいいし、新しいrelayを勝手に立ててもいい。もちろん既存relayに便乗した方が楽だし、relayは[PDSからの通知](https://github.com/bluesky-social/atproto/blob/main/lexicons/com/atproto/sync/notifyOfUpdate.json)を受けられた方が効率良くなるが、いずれも必須ではない。relayでマスクされたところで、repositoryの一部だけであれば、署名検証で検出してPDSに直接取得しにいけばいい。\n\n現状のBluesky Socialで一般的に「モデレーション」と呼ばれるものは、概ね以下のいずれかの形で表れる。後のものほど強い。\n\n* クライアントによる表示のマスキング\n* appviewによるAPIレスポンスのマスキング\n* PDSによるAPIレスポンス・firehoseのマスキング\n* PDSによるアカウント削除\n\nそれぞれ判断材料は他所(labeler等)から提供される場合があるが、話がややこしくなるため後に回して、最終判断を下す主体から一通り説明する。\n\n### 様々なモデレーション\n\n#### クライアントによるマスキング\n\nBluesky利用者に一番馴染み深いのはやはりこれだろう。画像の警告とかワードミュートが該当する。別途説明するlabel周りは大体ここで処理される。\n\n閲覧側クライアントが各データの表示を制御する。基本的には利用者個々人の設定次第だろうが、クライアントによって強制される場合もある。\\\n例えば、公式クライアントはプラットフォームの規約上、誕生日を登録しないと性的コンテンツが表示できないようになっていたはず。\n\n強制の場合、クライアントを変えてどうにかなるかは微妙なところ。設定可能な範囲に関しては個々の利用者次第だ。\n\n#### appviewによるマスキング\n\n一般にBANと呼ばれる、「Account has been suspended」というやつは大体これ。atproto的にはtakedownと呼び、APIレスポンスから対象アカウントが除外される。\\\nモデレーションと呼ぶかは微妙だが、ブロックやアカウントミュートもここ。\n\n特定のコンテンツ(record/blob)だけtakedownする場合もある。実例は見たことないが、DMCA対応とかはこれになるだろう。\n\n回避するには異議を申し立てるか、別のappviewを使おうという話になる。ただし、appviewを変える必要があるのは、takedownを受けた側ではなく見る側である点に注意。アカウントごとtakedownを受けた場合、事後に代わりのappviewについて伝えるのは難しいかもしれない。また、今のところ既存appviewの代替を提供する人はいないので[^altappview]、そこは自力でなんとかするしかない。\n\n[^altappview]: コストや技術のハードルがあると思われるが、そもそも試み自体がほぼないので何とも言えない。やるとしたらそれこそモデレーション回避目的の可能性が最も高そう。\n\nappview単位なので、例えばBluesky SocialでtakedownされてもWhiteWindには影響無い。[^appviewmod]\n\n[^appviewmod]: 現実はもう少し面倒で、例えばWhiteWindのコメント欄はBluesky Socialに依存しているし、PDSのtakedownが同時に発生したりする。\n\n#### PDSによるマスキング\n\n発信側PDSもappviewと同様、所属アカウントやそのコンテンツにtakedownを行うことがある。根本を止められるので、appviewによるものより強い。\\\n閲覧側PDSは一応経路になってこそいるが、基本的に素通しなので無視していい[^pdsmoderation]。\n\n[^pdsmoderation]: 細かいことを言えば、受信側PDSがここに干渉することもできる。ただし、そのためには対象APIを知っており、対応ロジックをPDSに実装する必要がある。一般に、PDSはlexicon非依存であり、PDSの知らないAPIを仲介することがあるため、PDSが完全にコントロールすることは原理上困難と思われる。\n\n公式PDS(bsky.social)では、公式appview(api.bsky.app)のtakedownと同時にPDSでもtakedownされるのが一般的。詳細はBluesky Socialの話をするときに。\n\nPDSにtakedownされ、解除してもらう見込みもない場合、PDSを引っ越すことになる。幸い、takedownされても引越用の機能(データのエクスポート等)は利用可能だが、現状引越機能はユーザーフレンドリーとはとても言えないので、受け入れてくれるPDSが見つかっても尚ハードルが高いかもしれない。[^pdsimport]\\\nまた、PDSのtakedownがappviewに反映されたあとに引っ越した場合、ちゃんと解除できるかは実装依存。\n\n[^pdsimport]: 細かいことを言うと、実装上の問題により、公式PDSへの引越し(というかデータのインポート)は禁止されているが、この文脈では基本的に出ていく方なので、問題になることはないだろう。\n\n### PDSによるアカウント強制削除\n\n一番重い。[事例あり](https://bsky.social/about/reports/2023-07-22-timeline)。\n\n全部消えるので、事前にバックアップ等の準備をしていなければ、データの持ち出しどころか引越しもできない。\n\n### おまけ\n\nモデレーションと呼ぶかはともかく、「情報のフィルタリング」という観点では他にも何箇所かで起きている。\n\n太字はフィルタリングする主体。\n\n* client->**PDS**\n  * lexiconのバリデーションや、データサイズ・レート制限がこれ。\n  * PDS管理者の権限によってアカウントが削除される可能性もある。\n* **PDS**->relay\n  * PDSは特定のアカウントやデータを渡さない場合があり、(PDSによる)takedownと呼ばれる。\n  * 特定relay以外のクローリングを拒否する可能性もあるが、現状一般的ではない。\n* PDS->**relay**\n  * そもそもどのPDSをクローリングするかはrelayが決めるものだが、各PDSのfirehoseから特定のアカウントを無視することもある。\n    * 基本的にアカウント単位より小さくならないし、仮になってもappviewによる検出・回避は比較的容易。\n  * 2024年前半にあった、サードパーティクライアントに対する1PDS10アカウント制限がこれ。\n* **relay**->appview\n  * PDSのtakedown通知を受けて出力をマスクすることがある。\n  * 今のところ無いが、DID認証で行儀の良いappviewのみ許す、といったことも可能。\n* relay->**appview**\n  * firehose上から必要なデータを選別する。\n  * bsky appviewがpostの上書きを無視するとか、whtwnd entryを無視するとか。\n* **appview**->PDS\n  * lexiconの示すスキーマにさえ従えば大体なんでもできる。\n  * appviewによるtakedown・labelによるフィルタリング・ミュートやブロックの反映等\n* **client**->user\n  * 特定labelの非表示やスレッドミュート等\n\nちなみに、矢印の一方だけしかモデレーションしない場合、もう一方は大体主体的に通信相手を選べる。どのクライアントを使うかはユーザの自由だし、どのrelayからデータを取得するかはappviewの自由だ。\n\n\n### Next\n\n[label編](https://whtwnd.com/did:plc:qi6xg6zplzivyu7zrylxuugk/3lb4y3p756w22)",
  "createdAt": "2024-11-18T01:45:21.350Z",
  "visibility": "public"
}