1
00:00:00,100 --> 00:00:06,432
本内容改编自小山学堂《学 AI 产品，从入门到精通》，为二次演绎配音版。

2
00:00:06,382 --> 00:00:13,677
这一集讲一套特别适合直接抄走的工程方法论，用 AI 开发 AI 的时候，怎么防止团队失忆。

3
00:00:13,677 --> 00:00:19,759
先把问题说清楚，这个问题在大规模用 AI 写代码的仓库里格外尖锐。

4
00:00:19,759 --> 00:00:24,362
AI 每次会话都是新的，它不记得上个月否决过什么。

5
00:00:24,362 --> 00:00:29,639
人也一样，三个月前为什么否掉某个方案，早忘干净了。

6
00:00:29,639 --> 00:00:38,209
这两件事叠在一起的结果就是，同一个坏主意被反复提出，同一段代码被反复重构回去，来回拉锯。

7
00:00:38,209 --> 00:00:44,579
文档呢，写了没人更新，慢慢就烂掉了，最后变成一个谁都不敢信的东西。

8
00:00:44,579 --> 00:00:47,500
这套系统的答案是两份东西。

9
00:00:47,500 --> 00:00:55,024
一套会流转的设计笔记，记两件代码和文档装不下的事，为什么这么做，以及放弃了什么。

10
00:00:55,024 --> 00:01:02,415
一份给 AI 看的行为守则，把仓库的硬规矩写成 AI 每次会话都会读到的标准指令。

11
00:01:02,415 --> 00:01:07,427
先说清楚这集的实用价值，它给的是能立刻动手的东西。

12
00:01:07,427 --> 00:01:12,584
结尾我会给三步，半天工作量就能在你自己仓库里搭起来。

13
00:01:12,720 --> 00:01:14,232
先看笔记。

14
00:01:14,182 --> 00:01:20,684
每篇笔记的路径就是它的完整身份，生命周期斜杠类别斜杠日期加主题。

15
00:01:20,684 --> 00:01:28,533
就这么一个路径，把状态、类别、时间、主题全说清楚了，不用打开文件就知道它是什么。

16
00:01:28,533 --> 00:01:32,031
生命周期是顶层文件夹，四个。

17
00:01:32,031 --> 00:01:36,670
提案状态，实施前评审，本地快照里二十五篇。

18
00:01:36,670 --> 00:01:43,232
已实施状态，决策已交付，五百零六篇，这是与代码同步的活文档。

19
00:01:43,232 --> 00:01:48,052
已否决状态，否决后冻结，十一篇，管它叫疫苗。

20
00:01:48,052 --> 00:01:53,052
归档层，一百四十二篇，永久冻结的历史，是化石层。

21
00:01:53,052 --> 00:02:00,444
类别是嵌套文件夹，六种，特性、缺陷修复、简化、架构、流程、测试。

22
00:02:00,444 --> 00:02:04,374
这是个封闭集合，多一种都会被门禁拒绝。

23
00:02:04,374 --> 00:02:10,576
为什么要封闭，后面讲遍历的时候你会明白，放错地方的笔记会对遍历隐身。

24
00:02:10,576 --> 00:02:16,790
每篇笔记还配中文对侧文件和一份一致性记录，这是双语纪律的一部分。

25
00:02:16,790 --> 00:02:23,677
中文不是翻译完就完事，两侧要一起维护，改了一侧没同步另一侧，门禁会变红。

26
00:02:23,677 --> 00:02:29,050
这里有个数字值得停下来感受一下，五百零六篇已实施笔记。

27
00:02:29,050 --> 00:02:32,956
这不是一个文档库，这是一部项目编年史。

28
00:02:32,956 --> 00:02:42,523
一个仓库能把五百多个决策连同它们击败了谁一起记下来，后来者和 AI 上手时能省掉的摸索，是没法用小时计算的。

29
00:02:42,523 --> 00:02:48,785
状态怎么流转，答案特别朴素，换状态就是移动文件加改 Status 行。

30
00:02:48,785 --> 00:02:54,194
这两件事必须在同一个变更里完成，门禁会交叉检查。

31
00:02:54,194 --> 00:02:59,699
从提案转已实施的时候，提案章节要改写成现在时的决策章节。

