dotnet-slopwatch

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Slopwatch: LLM Anti-Cheat for .NET

Slopwatch:面向.NET的LLM反作弊工具

When to Use This Skill

何时使用该工具

Use this skill constantly. Every time an LLM (including Claude) makes changes to:
  • C# source files (.cs)
  • Project files (.csproj)
  • Props files (Directory.Build.props, Directory.Packages.props)
  • Test files
Run slopwatch to validate the changes don't introduce "slop."
**请持续使用该工具。**每当LLM(包括Claude)对以下文件进行变更时:
  • C#源文件(.cs)
  • 项目文件(.csproj)
  • 属性文件(Directory.Build.props、Directory.Packages.props)
  • 测试文件
运行slopwatch来验证变更是否引入了“slop”。

What is Slop?

什么是Slop?

"Slop" refers to shortcuts LLMs take that make tests pass or builds succeed without actually solving the underlying problem. These are reward hacking behaviors - the LLM optimizes for apparent success rather than real fixes.
“Slop”指的是LLM为了让测试通过或构建成功而采取的捷径,但并未真正解决潜在问题。这些属于奖励黑客行为——LLM为了表面上的成功而优化,而非真正修复问题。

Common Slop Patterns

常见的Slop模式

PatternExampleWhy It's Bad
Disabled tests
[Fact(Skip="flaky")]
Hides failures instead of fixing them
Warning suppression
#pragma warning disable CS8618
Silences compiler without fixing issue
Empty catch blocks
catch (Exception) { }
Swallows errors, hides bugs
Arbitrary delays
await Task.Delay(1000);
Masks race conditions, makes tests slow
Project-level suppression
<NoWarn>CS1591</NoWarn>
Disables warnings project-wide
CPM bypass
Version="1.0.0"
inline
Undermines central package management
Never accept these patterns. If an LLM introduces slop, reject the change and require a proper fix.

模式示例危害
禁用测试
[Fact(Skip="flaky")]
掩盖失败而非修复问题
抑制警告
#pragma warning disable CS8618
屏蔽编译器警告但不解决问题
空catch块
catch (Exception) { }
吞噬错误,隐藏bug
任意延迟
await Task.Delay(1000);
掩盖竞态条件,拖慢测试速度
项目级抑制
<NoWarn>CS1591</NoWarn>
全局禁用项目中的警告
绕过CPM
Version="1.0.0"
内联
破坏中央包管理机制
**绝不要接受这些模式。**如果LLM引入了slop,请拒绝变更并要求提供正确的修复方案。

Installation

安装

As a Local Tool (Recommended)

作为本地工具(推荐)

Add to
.config/dotnet-tools.json
:
json
{
  "version": 1,
  "isRoot": true,
  "tools": {
    "slopwatch.cmd": {
      "version": "0.2.0",
      "commands": ["slopwatch"],
      "rollForward": false
    }
  }
}
Then restore:
bash
dotnet tool restore
将以下内容添加到
.config/dotnet-tools.json
json
{
  "version": 1,
  "isRoot": true,
  "tools": {
    "slopwatch.cmd": {
      "version": "0.2.0",
      "commands": ["slopwatch"],
      "rollForward": false
    }
  }
}
然后执行恢复命令:
bash
dotnet tool restore

As a Global Tool

作为全局工具

bash
dotnet tool install --global Slopwatch.Cmd

bash
dotnet tool install --global Slopwatch.Cmd

First-Time Setup: Establish a Baseline

首次设置:建立基线

Before using slopwatch on an existing project, create a baseline of current issues:
bash
undefined
在现有项目中使用slopwatch之前,请创建当前问题的基线:
bash
undefined

Initialize baseline from existing code

从现有代码初始化基线

slopwatch init
slopwatch init

This creates .slopwatch/baseline.json

此命令会创建.slopwatch/baseline.json

git add .slopwatch/baseline.json git commit -m "Add slopwatch baseline"

**Why baseline?** Legacy code may have existing issues. The baseline ensures slopwatch only catches **new** slop being introduced, not pre-existing technical debt.

