Skill Auditor — エージェント能力の劣化と適合性評価
概要
スキルは償却資産です。 モデルバージョンは数ヶ月ごとにリリースされます。先四半期に合格したスキルは、静かに劣化する可能性があります — 出力形状の誤り、ツールコールの破損、トリガー見逃しなど。ユーザーにはエージェントが劣化したことが伝わりません。
このスキルは評価方法論です。以下の3つの問いに答えます:
- スキルは劣化しているか? — モデルバージョン間での能力退行。
- 新しいスキルは実際に良いか? — 効果対コスト。
- スキルはこのユーザーに適合するか? — トリガーの正確性 + 環境 + スタイル。
5つの実行可能なエントリポイントがあります:
scripts/console.py— 常駐コンソール(データ層):ホストごとにregistry.<host>.jsonを維持し、モデルバージョンの変更を検出(bump/check)、推奨/削除パネルを出力します。完全なコマンドセットはUSAGE.mdを参照。scripts/regress.py— ゴールデンセットのリプレイ結果を基に、合格率マトリックスを計算し、劣化(しきい値 + 方向)をフラグ付けし、アセットが編集された場合はFINGERPRINT-DRIFTをフラグ付けします。scripts/baseline.py— リプレイチェックリストをスキャフォールドし、記録された判定結果をbaseline-results.jsonにマージします(アセットごと、--replaceで完全上書き)。下書きのゴールデンケースは--allow-draftがない限りスキップされます。scripts/fingerprint.py— スタンドアロンのレポートCLI。scanと同じハッシュコードの薄いラッパーです。fingerprint-report.*のみを書き込み、レジストリは書き込みません。scripts/install.py— このスキルをマシン上のすべてのエージェントホストにインストールします(~/.workbuddy-ai/skills、~/.claude/skills、~/.agents/skills、~/.dsh/skills、~/.codex/skills)。インストール後に検証し、空のディレクトリを残さず、個人データをコピーしません。
中核原則:ベースラインなしに測定はない。劣化 = 変更されていないフィンガープリントでの有意な合格率低下 — 「なんとなく劣化した」ではありません。
マルチホストアーキテクチャ(スキル vs プラグイン)
1つのコアエンジン、ホストごとのアダプター。同じフィンガープリント/ベースライン/回帰/推奨/ニーズ提案ロジックがすべての場所で動作します。アダプターは「アセットがどこにあるか」と「マニフェストの読み方」だけを知っています。
| ホスト | 種別 | デフォルトルート | マニフェスト |
|---|---|---|---|
| workbuddy | skill | このスキルを含むskillsルート | SKILL.md |
| claude-code | skill | ~/.claude/skills | SKILL.md |
| deepseek | プラグイン | ~/.dsh/profiles/desktop (package.jsonのdepsを読み取る) | package.json / plugin.json |
| generic | アセット | --rootを渡す | plugin.json / manifest.json / SKILL.md / package.json |
- 各ホストは独自のレジストリを保持:
registry.<host>.json— ホスト間の上書きはありません。 - ベースライン結果とゴールデンセットは共有され、アセット名でキーリングされます。
--host <name> --root <path>で実行。カスタムホストはhosts.jsonに追加。console.py hostsはすべてのプロファイル、その解決済みルート、検出されたアセット数を表示します。
つまり、WorkBuddyではスキルを評価し、DeepSeekハーネスではプラグインを評価します — 同じコマンド、異なるアダプター。新しいホストの追加はhosts.jsonへのエントリ追加(種別 + ルート + マニフェストファイル名)で完了し、コード変更は不要です。
使用すべき場合
- 新しいスキルやプラグインをデプロイする前(「スキルを作って、評価フローで進めて」)。
- モデルバージョンアップ後、既存のスキルが劣化していないか確認するため。
- スキルが「なんかおかしい」と感じたとき — 感覚ではなくデータで確認するため。
- スキルを維持/書き換え/廃止するか判断するとき。
- ユーザーにスキルやプラグインを推奨するとき(適合性とエビデンス)。
使用すべきでない場合: 再利用可能なスキルがない単発タスク、純粋なナラティブドキュメント。
中核概念:バージョンフィンガープリント
フィンガープリントは劣化マトリックスの行です。
フィンガープリント = hash(能力面ファイルの内容 + 相対パス) # 口径 v2-能力面
「能力面」に含まれるもの(変更が実際に動作に影響を与えるファイル):
- 含む:
SKILL.md、scripts/*、lib/*、dist/*、package.json、plugin.json、cordis.patch.yml、テンプレート - 除外:
README*、CHANGELOG*、LICENSE*、画像/オーディオ/フォント、*.map、ロックファイル、node_modules/、test*/、docs/
なぜ除外するか:READMEの編集は能力を変えませんが、ハッシュ化するとフィンガープリントが動き、機能変更がないのに偽の FINGERPRINT-DRIFT(「アセットが編集された」)を生成します。プラグインではこれが悪化します — インストールされたプラグインは、16MBのバンドル出力と57KBのREADMEを持つことがあります。
ルール:
- フィンガープリントが変更されていない ⇒ 行は維持される;合格率の低下はモデルの退行である。
- フィンガープリントが変更された ⇒ 変更はモデルではなくスキル自身の責任である。 古い行と新しい行が共存するため、スキルの編集がモデルのドリフトに誤って帰属されることはありません。
python scripts/console.py scan を実行してフィンガープリントを計算し、レジストリに保存します。fingerprint.py はスタンドアロンのレポートラッパーであり、レジストリには触れません。
能力面(なぜプラグインに第2の軸が必要か)
フィンガープリントは「ファイルが変わったか」を示します。「同じものを提供し続けているか」は言えません。
そのためscanは、アセットごとに**能力面(capability surface)**も記録し、前回のスキャンと差分を取ります:
| アセット種別 | 該当面が記録するもの |
|---|---|
| プラグイン | patch(dsh.bundle.patch)、main/module、bin、exports、deps、skills、mcp、hooks、insert(cordis行)、scripts |
| スキル | tools(許可ツール数)、scripts |
変更があった場合、scanは明示的に表示します:
[caps] 1個のアセットの能力面に変更があります(「これが外部に提供するものが変わった」ことで、通過率とは関係ありません):
plug-a +bin
なぜこれがプラグインにとって重要なのか: プラグインの劣化は「ツールを登録しない/ルートが404になる/フックが動作しない」ことで起こり、「回答が悪くなる」ことではありません。ゴールデンセットのプロンプトはプラグインにとって誤ったものを測定します。能力面の差分は「v1.1.0がエントリポイントを削除した」ことを、ホストを起動せずにキャッチします。
既知の境界(誤魔化さないでください): 能力面は宣言された能力であり、観測された能力ではありません。マニフェストが嘘をつくプラグイン(読み込みに失敗するパッチを宣言する)については、これではキャッチできません。
ランタイムエビデンス(第3の軸とその限界)
「ランタイムプローブ」と呼ばれるものには2つの非常に異なる種類があります。混同してはいけません:
| 能動的プローブ (active probe) | 受動的エビデンス (passive evidence) — 実装済み | |
|---|---|---|
| 動作 | ホストを起動し、「実際に登録されたツールはどれか」を問い合わせる | ホストがすでに書き込んでいるログを読む |
| コスト | DSH desktopプロファイルはElectron専用 — dsh --profile desktop --dump-configは拒否される;ヘッドレスエントリなし → IPCのリバースエンジニアリングまたはUI操作が必要 | 1つのファイル読み取り、約10ms |
| キャッチできるもの | マニフェストが嘘をつくプラグインを含むすべて | プラグインがログに記録したものすべて |
| ステータス | 未構築 | console.py probe / skill_audit_probe |
probeは~/.dsh/logs/*.log(hosts.jsonの"logs"でホストごとに設定可能)を読み取り、<iso> [level] [source] messageをパースし、sourceがインストールされたアセット名と一致する行を属性付け、障害語彙(fail|error|ENOENT|unavailable|timeout|…)に一致する行をフラグ付けします。
実機でのキャッチ例:
@wxg-prc-cpg/browser-skill-dsh-plugin 2 件の障害兆候
bsk probe failed (spawn bsk ENOENT); browser tools will report install guidance…
ファイルは存在し、マニフェストは有効、caps=4 — すべての静的チェックは合格します。プラグインは読み込まれ、ツールは登録されていますが、動作できません:シェルアウトするbsk CLIがPATHにありません。ファイルハッシュではこれを発見できません。
盲点(認識し、隠さないこと): ログを出力しないプラグインは不可視;ログローテーションは古い障害を消去;誰も使ったことのないプラグインにはエビデンスがない;infoレベルの障害はキーワードマッチングでキャッチされるため、見逃しと誤検出の両方があり得る。エビデンスの欠如は正常性のエビデンスではない — probeは緑色のチェックマークではなく、この文自体を表示します。
実装済み vs 方法論のみ(この線をぼかさないこと)
以下の方法論はコードよりも広範囲です。ユーザーは自分がどちらの半分を手にしているかを知るべきです:
| 領域 | ステータス |
|---|---|
能力面に対するフィンガープリント、scan/status、能力差分 | 実装済み |
| ゴールデンスキャフォールド + ベースライン取り込み(アセットごとにマージ、ドラフトガード) | 実装済み (baseline.py) |
合格率マトリックス、≥20pp しきい値 + 方向、FINGERPRINT-DRIFT | 実装済み (regress.py) |
モデル変更検出(bump/check)、ホストごとのタイムスタンプ | 実装済み — ただしイベントソースは手動;スケジュールされたcheckは誰かがbumpするまで緑色のまま |
| 推奨/削除パネル、ニーズ提案、履歴マイニングによるドラフト | 実装済み(ヒューリスティック;提案はエビデンスではない) |
| ホストログからのランタイムエビデンス | 実装済み(受動的;プラグインがログに記録したもののみ) |
| アブレーション、シャドウモード採用率、ネット価値/トークンテレメトリー | 方法論のみ — コードなし |
| トリガー精度/再現率、環境調整、スタイルベースライン | 方法論のみ — コードなし |
| K≥3 リプレイ、LLM-Judge 相互検証 | 未実装;現在の判定はK=1の自己評価 |
risk 列 | メンテナンス面のプロキシ — 価値ではない |
このファイル内の主張が「実装済み」とマークされた行にトレースできない場合、それは監査を実行する人間へのアドバイスとして扱い、ツールが代わりに行うものとしては扱わないでください。
判断1 — 能力劣化
4つのステップ:
- ゴールデンセットを手動ではなく履歴から構築する。 過去のセッションをマイニング:ユーザーが抵抗なく採用した → ポジティブリプレイ;ユーザーが抵抗/書き換えを要求した → ネガティブ。リプレイ=退行。ユーザー自身の使用履歴がコーパスです — 発明されたテストセットは不要。
- 同じゴールデンセットで両方のモデルを実行する、K≥3(LLM-Judgeスコアリングケース:K≥5、判定者がノイジーなため)。(フィンガープリント、モデルバージョン)ごとの合格率を記録。
- 決定ルール: ≥20ppの低下かつ方向的一貫性あり → 劣化を報告;しきい値未満 → 「ボラティリティウォッチ」。これにより「この出力が変だ」が再現可能な基準に変わります。
- フラグを立てるだけでなく、帰属する。 中間成果物を検査:
- ツールコールエラー/形式変更 → ツール説明を修正。
- 出力構造は正しいが内容が間違っている → 指示を書き直し。
- トリガーすべきだったがしなかった → トリガー説明を修正。
- すべての中間成果物が正しく、最終出力のみ間違っている → モデル内部の退行;スキルを「単一モデル依存」とマークし、モデル修正を待つ。
「7個が劣化、2個が書き換え推奨」の行は、ステップ4の出力の帰属可能なサブセットです — これがレポートを実用的にします。
判断2 — 新しいスキルは良いか?
測定可能な2つの軸に分割:効果(より良い結果)と経済性(低コスト)。
- デプロイ前のアブレーション。 同じタスクバッチ、2つのアーム:Aはスキルなし、Bはスキルあり。成功率、人間による修正回数、トークンコストを記録。
ネット便益 = 成功率向上率 × タスク頻度 − 限界コスト成功率を30%向上させるが、年間3回のトリガーで毎回+50kトークンかかるスキルは、資産ではなく負債です。 - デプロイ後のシャドウモード。 新しいスキルは静かに実行:提案を生成するが自動実行はしない;「何が起こったか」をログに記録。採用率(受け入れられた vs 上書きされた)を監視。採用率は「良い」の究極の判定者であり、オフラインメトリックよりも正直です。境界:書き込み操作スキル(ファイル削除、メール送信)はシャドウモードではシミュレート/注釈のみ可能で、実際には実行できません。
- ネット価値カード。 スキルごとに1つのダッシュボード:呼び出し回数、成功率、採用率、平均トークン数、累積ネット便益。90日間ネットネガティブ → 書き換えまたは廃止を提案。これが劣化テーブルの消費者側です。
判断3 — それはこのユーザーに適合するか?
「あなたに合う」= トリガーが正確 + 前提が成立 + スタイルが一致。すべて自動化可能:
- トリガー精度(最も感触に影響し、最もスキップされる)。ポジティブ(トリガーすべき)とネガティブ(似ているがトリガーすべきでない — 「このバグを修正して」 vs 「バグとは何か説明して」)の履歴サンプル。リプレイ → 精度/再現率。低精度 = 迷惑(過剰トリガー);低再現率 = 無駄なインストール。最初に10〜20件を手動ラベル、その後セミオート、LLMコストゼロ。
- 環境調整(インストール済み ≠ 実行可能)。スキルメタデータが依存関係を宣言:どのツール/MCP/権限/パスの習慣/言語、さらに暗黙のモデル能力前提(長いコンテキスト、コード実行、マルチモーダル)。ユーザーの実際の環境と調整;欠落 → レッドフラグ。「macOSを前提」、「日本語を出力」、「200kコンテキストが必要」 — 見えない前提はスキルが使われなくなる最大の理由です。これは判断1にもフィードバックされます:失敗した能力前提 = 静かな劣化。
- スタイルベースライン(最も低い重み)。ユーザーの過去の出力 +
USER.mdを参照として使用;LLM-Judgeが形式、言語、冗長性を比較。同じ評価のスキル間のタイブレークにのみ使用。
組み込みワークフロー(「新しいスキルを作る」場合)
ユーザーがスキル作成を依頼した場合、配信前にインラインプロトコルを実行します:
- 環境調整 — ユーザーの環境はスキルの宣言された依存関係 + 能力前提を満たしているか?
- トリガーリプレイ — 10〜20件のサンプルケースをリプレイ;精度/再現率を報告。
- アブレーション — 小さなタスクバッチで、向上率対コストを測定。
- 監視の開始 — 合格時に、フィンガープリント + ゴールデンセットを登録;常駐コンソールがモデルバンプのたびに再実行。
ニーズベースの提案(一致するスキルがない場合)
これは「空の棚」の動作です:ユーザー(特にスキル/プラグインがゼロのユーザー)が、インストール済みのスキルでカバーされないものを要求した場合です。「できません」とは言わず、ギャップを表面化し、埋めることを提案します。
- 会話からニーズを検出:タスクタイプ + ドメイン(例:「四半期財務レポート」→ ファイナンス/分析;「AIトーンを削除して」→ ヒューマナイザー;「ダッシュボードを作って」→ フロントエンド/チャート)。
- まずレジストリを確認 —
python scripts/console.py suggest --need "<need>"。以下のいずれかを返します:✓ 利用可能なスキル/プラグインがあります:<name>→ それを使って、何もインストールしない;または💡 新規追加を提案:[install:<slug>] <title>→ カバーなし、カテゴリを推奨。
- カバーがない場合、マーケットプレイスを検索して実際の候補(スキル/プラグイン/エキスパート)を見つけ、エビデンス付きのカードを提示:その機能、なぜこのニーズに適合するか、ソース。決して自動インストールしない — ユーザーが選択します。
- 処理中…