32
00:02:59,699 --> 00:03:08,317
注意这个时态变化，它逼着你把「我们打算这么做」改写成「我们现在这么做」，这在心理上是完全不同的一件事。

33
00:03:08,470 --> 00:03:18,095
然后是那条硬规矩，写在根 AGENTS.md 第一百二十二行：非平凡变更必须在同一个 PR 里新增或更新至少一篇笔记。

34
00:03:18,045 --> 00:03:19,800
什么算非平凡？

35
00:03:19,800 --> 00:03:29,211
改了行为、架构、跨包约定、流程工具、磁盘格式、协议格式，或者任何维护者日后可能重新审视的决策。

36
00:03:29,211 --> 00:03:32,264
只有纯机械的局部编辑才豁免。

37
00:03:32,264 --> 00:03:39,295
这个清单给的是判断标准不是感觉，你不用去争论这次改算不算大，对照清单一看就知道。

38
00:03:39,295 --> 00:03:43,586
关键在于笔记跟代码走同一个评审、同一次合并。

39
00:03:43,586 --> 00:03:49,391
这一句解决了文档体系最常见的死法，代码先上、文档欠着。

40
00:03:49,391 --> 00:03:56,627
欠着的文档永远不会补，因为它没有截止日期，也没有人会因为它在评审里打回你。

41
00:03:56,627 --> 00:04:02,420
一旦把它钉进同一个 PR，它就变成合并的前置条件，不写就合不进去。

42
00:04:02,420 --> 00:04:06,002
每篇笔记还必须有一节，备选方案考虑。

43
00:04:06,002 --> 00:04:10,281
这一节要求列出每个真实的备选方案和落选原因。

44
00:04:10,281 --> 00:04:17,456
文档里第一百一十五行的原话是，记录决策时不记录它击败了什么，就是在邀请反复争论。

45
00:04:17,456 --> 00:04:20,148
这一节才是防失忆的核心。

46
00:04:20,148 --> 00:04:26,903
下次有人或者 AI 提出同样的方案，翻开笔记就能看到它当年输给了谁、为什么。

47
00:04:26,903 --> 00:04:32,793
不是「我们考虑过」这种含糊的说法，是有名字、有理由的具体记录。

48
00:04:32,950 --> 00:04:36,049
被否决的提案怎么处理，删掉吗。

49
00:04:35,999 --> 00:04:40,506
答案是冻结保存，这就是十一篇 rejected 笔记的来历。

50
00:04:40,506 --> 00:04:44,304
但保留有门槛，不是所有被否决的都留。

51
00:04:44,304 --> 00:04:50,073
只有决策依据还能防住一种诱人且影响重大的错误，才留下来。

52
00:04:50,073 --> 00:04:56,035
否则三个文件一起删，英文、中文、一致性记录，一个不留。

53
00:04:56,035 --> 00:05:03,751
这个门槛很重要，否则 rejected 目录会变成一个什么破烂都往里塞的垃圾场，很快就没人看了。

54
00:05:03,751 --> 00:05:11,047
留下来的一定是那种，你看到就会想这么干很合理啊，然后翻到结论发现当年踩过的坑。

55
00:05:11,047 --> 00:05:17,092
结论写在 Status 行的第一眼就能看到的位置，不是埋在正文里让人去翻。

56
00:05:17,092 --> 00:05:18,727
再看归档层。

57
00:05:18,727 --> 00:05:28,847
指导价值降低的已实施笔记移入归档层后永久冻结，禁止编辑、禁止翻译、禁止移动、禁止删除，清单只追加。

58
00:05:28,847 --> 00:05:34,676
这一层的哲学特别值得说一句，历史是证据，改过的证据不能作证。

59
00:05:34,676 --> 00:05:38,342
你改一份历史文档，等于修改了证据链。

60
00:05:38,342 --> 00:05:43,811
以后有人追溯为什么当年这么决定，看到的是被修饰过的版本。

61
00:05:43,811 --> 00:05:48,991
所以归档层宁可让它变得不方便，也要保证它不可篡改。

62
00:05:49,150 --> 00:05:53,066
这套体系没有停在文档层面，它有门禁。

63
00:05:53,016 --> 00:05:59,314
一个九十四行的校验脚本，是文档同步门禁的一环，持续集成每次都跑。

