メインコンテンツまでスキップ

既知の想定外の挙動

このファイルでは、エージェントのミスにつながったリポジトリ固有の混乱ポイントを記録します。

エントリの追加基準

次のすべてを満たす場合にのみエントリを追加してください。

  • このリポジトリに固有の内容である (一般的な助言ではない)。
  • 今後のエージェントでも再発する可能性が高い。
  • 実際にたどれる具体的な対処法がある。

判断に迷う場合は、エントリを追加する前に開発者に確認してください。

エントリのテンプレート

### [Short title]

- **Date:** YYYY-MM-DD
- **Observed by:** agent name or contributor
- **Context:** where/when it happened
- **What was surprising:** concrete unexpected behavior
- **Impact:** what went wrong or could go wrong
- **Mitigation:** exact step future agents should take
- **Status:** confirmed | superseded

エントリ

Vercel アプリの本番ドメインが Git master のデプロイに逆戻りすることがある

  • 日付: 2026-04-28
  • 報告者: Tommaso + Codex
  • 経緯: Bitsocial Web のアプリディレクトリで Seedit と 5chan のアプリミラーを検証していたとき。
  • 想定外だった点: Vercel の seedit および 5chan プロジェクトが gitProviderOptions.createDeployments = "enabled" になっていたため、GitHub の master へのプッシュが本番ドメインに昇格されていた。リポジトリのポリシーでは、本番のアプリミラーはリリース成果物だけを配信する想定である。
  • 影響: 本番ドメインが、about/src/lib/apps-data.tsindex.html のハッシュを記録している GitHub リリースの ZIP ではなく最新の開発コミットを配信するため、アプリディレクトリの検証済みミラーバッジが実態と食い違うことがある。
  • 対処: ミラー検証のメタデータを追加・更新する前に、vercel api /v9/projects/<project-id> で Vercel プロジェクトを確認し、gitProviderOptions.createDeployments = "disabled" になっていることを確かめる。リリース ZIP の中身は vercel deploy --prebuilt --prod でデプロイし、開発用のデプロイには seedit-omega.vercel.app または 5chan-omega.vercel.app を使う。
  • ステータス: 確認済み

ランチャーが HTTPS を強制しない限り、Portless 0.11 は古いプロキシ状態を再利用する

  • 日付: 2026-04-28
  • 報告者: Tommaso + Codex
  • 経緯: 通常の yarn start フローを、従来のプロキシ URL http://bitsocial.localhost:1355 から新しい正規 URL へ移行していたとき。移行先は https://bitsocial.localhost.
  • 想定外だった点: portless@0.11.1 をインストールしていても、Portless は既存の ~/.portless/proxy.port = 1355 の HTTP プロキシを再利用し、従来の :1355 付き URL を表示した。
  • 影響: パッケージのバージョンやドキュメントを更新するだけでは足りない。貢献者の環境に古い Portless の状態が残っていると、yarn start は引き続き古い URL を告知し、実際にそれを使ってしまう。
  • 対処: アプリのルートを登録する前に、起動スクリプトが明示的にポート 443 で Portless の HTTPS プロキシを起動するようにしておく。そうすれば、永続化された 1355 の状態を引き継ぐのではなく、そこから移行できる。
  • ステータス: 確認済み

Portless は正規のローカルアプリ URL を変える

  • 日付: 2026-03-18
  • 報告者: Codex
  • 経緯: ブラウザ検証とスモークフロー
  • 想定外だった点: 既定のローカル URL は通常の Vite のポートではない。このリポジトリは Portless 経由の https://bitsocial.localhost を前提としているため、localhost:3000localhost:5173 を確認すると別のアプリに当たるか、まったく何も返ってこないことがある。
  • 影響: 開発サーバーが正常に動いていても、ブラウザ検証が失敗したり、誤ったターゲットを検証してしまったりする。
  • 対処: まず https://bitsocial.localhost を使う。Vite のポートへ直接つなぐ必要が明確にある場合にのみ、PORTLESS=0 corepack yarn start で回避する。
  • ステータス: 確認済み

Commitizen のフックが非対話的なコミットをブロックする

  • 日付: 2026-03-18
  • 報告者: Codex
  • 経緯: エージェント主導のコミットワークフロー
  • 想定外だった点: git commit は Husky 経由で Commitizen を起動し、対話的な TTY 入力を待つため、非対話的なエージェントのシェルがハングする。
  • 影響: 普通のコミットで済むはずの場面で、エージェントが無期限に止まってしまう。
  • 対処: エージェントが作るコミットには git commit --no-verify -m "message" を使う。人間は引き続き corepack yarn commitcorepack yarn exec cz を使える。
  • ステータス: 確認済み

