【Bluesky】自前PDSが「投稿されているのに表示されない」問題を、生成AIと一緒に解決した話

この記事は約9分で読めます。

※この記事にはプロモーションが含まれています。

導入:ある日、自前PDSの投稿が「ネットの海に届かなくなった」

Bluesky の自前 PDS を運用していると、ある日突然こういう現象に出会いました。

  • クライアント(bsky.app やアプリ)から投稿すると、エラーは出ない
  • repo.listRecords で見ると、PDS 内にはちゃんと投稿レコードが存在している
  • 著者フィードも PDS 内では正しく取得できる
  • しかし、bsky.app のプロフィールにもホームタイムラインにも、一切出てこない

しかも、他人の投稿はホームフィードに普通に流れてくる。「世界は動いているのに、自分の声だけネットワークに乗っていない」状態でした。

ログを追っても PDS は落ちていないし、describeServer も正常応答。正直、「どこから手を付けるべきか分からない」タイプのトラブルです。

ここから、生成AIをフル活用したトラブルシュートが始まりました。


現象の切り分け:PDS内部 vs 公開ネットワーク

最初にやったのは、「どこまでが正常で、どこからがおかしいか」を明確にすることです。

1. PDS内部の確認

まずは PDS ローカルに対して XRPC を叩きます。

curl "http://localhost:3000/xrpc/com.atproto.repo.listRecords?repo=did:plc:...&collection=app.bsky.feed.post&limit=5"

結果:

  • 新規投稿(「てすと」「こんばんわ」「テスト after v0.4.193」など)が きちんと並んでいる
  • createdAt も現在時刻と整合している

さらに、認証トークンを取得して app.bsky.feed.getAuthorFeed を叩くと、著者フィードにも同じ投稿が出てきます。

PDS 内部では、投稿の保存とフィード生成は完全に正常 だと判断できました。

2. DID / ハンドルの整合確認

次に DID 周り。

  • アカウント DID:did:plc:xxxx...
  • plc.directory 上の DID ドキュメント:
"alsoKnownAs": ["at://kumego.bluesky.j-makoto.online"],
"service": [
  {
    "id": "#atproto_pds",
    "type": "AtprotoPersonalDataServer",
    "serviceEndpoint": "https://bluesky.j-makoto.online"
  }
]

PDS ローカルでの解決:

curl "http://localhost:3000/xrpc/com.atproto.identity.resolveHandle?handle=kumego.bluesky.j-makoto.online"
{"did":"did:plc:xxxx..."}

ハンドル → DID → PDS URL の流れは整合している ことが確認できました。

3. 外部からの疎通確認

クライアントと BGS(インデクサ)が叩くであろう URL もチェックします。

curl "https://bluesky.j-makoto.online/xrpc/com.atproto.server.describeServer"

結果:

{"did":"did:web:bluesky.j-makoto.online", ...}

TLS も問題なく、200 OK。
Caddy のログや lsof -i :443 からも、世界中から HTTPS アクセスが来ていることが分かります。

公開 HTTP レイヤーも生きている

4. それでも bsky.app のプロフィールには何も出ない

ここまでが全部「正常」なのに、bsky.app のプロフィールページは沈黙したまま。

  • PDS内部:OK
  • DID / エンドポイント:OK
  • HTTPS公開:OK
  • 他人の投稿:ホームに出る
  • 自分の投稿:どこにも出ない

この時点で、「PDS内部」と「Bluesky公共ネットワーク(BGS / bsky.app)」のあいだで何かが壊れていると判断しました。

生成AIとの対話:原因候補を潰し込んでいく

ここから先は、人間だけでログを眺めていても埒が明かないレベルの情報量になります。そこで、ChatGPT などの生成AIを“対話型のペアプロ相手”として使うことにしました。

やったことはシンプルです:

  • 手元のログ・設定・コマンド結果を、AI にそのまま貼る
  • 「ここから何が言えそうか」「次にどのコマンドを打つべきか」を相談する
  • 実際に叩いて結果をまた貼る
  • …を延々と繰り返す

