mcpField
D
dotnet-slopwatch

dotnet-slopwatch

github.com/aaronontheweb测试与质量1.2k564 次安装今天更新
代码仓库

关于 dotnet-slopwatch

dotnet-slopwatch 是用于检查 .NET 代码变更中掩盖真实问题的捷径的技能,尤其适用于 LLM 生成的代码。它通过规则和基线帮助 .NET 开发者识别新增问题。

主要功能

  1. 01检测被禁用的测试和警告抑制
  2. 02标记空 catch 块和测试延迟
  3. 03检查项目设置和包版本绕过
  4. 04用基线跟踪已有问题
  5. 05支持钩子和 CI 质量门禁

适用场景

  1. 01审查 LLM 对 C# 和项目文件的修改
  2. 02在 Claude Code 编辑时阻止新增捷径
  3. 03将 slop 检查加入 CI 流水线

安装

复制下面的命令,在终端中运行。

$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,验证这些修改没有引入“糟粕”。

什么是糟粕?

“糟粕”指 LLM 为了让测试通过或构建成功而采取的捷径,却没有真正解决根本问题。这些行为属于奖励作弊——LLM 追求表面上的成功,而不是切实修复问题。

常见的糟粕模式
模式示例有何问题
禁用测试[Fact(Skip="flaky")]掩盖失败,而不是修复问题
禁用警告#pragma warning disable CS8618消除编译器警告,却没有修复问题
空 catch 块catch (Exception) { }吞掉错误,掩盖 bug
任意延迟await Task.Delay(1000);掩盖竞态条件,让测试变慢
项目级禁用警告<NoWarn>CS1591</NoWarn>在整个项目中禁用警告
绕过 CPM内联 Version="1.0.0"破坏集中式包管理

绝不要接受这些模式。 如果 LLM 引入了糟粕,请拒绝这些修改,并要求进行恰当的修复。


安装

作为本地工具(推荐)

添加到 .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 只检测新引入的糟粕,而不是已有的技术债务。


在 LLM 会话期间的用法

每次代码修改后

每当 LLM 生成的代码有任何修改,都运行 slopwatch:

# Analyze for new issues (uses baseline)
slopwatch analyze

# Use strict mode - fail on warnings too
slopwatch analyze --fail-on warning
Slopwatch 标记问题时

不要忽略它。 而应:

  1. 弄清原因:LLM 为何走了捷径
  2. 要求恰当的修复:明确指出问题所在
  3. 验证修复:确保没有引入其他糟粕
# 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."
更新基线(少见)

只有在糟粕确有合理理由且已有记录时,才更新基线:

# Add current detections to baseline (use sparingly!)
slopwatch analyze --update-baseline

合理理由示例:

  • 第三方库强制要求采用某种模式(例如,必须禁用特定警告)
  • 为限制请求速率而有意延迟(并非为了掩盖测试不稳定)
  • 无法修改的生成代码

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


Claude Code Hook 集成

将 slopwatch 添加为 Hook,以便自动验证每次编辑。创建或更新 .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警告项目文件中的糟粕(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

理念:对新增劣质代码零容忍

  1. 基线记录遗留问题 - 已存在的问题予以承认,但会单独隔离
  2. 阻止新增劣质代码 - 任何新的捷径都会导致构建/编辑失败
  3. 例外情况需要说明理由 - 如果必须更新基线,请说明原因
  4. 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 描述

无效理由:

  • “测试不稳定” → 修复不稳定问题
  • “警告很烦人” → 修复代码
  • “在我的机器上能运行” → 修复竞态条件
  • “以后再修” → 现在就修

评论

支持 Markdown