clr-activation-debugging について
mscoree.dll shim が生成する CLR アクティベーションログを使い、.NET Framework のランタイム起動問題を診断するスキルです。ランタイム選択や起動失敗、オンデマンド機能、COM や旧式ホスティングに関する問題を追跡できます。
主な機能
- 01CLRLoad アクティベーションログの分析
- 02CLR バージョン選択の追跡
- 03shim エラーと起動結果の解釈
- 04オンデマンド機能と COM 起動経路の調査
活用シーン
- 01CLR を読み込めないプロセスの診断
- 02予期しない CLR バージョンの調査
- 03.NET 3.5 オンデマンド機能の挙動確認
- 04COM のランタイム起動失敗の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dotnet/ skills --skill clr-activation-debuggingインストール後、Claude Code で/clr-activation-debuggingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/activation-flow.mdcom-activation.mdlog-format.md詳細
CLR のアクティベーションのデバッグ
シム(mscoree.dll)が生成する CLR アクティベーションログ(CLRLoad ログ)を分析して、.NET Framework のランタイムアクティベーションに関する問題を診断します。これらのログには、CLR のバージョンを選択して読み込む際にシムが行うすべての判断が記録されています。
使用する場面
- プロセスが CLR をまったく読み込めない(「使用するランタイムのバージョンが見つかりません」)
- シムが誤った CLR バージョンを選択する(例:v4.0 ではなく v2.0)
- 予期しない .NET 3.5 の Feature-on-Demand(FOD)インストールダイアログが表示される
- FOD ダイアログが表示されるはずなのに、表示されない
- CLR v2 と CLR v4 の両方が同じプロセスに読み込まれ、障害が発生する
- シムがランタイムを解決できず、COM オブジェクトのアクティベーションに失敗する
- レガシーのホスティング API(CorBindToRuntime)が予期しないバージョンにバインドされる
使用しない場面
- 最新の .NET(CoreCLR / .NET 5 以降) — このスキルの対象は .NET Framework のみです(mscoree.dll シム)
- アセンブリのバインド失敗 — CLR アクティベーションログではなく、Fusion ログ(fuslogvw.exe)を使用してください
- CLR の読み込み後に発生するランタイムクラッシュ — アクティベーションは成功しています。問題は別のところにあります
背景
シムのアーキテクチャ
.NET Framework シムは 2 つの層で構成されています。
- mscoree.dll(「シェルシム」) — CLR ホスト型 COM オブジェクトの登録済み
InprocServer32となる公開 DLL であり、_CorExeMain、レガシー API などのエントリポイントです。 - mscoreei.dll — ランタイムの選択ロジック、ログ記録、アクティベーションの判断を担う、実際のシム実装です。mscoree.dll は mscoreei.dll に処理を転送します。
ログを読む際、FOD コマンドラインの caller-name:mscoreei.dll はこの仕組みを反映しており、処理を行っているのが mscoreei.dll であることを示しています。
.NET 3.5 / v2.0.50727 のバージョン対応
.NET 2.0、3.0、3.5 はすべて同じ CLR ランタイムバージョン、v2.0.50727 を共有しています。「3.0」と「3.5」は、CLR v2.0 にライブラリを追加したリリースです。アクティベーションでは、すべて「v2.0.50727」として扱われます。シムが v2.0.50727 を選択したり、FOD が「NetFx3」のインストールを提示したりする場合、CLR v2.0 ランタイム(および 3.0/3.5 のライブラリ)がインストールされます。同様に、CLR v4.0(v4.0.30319)は、.NET Framework 4.0 から 4.8.x までのすべてのバージョンに対応します。
最近の Windows における .NET 3.5 の提供状況
最近の Windows バージョン(Windows 11 Insider Preview Build 27965 および今後のプラットフォームリリース)では、.NET Framework 3.5 は Windows のオプションコンポーネント(Feature-on-Demand)として提供されなくなりました。スタンドアロン MSI からインストールする必要があります。そのため、FOD ダイアログ(fondue.exe /enable-feature:NetFx3)が表示されても、これらのシステムではインストールに成功しません。Windows 10 および 25H2 までの Windows 11 では、引き続き FOD を利用できます。.NET Framework 3.5 のサポートは 2029 年 1 月 9 日に終了します。
シムの HRESULT コード
シムが失敗すると、0x8013xxxx の範囲の特定の HRESULT が返されます。呼び出し元が受け取るエラーは次のとおりです(アクティベーションログには表示されません。ログには人が読めるメッセージが記録されます)。
| HRESULT | シンボル | 意味 |
|---|---|---|
0x80131700 | CLR_E_SHIM_RUNTIMELOAD | 適切なランタイムバージョンが見つからないか、読み込めません。最もよく発生するシムエラーです — v4 のみがインストールされたマシンで、制限されたレガシーアクティベーションに失敗したときに呼び出し元が受け取るエラーです。 |
0x80131701 | CLR_E_SHIM_RUNTIMEEXPORT | ランタイムは見つかりましたが、必要なエクスポートまたはインターフェイスの取得に失敗しました。 |
0x80131702 | CLR_E_SHIM_INSTALLROOT | .NET Framework のインストールルートがレジストリにないか、無効です。 |
0x80131703 | CLR_E_SHIM_INSTALLCOMP | インストールに必要なコンポーネントがありません。 |
0x80131704 | CLR_E_SHIM_LEGACYRUNTIMEALREADYBOUND | 別のランタイムがすでにレガシーランタイムとしてバインドされています。レガシー API が、すでに選択されているバージョンと競合するバージョンへのバインドを試みました。 |
0x80131705 | CLR_E_SHIM_SHUTDOWNINPROGRESS | シムはシャットダウン中のため、要求を処理できません。 |
ユーザーからこれらの HRESULT(特に 0x80131700)が報告された場合、CLR アクティベーションログが適切な診断ツールです。
前提条件
ログファイルを生成するには、CLR のアクティブ化ログを有効にする必要があります。ユーザーがまだログを持っていない場合は、ログを有効にするよう案内してください。
環境変数を使用する方法(推奨 — 現在のセッションに限定):
set COMPLUS_CLRLoadLogDir=C:\CLRLoadLogs
レジストリを使用する方法(マシン全体 — すべての .NET Framework プロセスに影響):
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework
CLRLoadLogDir = "C:\CLRLoadLogs" (REG_SZ)
64 ビットシステムでは、32 ビットプロセスが関係する場合、Wow6432Node の下にも設定してください。
⚠️ ログディレクトリは事前に存在している必要があります。 shim はディレクトリを作成しません。ディレクトリが存在しない場合、ログは書き込まれず、エラーも失敗を示す通知もありません。
ログは {ProcessName}.CLRLoad{NN}.log として書き込まれます(NN = 00–99、プロセスインスタンスごとに 1 つ)。プロセスが終了するまでログを読み取ることはできません — ファイルは開いたまま保持されます。
ログを取得したら、ログを停止するために環境変数またはレジストリキーを削除してください。
入力
| 入力 | 必須 | 説明 |
|---|---|---|
| CLR アクティブ化ログファイル | はい | 1 つ以上の .CLRLoad*.log ファイル |
| 症状の説明 | 推奨 | ユーザーが確認した内容(FOD ダイアログ、誤ったランタイム、失敗など) |
| 期待される動作 | 推奨 | ユーザーが期待していた動作 |
ワークフロー
ステップ 1:参考資料を読み込む
同梱されているパスは、ユーザーのワークスペースではなく、この SKILL.md が含まれるディレクトリを基準に解決してください。詳細なログ形式、判定フロー、CLSID レジストリのドキュメントが記載された参考ファイルを、次の順序で読み込みます。
references/log-format.md— ログ行の形式、フィールド、既知のすべてのログメッセージの種類references/activation-flow.md— ランタイム選択における shim の決定木references/com-activation.md— COM(DllGetClassObject)アクティブ化の詳細、CLSID レジストリの構成
直接読み込みに失敗した場合は、このスキルの references/ ディレクトリを 1 回一覧表示し、その一覧に想定されるファイルが含まれている場合に限り、再試行してください。ワークスペース内のファイル検索やテキスト検索を使って、スキルのインストール先を探さないでください。
想定される参考ファイルが 1 つ以上利用できないままの場合は、利用可能な参考資料を活用し、不足する情報には以下のインライン情報を使用してください。不足した相対パスを <paths> に置き換えて、最終診断に Reference coverage: reduced; unavailable: <paths>; used inline guidance for missing references. を含めてください。
ステップ 2:ログファイルを調査する
個々のログに詳しく目を通す前に、全体像を把握してください。
- すべてのログファイルを一覧表示し、プロセス名ごとにグループ化します。これにより、どの実行ファイルが CLR のアクティブ化をトリガーしたかがわかります
- 各プロセスについて、結果を示す行を確認します。
Decided on runtime: vX.Y.Z— 解決成功ERROR:— 解決失敗Launching feature-on-demand— FOD ダイアログが表示されたCould have launched feature-on-demand— FOD が実行されるはずだったが、抑制されたV2.0 Capping is preventing consideration— 上限設定のため v4 以降がスキップされた
grep -l "ERROR:\|Launching feature-on-demand\|Could have launched" *.log
grep -c "Launching feature-on-demand" *.log
- サマリーテーブルを作成します。
| プロセス | ログファイル | 結果 | 選択されたランタイム | FOD? |
|---|---|---|---|---|
| ... | ... | ... | ... | ... |
ステップ 3:問題のあるログを分析する
想定外の結果となった各ログファイルについて、アクティブ化フロー全体を追跡します。ログを先頭から末尾まで読み、次の点を確認してください。
⚠️ ネストされたログエントリ: shim 内部の呼び出しによって、すでに記録中のアクティブ化シーケンス内で追加のログエントリが生成されることがあります。たとえば、
DllGetClassObjectの呼び出しが内部でComputeVersionStringを呼び出し、それがFindLatestVersionを呼び出すと、それぞれのログ行が生成されます。FOD チェック(「Checking if feature-on-demand installation would help」)が実行されると、バージョン計算全体が再実行されます。その結果、同じアクティブ化内に 2 つ目のComputeVersionStringブロックが生成されます。こうしたネストされた再入エントリを、別々のアクティブ化試行と誤認しないでください。
3a. エントリーポイント
最初の FunctionCall: または MethodCall: の行から、アクティベーションがどのように開始されたかがわかります。
| エントリーポイント | 意味 |
|---|---|
_CorExeMain | マネージド EXE の起動 — バイナリ自体が .NET アセンブリです |
DllGetClassObject. Clsid: {guid} | COM アクティベーション — 何らかの処理が COM クラスを CoCreate し、mscoree.dll 経由でルーティングされています |
ClrCreateInstance | 最新のホスティング API(v4 以降) |
CorBindToRuntimeEx | 旧式のホスティング API(v1/v2)— プロセスを単一のランタイムにバインドします |
ICLRMetaHostPolicy::GetRequestedRuntime | ポリシーベースのホスティング API(他のエントリーポイントの後に内部的に呼び出されることがよくあります) |
LoadLibraryShim | 名前でフレームワーク DLL を読み込む旧式の API |
3b. 入力パラメーター
エントリーポイントの直後に、バージョンの計算に使われる入力値がログに出力されます。
IsLegacyBind:旧式(v4 より前)のアクティベーション経路ですか?値が 1 の場合、シムは単一ランタイムという「旧式」の見方を使用します。旧式の API(CorBindToRuntimeEx、旧式 COM のDllGetClassObject、LoadLibraryShimなど)がこの値を設定します。IsCapped:値が 1 の場合、シムのロールフォワードの範囲は Whidbey(v2.0.50727)までに制限され、インストール済みランタイムの列挙時に v4.0 以降は考慮されません。これにより、v4 のインストールが影響を及ぼさないようになっています。旧式のコードパスは、v4 が存在しないかのように動作し続けます。v4 しかなく、.NET 3.5 がインストールされていないマシンでは、上限付きの列挙でランタイムが一つも見つかりません。上限設定によって、特定の v4 バージョン文字列が明示的に指定されている場合(例:CorBindToRuntimeEx("v4.0.30319", ...)経由、またはuseLegacyV2RuntimeActivationPolicyを使った構成経由)に v4 以降を読み込めなくなることはありません。SkuCheckFlags:SKU(エディション)の互換性チェックを制御します。ShouldEmulateExeLaunch:ポリシー上、EXE の起動として扱うかどうかを指定します。LegacyBindRequired:旧式のバインドが必須かどうかを指定します。
3c. 構成ファイルの処理
構成ファイルの解析結果を確認します。
Parsing config file: {path}— シムが.configファイルを探していますConfig File (Open). Result:00000000— 構成ファイルが見つかり、正常に開かれましたConfig File (Open). Result:80070002— 構成ファイルが見つかりません(ERROR_FILE_NOT_FOUND の HRESULT)Found config file: {path}— 構成ファイルが正常に読み込まれましたUseLegacyV2RuntimeActivationPolicy is set to {0|1}—<startup useLegacyV2RuntimeActivationPolicy="true">が存在するかどうかを示します。値が 1 の場合、すべてのランタイムが旧式のコードパスの候補として扱われます。つまり、旧式のシム API が v4 以降を列挙して選択できるようになります。これは複数の<supportedRuntime>エントリや他の構成オプションと併用できます。また、<supportedRuntime>エントリがなくても使用でき、その場合、旧式の API は単に v4 を列挙できます。副作用: v4 より前のランタイムとのインプロセス SxS が無効になり、それらのランタイムはプロセスから排除されます。Config file includes SupportedRuntime entry. Version: vX.Y.Z, SKU: {sku}— 構成ファイル内で見つかった各<supportedRuntime>
重要なポイント: 構成ファイルがなく、プロセスが上限付きの旧式バインドを行う場合、シムには v4.0 へ誘導する手段がありません。インストール済みランタイムを列挙しますが、対象は v2.0 以下に制限されます。.NET 3.5 がインストールされていなければ何も見つからず、失敗します。これは仕様どおりです。v4 のインストールが影響を及ぼさないよう、これらのコードパスでは意図的に v4 が認識されないようになっています。
3d. バージョンの解決
Installed Runtime: vX.Y.Z. VERSION_ARCHITECTURE: N— マシンにインストールされているランタイム{exe} was built with version: vX.Y.Z— バイナリの PE ヘッダーに記録されたバージョン(マネージドアセンブリのみ。ネイティブ EXE には含まれません)Using supportedRuntime: vX.Y.Z— シムが構成ファイルの<supportedRuntime>リストからバージョンを選択しましたFindLatestVersion is returning the following version: vX.Y.Z ... V2.0 Capped: {0|1}— ポリシーベースの最新バージョン検索の結果Default version of the runtime on the machine: vX.Y.Zまたは(null)— シムが最終的に選択したバージョン。(null)は何も見つからなかったことを示しますDecided on runtime: vX.Y.Z— 最終決定 — これが読み込まれるバージョンです
3e. 失敗と FOD のパス
バージョンの解決に失敗した場合:
ERROR: Unable to find a version of the runtime to use— shim が適切なランタイムを見つけられませんでしたSEM_FAILCRITICALERRORS is set to {value}— プロセスのエラーモードを確認します:- 値 0:エラーダイアログと FOD は許可されています
- ゼロ以外(いずれかのビットが設定されている場合。一般的には 0x8001):エラーダイアログと FOD は抑制されています。
SEM_FAILCRITICALERRORSフラグ(0x0001)は親プロセスから継承されます。
Checking if feature-on-demand installation would help— shim がバージョンの計算を再度実行し、.NET 3.5 をインストールすれば要求が解決するか確認します- その後、次のいずれかが発生します:
Launching feature-on-demand installation. CmdLine: "...\fondue.exe" /enable-feature:NetFx3— FOD ダイアログが表示されますCould have launched feature-on-demand installation if was not opted out.—SEM_FAILCRITICALERRORSが設定されていたため、FOD は抑制されます
3f. 1 つのプロセスでの複数回のアクティベーション
1 つのログに複数のアクティベーションシーケンスが含まれる場合があります。それぞれは新しい FunctionCall: または MethodCall: エントリで始まります。よくあるパターンは次のとおりです:
ClrCreateInstance/GetRequestedRuntimeによる最初のアクティベーション → 成功します(構成ファイルを使用して v4.0 を読み込みます)DllGetClassObject(COM)による 2 回目のアクティベーション → レガシーバインドで上限が設定され、失敗します
これは、ネイティブ EXE(link.exe や mt.exe など)が主要な処理のために CLR を正常に読み込んだ後、2 次的な COM アクティベーション要求(例:diasymreader 用)が別個のレガシー解決を発生させ、v2.0 を見つけられない場合に起こります。
ステップ 4:システムの状態を確認する(必要な場合)
ログの分析から登録または構成の問題が疑われる場合は、次を確認します:
CLSID の登録(COM アクティベーションの問題の場合):
# Check the CLSID entry
Get-ItemProperty 'Registry::HKCR\CLSID\{guid}'
Get-ItemProperty 'Registry::HKCR\CLSID\{guid}\InprocServer32'
Get-ChildItem 'Registry::HKCR\CLSID\{guid}\InprocServer32' | ForEach-Object {
Write-Output "--- $($_.PSChildName) ---"
Get-ItemProperty "Registry::$($_.Name)"
}
InprocServer32 の主な値:
(Default)は、CLR でホストされる COM オブジェクトの場合、mscoree.dllである必要があります- バージョンのサブキー(例:
2.0.50727、4.0.30319)は、この CLSID を登録したランタイムのバージョンを示します - バージョンのサブキーにある
ImplementedInThisVersionは、そのランタイムバージョンが COM クラスをネイティブに実装していることを意味します(マネージド相互運用経由ではありません) - バージョンのサブキーにある
AssemblyとClassは、マネージド COM 相互運用の登録を示します - バージョンのサブキーにある
RuntimeVersionは、このオブジェクトをホストする CLR のバージョンを指定します
インストール済みランタイム:
Get-ChildItem 'Registry::HKLM\SOFTWARE\Microsoft\.NETFramework\policy'
プロセスのエラーモード(FOD が実行された、または実行されなかった理由):
SEM_FAILCRITICALERRORS フラグは親プロセスから継承されます。ビルドシステムまたはスクリプトがこのフラグを設定する(または SetErrorMode を呼び出す)と、すべての子プロセスがその設定を継承します。
ステップ 5:診断して報告する
次の内容を網羅した明確な診断を提示します:
- 何が起きたか — アクティベーションの問題が発生したプロセスと、その症状
- なぜ起きたか — 結果につながった shim 内の具体的な判断経路
- 動作を制御する要因 — 結果を左右した具体的な入力(構成ファイルの有無、エラーモード、CLSID の登録、上限の設定状態)
- 何が変わったか(該当する場合)— ユーザーが動作の変化を述べている場合、変化した可能性のある入力(親プロセスのエラーモード、構成ファイル、CLSID の登録、インストール済みランタイム)を特定します
よくあるシナリオ
予期しない FOD ダイアログ
パターン: DllGetClassObject → IsCapped: 1 → 設定ファイルなし → (null) → SEM_FAILCRITICALERRORS: 0 → FOD が起動
根本原因: ネイティブ EXE が、mscoree.dll の下に登録された CLSID を COM アクティベーションしています。これにより、v2.0 に制限されたレガシーコードパスが使われます。設定ファイルがなく(また、useLegacyV2RuntimeActivationPolicy もない場合)、このコードパスから v4 は認識されません。.NET 3.5 がインストールされていないマシンでは、認識されるランタイムがなく、SEM_FAILCRITICALERRORS も設定されていないため、FOD ダイアログが表示されます。
重要な問い: なぜ SEM_FAILCRITICALERRORS が変わったのでしょうか?これは親プロセスから継承されます。起動方法(スクリプト経由か直接実行か、ビルドシステムの違いなど)によって、エラーの現れ方が変わります。v4 しかないマシンで制限付きレガシーバインドに失敗するという根本的な問題は常に存在します。SEM_FAILCRITICALERRORS によって、その問題が目に見えるダイアログとして現れるか、何も表示されずに失敗するかが決まるだけです。
誤ったランタイムが選択される
パターン: 設定ファイル内の supportedRuntime エントリに複数のバージョンが指定されている場合、シムはインストール済みの最初のバージョンを選択します。v2.0 が最初に記載されていて .NET 3.5 がインストールされている場合は、v4.0 も利用可能であっても v2.0 が選ばれます。
重要なポイント: 設定ファイル内の <supportedRuntime> エントリは、記載順に評価されます。最初に一致したインストール済みバージョンが選択されます。
v2 と v4 の両方が読み込まれる
パターン: 同じプロセスのログに複数のアクティベーションシーケンスが記録されます。一方は v4 にバインドし、もう一方は v2 にバインドします(またはその逆です)。同じプロセスで CLR v2 と v4 をサイドバイサイドで読み込むことはサポートされていますが、共有状態に関する問題が発生する可能性があります。
重要なポイント: 同じログファイル内で、異なるバージョンを示す Decided on runtime の行が別々に記録されていないか確認してください。
レガシーランタイムがすでにバインドされている
パターン: プロセスの早い段階でレガシーコードパスが成功します(たとえば、v4 を明示的に指定した CorBindToRuntimeEx や、useLegacyV2RuntimeActivationPolicy を含む設定ファイルなど)。これにより、レガシーランタイムが v4.0 に設定されます。その後のすべてのレガシーアクティベーションは、ほかの方法では失敗するはずの制限付き COM アクティベーションも含めて、すでにバインドされたレガシーランタイムを再利用して、エラーを報告せずに成功します。
重要なポイント: プロセス内でアクティベーションが発生する順序は重要です。v4.0 が最初にレガシーランタイムとしてバインドされると、制限付き COM アクティベーションは成功します。制限付き COM アクティベーションが、レガシーランタイムのバインドより先に発生すると失敗します。そのため、どのコンポーネントが最初にアクティベーションを行うかによって動作が変わることがあります。並行コードでは競合状態によって結果が変わる可能性があります。
よくある落とし穴
| 落とし穴 | 正しい対処法 |
|---|---|
IsCapped: 1 は v4.0 を絶対に読み込めないことを意味すると考える | キャッピングで制限されるのはロールフォワード時の列挙のみです。次の場合は v4.0 を読み込めます。特定のバージョン文字列を明示的に渡す、設定に useLegacyV2RuntimeActivationPolicy="true" と <supportedRuntime version="v4.0"/> を指定する、またはレガシーランタイムがすでに v4 以降にバインドされている場合です。 |
| キャッピングは壊れている、またはバグだと考える | キャッピングは意図された仕様であり、v4 のインストールによる影響をなくします。v4 のみがインストールされたマシンでは、レガシーコードパスからランタイムが見えないのが正しい動作です。これは仕様どおりに動作しています。 |
| FOD はプロセスごとに制御されると考える | SEM_FAILCRITICALERRORS は親プロセスから継承されます。親プロセス(ビルドシステム、スクリプト、シェル)で変更すると、すべての子プロセスの動作が変わります。 |
| ログの最初のアクティベーションだけを確認する | 1 つのログに、複数の独立したアクティベーションシーケンスが含まれることがあります。問題の原因は、最初の CLR 読み込みではなく、2 回目以降の COM アクティベーションであることがよくあります。 |
| 設定ファイルがないのは問題ないと考える | レガシーまたはキャップされたバインドで COM アクティベーションを行うネイティブ EXE では、設定ファイル(useLegacyV2RuntimeActivationPolicy を含む)が、レガシーコードパスから v4.0 を認識できるようにする主な手段です。設定ファイルがなければキャッピングされ、v4 は認識されません。 |
useLegacyV2RuntimeActivationPolicy を指定せずに <supportedRuntime> を追加する | useLegacyV2RuntimeActivationPolicy="true" がない場合、設定による v4 へのロールフォワードは EXE のメイン読み込みでは機能しますが、レガシーコードパス(COM アクティベーション、mscoree.h API への P/Invoke)は v2.0 にキャップされたままです。レガシーコードパスには両方が必要です。 |
トレードオフを理解せずに useLegacyV2RuntimeActivationPolicy を設定する | この属性を指定するとインプロセス SxS が無効になり、v4 より前のランタイムはプロセス内で使用できなくなります。ビルドツールでは通常問題ありませんが、v2 と v4 の両方をホストする必要があるアプリでは考慮が必要です。 |
検証
診断を提示する前に、以下を確認してください。
- エラーまたは FOD の発生要因を含むログファイルをすべて分析した(最初のログだけではない)
- 問題のある各アクティベーションのエントリポイントを特定した
- 各アクティベーションシーケンスについて、キャッピングとレガシーバインドの状態を記録した
- 設定ファイルの有無を確認した
- FOD 関連の問題について、SEM_FAILCRITICALERRORS の状態を記録した
- 1 つのログ内に複数のアクティベーションがある場合、それぞれを個別に追跡した
- 診断で結果だけでなく、具体的な判定経路を説明した