dotnet-slopwatch について
dotnet-slopwatch は、.NET の変更に潜む根本問題を隠す近道を検出するスキルです。特に LLM 生成コードを対象とし、ルールとベースラインで新たな問題を確認できます。
主な機能
- 01無効化されたテストと警告抑制の検出
- 02空の catch ブロックやテスト遅延の検出
- 03プロジェクト設定とパッケージバージョンの迂回確認
- 04ベースラインによる既存問題の追跡
- 05フックと CI 品質ゲートへの対応
活用シーン
- 01C# やプロジェクトファイルへの LLM の変更を確認
- 02Claude Code の編集時に近道を阻止
- 03CI パイプラインに slop 検査を追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ aaronontheweb/ dotnet-skills --skill dotnet-slopwatchインストール後、Claude Code で/dotnet-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" inline | 一元化されたパッケージ管理を損ないます |
これらのパターンは決して受け入れないでください。 LLM が slop を持ち込んだ場合は変更を却下し、適切な修正を求めてください。
インストール
ローカルツールとして(推奨)
.config/dotnet-tools.json に追加します:
{
"version": 1,
"isRoot": true,
"tools": {
"slopwatch.cmd": {
"version": "0.4.2",
"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 だけを検出できます。
LLM セッション中の使い方
コードを変更するたびに
LLM が生成したコードに変更を加えた後は、毎回 slopwatch を実行します:
# Analyze for new issues (uses baseline)
slopwatch analyze
# Use strict mode - fail on warnings too
slopwatch analyze --fail-on warning
Slopwatch が問題を指摘した場合
無視しないでください。 代わりに:
- LLM が近道を選んだ理由を理解する
- 適切な修正を依頼する ― 問題点を具体的に伝えます
- 修正によって別の slop が持ち込まれていないことを確認する
# Example: LLM disabled a test
❌ SW001 [Error]: Disabled test detected
File: tests/MyApp.Tests/OrderTests.cs:45
Pattern: [Fact(Skip="Test is flaky")]
# Correct response: Ask for actual fix
"This test was disabled instead of fixed. Please investigate why
it's flaky and fix the underlying timing/race condition issue."
ベースラインの更新(まれなケース)
slop が 本当に正当化でき、その根拠が文書化されている場合に限り、ベースラインを更新します:
# Add current detections to baseline (use sparingly!)
slopwatch analyze --update-baseline
正当化できる例:
- サードパーティーライブラリが特定のパターンを強制する(例:特定の警告を抑制する必要がある)
- レート制限のための意図的な遅延(テストの不安定さへの対処ではない)
- 変更できない生成コード
ベースラインの更新時には、コードコメントに理由を記載してください。
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 との統合
品質ゲートとして slopwatch を CI パイプラインに追加します:
GitHub Actions
jobs:
slopwatch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.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'
検出ルール
| ルール | 重大度 | 検出内容 |
|---|---|---|
| SW001 | エラー | 無効化されたテスト(Skip=、Ignore、#if false) |
| SW002 | 警告 | 警告の抑制(#pragma warning disable、SuppressMessage) |
| SW003 | エラー | 例外を握りつぶす空の catch ブロック |
| SW004 | 警告 | テスト内の根拠のない遅延(Task.Delay、Thread.Sleep) |
| SW005 | 警告 | プロジェクトファイルの slop(NoWarn、TreatWarningsAsErrors=false) |
| SW006 | エラー | CPM の回避(VersionOverride、インラインの Version 属性) |
設定
特定のパスに対するルールを、正当化の理由とともに抑制するには、.slopwatch/config.json を作成します:
{
"suppressions": [
{
"ruleId": "SW002",
"pattern": "**/Generated/**",
"justification": "Generated code from tooling cannot be manually changed"
}
],
"globalSuppressions": []
}
-c または --config を使うと別の場所にある設定ファイルを指定でき、--exclude を使うとパスを解析対象から完全に除外できます:
slopwatch analyze -d . --config path/to/config.json
slopwatch analyze -d . --exclude "**/Generated/**,**/obj/**,**/bin/**"
厳格モード(LLM セッションに推奨)
LLM のコーディングセッション中に最大限の保護を実現するには、エラーだけでなく警告でも失敗させます。
slopwatch analyze -d . --fail-on warning
基本理念:新たなスロップを一切許容しない
- ベースラインでレガシーを把握する - 既存の問題は認識したうえで、切り分けます
- 新たなスロップをブロックする - 新たな近道はすべて、ビルド/編集を失敗させます
- 例外には正当な理由が必要です - ベースラインを更新する必要がある場合は、その理由を記録します
- LLM も特別扱いしません - 人間が書いたコードにも AI が生成したコードにも、同じルールを適用します
LLM が「本当の問題を修正する」よりも「テストを通す」ことを優先した結果、技術的負債が徐々に蓄積するのを防ぐことが目標です。
クイックリファレンス
# 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
上書きする場合(ほとんどありません)
ベースラインの更新またはルールの無効化が認められる理由は、次のものに限られます。
| シナリオ | 対応 | 必須事項 |
|---|---|---|
| サードパーティがパターンを強制する | ベースラインを更新する | 理由を説明するコードコメント |
| 生成されたコード(編集不可) | 除外リストに追加する | 設定に記録する |
| 意図的なレート制限の遅延 | ベースラインを更新する | テスト内ではなく、コードコメントに記載する |
| レガシーコードのクリーンアップ | 一度限りのベースライン更新 | PR の説明 |
認められない理由:
- 「テストが不安定」→ 不安定さを修正します
- 「警告が煩わしい」→ コードを修正します
- 「自分のマシンでは動く」→ 競合状態を修正します
- 「後で修正する」→ 今すぐ修正します