第 10 天:实操——把 sdd-harness 装进测试仓库并体验提交被拦

SDD+Harness 四周学习计划 · Week 2 · Day 10

Posted by LSG on August 19, 2026

SDD + Harness 四周学习计划 · Week 2 · Day 10(全计划第 10 课)

今日主题:实操:安装 harness——clone sdd-harness 到测试仓库,装 pre-commit hook,体验「改了代码没写 spec → 提交被拦」

建议用时:60–90 分钟 | 前置:Day 9 的 .ai/ 结构精读;本地已 clone sdd-harness;熟悉 Git 基础命令

输出物:一个已装好 harness 的测试仓库 + 一次「被拦截」的提交尝试记录(git log / 终端输出留痕)


0. 一句话剧透

前两天的纸面功夫今天落地。你把 sdd-harness 装进一个专门用来破坏的测试仓库,然后做一件很反直觉的事:故意在 feat 分支上只改代码、不写 spec,然后提交——等着被 pre-commit hook 拦下来。

被拦不是失败,被拦是今天的目标。只有亲眼看见「改了代码没写 spec → 提交被拒」,你才算真正理解了护栏三「事后验证」不是概念,是机制。


1. 今日目标(学完你能做到)

  • 能独立在测试仓库里安装 sdd-harness(两种方式至少跑通一种)
  • 能确认 .ai/ 目录已生成、pre-commit hook 已生效
  • 能复述 pre-commit hook 的判定规则(哪些分支拦、哪些豁免、显式例外是什么)
  • 亲手制造一次「被拦截」的提交,并读懂终端输出
  • 能说出 post-commit hook 与 pre-commit hook 的分工(拦 vs 记)
  • 完成实操记录:把被拦截的输出贴进学习笔记

对应计划 Day 10 主题:实操:安装 harness。今天起你有一个「自己的 harness」——Week 3、Week 4 都会用到它。


2. 学习动线(时间盒)

步骤 内容 用时
1 准备工作:建测试仓库 + 确认 clone 10 分钟
2 安装方式 A(bootstrap.sh 一键)或方式 B(clone + install.sh) 15–20 分钟
3 验证安装:.ai/ 结构 + hook 生效 10 分钟
4 精读「6」:pre-commit hook 判定规则 10 分钟
5 实操:体验「改了代码没写 spec → 被拦」 15 分钟
6 观察 post-commit trace + 记录 + 打卡 10 分钟

本日命令全部在测试仓库里执行。不要拿真实项目试——今天的目标就是故意制造「非法提交」。


3. 准备工作:建测试仓库

开一个终端,在安全的位置建测试仓库(不要建在你的真实项目里):

1
2
3
4
5
6
7
8
9
10
11
# ① 建目录并初始化
mkdir harness-test
cd harness-test
git init

# ② 放一个最简「代码」文件(generic 栈,够用)
echo "print('hello from harness-test')" > app.py

# ③ 初始提交(注意:此时默认分支通常是 main/master,见下节 hook 规则)
git add .
git commit -m "chore: init test repo"

确认你本地已有 Day 7 预习时 clone 的 sdd-harness;没有的话现在补:

1
git clone https://github.com/iMark21/sdd-harness

小知识:git init 后的默认分支名取决于你的 Git 配置(mainmaster)。sdd-harness 的日常分支是 develop,后面切分支时留意。


4. 安装方式 A:bootstrap.sh 一键脚本

README 提供的一键安装(在测试仓库根目录执行):

1
curl -sSL https://raw.githubusercontent.com/iMark21/sdd-harness/main/bootstrap.sh | bash -s -- --stack generic
  • --stack 指定技术栈:python / swift / android / node / go / rust / generic
  • 测试仓库没有具体技术栈,用 generic 即可
  • 脚本从 GitHub 拉取并执行,如果你所在网络访问 GitHub 受限,见方式 B 或自行配置代理

5. 安装方式 B:clone + install.sh + init

如果你已经 clone 了 sdd-harness(Day 7 预习动作),可以走本地安装:

1
2
3
4
# 在 sdd-harness 仓库目录里运行安装脚本
cd sdd-harness
./install.sh          # 安装脚本,具体参数以仓库 README 为准
sdd-harness init      # 初始化命令(由安装脚本提供到 PATH)

init 之后回到测试仓库目录,确认 .ai/ 已生成:

1
2
cd ../harness-test
ls -a .ai

两种方式跑通一种即可。若安装脚本行为与上述描述有出入,以仓库 README 与脚本实际输出为准(本讲义未逐行核验安装脚本源码,细节标「待核验」)。


6. pre-commit hook 的判定规则(先看懂再动手)

hook 是 hooks/pre-commit-spec-check.sh。它不是一个「无脑拦所有提交」的脚本,判定规则如下(已核验):

