首页/文章/测试已红还说 done?在新加坡 Mac mini 上用 Stop hook 拦假完成并要证据

测试已红还说 done?在新加坡 Mac mini 上用 Stop hook 拦假完成并要证据

· Zumac.Ai

测试已红,会话却说 done

长任务跑完时,Claude Code 有时会直接宣告「完成」:改动已提交、测试已通过、可以合并。你回头一看终端,测试其实是红的——或者根本没跑。公开讨论里这类「假完成」反复出现:模型在上下文末尾急于收束,把「打算跑通」说成「已经跑通」,却没有把命令输出当成硬证据。

CLAUDE.md 里写「完成前必须跑测试」不够稳;PreToolUse 拦的是工具调用前的危险动作,拦不住「什么都没再跑就宣布结束」。要挡的是会话的停止瞬间,对应机制是 Stop hook:在允许 stop 之前跑你的验收脚本,失败就拒绝结束并要求补证据。

本文只讲 Stop hook 拦假完成;软提示 vs PreToolUse 的分工见此前文章。Claude 账号由你自己开通;机器侧提供稳定合规的使用环境。

Stop hook 和 PreToolUse 差在哪

| 钩子 | 触发时机 | 适合拦什么 | 拦不住什么 | |------|----------|------------|------------| | PreToolUse | 某次工具调用之前 | 危险 Bash、写密钥路径、force-push | 模型根本不再调用工具就说 done | | PostToolUse | 工具调用之后 | 记账、扫日志、二次校验输出 | 会话已决定停止 | | Stop | 会话准备结束时 | 测试/lint/证据清单未过就禁止 stop | 你从未注册 Stop、或脚本 fail-open |

经验法则:

  1. 漏一次会污染仓库或密钥 → PreToolUse(此前文章已写)。
  2. 漏一次会把红构建当成绿 → Stop hook:exit 非零或按文档返回 block,直到证据齐全。
  3. 风格与命名 → 继续放 CLAUDE.md,不要指望它挡住「假 done」。
相关阅读:CLAUDE.md 管风格,硬规则放 hooks、安全 hook 要失败即拦截。本文补的是「完成门」;那两篇补的是「调用前门」与 fail-closed。

在新加坡 Mac mini 上注册 Stop hook

把权威环境固定在一台常开整机上,避免笔记本 A 挂了 Stop、笔记本 B 仍能「口头 done」。用 SSH 或 UU 远程连接进入 Mac mini:

mkdir -p ~/work/your-repo/.claude/hooks
cd ~/work/your-repo
claude --version

1)验收脚本:跑测试 + 要求证据文件

# .claude/hooks/require-green-before-stop.sh
#!/bin/bash
set -euo pipefail
cd "${CLAUDE_PROJECT_DIR:-.}"

# 1. 跑你的最小验收(按项目改成 npm test / pytest / xcodebuild 等)
if ! npm test --silent; then
  echo "Stop blocked: tests are red. Fix failures, then try again." >&2
  exit 2
fi

# 2. 要求会话留下证据(例如测试摘要),避免「口头说绿」
EVIDENCE=".claude/last-verify.txt"
if [[ ! -s "$EVIDENCE" ]]; then
  echo "Stop blocked: missing $EVIDENCE — paste a short test summary there first." >&2
  exit 2
fi

# 3. 证据里至少出现通过标记(按你工具输出改关键字)
if ! grep -Eiq 'pass|ok|succeeded|0 failed' "$EVIDENCE"; then
  echo "Stop blocked: $EVIDENCE has no pass marker." >&2
  exit 2
fi

exit 0
chmod +x .claude/hooks/require-green-before-stop.sh

要点:

  • 失败用 exit 2(或你当前版本文档要求的 block 退出码),让 Stop 被拒绝,而不是静默放行。
  • 证据文件由助手在声称完成前写入;你也可以改成「必须存在 coverage/lcov.info」等更硬的产物。
  • npm test 只是示例;iOS 项目可换成 xcodebuild test 的最小 scheme。目标是可重复、可失败。