64
00:05:59,314 --> 00:06:04,602
它的规则表定义了每个生命周期的 Status 行语法和必填章节。

65
00:06:04,602 --> 00:06:09,338
提案状态必须有提案、验收标准、风险三节。

66
00:06:09,338 --> 00:06:13,160
已实施状态必须有决策、影响两节。

67
00:06:13,160 --> 00:06:15,768
已否决状态必须有提案节。

68
00:06:15,768 --> 00:06:18,617
所有笔记都必须以问题开头。

69
00:06:18,617 --> 00:06:25,155
注意已否决状态的正则，Status 行必须带一行拒绝理由，光写个已否决过不了。

70
00:06:25,155 --> 00:06:30,660
这个细节很妙，它强制你写下为什么，而不是只记录一个结果。

71
00:06:30,660 --> 00:06:39,771
规则表下面还有一条禁令，已实施的笔记里不许出现提案、计划、迁移计划、验收标准这类提案腔的标题。

72
00:06:39,771 --> 00:06:45,900
理由是已实施笔记描述的是现在时的事实，计划早就该兑现成决策了。

73
00:06:45,900 --> 00:06:52,643
留着提案腔的标题，说明这篇笔记的流转没走完，或者走完了但没清理干净。

74
00:06:52,643 --> 00:06:57,078
所以门禁查的不只是格式，它查的是流转的完整性。

75
00:06:57,078 --> 00:07:02,102
一篇笔记是不是真的走完了它该走的路，看标题就知道。

76
00:07:02,250 --> 00:07:08,425
还有一个反直觉的设计，这六百八十四篇活跃与归档笔记，没有目录。

77
00:07:08,375 --> 00:07:12,089
没有 INDEX.md，没有任何集中式索引。

78
00:07:12,089 --> 00:07:16,681
目录树本身就是清单，检索靠文件夹加全文搜索。

79
00:07:16,681 --> 00:07:24,637
有人想建索引怎么办，结构检查脚本遍历根目录时专门盯着这个文件名，一旦出现直接报错。

80
00:07:24,637 --> 00:07:33,063
错误文案把话说死，集中式的笔记索引被禁止，请浏览生命周期与类别的目录树，或全仓库搜索。

81
00:07:33,063 --> 00:07:34,782
为什么要这么绝。

82
00:07:34,782 --> 00:07:42,510
因为集中式索引是最容易腐烂的文档，每加一篇笔记都要记得更新它，忘一次它就开始撒谎。

83
00:07:42,510 --> 00:07:51,633
而一份会撒谎的索引比没有索引更糟，没有索引你至少知道要去搜，有索引你会信它，然后漏掉它没记的东西。

84
00:07:51,633 --> 00:07:54,830
删掉索引，腐烂的可能性就为零。

85
00:07:54,830 --> 00:08:03,243
同一个循环还顺手把生命周期集合钉成了封闭集，任何不认识的顶层文件夹都会报未知生命周期。

86
00:08:03,243 --> 00:08:16,464
回到前面留的那个问题，为什么要封闭，因为遍历是按照已知的生命周期去扫的，你放到一个它不认识的文件夹里，这篇笔记就对遍历隐身了，门禁查不到，人也找不到。

87
00:08:16,464 --> 00:08:21,236
这个禁令本身也是一篇笔记，存在已实施流程目录下。

88
00:08:21,236 --> 00:08:27,883
这很有意思，一个禁止某种文档的决定，自己也遵守了必须有笔记的规矩。

89
00:08:28,030 --> 00:08:34,794
再看另一半，根目录的 AGENTS.md，一百四十九行，AI 每次会话都会加载。

90
00:08:34,744 --> 00:08:39,276
它的约定一节值得逐条抄，挑四条最有代表性的。

91
00:08:39,276 --> 00:08:41,836
第一条，信任类型边界。

92
00:08:41,836 --> 00:08:50,009
在类型化的同进程边界上信任 TypeScript，别为静态接口已经保证的值再写运行时校验和防御测试。

93
00:08:50,009 --> 00:08:57,821
校验只放在真正的边界上，配置解析、模型返回的 JSON、磁盘文件、进程与协议边界。