Yarn classic を避けるには Corepack が必要

  • 日付: 2026-03-19
  • 報告者: Codex
  • 経緯: パッケージマネージャーの Yarn 4 への移行
  • 想定外だった点: このマシンには PATH 上にグローバルな Yarn classic のインストールが残っているため、素の yarn を実行すると、固定された Yarn 4 ではなく v1 に解決されることがある。
  • 影響: 開発者がリポジトリのパッケージマネージャー固定をうっかり回避してしまい、インストールの挙動やロックファイルの出力が変わる。
  • 対処: シェルコマンドでは corepack yarn ... を使うか、先に corepack enable を実行して素の yarn が固定された Yarn 4 に解決されるようにする。
  • ステータス: 確認済み

固定の Portless アプリ名は Bitsocial Web のワークツリー間で衝突する

  • 日付: 2026-03-30
  • 報告者: Codex
  • 経緯: 別のワークツリーがすでに Portless 経由で配信している状態で、ある Bitsocial Web のワークツリーで yarn start を実行したとき
  • 想定外だった点: すべてのワークツリーで Portless のアプリ名にリテラルの bitsocial を使うと、背後のポートが違ってもルート自体が衝突するため、bitsocial.localhost はすでに登録済みだとして 2 つ目のプロセスが失敗する。
  • 影響: Portless は複数のブランチが安全に共存できるようにするためのものなのに、並行する Bitsocial Web のブランチ同士が互いをブロックしてしまう。
  • 対処: Portless の起動は scripts/start-dev.mjs に任せる。このスクリプトは、正規のケース以外ではブランチ単位の *.bitsocial.localhost ルートを使い、素の bitsocial.localhost という名前がすでに使われている場合はブランチ単位のルートにフォールバックする。
  • ステータス: 確認済み

ドキュメントのプレビューはかつてポート 3001 をハードコードしていた

  • 日付: 2026-03-30
  • 報告者: Codex
  • 経緯: 他のローカルリポジトリやエージェントと並行して yarn start を実行していたとき
  • 想定外だった点: ルートの開発コマンドがドキュメントのワークスペースを docusaurus start --port 3001 で起動していたため、別のプロセスがすでに 3001 を使っていると、メインのアプリが Portless を使っているにもかかわらず開発セッション全体が失敗した。
  • 影響: yarn start が起動直後に Web プロセスを落とし、ドキュメントのポート衝突のせいで無関係なローカル作業まで中断されることがあった。
  • 対処: ドキュメントの起動は yarn start:docs に任せる。このコマンドは Portless と scripts/start-docs.mjs を使い、外部から渡された空きポートを尊重するか、直接実行された場合は次に空いているポートへフォールバックする。
  • ステータス: 確認済み

ドキュメント用の Portless ホスト名が固定でハードコードされていた

  • 日付: 2026-04-03
  • 報告者: Codex
  • 経緯: 別のワークツリーがすでに Portless 経由でドキュメントを配信している状態で、副次的な Bitsocial Web のワークツリーで yarn start を実行したとき
  • 想定外だった点: about アプリは自分のホスト名について Portless のルート衝突を避けられるようになっていたのに、start:docs は依然としてリテラルの docs.bitsocial.localhost を登録していたため、yarn start が失敗することがあった。
  • 影響: ドキュメントのプロセスが先に終了し、続いて concurrently がセッションの残りも落とすため、並行するワークツリーでルートの開発コマンドを安定して使えなかった。
  • 対処: ドキュメントの起動は scripts/start-docs.mjs に任せる。このスクリプトは about アプリと同じブランチ単位の Portless ホスト名を導出し、その共有 URL を /docs の開発プロキシのターゲットへ注入する。
  • ステータス: 確認済み