2)在 settings.json 挂上 Stop

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/require-green-before-stop.sh",
            "onFailure": "block"
          }
        ]
      }
    ]
  }
}

把这段合并进项目 .claude/settings.json(已有 PreToolUse 时只追加 Stop 键)。字段名以你本机 /hooks 与当前 Claude Code 文档为准;若版本支持 matcher,按文档填写,没有就整段挂在 Stop 上。

安全类脚本建议加 onFailure: "block",避免缺 jq/缺依赖时 fail-open。用 git 提交 hooks 与 settings,日常只在这台 Mac mini 上 git pull 后开 Claude Code。

十分钟验收清单

在仓库根目录启动 Claude Code(避免子目录漏加载项目 settings):

  1. /hooks(或设置里等价入口)能看到 Stop 与脚本路径。
  2. 故意红测:改一处必败断言,让助手「收工」——应被 Stop 拦住,会话不能干净结束。
  3. 故意缺证据:测试改回绿,但不写 .claude/last-verify.txt——仍应被拦。
  4. 绿灯放行:跑通测试、写入带 pass 标记的证据文件,再允许 stop;确认 exit 0。
  5. tmux 挂长会话;SSH 断开再连,hooks 仍在磁盘上,不依赖某一扇本地窗口。

若助手在被拦后改口「跳过测试」,把「禁止跳过 Stop 验收」写进 CLAUDE.md 作提醒,真正拦截仍靠脚本 exit 码。

和自动续跑、权限模式怎么配合

Stop hook 管的是质量门,不是额度空窗:

  • 会话触顶后的 auto-continue / /config 见今日另一篇;续跑回来后,Stop 仍应要求同一套证据。
  • 长任务无人值守时,更要把完成标准写进 Stop,而不是依赖跳过确认类启动参数。
  • 密钥不进明文;MCP 与环境变量继续走钥匙串或受控配置。

这些都是稳定合规的使用环境的一部分:账号合规,完成门也可审计。

为什么固定在新加坡常开 Mac mini

  • 一份完成门:Stop 脚本与 settings.json 只维护一份,远程用 SSH / UU 远程连接进入同一台整机。
  • 长任务不断电:笔记本合盖会睡;常开机器上跑完测试再允许 stop,验收不丢。
  • 整机独享:项目钩子与本地产物路径不与其他客户混用;退租抹机时配置一并结束。
  • 真 macOS 工具链:你拦的 npm test / xcodebuild 与上线环境一致。

Zumac.Ai 提供位于新加坡的实体 Mac mini M6,整机独享,支持 SSH 与 UU 远程连接,FileVault 全盘加密,退租时抹机重装。新客户整机租用 ¥999/月起,季付 ¥2,697.30,半年付 6 送 1 为 ¥5,994,年付 12 送 2 为 ¥11,988;已购买客户续费保持原价。新客户首单自审核开通当天起租,续费及老客户新订单自付款当天起租。建议先租一个月,把「Stop 拦假完成 + 证据文件」在同一台机器上跑通。实际延迟取决于你本地的网络线路。

小结

  • 测试已红仍说 done,是完成门缺失,不是文案写得不够狠。
  • PreToolUse 拦调用前;Stop hook 拦结束瞬间——跑测试、查证据,失败则禁止 stop。
  • 在新加坡常开 Mac mini 上注册脚本与 settings.json,用十分钟清单验收红测/缺证据/绿灯三条路径。
  • 用 SSH 或 UU 远程连接日常接入;完成标准跟仓库走,不跟某一台笔记本走。

有问题可以在 Telegram 联系 @singatao,或直接看 价格与付款周期。

Zumac.Ai 新加坡 Mac mini M6,整机独享,¥999/月起,联系 Telegram @singatao。
查看方案与费用 · 帮助中心

返回首页 · 更多文章

Telegram 客服