AI は以下のような観点をどんどん提示してくれました:

  • PDS バージョン(0.4 はかなり古いので、まずは最新の 0.4 系に上げよう)
  • BGS との接続ログ(com.atproto.sync.subscribeRepos の挙動)
  • DID種別の混在(サーバDIDが did:web、アカウントDIDが did:plc
  • plc.directory 上の DID ドキュメントと PDS 設定の整合
  • Bluesky Debug Page(DNS / HTTP 検証)の状態

最終的に決定打になったのは、PDS ログのこの一行でした。

{"msg":"request to com.atproto.sync.subscribeRepos","cursor":229}

これが、同じ cursor のまま延々とループしていたのです。

→ 「subscribeRepos のカーソルが進んでいない=BGSとの同期ポジションが壊れているのでは?」という仮説にたどり着けました。


GitHub Issue へ:#318 で公式に相談する

AI とのやり取りである程度絞り込んだところで、「これはもうPDS実装側 or BGS側の領域だ」と判断し、GitHub に issue を立てました。

  • これまでに確認したこと(PDS内部は正常、DIDはOK、describeServerはOK)
  • 実際のコマンド例・ログ(特に subscribeRepos の cursor ループ)
  • 「0.4 → 0.4.193」に上げても症状が変わらなかったこと
  • こちらの仮説:BGSが覚えている sequence と PDS内部の sequence がズレているのでは?

この「経緯の説明&仮説の整理」自体も、AI に英文ドラフトを作ってもらい、それをベースに自分用に微修正して投稿しました。

ほどなくして、コア開発者から非常に具体的な回答が付きます。


解決編:BGS と PDS のシーケンス番号を合わせる

開発者が教えてくれた手順は、要するにこうです:

BGS(relay)が覚えている最後の sequence 番号を取得し、
PDS 内部の repo_seq テーブルのシーケンス番号を その値にリセットする。

1. BGS が覚えている seq を取得

docker exec pds sh -c 'goat relay host status "$PDS_HOSTNAME" --json'

出力例:

{"hostname":"bluesky.j-makoto.online","seq":483,"status":"idle"}

ここで seq: 483 が「BGSがこのPDSについて最後に見たシーケンス番号」です。

2. PDSサービスを停止

sudo systemctl stop pds

(Docker Compose で起動しているので、裏では docker compose down が走ります)

3. sequencer.sqlite のシーケンスを上書き

sqlite3 /pds/sequencer.sqlite \
  "UPDATE sqlite_sequence SET seq = 483 WHERE name = 'repo_seq';"

※ 483 の部分は、さきほど goat で取った seq の値を使います。

4. PDSを再起動

sudo systemctl start pds

起動後、念のためログを確認:

docker logs --tail=200 pds | grep -Ei "subscribeRepos"

すると、以前は cursor:229 でループしていたものが、
再起動後は別の値(263→さらに進む)に変化し、BGS との同期が再開している様子が見えてきます。

5. 再投稿テスト:ついに bsky.app に現れた

最後に、bsky.app から新規投稿を行いました。

  • テキスト:「テスト after seq reset 2」

PDS 内では当然のように listRecords に現れ、しばらく待ってからプロフィールページを開くと——

ちゃんと bsky.app のプロフィールに表示されました。

まさに、「ネットワークに戻ってきた」瞬間です。


生成AIは「答えを知っている」わけではない。でも、エンジニアにとっては強力な相棒になる

今回のケースで重要だったのは、

生成AIが「この問題の答え」を知っていたわけではない

という点です。

  • seq リセットの具体コマンドは、最終的には GitHub Issue の開発者コメントから得ました。
  • しかし、そこにたどり着くまでのログの読み解き・仮説の整理・英文のドラフトは、 ほとんど AI との対話を通じて行われました。

具体的には:

  • 「まず何を疑うべきか?」という切り分け順序を提案してくれる
  • コマンド結果やログを貼ると、人間だと見落としがちなパターン(例:subscribeRepos の cursor ループ)を拾ってくれる
  • 自分の頭の中にある仮説を英語で整理してくれるので、公式リポジトリへの問い合わせが一気に楽になる

生成AIは「魔法の答えマシン」ではなく、

**ログと設定を一緒に眺めてくれる“とんでもなく粘り強い相棒”**だと感じました。


ソフトウェアエンジニアにとって、生成AIはもはや「なくてはならない工具」のひとつ

今回のようなトラブルは、ドキュメントや FAQ にはまず載りません。

  • 自前PDS
  • BGSとの同期
  • DID種別の混在
  • 特定アカウントだけが見えない
    …といった複合条件が絡んでいて、完全に「現場のバグ報告」レベルの話です。

こういうとき、昔なら:

  • ひたすらログを grep し続ける
  • 英文の issue を数時間かけて書く
  • 書いているうちに、自分でも何が言いたいのか分からなくなる(笑)

といった消耗をしていたと思います。

今は、

  • ログをそのまま AI に投げて、「このパターンから何が言えそう?」と聞ける
  • 設定ファイルの断片を貼って、「これ矛盾してない?」とレビューしてもらえる
  • GitHub Issue 用の本文を、半自動で整形してもらえる

という意味で、生成AIは「開発環境」「デバッガ」「テキストエディタ」に次ぐ、第四の必須ツールになりつつあると実感しています。

もちろん、AIが間違った仮説を出すこともあります。でも、それは「頭の中でひとりで間違った仮説を抱え続ける」よりずっとマシで、対話しながら潰していけるぶんだけ前に進みやすい。


まとめ

  • 自前Bluesky PDSで「投稿はできているのに、bsky.appにはまったく出ない」状態になった
  • PDS内部・DID・公開エンドポイントは正常だったが、BGSのカーソルとPDS内部のシーケンスがズレていた
  • 開発者の案内に従い、goat で BGS の seq を取得し、sequencer.sqliterepo_seq をその値に合わせることで復旧した
  • ここに至るまでの整理・英文化・ログ読みは、生成AIを相棒にすることで生産的に進められた

ソフトウェアエンジニアにとって、生成AIはもう「おもしろガジェット」ではなく、日常的なトラブルシュートを支える実用ツールになっています。

もしあなたも、似たような「原因が見えない不具合」に悩まされているなら、一人で抱え込まずに、ログと設定をそのまま AI に見せてみることをおすすめします。

「あ、そこ見落としてたわ」というポイントを、一緒に拾ってくれるかもしれません。

誠ちゃん
誠ちゃん

最後まで読んでいただき、ありがとうございます!

error: Content is protected !!
タイトルとURLをコピーしました