slopwatch について
slopwatchは、問題を隠す近道がコード変更に含まれていないか確認する、.NET向けスキルです。特にLLMによる変更を対象とし、ベースライン、設定可能なルール、フック、CI検査を使うCLI手順を説明します。
主な機能
- 01無効化されたテストと警告抑制の検出
- 02空のcatchブロックとテスト遅延の検出
- 03プロジェクト設定とパッケージ版上書きの確認
- 04ベースラインによる既存問題の切り分け
- 05フックとCI検査への対応
活用シーン
- 01LLMによるC#やプロジェクトファイルの変更確認
- 02ローカル分析で新たな近道を阻止
- 03CIパイプラインでslop検査を実行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill slopwatchインストール後、Claude Code で/slopwatchを入力して読み込まれたか確認します。
詳細
Slopwatch:.NET 向け LLM 不正防止ツール
このスキルを使用するタイミング
このスキルは常に使用してください。 LLM(Claude を含む)が次のファイルに変更を加えるたびに:
- C# ソースファイル(.cs)
- プロジェクトファイル(.csproj)
- Props ファイル(Directory.Build.props、Directory.Packages.props)
- テストファイル
slopwatch を実行して、変更によって「slop」が持ち込まれていないことを検証してください。
Slop とは?
「Slop」とは、根本的な問題を実際に解決せずに、テストを通過させたりビルドを成功させたりするために LLM が使う近道を指します。これは報酬ハッキングの一種で、LLM が実際の修正ではなく、見かけ上の成功を優先します。
よくある Slop のパターン
| パターン | 例 | 問題点 |
|---|---|---|
| テストの無効化 | [Fact(Skip="flaky")] | 修正する代わりに失敗を隠します |
| 警告の抑制 | #pragma warning disable CS8618 | 問題を修正せずにコンパイラーを黙らせます |
| 空の catch ブロック | catch (Exception) { } | エラーを握りつぶし、バグを隠します |
| 恣意的な遅延 | await Task.Delay(1000); | 競合状態を覆い隠し、テストを遅くします |
| プロジェクトレベルでの抑制 | <NoWarn>CS1591</NoWarn> | プロジェクト全体で警告を無効にします |
| CPM の回避 | インラインの Version="1.0.0" | 集中型パッケージ管理を損ないます |
これらのパターンは決して受け入れないでください。 LLM が slop を持ち込んだ場合は、その変更を却下し、適切な修正を求めてください。
インストール
ローカルツールとして(推奨)
.config/dotnet-tools.json に追加します:
{
"version": 1,
"isRoot": true,
"tools": {
"slopwatch.cmd": {
"version": "0.3.3",
"commands": ["slopwatch"],
"rollForward": false
}
}
}
次に復元します:
dotnet tool restore
グローバルツールとして
dotnet tool install --global Slopwatch.Cmd
初回セットアップ:ベースラインを作成する
既存のプロジェクトで slopwatch を使用する前に、ベースラインを作成します:
# Initialize baseline from existing code
slopwatch init
# This creates .slopwatch/baseline.json
git add .slopwatch/baseline.json
git commit -m "Add slopwatch baseline"
ベースラインが必要な理由: レガシーコードには、既存の問題が含まれている場合があります。ベースラインを作成することで、slopwatch は新たに持ち込まれた slop のみを検出します。
使用方法
基本的な分析
# Analyze current directory for slop
slopwatch analyze
# Analyze specific directory
slopwatch analyze -d ./src
# Strict mode -- fail on warnings too
slopwatch analyze --fail-on warning
# JSON output for tooling integration
slopwatch analyze --output json
# Show performance stats
slopwatch analyze --stats
ベースラインの更新(まれ)
slop が本当に正当化できるものであり、その理由が文書化されている場合に限り、更新してください:
slopwatch analyze --update-baseline
妥当な理由:サードパーティライブラリによってパターンが強制される場合、意図的なレート制限の遅延(テストの不安定さによるものではない場合)、変更できない生成コード。正当化する理由を説明するコードコメントを必ず追加してください。
設定
.slopwatch/slopwatch.json を作成してカスタマイズします:
{
"minSeverity": "warning",
"rules": {
"SW001": { "enabled": true, "severity": "error" },
"SW002": { "enabled": true, "severity": "warning" },
"SW003": { "enabled": true, "severity": "error" },
"SW004": { "enabled": true, "severity": "warning" },
"SW005": { "enabled": true, "severity": "warning" },
"SW006": { "enabled": true, "severity": "warning" }
},
"exclude": [
"**/Generated/**",
"**/obj/**",
"**/bin/**"
]
}
厳格モード(LLM セッションに推奨)
{
"minSeverity": "warning",
"rules": {
"SW001": { "enabled": true, "severity": "error" },
"SW002": { "enabled": true, "severity": "error" },
"SW003": { "enabled": true, "severity": "error" },
"SW004": { "enabled": true, "severity": "error" },
"SW005": { "enabled": true, "severity": "error" },
"SW006": { "enabled": true, "severity": "error" }
}
}
検出ルール
| ルール | 深刻度 | 検出対象 |
|---|---|---|
| SW001 | Error | 無効化されたテスト(Skip=、Ignore、#if false) |
| SW002 | Warning | 警告の抑制(#pragma warning disable、SuppressMessage) |
| SW003 | Error | 例外を握りつぶす空の catch ブロック |
| SW004 | Warning | テスト内の恣意的な遅延(Task.Delay、Thread.Sleep) |
| SW005 | Warning | プロジェクトファイル内の slop(NoWarn、TreatWarningsAsErrors=false) |
| SW006 | Warning | CPM の回避(VersionOverride、インラインの Version 属性) |
Slopwatch が問題を検出した場合
❌ SW001 [Error]: Disabled test detected
File: tests/MyApp.Tests/OrderTests.cs:45
Pattern: [Fact(Skip="Test is flaky")]
- 理由を理解する — LLM が近道を選んだ理由を確認します
- 適切な修正を求める — 問題点を具体的に伝えます
- 修正を検証する — 別の slop が持ち込まれていないことを確認します
ビルドを成功させるためにテストを無効化してはいけません。 根本的な問題を修正してください。
Claude Code フックとの統合
すべての編集を自動的に検証するフックとして slopwatch を追加します。.claude/settings.json を作成または更新します:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "slopwatch analyze -d . --hook",
"timeout": 60000
}
]
}
]
}
}
--hook フラグは次の動作をします:
- Git で変更されたファイルのみを分析します(大規模なリポジトリでも高速です)
- エラーを読みやすい形式で stderr に出力します
- 警告またはエラーがある場合は編集をブロックします(終了コード 2)
- Claude はエラーを確認し、すぐに修正できます
CI/CD との統合
GitHub Actions
jobs:
slopwatch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Install Slopwatch
run: dotnet tool install --global Slopwatch.Cmd
- name: Run Slopwatch
run: slopwatch analyze -d . --fail-on warning
Azure Pipelines
- task: DotNetCoreCLI@2
displayName: 'Install Slopwatch'
inputs:
command: 'custom'
custom: 'tool'
arguments: 'install --global Slopwatch.Cmd'
- script: slopwatch analyze -d . --fail-on warning
displayName: 'Slopwatch Analysis'
基本理念:新たな Slop は一切許容しない
- ベースラインでレガシーの問題を記録する — 既存の問題を認識しつつ、切り分けます
- 新たな slop をブロックする — 新しい近道があれば、ビルドまたは編集を失敗させます
- 例外には正当な理由が必要 — ベースラインを更新する必要がある場合は、その理由を記録します
- LLM も例外ではない — 人間が書いたコードにも AI が生成したコードにも、同じルールを適用します
クイックリファレンス
# First time setup
slopwatch init
git add .slopwatch/baseline.json
# After every LLM code change
slopwatch analyze
# Strict mode (recommended)
slopwatch analyze --fail-on warning
# With stats (performance debugging)
slopwatch analyze --stats
# Update baseline (rare, document why)
slopwatch analyze --update-baseline
# JSON output for tooling
slopwatch analyze --output json
# Hook mode (for Claude Code integration)
slopwatch analyze -d . --hook
オーバーライドする場合(ほとんどありません)
ベースラインを更新するか、ルールを無効にする正当な理由は次のとおりです。
| シナリオ | 対応 | 必須事項 |
|---|---|---|
| サードパーティがパターンを強制する | ベースラインを更新 | 理由を説明するコードコメント |
| 生成されたコード(編集不可) | 除外リストに追加 | 設定に記載 |
| 意図的なレート制限による遅延 | ベースラインを更新 | コードコメント(テスト内ではなく) |
| レガシーコードのクリーンアップ | ベースラインを一度だけ更新 | PR の説明 |
正当ではない理由:
- 「テストが不安定」→ 不安定さを修正する
- 「警告が煩わしい」→ コードを修正する
- 「自分の環境では動く」→ 競合状態を修正する
- 「後で修正する」→ 今すぐ修正する
エージェント向けの注意事項
- slopwatch の検出結果を抑制しないでください。 slopwatch が問題を検出した場合は、コードを修正してください。
- 最後だけでなく、コードを変更するたびに実行してください。
- Claude Code のフックでは、単独の
analyzeではなく--hookフラグを使用してください。 - ベースラインは何でも入れる場所ではありません。 項目を追加するには、理由を記録する必要があります。
- グローバルツールよりローカルツールを優先してください。
.config/dotnet-tools.jsonを使用してください。