---
git add .slopwatch/baseline.json git commit -m "Add slopwatch baseline"

**为什么需要基线?**遗留代码可能存在现有问题。基线确保slopwatch仅捕获**新增的**slop,而非预先存在的技术债务。

---

Usage During LLM Sessions

LLM会话期间的使用方法

After Every Code Change

每次代码变更后

Run slopwatch after any LLM-generated code modification:
bash
undefined
在LLM生成任何代码修改后运行slopwatch:
bash
undefined

Analyze for new issues (uses baseline)

分析新增问题(使用基线)

slopwatch analyze
slopwatch analyze

Use strict mode - fail on warnings too

使用严格模式——遇到警告也会失败

slopwatch analyze --fail-on warning
undefined
slopwatch analyze --fail-on warning
undefined

When Slopwatch Flags an Issue

当Slopwatch标记问题时

Do not ignore it. Instead:
  1. Understand why the LLM took the shortcut
  2. Request a proper fix - be specific about what's wrong
  3. Verify the fix doesn't introduce different slop
undefined
**不要忽略它。**请执行以下步骤:
  1. 理解原因:LLM为什么采取了捷径
  2. 要求正确修复——明确指出问题所在
  3. 验证修复:确保修复没有引入其他slop
undefined

Example: LLM disabled a test

示例:LLM禁用了一个测试

❌ SW001 [Error]: Disabled test detected File: tests/MyApp.Tests/OrderTests.cs:45 Pattern: [Fact(Skip="Test is flaky")]
❌ SW001 [Error]: 检测到禁用的测试 文件: tests/MyApp.Tests/OrderTests.cs:45 模式: [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."
undefined
"这个测试被禁用而非修复。请调查它不稳定的原因,并修复潜在的时序/竞态条件问题。"
undefined

Updating the Baseline (Rare)

更新基线(极少情况)

Only update the baseline when slop is truly justified and documented:
bash
undefined
只有当slop真正合理且有文档记录时,才更新基线:
bash
undefined

Add current detections to baseline (use sparingly!)

将当前检测结果添加到基线(谨慎使用!)

slopwatch analyze --update-baseline

**Justification examples:**
- Third-party library forces a pattern (e.g., must suppress specific warning)
- Intentional delay for rate limiting (not test flakiness)
- Generated code that can't be modified

Document why in a code comment when updating baseline.

---
slopwatch analyze --update-baseline

**合理场景示例:**
- 第三方库强制要求的模式(例如,必须抑制特定警告)
- 用于速率限制的有意延迟(非测试中的延迟)
- 无法修改的生成代码

更新基线时,请在代码注释中说明原因。

---

Claude Code Hook Integration

Claude代码钩子集成

Add slopwatch as a hook to automatically validate every edit. Create or update
.claude/settings.json
:
json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "slopwatch analyze -d . --hook",
            "timeout": 60000
          }
        ]
      }
    ]
  }
}
The
--hook
flag:
  • Only analyzes git dirty files (fast, even on large repos)
  • Outputs errors to stderr in readable format
  • Blocks the edit on warnings/errors (exit code 2)
  • Claude sees the error and can fix it immediately

添加slopwatch作为钩子,自动验证每次编辑。创建或更新
.claude/settings.json
json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "slopwatch analyze -d . --hook",
            "timeout": 60000
          }
        ]
      }
    ]
  }
}
--hook
标志的作用:
  • 仅分析git未提交的文件(速度快,即使在大型仓库中)
  • 以可读格式将错误输出到stderr
  • 遇到警告/错误时阻止编辑(退出码2)
  • Claude会看到错误并可以立即修复

CI/CD Integration

CI/CD集成

Add slopwatch to your CI pipeline as a quality gate:
将slopwatch添加到CI流水线中作为质量门:

GitHub Actions

GitHub Actions

yaml
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
yaml
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

Azure Pipelines

yaml
- 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'

yaml
- 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'

Detection Rules

