debug-broken-ui について
実行中のアプリで操作を再現し、証拠を追ってソース位置を特定する、Reticle向けのUIデバッグスキルです。
主な機能
- 01操作を再現して結果を確認
- 02ネットワーク、コンソール、状態、ストレージの変化を関連付け
- 03要素の表示状態とソース位置を調査
- 04明示的な判定で修正を確認
活用シーン
- 01クリックでリクエストが発生しない原因の追跡
- 02UIとストアの状態不整合の発見
- 03遮蔽または無効なコントロールの特定
MCP 対応
Reticleは、このスキルが使うページ検査と操作の機能をMCPツールとして提供します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ reticlehq/ reticle --skill debug-broken-uiインストール後、Claude Code で/debug-broken-uiを入力して読み込まれたか確認します。
詳細
アプリが壊れているのに、コードは問題なさそうに見える
ソースを読み直しても、原因はわかりません。証拠は実行中のアプリにありますが、そのほとんどは画面に現れません。失敗したリクエスト、動かなかったストア、バインドされなかったハンドラー、見えない何かに覆われた要素などです。
Reticle はページ内から、そのすべてを読み取ります。まだセットアップしていない場合は、reticle スキルに従ってください。Reticle をインストールし、init によるアプリのファイル変更前にユーザーに確認し、1つのフローで動作を実証します。
推測から始めないでください。再現から始めてください。
reticle_look({ action: "page", sessionId, mode: "interactive" }) // controls only, with refs
reticle_act_and_wait({ sessionId, ref, action: "click", until: { kind: "element", query: { testid: "..." } } })
判定によって、すでに原因を絞り込めています。no / contradicted は、あるチャネルが UI と矛盾するものを検出したことを意味します。バグがあります。unknown は、Reticle が操作を行ったものの判断できなかったことを意味し、「失敗した」とは別の調査が必要です。
ほかのものを呼び出す前に、act の結果を読んでください。 summary ブロックには、その1回のクリックに関する因果関係の全体がすでに含まれています。net {total, errors, headline}、consoleErrors、stateDiffs [{path, from, to}]、storageDiffs [{key, from, to}]、route、signals、layoutShift、longTasks など、件数ではなく、実際の実行前→実行後の差分がわかります。以下のコンソール、ネットワーク、ストレージ、状態の各呼び出しは、サマリーがすでに示した箇所をさらに詳しく調べるためのものです。act の直後に3つすべてを呼び出すと、すでに手元にある証拠のために、モデルとの往復が3回(承認が必要なクライアントでは、ユーザーのクリックも3回)発生します。
summary.stateUnwatched: true は、状態チャネルが機能していないことを意味します。購読可能なストアが登録されていないため、空の stateDiffs は 変化なし ではなく 監視対象外 を意味し、誰かがストアを登録するまでは、状態に基づく結論を出せません。ここにあるフィールドの中で、アプリではなくインストルメンテーションについて示すのはこれだけです。
サマリーが調査箇所を示した場合は、直前の操作にスコープを絞ってそのチャネルを読み取ってください。act の結果から since を渡さないと、クリックより前のバッファを読み取ることになります。
reticle_observe({ action: "console", sessionId, since })
reticle_observe({ action: "network", sessionId, since })
reticle_look({ action: "state", sessionId, store })
診断表
| 表示されている状況 | 原因 | 次にすること |
|---|---|---|
| リクエストがまったく送信されない | ハンドラーがバインドされていないか、クライアントキャッシュが古い値を返しています | 対象の要素に reticle_look { action: "element" } を実行して file:line を確認します。TanStack Query を使っている場合はキャッシュを確認します |
リクエストは送信されたが、4xx / 5xx | UI が隠している、実際のバックエンド障害です | レスポンスボディはネットワークエントリーにあります |
2xx だが何も変わらない | アプリがレスポンスを読み取っていません。判定には outcome_unread と表示されます | 多くの場合、成功時の処理に実際のバグがあります |
| リクエストは正常、DOM も正常、ストアは古いまま | UI と状態の不整合です。スクリーンショットでは検出できません | reticle_look { action: "state" } だけが確認手段です。ここで最も価値の高い読み取りです |
| クリックしても何も起きず、エラーもない | コントロールが無効、遮蔽、または無効化されています | reticle_look { action: "element" } は、occluded、box(0×0)、styles.cursor、opacity を返します |
| 見えているのに要素が「見つからない」 | 仮想化リストで、まだ要素がマウントされていません | reticle_run({ tool: "reticle_scroll_to", args: { by: "text", value } }) を実行します。find で見つからなくても、存在しない証拠にはなりません |
| ログイン済みに見えるのに、ログアウト状態のように動作する | トークンが保存されていません | reticle_run({ tool: "reticle_storage", args: {} }) を実行します |
| クリックより前からコンソールエラーがある | 既存の障害であり、今回のバグではありません | 続ける前に、その旨を明示します |
理論ではなく、ファイルを特定する
reticle_look({ action: "element", sessionId, ref })
調べている要素のコンポーネントと source: { file, line } に加えて、遮蔽されているか、サイズがあるか、無効化されているか、テーマから外れているかを返します。これが開くべきファイルへの手がかりです。仮説ではなく、場所を特定して調査を終えましょう。
フローが長い場合
失敗するステップを探すために、act → snapshot → act → snapshot と行き来しないでください。reticle_act { steps: [...] } で一連の操作を行い、1回だけアサートしてください。結果が失敗した最初のステップを調べればよく、見つけるための呼び出し回数も大幅に減らせます。
修正済みと言う前に
ページを目視で確認するのではなく、判定として再現手順をもう一度実行してください(結果を最初に明示して reticle_act_and_wait を実行します)。見て確認しただけで修正済みと判断することが、このチケットを生んだ失敗パターンです。
そして、合格させるためにチェックを決して弱めないでください。
アプリではなく Reticle 自体のトラブルシューティングについては、curl https://docs.reticle.sh/troubleshooting.md を実行してください。それ以外については、curl https://docs.reticle.sh/llms.txt を実行してください。Reticle が必要なものを認識できなかった場合は、kind: "gap" を指定して reticle_session { action: "feedback" } を実行してください。