ワークツリーのシェルはリポジトリが固定した Node バージョンを取り逃すことがある

  • 日付: 2026-04-03
  • 報告者: Codex
  • 経緯: .claude/worktrees/* や兄弟のワークツリーチェックアウトなどで yarn start を実行したとき
  • 想定外だった点: リポジトリは .nvmrc22.12.0 を固定しているのに、一部のワークツリーのシェルでは nodeyarn node が Homebrew の Node 25.2.1 に解決され、yarn start が誤ったランタイムで開発ランチャーを動かしかねなかった。
  • 影響: メインのチェックアウトとワークツリーとで開発サーバーの挙動がずれ、バグの再現が難しくなるうえ、リポジトリが想定する Node 22 のツールチェーンにも反する。
  • 対処: 開発ランチャーは scripts/start-dev.mjsscripts/start-docs.mjs に任せる。これらは、現在のシェルのバージョンが違う場合に .nvmrc の Node バイナリで自身を再実行する。シェルの設定側でも nvm use を優先すること。
  • ステータス: 確認済み

リファクタ後、docs-site/ の残骸がドキュメントソースの欠落を隠すことがある

  • 日付: 2026-04-01
  • 報告者: Codex
  • 経緯: Docusaurus プロジェクトを docs-site/ から docs/ へ移した後の、マージ後のモノレポ整理
  • 想定外だった点: 追跡対象のリポジトリが docs/ へ移った後も、古い docs-site/ フォルダが i18n/ のような古くはあるが重要なファイルを抱えたままディスクに残ることがある。そのためローカルではリファクタが二重になったように見え、追跡対象のドキュメント翻訳が実際には docs/ へ移されていないという事実が隠れてしまう。
  • 影響: エージェントが古いフォルダを「ゴミ」とみなして削除し、ドキュメント翻訳の唯一のローカルコピーを失ったり、すでに存在しない docs-site/ のパスを参照し続けるスクリプトを編集し続けたりする。
  • 対処: docs/ を唯一の正規ドキュメントプロジェクトとして扱う。ローカルの docs-site/ の残骸を削除する前に、docs/i18n/ のような追跡対象のソースを復元し、スクリプトやフックが docs-site を参照しないように更新する。
  • ステータス: 確認済み

多言語ドキュメントのプレビューは検証中に RAM を大きく消費しうる

  • 日付: 2026-04-01
  • 報告者: Codex
  • 経緯: yarn start:docs と Playwright を使って、ドキュメントの i18n、ロケールルーティング、Pagefind の挙動を修正していたとき
  • 想定外だった点: ドキュメントプレビューの既定モードは、配信の前に多言語ドキュメントのフルビルドと Pagefind のインデックス作成を行うようになった。そのプロセスを起動したまま Playwright や Chrome のセッションを複数動かすと、通常の Vite や単一ロケールの Docusaurus 開発ループよりもはるかに多くの RAM を消費する。
  • 影響: マシンのメモリが逼迫してブラウザセッションがクラッシュしたり、中断された実行が古いドキュメントサーバーやヘッドレスブラウザを残してメモリを食い続けたりする。
  • 対処: ロケールルートや Pagefind の検証が不要なドキュメント作業では DOCS_START_MODE=live yarn start:docs を優先する。既定の多言語プレビューは、翻訳されたルートや Pagefind を検証する必要があるときにだけ使う。Playwright のセッションは 1 つに保ち、新しいセッションを開く前に古いものを閉じ、検証が終わって不要になったドキュメントサーバーは停止する。
  • ステータス: 確認済み

translate-docs.py はドキュメントのロケールを中途半端な翻訳や壊れたリンク先のまま残すことがある

  • 日付: 2026-04-06
  • 報告者: Codex
  • 経緯: yarn start:docs が英語の詳細ページを配信したりロケール出力のビルドに失敗したりした後、ローカライズされたドキュメントのルートとコンテンツを修正していたとき
  • 想定外だった点: ドキュメント翻訳のパイプラインには、このリポジトリ固有の失敗モードが同時に 2 つあった。scripts/translate-docs.py は、tr(...) の呼び出しがパースできない書き方だと DocsHome のメッセージをごく一部しか抽出しなかった。また、docs/i18n/** 配下の翻訳済みマークダウンには、リンク先の中に機械翻訳されたスラッグや ZXQPLACEHOLDER の残骸が混じることがあった。
  • 影響: ローカライズされたホームページが黙って英語にフォールバックしたり、ローカライズされた詳細ページが未翻訳のまま見えたり、元のドキュメント自体は正しいのにロケールのリンク切れで yarn docs:build 全体が失敗したりする。
  • 対処: ドキュメント翻訳を変更したりロケールファイルを再生成したりしたら、必ずリポジトリのルートから yarn docs:build を実行し、docs/i18n/** のマークダウンに ZXQPLACEHOLDER が残っていないか調べ、翻訳されたリンクが翻訳済みの URL パスではなく /apps/5chan/ のような正規のドキュメントスラッグを指したままか確認する。DocsHome の文言が変わった場合は、scripts/translate-docs.pydocs.home.* のメッセージをすべて抽出できているかを確かめる。
  • ステータス: 確認済み

about サイトの no-JS チェックは、単独の SSR プレビューではなく Portless のルートで行う

  • 日付: 2026-04-12
  • 報告者: Codex
  • 経緯: ブランチのワークツリーから about/ サイトの no-JS 対応を検証していたとき
  • 想定外だった点: 単独の SSR プレビューが正常に見えていても、実際のブランチ単位の Portless ルートは誤ったアプリシェルや古いプロセスを配信していることがある。このリポジトリでのローカルの本当の契約は、その場しのぎのプレビューサーバーではなく yarn start が使う Portless のホスト名である。
  • 影響: エージェントが no-JS 対応は動いていると誤って主張したり、*.bitsocial.localhost でしか現れないリグレッションを見逃したりする。
  • 対処: about/ のブラウザ検証では、必ず yarn start または yarn start:about で本物のローカルサーバーを起動し、まずブランチ単位の Portless URL でテストする。Portless のホスト名が古そうに見える場合は、再テストの前に古いプロセスを調べて停止する。
  • ステータス: 確認済み

chain/yarn build:verifyyarn doctor から見えていなかった

  • 日付: 2026-07-05
  • 報告者: Codex
  • 経緯: chain/ ワークスペース (chain.bitsocial.net 向けのスタンドアロン Vite アプリ) をモノレポに追加した後、chain/ だけの差分を検証していたとき。
  • 想定外だった点: scripts/verify-build.mjsabout/docs/stats/ のパスプレフィックスしか認識していなかったため、ルートの package.json にすでに build:chain があるにもかかわらず、chain/ だけの差分では "No targeted build checks matched the current diff" と表示され、ビルドが一切実行されなかった。さらに yarn doctorreact-doctor about -y にハードコードされていたため、chain/src 配下の React の変更は React Doctor のカバレッジがゼロだった。
  • 影響: chain の変更を検証するエージェントは、yarn build:verify を信頼する代わりに yarn build:chain を直接呼ぶ必要があると知っていなければならず、chain/src の React の問題 (エフェクト、フック、デッドコード) は yarn doctor では検出されなかった。
  • 対処: scripts/verify-build.mjs には about/ と同じ形の chain/ 分岐が追加され、doctordoctor:verbose は 1 回の呼び出しで react-doctor --project about,chain -y を実行するようになった。doctor:scoreabout のみのままにしてある。--score は複数プロジェクトを指定した --project と組み合わせると何も出力しなくなるためで、chain のスコアが必要な場合は yarn react-doctor --project about,chain --verbose -y (または --json) を使う。
  • ステータス: 確認済み

ブラウザ P2P はセキュアな WebSockets 上で動き、pkc-js は既定で WebRTC と WebTransport を拒否する

  • 日付: 2026-08-02
  • 報告者: Claude
  • 経緯: Bitsocial のブラウザ P2P の仕組みについて、ランディングページとドキュメントの文章を書いていたとき
  • 想定外だった点: @pkcprotocol/pkc-js には、ブラウザでの WebRTC と WebTransport のダイヤルを拒否する既定のコネクションゲーターが同梱されている。dist/browser/helia/dial-transport-filter.jsDENIED_DIAL_TRANSPORTS_BY_DEFAULT = ["webrtc", "webrtc-direct", "webtransport"] をエクスポートしている。その理由はソースのコメントに書かれており、ブラウザではこれらのトランスポートが接続確立に時間のかかる失敗しやすい経路 (STUN/ICE、certhash のローテーション) を増やして読み込みを遅くする一方、WebSocket は直接的で信頼できる、というものだ。ブログの P2P ステータスパネルに出る稼働中のピアは、どれも "Secure WebSocket" と表示される。このゲーターは node_modules の中にあるため、リポジトリ内にはその存在を示唆するものが何もない。
  • 影響: 技術的にはもっともらしいが実際には誤った公開向けの文章を、とても書きやすい。たとえば、2026 年 3 月に WebTransport がブラウザの Baseline に到達したことが Bitsocial のブラウザ P2P を可能にした、という説明である。その主張は開発者が気づくまでに、ランディングページ、比較表、ドキュメント 2 ページに出てしまっていた。公開ページのアーキテクチャに関する誤りは、まさにサイトが対象としている開発者層に見抜かれる。
  • 対処: Bitsocial がどのトランスポートを使っているかを、libp2p やブラウザプラットフォームが原理的にサポートしているものから推測してはいけない。現在の拒否リストは node_modules/@pkcprotocol/pkc-js/dist/browser/helia/dial-transport-filter.js で確認し、about/src/ 配下に connectionGater の上書きがないことを確かめ、公開向けの主張をする前にブログの「P2P status」パネルで実際のトランスポートのラベルを読むこと。ブラウザからの公開を実際に可能にしたアップストリームの変更は、@libp2p/gossipsub 15.0.21 (2026 年 5 月) の gossipsub における単調増加 seqno の修正である。pkc-js が現在同梱しているのは 16.0.4 である。
  • ステータス: 確認済み

未翻訳のドキュメントページからの相対 ./page.md リンクは、すべてのローカライズビルドを壊す

  • 日付: 2026-08-02
  • 報告者: Claude
  • 経緯: 英語のみの新しいページ docs/browser-p2p.md を追加し、そこから ./peer-to-peer-protocol.md./apps/5chan.md で既存のドキュメントへリンクしたとき
  • 想定外だった点: docs/i18n/<lang>/docusaurus-plugin-content-docs/current/ 配下の各ロケールはドキュメントツリーを鏡写しにしている。それらのミラーに存在しない新しいページも英語フォールバックによってすべてのロケールで描画されるが、その相対マークダウンリンクはもう解決されない。Docusaurus は /ar/browser-p2p/peer-to-peer-protocol.md/ を出力し、"Docusaurus found broken links!" でビルドを失敗させる。しかも重要なことに、yarn build:verifyyarn docs:build:verifyen しかビルドしないため問題なく通る。これが表面化するのは完全な yarn docs:build だけで、しかもアルファベット順で最初のロケール (ar) で中断する。
  • 影響: ドキュメントの変更が高速なローカルチェックをすべて通過しても、本番の多言語ビルドを壊すことがある。エラーが作者の触っていないロケールのパスを示すため、失敗自体も変更と無関係に見える。
  • 対処: docs/i18n/** にミラーされていないドキュメントページでは、相対的な .md リンクではなくルート相対のリンク (/peer-to-peer-protocol//apps/5chan/) を使う。Docusaurus が自動的にロケールのプレフィックスを付けてくれる。既存の例は docs/build-your-own-client.md である。ドキュメントページを追加したりリンクしたりする変更を引き渡す前には、build:verify だけでなく完全な yarn docs:build を実行すること。
  • ステータス: 確認済み

update-translations.jsabout/ から実行する必要があり、同時実行は黙ってキーを失う

  • 日付: 2026-08-02
  • 報告者: Claude
  • 経緯: translate スキルを使って、翻訳済みの i18next キー 26 個を 36 ロケールすべてへ適用していたとき
  • 想定外だった点: 同じスクリプトに罠が 2 つあった。1 つ目は、scripts/update-translations.js が対象を path.join(process.cwd(), "public", "translations") として解決するのに対し、このリポジトリは翻訳を about/public/translations に置いていること。ドキュメント通りのコマンドをリポジトリのルートから実行すると、毎回 "Translations directory not found" で失敗する。docs/agent-playbooks/translations.md には node scripts/update-translations.js ... と書かれており、これはリポジトリのルートで実行するコマンドに読める。2 つ目は、1 回の実行が 36 個すべてのロケールファイルに対する read-modify-write になっているため、2 つの実行が同時に走ると互いを上書きし、エラーも出ないままキーが 1 つ消えること。translate スキルは最大 4 つのサブエージェントを同時に起動するよう明示的に指示しており、そのいずれもがこのスクリプトを呼ぶ。
  • 影響: リポジトリのルートで実行する形は派手に失敗し、1 パス分の作業をまるごと無駄にする。同時実行の問題は静かに失敗する。任意のロケールからキーが消え、それでも差分はもっともらしく見える。
  • 対処: cd about && node ../scripts/update-translations.js --key <key> --map <abs-path> --write の形で実行する。翻訳のサブエージェントにロケールファイルを同時に書かせてはいけない。サブエージェントには辞書の JSON ファイルだけを出力させ、親エージェントからキーを 1 つずつ順番に適用する。適用後は、各キーが英語以外の 35 ロケールすべてに存在すること、どの値も英語の原文とバイト単位で一致していないことをプログラムで検証する。
  • ステータス: 確認済み