callidescope-triage について
callidescope の解析や gate の失敗を読み解くスキルです。コード上の指摘、未読プロジェクト、設定エラー、古いレポートを区別し、プロジェクトの制限を弱めずに対処する方法を説明します。
主な機能
- 01解析・gate メッセージの分類
- 02深さと幅の指摘の解説
- 03未読ソースの原因調査
- 04古いレポートの再生成方法
活用シーン
- 01深さ gate の失敗調査
- 02プロジェクトが判定されない原因の追跡
- 03古い生成レポートへの対応
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ organizzolini/ codebase --skill callidescope-triageインストール後、Claude Code で/callidescope-triageを入力して読み込まれたか確認します。
詳細
callidescope の失敗への対処
callidescope が失敗する理由はいくつかあり、どの理由で失敗したかを読み取ることが作業の大半を占めます。まず、それぞれを切り分けてください。
| 実行時の表示 | 意味 |
|---|---|
🚨 [DEPTH n > limit] | コードに関する指摘事項です。レイヤー構造を修正してください |
| 制限を超える breadth の行 | 指摘事項です。呼び出し可能な単位を分割してください |
A configured destination is stale | 乖離です。--write を再実行してください |
## Read nothing of its own (0 files) | ゲートが独自のファイルを一度も読み取っていないプロジェクトを判定しました。その判定には意味がありません |
🔭 Rejected a project it could not read | tsconfig.json が存在しないか、解析できませんでした。トレースはそこで停止しました |
🔭 Traced nothing | 実行時にコードがまったく見つかりませんでした。その下に表示される内容には意味がありません |
🔭 Rejected the command line | フラグの指定ミスです。何もトレースされませんでした |
🔭 Rejected a project configuration | プロジェクト独自の callidescope.config.ts が存在しない、不完全、またはワークスペースでのみ設定可能なフィールドの指定を拒否されました。何も報告されませんでした |
最後の 5 つはすべて、実行時にコードに対する判定が行われなかったことを意味します。どれも出力先に書き込まないため、いずれの場合もチェックアウトに変更はありません。また、これらのいずれかが表示された実行で、指摘事項があった場合も、なかった場合も、信頼すべきではありません。
limits コマンドでは、独自の読み取り失敗も同じ 🔭 Rejected a project configuration の見出しの下に表示されます。対処方法も同じです。詳しくは拒否されたプロジェクト設定を参照してください。
失敗した深度ゲート
スタックが limits.maximumDepth を超えて深くなりました。スタックを長くした変更こそが、問題を修正する変更です。深度をゲートにし、古さをゲートにしない理由は、これに尽きます。
失敗したゲートが対象とするのは、1 つのプロジェクトです。 制限はプロジェクトごとに、そのプロジェクト独自の callidescope.config.ts に記述されます。また、プロジェクトのゲートが判定するのは、そのプロジェクトが所有する検出結果だけです。スタックはそのルートを所有するプロジェクトに計上され、依存関係の違反はその依存関係自体のゲートに属します。したがって、修正できる場所はちょうど 2 つです。そのプロジェクトのコードか、そのプロジェクト独自の callidescope.config.ts です。後者を選ぶ前に、以下のセクション全体を踏まえて検討してください。
Nx ワークスペースでは、これはワークスペース全体に対する --check depth ではなく、失敗した gate ターゲットとして報告され、タスク名から開くべきプロジェクトがわかります。それ以外の場合は、検出結果自体の limit から、どの数値と比較されたのかがわかり、callidescope limits から、その数値が記述されているファイルがわかります。
何かする前に、出力されたスタックを読んでください。各フレームには、呼び出し可能なもののシグネチャと、そのドキュメントの 1 行要約が記載されています。この要約によって、次の 2 つのケースを見分けられます。
- すべてのフレームに異なる内容が書かれています。 レイヤー構造は実在しており、各段階がそれぞれの処理を行っています。すべての段階が必要なのか検討してください。ただし、レイヤーを 1 つずつ削除し始めてはいけません。このケースでは、単なる削減ではなく、通常は設計上の判断が必要です。
- 同じような内容のフレームが連続しています。 これらは引数を渡すだけの転送レイヤーです。まとめてください。 これが一般的なケースであり、まさにこの問題を明らかにするためにこのツールは作られています。そうでなければ問題を教えてくれるはずのツールは、一度に 1 つのファイルしか読まないため、転送処理は見えても深度はわかりません。
maximumDepth を引き上げても修正にはなりません。 制限は、リポジトリが望む構造を表しています。現在最悪のスタックに合わせて引き上げると、ゲートは機能しなくなり、それ以降のスタックはすべて、新しい数値まで無条件で通過できるようになります。プロジェクトにとって制限が本当に誤っているのであれば、別個の判断として、理由を記録したうえで変更してください。プルリクエストを通すための手段にしてはいけません。プロジェクトの数値を引き上げるのは、同じ誤りを小規模にしたものにすぎず、例外ではありません。その数値は、そのプロジェクトで測定された深度の 1 フレーム上になるよう境界テストされたものです。したがって 1 引き上げると、検出結果が問題としているプロジェクトに対して、ゲートが余裕枠に変わってしまいます。
サマリーの深度はプロジェクトの深度ではありません
参照する数値は、サマリー行に表示されるものではなく、判定結果が示すものです。🔭 Finished an analysis というログ行には maximumDepthTraced が表示されます。これは文字どおりの意味で、実行時の測定全体、つまり依存関係を含めて拡張されたトレース全体にわたる最大値です。そのため、対象にした箇所の深度ではなく、実行が到達した範囲のどこかにある最も深いスタックを示します。ゲートの判定を決めるプロジェクトごとのスコープは、まったく別のコードパスです。
この 2 つの値は、日常的に数フレームも異なります。synchronization をスコープ指定して実行すると maximumDepthTraced:13 と表示されますが、ゲートは宣言値 10 では通過し、9 では失敗します。10 はそのプロジェクトが所有する数値であり、13 は同時にトレースされた依存関係のものです。
したがって、その行の値を使ってプロジェクトの制限を設定しないでください。代わりに境界テストを行います。候補値を書き込み、ゲートを実行して、失敗時に実際の数値を示させてください。意味のある制限なら、記述した数値では通過し、その 1 つ下では失敗します。その境界を教えてくれるのは、ゲートの判定結果だけです。
≥ n であり、n ではない
≥ と表示される深さは、測定値ではなく下限値です。そのパス上で追跡できないもの(パラメーターを介して呼び出されるコールバック、target[key]() のような計算されたメンバー名、実装候補の上限を超えたために除外された構造展開など)があり、実行結果はそれを示しています。黙って過少報告しているわけではありません。
これは修正すべき不具合でも、信頼できない数値でもありません。実際の深さはその値以上という意味なので、上限が 6 のときに ≥ 10 なら、実際に失敗しています。サマリーの Unfollowable calls は、実行中に遭遇した追跡不能な呼び出しの数を示します。
orphan-root で始まるスタック
リポジトリ内でルートを呼び出すものがありません。デッドコードであるか、設定にエントリーポイントルールが不足しています。多くの場合、entryPoints.decorators にフレームワークのデコレーターが指定されていません。深さを実際の値として扱う前に、どちらなのか判断してください。フレームワークが実際に呼び出すルート配下のスタックは指摘事項ですが、本当にデッドコードの配下にあるスタックは、そのコードを削除する理由になります。
Stacks through recursion がゼロを超えている
深さを測定する前に、循環が折りたたまれています。相互再帰する 3 つの呼び出しのまとまりは、フレーム 3 つ分として一度だけ加算されます。上記と同じ理由で、深さは下限値です。また、折りたたみによって実行ごとに数値が変動しないようになっています。callidescope に指摘されたからといって、再帰を「修正」しようとしないでください。
幅のゲートに失敗した場合
呼び出し可能なものが、limits.maximumBreadth を超える数の呼び出し可能なものを直接呼び出しています。深さとは異なり、幅にはデフォルトの上限がありません。そのため、幅の判定に失敗するのは、プロジェクト自身の callidescope.config.ts で数値を指定しているプロジェクトだけです。ワークスペースレベルの maximumBreadth だけでは、何も判定されません。判定対象となるには、各プロジェクトがそれぞれ値を指定する必要があります。
修正するには、インライン化するのではなく、呼び出し先がすでにまとめている責務に沿って、呼び出し可能なものを分割します。分割箇所を決める前に、対象の呼び出し可能なもののアドレスを指定して breadth コマンドを実行し、直接の呼び出し先と呼び出し元を並べて確認してください。その読み方については、callidescope-trace スキルで説明しています。
対象プロジェクト自身のソースを何も読み取れなかった場合
## Read nothing of its own (0 files)
This run judged a project whose own code it never read:
- `packages/thing`
実行全体が空だったわけではありません。追跡した依存関係は読み取られています。そのため、これは 🔭 Traced nothing よりも限定的な状況で、判定対象プロジェクト自身のソースだけが見つからなかったということです。ゲートはこれを検出すると失敗しますが、trace は表示して処理を続行します。何も調べていないゲートでは、クリーンなプロジェクトと読み取り対象のないプロジェクトを見分けられません。一方、trace は判定を行わず、読者が確認するためのレポートとして表示します。
次の 2 点を、この順番で確認してください。
- 範囲に一致しすぎる
exclude。 プロジェクト自身のexcludeグロブは、プロジェクトのルートを基準に評価されます。そのため、ワークスペースを基準に書かれたものは何にも一致せず、広く書きすぎたものはすべてに一致します。プロジェクト全体に一致するパターンがないか、実行時のexcludeとexcludeFromも確認してください。 tsconfig.jsonのincludesが参照するソースを置いていないプロジェクト。 ソースルートを移動した場合や空にした場合も、読み取り結果はまったく同じになります。
ゲートを削除して、これを黙殺しないでください。 ワークスペース設定で除外されたプロジェクトには、意図的にゲートが設定されず、このメッセージにも到達しません。ゲートが設定されたままのプロジェクトにはコードがあることが想定されています。何もない状態で合格判定を出すことを防ぐために、これが設けられています。
古くなったレポート
設定済みの出力先のうち、1 つ以上で、最新の実行で書き込まれる内容と一致しなくなっています。この実行では、最初の不一致で停止せず、ずれが生じたすべてのファイルを列挙します。
--write を再実行してください。それだけで修正できます。
npx callidescope --config configuration/callidescope.config.ts --write
古くなったレポートが意味しないことが 3 つあります。
- 不具合ではありません。 呼び出しグラフはコードとともに変化するため、どこかで何かが変わるたびにレポートは古くなります。だからこそ、
--check reportsはプルリクエストではなく、デフォルトブランチに設定します。 - 手作業で編集するものではありません。 次の
--writeでは、マーカーで囲まれたブロック全体が置き換えられるため、編集したレポートは差分として現れても、次回の実行で何も通知されずに消えます。 - プルリクエストのゲートに
--check reportsを追加する理由にはなりません。 そうすると、プルリクエストで発生させていないずれが原因で、プルリクエストが失敗します。
再生成の前にリンターを実行し、後には実行しないでください。 各レポートの各フレームには file:line が記載されています。クラスメンバーを並べ替えるフォーマッターは、挿入した箇所より後にあるすべての行番号を変えてしまうため、その並べ替えの前に書き込んだレポートは、取り込まれた時点ですでに古くなっています。
拒否されたコマンドライン
トレースは実行されませんでした。メッセージには理由が記載されています。想定される理由は次のとおりです。
--configがありません。 設定を読み込むすべてのコマンド (callidescope、depth、breadth、limits)で必要です。ファイルの検索や デフォルトの設定は行われません。ワークスペースファイルを指定してください。例:--config configuration/callidescope.config.ts。Nx では、同じ パスがnx.jsonの登録におけるプラグインのconfigurationPathオプションと、手書きのターゲットのconfigurationオプションになります。 どちらもConfigurationPathRequiredErrorと同じ文言で、名前を示して拒否されます。--checkに値が必要です。 値のないフラグ、空文字列、カンマのみの値は、 いずれも同じ誤りです。何も含まれないセットは、フラグが指定されていない状態と 区別できません。また、「何もチェックしない」と解釈すると、失敗することのない チェックになります。環境変数が未設定の状態で--check "$GATES"を指定すると、 許容範囲の 2 倍の深さを持つスタックでも永遠に通過してしまいます。保護されている ように見えるため、チェックがない場合よりも悪い状態です。--checkはその値を受け付けません。breadth、depth、reportsから選んだ カンマ区切りのセットを指定します。メッセージには選択肢が記載されています。--writeと--check reportsは併用できません。 レポートは書き込んだ実行内で 古くなることはないため、この組み合わせでは、本来検出するはずだった問題を 何でも通過させてしまいます。プルリクエストの該当する各段階で、別々に実行してください。- 動詞なしで出力先フラグを指定しています。
--json、--markdown、--mermaidは レポートの出力先を指定します。--writeと--check reportsは、レポートを書き込むか 比較するかを指定します。出力先だけを指定し、どちらの動詞も指定しない場合、 暗黙に従うのではなく実行が拒否されます。メッセージに示された動詞を追加してください。--check reportsも出力先を比較するため、動詞の 1 つとして扱われ、出力先の上書きも 意味を持ちます。 - 設定で宣言されていない出力先を、出力先フラグで上書きしようとしています。
--json、--markdown、--mermaidは、宣言済みのレポートの出力先を変更します。 設定で要求されていないレポートを新たに作り出すことはできません。そうでなければ、 設定を完全にする要件をターミナルから回避できてしまいます。この実行で読み込む設定に、 メッセージで指定されたwrite.json、write.markdown、またはwrite.mermaidを追加し、 そのうえでフラグを使って別の出力先を指定してください。 --formatはその値を受け付けません。markdown、mermaid、jsonを指定します。 メッセージには選択肢が記載されています。認識できない値は、以前のように markdown に 書き換えられるのではなく、拒否されます。以前は--format mermiadでツリーを出力する 実行が終了コード 0 で終わり、フラグが何もしないことを利用者に教えてしまっていました。- 設定で宣言されていない制限を
--maximum-breadthで上書きしようとしています。 出力先フラグと同じ理由で拒否されます。スコープ内のどこにもlimits.maximumBreadthが宣言されていない設定では、上書きする対象がありません。 コマンドラインから値を指定してしまうと、どの設定でも選ばれていない数値で ワークスペースをチェックすることになります。 - アドレスなしで
depthまたはbreadthを指定しています。 これらのコマンドには<file>#<qualified-name>を指定します。CI 外の実際のターミナルでは、まずトレースを 実行し、見つかったすべての呼び出し可能な対象に照らし合わせてアドレスを補完します。 そのため、名前を思い出す必要はなく、候補から選べます。同じファイル内で名前が 2 回宣言されている場合は、すでに:<line>が付いた状態で表示されます。 スクリプトや CI ジョブではプロンプトが無効になっているため、引数がない場合は 処理が停止するのではなく、拒否されます。
拒否されたプロジェクト設定
トレース対象のプロジェクト自体のルートにある callidescope.config.ts、
またはそのファイルが存在しない状態は拒否されました。何も出力されず、出力先にも
触れていないため、チェックアウトは実行前とまったく同じ状態です。<project> は
ワークスペース相対のプロジェクトルートです。ワークスペースファイルで宣言された
アドレスの場合は、代わりに the workspace configuration と表示されます。
プロジェクトには設定ファイルがまったくありません。
トレースする各プロジェクトには、それぞれ独自の callidescope.config.ts が必須です。任意ではありません。
このファイルがないプロジェクトは、トレース開始前に名前を示して拒否されます。修正するには、このファイルを追加し、ワークスペースの projectDefaults エクスポートを展開して、必要な設定を上書きします。
import { projectDefaults } from "../../configuration/callidescope.config.js";
export default { ...projectDefaults };
このインポートパスは例示であり、実際のものではありません。プロジェクト自身の場所を基準に記述してください。何も上書きしないファイルでも、設定として完全な記述です。つまり、このプロジェクトがすべてのデフォルトを採用すると明示しており、ファイルがなければそれを示すことはできません。
ファイルを読み取れなかったか、必須フィールドが不足しています。
Failed to read the callidescope configuration for <project> at <path>: <reason>
読み取りに失敗したか、オブジェクトがスキーマを満たしていません。<reason> は根本的な失敗の内容で、エラーの cause として保持されます。スキーマのエラーでは、該当フィールドが示されます。たとえば、entryPoints、exclude、limits、write のメンバーが不足している場合、正の整数ではない制限値が指定されている場合、addresses のエントリーが文字列ではない場合です。現在はすべてのフィールドが必須です。entryPoints は5つすべてのメンバー、limits は両方、write も両方、そして exclude が必要です。そのため、いずれかが省略されたファイルは、設定ファイルがまったくない場合と同様に拒否されます。projectDefaults を展開してから上書きすれば、ファイル内ですべてのフィールドを列挙する必要はありません。
ワークスペースでのみ設定できるフィールドが含まれています。
<project> sets <field>, which only the workspace configuration may set. A project configuration may set entryPoints, exclude, limits, write.markdown, and write.mermaid.
そのフィールドをワークスペースのファイルに移してください。<field> は、制限値の場合は limits.<name>、出力先の場合は write.<name>、それ以外のトップレベルフィールドの場合はフィールド名のみで表示されるため、メッセージで誤っている箇所がわかります。
この状態に至る原因は2つあり、修正方法も異なります。
- プロジェクト独自のファイルで、ワークスペースのデフォルトエクスポートを展開している場合。
その記述を削除し、代わりに
projectDefaultsを展開してください。デフォルトエクスポートにはdirectories、excludeFrom、write.jsonなど、ワークスペースでのみ設定できる項目が含まれます。projectDefaultsに含まれるのは、プロジェクトに設定が認められている項目だけなので、これを展開すれば、誤ってワークスペース専用フィールドを引き継ぐことはありません。 - 本当にワークスペースレベルのフィールド(
directories、excludeFrom、excludeCallees、write.json)の場合。これらはワークスペースのファイルに記述する必要があり、プロジェクトごとに設定する方法はありません。これらは実行時に読み取る対象、実行結果のレポートの出力先、またはワークスペースの分割方法を指定するものであり、トレースを実行する側とは異なる設定をプロジェクトが指定できないためです。
宣言されたアドレスが何も解決しませんでした。
<project> declares an entryPoints.addresses entry that resolves to nothing: "<address>". Check the file path and the qualified name callidescope prints for it in a stack.
対象の呼び出し可能な項目の名前が変更されたか、移動されたか、今回の実行対象から除外されています。アドレスを修正するか、削除してください。無視してはいけません。この拒否があるのは、名前の変更によって宣言済みのルートが黙って削除されると、出力に何の説明もないままそのプロジェクトの測定深度が下がり、誰も確認しようと思わないコミットでゲートが緩んでしまうためです。アドレスが正しいのに呼び出し可能な項目が今回のトレース範囲外にある場合、問題なのはアドレスではなくスコープです。
宣言されたアドレスが複数の候補に解決されました。
<project> declares an entryPoints.addresses entry that matches more than one declaration: "<address>". Candidates: <address>:<line>, <address>:<line>. Add ":<line>" to the address to pick one.
各候補は、その候補を選択するアドレスとして表示されるため、そのうち1つを設定にコピーしてください。同じ1行上にある2つの宣言は、この方法では区別できません。その場合は列が表示され、案内は次のように変わります。
同じ行にある2つの宣言は「:<line>」では区別できません。どちらかの名前を変更するか、別の呼び出し可能な項目を指定してください。
宣言されたアドレスの形式が正しくありません。
<project> declares an invalid entryPoints.addresses entry. "<address>" is not a callable address. It needs a file path and a qualified name joined by "#", as in "src/foo.service.ts#FooService.bar", optionally followed by ":<line>" to disambiguate.
よくある例は、ファイルパスのみ、修飾名のみ、または # を置くべき箇所にパス区切り文字を使っている場合です。パスはワークスペースを基準にします。
実行時には、拒否する前に解決できなかったアドレスをすべて収集します。そのため、複数ある場合は番号付きで表示され、
<count> 個の宣言されたエントリーポイントを解決できませんでした。
というメッセージの後に列挙されます。depth コマンドと breadth コマンドでも、プロンプトに入力したアドレスについて同じ3種類の問題が報告されます。文言はその状況に合わせたもので、同じコードで表示されます。
何も拒否せず、何もしないプロジェクト設定
キーのスペルミスは拒否されません。スキーマには受け付けるフィールドがすべて記載されているため、正しく記述した maximumDepth と並べて limits: { maxDepth: 10 } を指定すると、スペルミスがそのまま残るのではなく、認識されないキーとしてエラーになります。スキーマを通過した後もプロジェクトの制限が適用されていないように見える場合は、ファイルを読み直すのではなく、実際にどの値に解決されたかを確認してください。
npx callidescope limits --config configuration/callidescope.config.ts
そのプロジェクトの行に、数値と、その値の取得元ファイルが表示されます。
プロジェクトの exclude が機能しないのは、別の理由です。 グロブはそのプロジェクト自体のルートを基準にするため、ワークスペース相対のパスである packages/thing 自身のファイルに記述した packages/thing/src/generated/** は何にも一致せず、そのファイルはトレースされたままになります。先頭からプロジェクトのルートを取り除いてください:src/generated/**。別のプロジェクトにまで及ぶグロブはここには記述できません。複数のプロジェクトにまたがるノイズは、実行自体の exclude に指定してください。
読み取れなかったプロジェクト
あるプロジェクトの tsconfig.json が存在しないか、解析できず、実行はそこで停止しました。メッセージにはパスと、コンパイラ自身の診断、またはそのディレクトリに tsconfig.json が存在しないことが含まれます。depth と breadth でも同じ見出しでこのエラーが発生します。検索は一致判定より前にトレースを行うため、ワークスペース全体をトレースする場合と同じように、同じ読み取り不能なプロジェクトに到達する可能性があるためです。
何も出力されず、出力先にも何も書き込まれていません。これは、問題を飛ばすのではなく停止することが重要だからです。呼び出し元は検出結果を評価する前にレポートを書き込むため、不完全なグラフを公開してから、プロジェクトが欠けたワークスペースで測定された深さだと判明することになります。停止すれば、取り消すコミットもありません。
解決方法は2つあります。どちらが適切かは、ファイルを解析できない理由によって異なります。
- 設定が誤って壊れています。 修正してください。メッセージにはコンパイラ自身の診断が含まれており、通常はオプション名が示されます。
- 設定は意図的に壊されています。 一部のリポジトリでは、フィクスチャとして壊れた
tsconfig.jsonをコミットしています。このワークスペースではcodependix-examplesにそのようなファイルがあり、修正すると、その失敗を実証する唯一の場所がなくなってしまいます。代わりに、ディレクトリをexcludeFromの無視ファイルに追加するか、excludeグロブを指定して、そのプロジェクトを除外してください。除外はtsconfig.jsonを開く前に適用されるため、これで実行がそのファイルに到達することはありません。プロジェクトの ファイル を除外しても効果はありません。失敗するのは設定を開く段階であり、それが先に行われるためです。
何もトレースしなかった実行
判定対象が何もないため、上記のすべてのゲートを通過し、実行自体が空であることを理由に失敗します。これは正常な結果ではありません。次の項目を順に確認してください。
- コードが除外されていませんか?
excludeグロブは組み込みのデフォルト設定に追加されます。また、excludeFromファイルの指定は忘れやすいものです。すべてのプロジェクトを対象とするほど広い除外設定があると、実行結果は空になります。 --directoriesの指定先は意図した場所ですか? 指定するのは、プロジェクト名ではなく、それぞれのtsconfig.jsonを含むパスです。
スタックが見つからなかった実行
これは失敗ではありません。実際のコードをトレースしたうえで検出結果がなかった実行は、通常の結果です。サマリーには、確認を行ったことを示す呼び出し可能な項目、ファイル、エッジの数が表示され、制限内にあるリポジトリには名前を挙げるスタックがありません。
検出結果が示す問題の所在
深さまたは幅の行が示すのはコードについてであり、それを測定した設定についてではありません。修正すべきなのはコードです。測定自体が間違っている場合、たとえばエントリーポイントのルールが不足している場合や、横断的なロガーがすべての数値を押し上げている場合にのみ、設定を見直してください。それぞれについては callidescope-configure スキルで説明しています。