94
00:08:57,821 --> 00:09:03,819
这条的价值在于它同时说了两件事，哪里不用写，以及哪里必须写。

95
00:09:03,819 --> 00:09:06,379
只说一边的规范等于没说。

96
00:09:06,379 --> 00:09:09,985
第二条，插件里不许硬编码可调参数。

97
00:09:09,985 --> 00:09:16,788
随部署变化的选择必须是配置文件里可改的字段，一个默认值常量不算可配置。

98
00:09:16,788 --> 00:09:21,151
协议常量和安全不变量除外，那些就该焊死。

99
00:09:21,151 --> 00:09:24,324
第三条，配置错了就大声失败。

100
00:09:24,324 --> 00:09:33,170
能在加载时发现的错配就在加载时抛，不行也要在最早能解析的时刻抛，绝不静默跳过一个缺失的引用。

101
00:09:33,170 --> 00:09:35,946
第四条，空 catch 必须署名。

102
00:09:35,946 --> 00:09:43,470
吞掉了什么异常、为什么别的异常到不了这里，都要写出来，而且 try 块只许一条语句。

103
00:09:43,470 --> 00:09:47,268
这四条有个共同点，每一条都能被检查。

104
00:09:47,268 --> 00:09:52,208
要么门禁能查，要么评审者扫一眼就能判断违没违反。

105
00:09:52,208 --> 00:09:57,341
像代码要优雅这种写了等于没写的口号，一条都没有。

106
00:09:57,341 --> 00:10:01,163
文档本身也不是法外之地，也有自己的门禁。

107
00:10:01,163 --> 00:10:10,093
词数预算，根 AGENTS.md 不超过一千六百词，超了门禁变红，要么把内容挪去它该在的层级，要么压缩。

108
00:10:10,093 --> 00:10:19,180
这条的深意在于，给 AI 看的规范如果太长，它根本读不进去，所以超预算不是排版问题，是有效性问题。

109
00:10:19,180 --> 00:10:25,021
一个事实一个家，同一条规则只许有一个权威出处，别处只放链接。

110
00:10:25,021 --> 00:10:32,569
这条特别重要，同一条规则写两处，两处就会慢慢分叉，最后没人知道哪个是对的。

111
00:10:32,569 --> 00:10:43,747
双语配对，每份文档是英文、中文加一份配对记录三个文件，记录里存两侧的 git 对象哈希，改了任何一侧没重新确认配对，门禁变红。

112
00:10:43,747 --> 00:10:48,867
这些门禁统一由一个命令驱动，完整清单在门禁脚本里。

113
00:10:48,867 --> 00:10:54,143
也就是说文档纪律不是靠自觉，是靠持续集成变红。

114
00:10:54,290 --> 00:10:58,002
最后是横向对比和落地步骤，放一起讲。

115
00:10:57,952 --> 00:10:59,454
先看别家。

116
00:10:59,454 --> 00:11:04,754
Claude Code 闭源，决策记录散在博客、发布说明和代码注释里。

117
00:11:04,754 --> 00:11:14,839
还原源码里能看到一类很有价值的注释，比如带生产数据的断路器注释，这是嵌在代码里的微型决策记录，质量不低。

118
00:11:14,839 --> 00:11:22,206
但没有状态、没有格式门禁、没法按生命周期检索，被否决的方案更是基本无处可查。

119
00:11:22,206 --> 00:11:30,872
Grok Build 基于已核对的本地快照，仓库里没有等价的设计笔记目录，决策依据主要在模块注释和提交历史里。

120
00:11:30,872 --> 00:11:37,903
模块注释写得不错，每个模块开头一句职责说明，但被否决的方案这个维度是缺失的。

121
00:11:37,903 --> 00:11:41,954
那十一篇 rejected 笔记在三家对比里是独一份。

122
00:11:41,954 --> 00:11:52,591
OpenAI Codex 把约束写成仓库根 AGENTS.md 的硬性禁令，再配一份会把同一节重读一遍的评审 skill，这条线比这套系统更硬。

123
00:11:52,591 --> 00:11:59,430
缺的是另一半，没有已否决目录，某次改动为何撤回，后来者只能去代码里倒推。

124
00:11:59,430 --> 00:12:02,146
落到你自己团队，三步。

