代码质量哨兵Skill dotnet-slopwatch

Slopwatch是一款专门用于检测和阻止AI代码助手(如LLM)在.NET开发中引入“奖励黑客”行为的工具。它能自动扫描C#代码变更,识别并标记那些为了表面通过测试而采取的快捷方式,例如禁用测试、抑制警告、空的异常捕获块、任意延迟等不良实践。该工具通过建立基线来区分遗留问题和新引入的缺陷,并可与CI/CD管道及Claude等AI助手集成,实现自动化代码质量门禁,确保AI生成的代码符合高质量标准,防止技术债务的隐形积累。关键词:AI代码审查,.NET代码质量,LLM反作弊,奖励黑客检测,自动化测试,DevOps工具,C#静态分析,技术债务预防。

测试 0 次安装 0 次浏览 更新于 2/26/2026

名称: dotnet-slopwatch 描述: 使用Slopwatch检测.NET代码变更中的LLM奖励黑客行为。每次代码修改后运行,捕获被禁用的测试、被抑制的警告、空的catch块以及其他掩盖真实问题的快捷方式。 可调用: true

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) { } 吞掉错误,隐藏bug
任意延迟 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.2.0",
      "commands": ["slopwatch"],
      "rollForward": false
    }
  }
}

然后恢复:

dotnet tool restore

作为全局工具

dotnet tool install --global Slopwatch.Cmd

首次设置:建立基线

在现有项目上使用slopwatch之前,创建当前问题的基线:

# 从现有代码初始化基线
slopwatch init

# 这会创建 .slopwatch/baseline.json
git add .slopwatch/baseline.json
git commit -m "添加slopwatch基线"

为什么需要基线? 遗留代码可能存在现有问题。基线确保slopwatch只捕获引入的slop,而不是预先存在的技术债务。


在LLM会话期间的使用

每次代码更改后

在任何LLM生成的代码修改后运行slopwatch:

# 分析新问题(使用基线)
slopwatch analyze

# 使用严格模式 - 警告也导致失败
slopwatch analyze --fail-on warning

当Slopwatch标记问题时

不要忽略它。 相反:

  1. 理解为什么 LLM采取了快捷方式
  2. 请求适当的修复 - 明确指出问题所在
  3. 验证修复 没有引入不同的slop
# 示例:LLM禁用了测试
❌ SW001 [错误]: 检测到被禁用的测试
   文件: tests/MyApp.Tests/OrderTests.cs:45
   模式: [Fact(Skip="Test is flaky")]

# 正确回应:要求实际修复
"这个测试被禁用了而不是修复。请调查为什么
它是flaky的,并修复底层的时序/竞态条件问题。"

更新基线(罕见)

仅在slop确实合理且有文档记录时更新基线:

# 将当前检测添加到基线(谨慎使用!)
slopwatch analyze --update-baseline

合理理由示例:

  • 第三方库强制使用某种模式(例如,必须抑制特定警告)
  • 用于速率限制的故意延迟(不在测试中)
  • 无法修改的生成代码

更新基线时在代码注释中记录原因。


Claude代码钩子集成

将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: 设置 .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '9.0.x'

      - name: 安装 Slopwatch
        run: dotnet tool install --global Slopwatch.Cmd

      - name: 运行 Slopwatch
        run: slopwatch analyze -d . --fail-on warning

Azure Pipelines

- task: DotNetCoreCLI@2
  displayName: '安装 Slopwatch'
  inputs:
    command: 'custom'
    custom: 'tool'
    arguments: 'install --global Slopwatch.Cmd'

- script: slopwatch analyze -d . --fail-on warning
  displayName: 'Slopwatch 分析'

检测规则

规则 严重性 捕获内容
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/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会话)

为了在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" }
  }
}

理念:对新Slop零容忍

  1. 基线捕获遗留问题 - 现有问题被承认但隔离
  2. 新slop被阻止 - 任何新的快捷方式都会导致构建/编辑失败
  3. 例外需要理由 - 如果必须更新基线,请记录原因
  4. LLM没有特权 - 相同的规则适用于人类和AI生成的代码

目标是防止当LLM优化“让测试通过”而不是“解决实际问题”时逐渐积累的技术债务。


快速参考

# 首次设置
slopwatch init
git add .slopwatch/baseline.json

# 每次LLM代码更改后
slopwatch analyze

# 严格模式(推荐)
slopwatch analyze --fail-on warning

# 带统计信息(性能调试)
slopwatch analyze --stats

# 更新基线(罕见,记录原因)
slopwatch analyze --update-baseline

# JSON输出用于工具化
slopwatch analyze --output json

何时覆盖(几乎从不)

更新基线或禁用规则的唯一有效理由:

场景 操作 要求
第三方强制模式 更新基线 代码注释解释原因
生成代码(不可编辑) 添加到排除列表 在配置中记录
故意的速率限制延迟 更新基线 代码注释,不在测试中
遗留代码清理 一次性基线更新 PR描述

无效理由:

  • “测试是flaky的” → 修复flakiness
  • “警告很烦人” → 修复代码
  • “在我机器上能工作” → 修复竞态条件
  • “我们稍后会修复” → 现在就修复