检测规则

RuleSeverityWhat It Catches
SW001ErrorDisabled tests (
Skip=
,
Ignore
,
#if false
)
SW002WarningWarning suppression (
#pragma warning disable
,
SuppressMessage
)
SW003ErrorEmpty catch blocks that swallow exceptions
SW004WarningArbitrary delays in tests (
Task.Delay
,
Thread.Sleep
)
SW005WarningProject file slop (
NoWarn
,
TreatWarningsAsErrors=false
)
SW006WarningCPM bypass (
VersionOverride
, inline
Version
attributes)

规则严重程度检测内容
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
属性)

Configuration

配置

Create
.slopwatch/slopwatch.json
to customize:
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/**"
  ]
}
创建
.slopwatch/slopwatch.json
来自定义配置:
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/**"
  ]
}

Strict Mode (Recommended for LLM Sessions)

严格模式(LLM会话推荐使用)

For maximum protection during LLM coding sessions, elevate all rules to errors:
json
{
  "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" }
  }
}

在LLM编码会话中,为了获得最大保护,请将所有规则提升为错误级别:
json
{
  "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" }
  }
}

The Philosophy: Zero Tolerance for New Slop

理念:零容忍新增Slop

  1. Baseline captures legacy - Existing issues are acknowledged but isolated
  2. New slop is blocked - Any new shortcut fails the build/edit
  3. Exceptions require justification - If you must update baseline, document why
  4. LLMs are not special - The same rules apply to human and AI-generated code
The goal is to prevent the gradual accumulation of technical debt that occurs when LLMs optimize for "make the test pass" rather than "fix the actual problem."

  1. 基线覆盖遗留问题——已存在的问题被确认但隔离
  2. 新增Slop被阻止——任何新的捷径都会导致构建/编辑失败
  3. 例外情况需要理由——如果必须更新基线,请记录原因
  4. LLM不享有特殊待遇——规则对人类和AI生成的代码同样适用
目标是防止LLM为了“让测试通过”而非“修复实际问题”而导致的技术债务逐渐累积。

Quick Reference

快速参考

bash
undefined
bash
undefined

First time setup

首次设置

slopwatch init git add .slopwatch/baseline.json
slopwatch init git add .slopwatch/baseline.json

After every LLM code change

每次LLM代码变更后

slopwatch analyze
slopwatch analyze

Strict mode (recommended)

严格模式(推荐)

slopwatch analyze --fail-on warning
slopwatch analyze --fail-on warning

With stats (performance debugging)

带统计信息(性能调试)

slopwatch analyze --stats
slopwatch analyze --stats

Update baseline (rare, document why)

更新基线(极少情况,记录原因)

slopwatch analyze --update-baseline
slopwatch analyze --update-baseline

JSON output for tooling

为工具输出JSON格式结果

slopwatch analyze --output json

---
slopwatch analyze --output json

---

When to Override (Almost Never)

何时可以覆盖规则(几乎从不)

The only valid reasons to update baseline or disable a rule:
ScenarioActionRequired
Third-party forces patternUpdate baselineCode comment explaining why
Generated code (not editable)Add to exclude listDocument in config
Intentional rate limiting delayUpdate baselineCode comment, not in test
Legacy code cleanupOne-time baseline updatePR description
Invalid reasons:
  • "The test is flaky" → Fix the flakiness
  • "The warning is annoying" → Fix the code
  • "It works on my machine" → Fix the race condition
  • "We'll fix it later" → Fix it now
更新基线或禁用规则的唯一有效理由:
场景操作要求
第三方库强制要求的模式更新基线代码注释说明原因
生成的代码(不可编辑)添加到排除列表在配置中记录
有意的速率限制延迟更新基线代码注释,且不在测试中
遗留代码清理一次性更新基线PR描述中说明
无效理由:
  • “测试不稳定” → 修复不稳定问题
  • “警告很烦” → 修复代码
  • “在我机器上能运行” → 修复竞态条件
  • “我们以后再修” → 现在就修