场景 结果
feat/*feature/* 分支上,改了代码,但没有改动 .ai/specs/.ai/adrs/ 提交被拒
chore/*docs/*fix/*hotfix/* 分支上 豁免(不检查)
设了环境变量 SH_SDD_SKIP=1 显式例外,放行(且 shell 历史会留下痕迹)

两个关键点:

  1. 它检查的是「你有没有碰 spec/ADR」,不是「spec 写得好不好」。 守门守的是「spec-first 这个动作有没有发生」,内容质量靠 review(Day 11 的 review 命令)把关。
  2. 被拦在哪个分支、被豁免在哪个分支,是写死的规则——这也是为什么 Day 9 说「规则是机制,不是自觉」。

术语回顾:这就是 spec-first 的强制形态——spec 先于/伴随代码进入提交,hook 保证「只改代码」过不了门。


7. 实操:体验「改了代码没写 spec → 提交被拦」

7.1 先按规范起分支

1
2
3
# 从 develop 起一个 feat 分支(若仓库没有 develop,先创建)
git checkout -b develop 2>/dev/null || git checkout develop
git checkout -b feat/notify

7.2 只改代码,不碰 .ai/specs/ 与 .ai/adrs/

1
2
3
echo "print('v2 - notify feature')" >> app.py
git add app.py
git commit -m "feat: 增加通知功能"

7.3 预期与记录

  • 预期:提交被拒。hook 判定你处于 feat/* 分支、改了代码、没动 .ai/specs/.ai/adrs/ → 拦截。
  • 把终端输出原样复制进学习笔记(这是今天的核心产出)。
  • 被拒后检查:git log --oneline——刚才那条提交不存在,你的代码改动还在工作区/暂存区,没有被丢。

提示:拒绝信息的具体文案以你实际安装版本为准(本讲义未核验逐字文本,标「待核验」)。你只需要确认两件事:①提交被拒;②被拒原因是「改了代码但没写 spec/ADR」。

7.4 顺便验证豁免分支

1
2
git checkout -b fix/typo          # 从当前分支切出 fix 分支
git commit -m "fix: 修正文案"      # 先 add 好改动
  • 预期:放行。fix/* 分支在豁免名单里,hook 不拦。
  • 这条提交成功,恰好反衬出 7.3 的拦截是「规则使然」而不是「hook 坏了」。

8. 提交成功后的 post-commit 观察

当你做出一条合法提交(比如 7.4 的 fix 提交,或后续补了 spec 的提交),观察终端里 post-commit hook 的输出:

  • post-edit-trace.sh:被动打印本次提交涉及了哪些 spec / ADR / 代码文件。
  • 不拦截——只做「痕迹记录」,让每次提交和 spec/ADR/代码的对应关系可追溯。

对比记忆:pre-commit 是「守门员」(拦),post-commit 是「记录员」(记)。 一个管「能不能过」,一个管「过了要留痕」。


9. 今日实操记录模板(提交进学习笔记)

1
2
3
4
5
# Day 10 实操记录:安装 harness + 体验被拦
日期:______ 测试仓库路径:______
安装方式:□ bootstrap.sh(--stack: ___) □ clone + install.sh + init
验证 .ai/ 目录:□ 已生成(列出你看到的子目录:______)
被拦截输出(原样粘贴):
<粘贴终端输出> ``` 我确认的三件事: 1. 提交被拒,git log 里没有这条提交:□ 2. 被拒原因指向「改了代码但没写 spec/ADR」:□ 3. fix/* 分支豁免生效(或 SH_SDD_SKIP 例外,Day 13 再测):□ ``` > 这份记录就是 Day 13「跑通 spec-first 提交三态」的前置条件——Day 13 你要在同一仓库里做放行 / 拦截 / SH_SDD_SKIP 三态对比。 --- ## 自测题 1. sdd-harness 的两种安装方式分别是什么?(简答) 2. `--stack` 参数的作用是什么?测试仓库该用什么值?(简答) 3. pre-commit hook 在什么条件下**拦截**提交?(简答) 4. 哪些分支**豁免**检查?(填空:`chore/*`、`docs/*`、`fix/*`、`___`) 5. `SH_SDD_SKIP=1` 的作用是什么?它和「豁免分支」有什么区别?(简答) 6. 判断:hook 会检查你写的 spec 内容质量,写得不合格也会被拦。(判断——正确答案:否,它只检查「有没有碰 spec/ADR」) 7. 判断:提交被拦后,你的代码改动会丢失。(判断——正确答案:否,改动还在) 8. 选择题:post-commit hook 的作用是: A. 拦截非法提交 B. 被动打印本次提交涉及的 spec/ADR/代码 C. 自动生成 spec D. 推送代码到远程 9. 为什么今天要求用「测试仓库」而不是真实项目?(简答) 10. 一句话:pre-commit 与 post-commit 的分工是什么?(简答) > 提示:第 5 题——豁免是「这类分支不检查」,SH_SDD_SKIP 是「这次提交我明确声明跳过」,后者会在 shell 历史留痕。 --- ## 延伸阅读 - sdd-harness 仓库(安装说明、README、hooks 源码都在这里):https://github.com/iMark21/sdd-harness - 《SDD 和 Harness:AI 编程的两大支柱》(Hooks 护栏的出处,回头对照「事后验证」):https://blog.csdn.net/qq_43284469/article/details/164267908 - 《AI 编程可闭环协作·卷三:Harness 与 SDD》(合并前自动检查,和今天 hook 的关系,Week 4 精读):https://juejin.cn/post/7647333934796537919 --- *本工作纸依据《SDD+Harness四周学习计划.md》Day 10 主题编制。整理日期:2026-09-09*