125
00:12:02,146 --> 00:12:07,891
第一，在仓库里建 notes 目录加四个文件夹，文件名带日期和主题。

126
00:12:07,891 --> 00:12:18,492
第二，定死格式，标题、Status 行、Problem 开头、备选方案必填，照那十几行规则写个校验脚本挂进持续集成，半天工作量。

127
00:12:18,492 --> 00:12:28,000
第三，在你的 AGENTS.md 里立三到五条能被机器或评审检查的硬契约，从怎样的改动必须附笔记这条开始。

128
00:12:28,000 --> 00:12:32,735
数量别贪多，这套系统也是从少量规则长起来的。

129
00:12:32,735 --> 00:12:36,077
第三步可以做个小练习，只写五条。

130
00:12:36,077 --> 00:12:48,096
要求很具体，每条不超过三行，每条要么能写成脚本查，要么评审者十秒内能判断违没违反，其中必须有一条规定什么样的改动必须附设计笔记。

131
00:12:48,096 --> 00:12:53,829
写完之后做个测试，把五条拿给同事看，问他们哪条没法执行。

132
00:12:53,829 --> 00:13:01,028
这个测试特别有效，因为它模拟的是真实的执行场景，而不是写规范时的自我感觉。

133
00:13:01,028 --> 00:13:04,538
凡是同事说没法执行的，删掉重写。

134
00:13:04,538 --> 00:13:06,629
再留一个推演给你。

135
00:13:06,629 --> 00:13:15,572
假设有人把一篇提案笔记直接移动到已实施目录，没改 Status 行，也没把提案章节改写成决策章节。

136
00:13:15,572 --> 00:13:18,841
对照那张规则表，门禁会报出什么。

137
00:13:18,841 --> 00:13:28,805
答案是三条，Status 行不匹配已实施的正则，缺少决策和影响两个必填章节，以及保留着提案这个属于提案状态的标题。

138
00:13:28,805 --> 00:13:30,367
三处全中。

139
00:13:30,367 --> 00:13:42,519
为什么门禁要求移动文件和改内容发生在同一个变更里，因为分开做就会出现这种半吊子状态，而半吊子状态的笔记比没有笔记更误导人。

140
00:13:42,670 --> 00:13:44,663
最后收几条原则。

141
00:13:44,613 --> 00:13:49,396
第一，把状态放进路径，而不是放进文件里的字段。

142
00:13:49,396 --> 00:13:59,457
文件夹路径是文件系统层面的事实，遍历、检索、门禁全都直接可用，不需要先解析文件内容才知道这是什么。

143
00:13:59,457 --> 00:14:04,961
状态就是文件夹，这个朴素的做法消除了整整一类同步问题。

144
00:14:04,961 --> 00:14:08,074
第二，决策记录必须写它击败了谁。

145
00:14:08,074 --> 00:14:16,788
不记录备选方案的决策记录，价值至少减半，因为它防不住最该防的那件事，同一个坏主意被反复提出。

146
00:14:16,788 --> 00:14:23,098
被否决的方案要连同理由一起冻结存档，这是防失忆最关键的一个动作。

147
00:14:23,098 --> 00:14:25,767
第三，规范必须可被检查。

148
00:14:25,767 --> 00:14:32,918
写进 AGENTS.md 的每一条，都要么能被脚本查，要么评审者十秒内能判断违没违反。

149
00:14:32,918 --> 00:14:40,334
检验方法很简单，把你的规范拿给同事看，问哪条没法执行，没法执行的删掉重写。

150
00:14:40,334 --> 00:14:45,298
第四，最容易腐烂的文档是集中式索引，直接别建。

151
00:14:45,298 --> 00:14:48,423
会撒谎的索引比没有索引更糟。

152
00:14:48,423 --> 00:14:53,567
同理，一个事实只许有一个权威出处，写两处就会分叉。

153
00:14:53,567 --> 00:14:57,557
第五，历史是证据，改过的证据不能作证。

154
00:14:57,557 --> 00:15:03,399
归档层禁止编辑这条看着不近人情，但它保护的是追溯能力。

155
00:15:03,399 --> 00:15:10,466
顺带一句，别让文档欠着，把笔记钉进同一个 PR，欠着的文档永远不会补。

