🛠️ 第14章 Codex 的边界、风险与工程方法论
📄 一句话概括

配套仓库三种用法稳定性差很远:pin 到 commit 零坏,跟 main 两处全挂。 模板只该留「需要你替换的洞」;判断标准是「这一行描述的是谁」。 书会过时的是命令名、模型名、界面位置、价格;不会过时的是闭环和四件套。

📝 本章和前面几章的关系

这是全书的最后一节。 讲三件跟时间有关的事:配套代码怎么用、模板怎么改、书过时了怎么办。 Demo 真建一个上游仓库和三个下游项目,让上游发一版破坏性变更,看三种用法各自坏几处; 再用 diff 量一次模板和项目之间的真实差异。

一、配套代码怎么看

拿到配套仓库,第一件事不是 clone,是决定「跟不跟」。 三种用法,稳定性差很远。

用法 升级后坏几处 待解冲突
pin 到 commit 0 无
跟 main 2 无
fork 后自己改 2 有

Demo 里上游发了一版破坏性变更:run 改名成 execute,--fast 改成 --speed。 两条探针分别查「符号还在不在」和「参数还认不认」。 pin 那份两处都不坏,因为它压根没跟着升。 这就是版本锁定的全部作用:把「必然发生」变成「可以选择」。 它不保证兼容,只保证「什么时候升」由你决定。 跟 main 那份两条全挂,原因很干净:接口真的变了。 fork 那份也坏两处,但原因不一样:pull 打出了 CONFLICT,冲突标记被写进文件,整个模块没法导入。 这一行正好说明「坏几处」这个指标会骗人:它分不清「接口变了」和「文件坏了」。 所以看到数字要先问一句「坏在哪」。 一个可用的默认:学的时候 pin 到 commit,用的时候跟 tag,不要跟 main。

二、模板怎么改

Demo 用 diff 量了一次模板和项目之间的真实差异:三个文件,加三行、删两行。

文件 加了几行 删了几行
AGENTS.md 1 1
config.yml 1 1
rules.md 1 0

改动量这么小,正是模板该有的样子:它只留下需要你替换的那几个洞。 如果一个模板要改几十行才能用,那它不是模板,是别人的项目。

文件 改动 该不该改
AGENTS.md 项目名 必须改:换成自己的
rules.md 加一条团队约定 该改:规则本来就该长
config.yml name 一个值 看情况:路径和名字要改

模板里最容易改错的是结构:把别人的目录约定、脚本名一起搬过来,结果在自己项目里对不上。 判断标准是「这一行描述的是谁」——描述项目名的必须改,描述流程的尽量别动。 「尽量别动」的意思不是「不能动」,是「先按原样跑通,再决定要不要动」。 先跑通能给你一个基准:动完之后坏了,你知道是改动引起的。

三、书会过时,方法不会

书里写的具体东西,隔一年就会有一部分不再成立。 但「哪些会变」本身是可以分类的。

会过时的 怎么在三十秒内验一下
命令名和参数 跑一次 --help,看参数还在不在
模型名 看厂商文档的模型列表
界面位置 打开工具,按书里说的路径找一遍
价格和限额 看账单页,不看旧文章
配套仓库的分支 git ls-remote,看分支还在不在
不会过时的 为什么
闭环:出题、执行、验证、交付 这是流程的形状,不是工具功能
四件套:说明、护栏、装配、流水线 再多工具也是这四类
验收标准先写 跟工具无关,是判断顺序
归因再动手 错因分类不随版本变
工作流会折旧 依赖会变,这是工程的性质

两张表的关系是:左边是你需要跟着更新的,右边是你需要记住的。 左边越用越旧,右边越用越熟。 一个具体建议:把左边那五行抄进 AGENTS.md,每次升级工具时照着走一遍。 这比收藏十篇「最新教程」有用——因为那五行是可执行的检查,而教程是不可执行的阅读。

四、本章小结

第十四章讲的是边界。 边界不是「能力不够」,是「知道它在哪一步会失手,并且提前把这一步变成可检查的」。

节 讲的事 压成一句
14.1 归因 先分类,再动手
14.2 出域 出域是单向的坡
14.3 分工 时间可交,责任不可交
14.4 折旧 当周修,别攒
14.5 更新 左边跟着换,右边记牢

五件事的共同点:它们都不提升上限,只保住下限。 保住下限听起来不性感,但工程里绝大多数事故不是因为上限不够,是因为下限漏了。 全书到这里结束。 从第 1 章的「交付与补全差在证据链」,到第 14 章的「边界是可检查的」, 中间的每一章都在回答同一个问题:怎么让一次成功变成可重复的成功。 答案是四个字:写下来,验一遍。 写下来解决「别人能不能用」,验一遍解决「你自己有没有把握」。 两件事都做到,工具换成什么都无所谓。

五、动手 Demo:配套仓库、模板与在线更新:书会过时,方法不会

真建一个上游仓库和三个下游项目,让上游发一版破坏性变更,看三种用法各坏几处。 再用 diff 量一次模板和项目之间的真实差异。 最后一张表是「哪些会过时、怎么三十秒验一次」。

up = fresh("up")
put(up, "tool/__init__.py", "def run(argv=None):\n    return 'v1'\n")
gitinit(up)
sha1 = git(up, "rev-parse", "HEAD")[1].strip()

pin = clone("proj_pin");  git(pin, "checkout", "-q", sha1)
main = clone("proj_main")
fork = clone("proj_fork")

# 上游发 v2:run -> execute,--fast -> --speed
put(up, "tool/__init__.py", "def execute(argv=None):\n    return 'v2'\n")
git(up, "commit", "-qam", "v2")

# 两条探针:符号还在不在、参数还认不认
PROBES = ["from tool import run",
          "import tool.cli as c; assert c.run_flag(['--fast'])"]

实跑输出:

--------------------------------------------------------------------
配套仓库、模板与在线更新:书会过时,方法不会
--------------------------------------------------------------------

  这一章最后一节,讲三件跟「时间」有关的事:配套代码怎么用、模板怎么改、书过时了怎么办。

  ① 配套仓库的三种用法,稳定性差很远
  --------------------------------------------------------------------
| 用法 | 升级后坏几处 | 待解冲突 |
|---|:---:|:---:|
| pin 到 commit | 0 | 无 |
| 跟 main | 2 | 无 |
| fork 后自己改 | 2 | 有 |

  两条探针分别查「run 这个名字还在不在」和「--fast 这个参数还认不认」。
  pin 那份两处都不坏,因为它压根没跟着升——这就是版本锁定的全部作用:
  把「必然发生」变成「可以选择」。
  跟 main 的两条探针全挂,原因很干净:run 改名成 execute,--fast 改成 --speed。
  fork 那份也坏两处,但原因不一样:pull 打出了 CONFLICT,冲突标记被写进了 cli.py,
  文件根本没法导入。
  这一行正好说明「坏几处」这个指标会骗人:它分不清「接口变了」和「文件坏了」。
  所以看到数字要先问一句「坏在哪」。
  ! 两条探针只能证明这两处没坏,证明不了全部兼容。这是升完级后最小的体检,不是完整的兼容性测试。

  ② 模板要改哪、不该改哪
  --------------------------------------------------------------------
| 文件 | 加了几行 | 删了几行 |
|---|:---:|:---:|
| AGENTS.md | 1 | 1 |
| config.yml | 1 | 1 |
| rules.md | 1 | 0 |

  三个文件加起来加了 3 行、删了 2 行——改动量很小,这正是模板该有的样子:
  它只留下需要你替换的那几个洞。
| 文件 | 改动 | 该不该改 |
|---|---|---|
| AGENTS.md | 项目名 | 必须改:换成自己的 |
| rules.md | 加一条团队约定 | 该改:规则本来就该长 |
| config.yml | name 一个值 | 看情况:路径和名字要改 |

  模板里最容易改错的是结构:把别人的目录约定、脚本名一起搬过来,结果在自己项目里对不上。
  判断标准是「这一行描述的是谁」——描述项目名的必须改,描述流程的尽量别动。

  ③ 一份三十秒能做的过期体检
  --------------------------------------------------------------------
  书里写的具体东西,隔一年就会有一部分不再成立。但「哪些会变」本身是可以分类的。
| 会过时的 | 怎么在三十秒内验一下 |
|---|---|
| 命令名和参数 | 跑一次 --help,看参数还在不在 |
| 模型名 | 看厂商文档的模型列表还是不是这个 |
| 界面位置 | 打开工具,按书里说的路径找一遍 |
| 价格和限额 | 看账单页,不看旧文章 |
| 配套仓库的分支 | git ls-remote,看分支还在不在 |

| 不会过时的 | 为什么 |
|---|---|
| 闭环:出题、执行、验证、交付 | 这是流程的形状,不是工具的功能 |
| 四件套:说明、护栏、装配、流水线 | 再多工具也是这四类 |
| 验收标准先写 | 跟工具无关,是判断顺序 |
| 归因再动手 | 错因分类不随模型版本变 |
| 工作流会折旧 | 依赖会变,这是工程本身的性质 |

  左右两张表的关系是:左边是你需要跟着更新的,右边是你需要记住的。左边越用越旧,右边越用越熟。
  一个具体建议:把左边那张表的五行抄进 AGENTS.md,每次升级工具时照着走一遍。
  这比收藏十篇「最新教程」有用。

  ④ 这一章、这本书的收尾
  --------------------------------------------------------------------
  第十四章讲的是边界。
  边界不是「能力不够」,而是「知道它在哪一步会失手,并且提前把这一步变成可检查的」。
  第 62 节讲归因,第 63 节讲出域,第 64 节讲分工,第 65 节讲折旧,第 66 节讲更新——五件事的共同点:
  它们都不提升上限,只保住下限。
  ! 保住下限这件事听起来不性感,但工程里绝大多数事故不是因为上限不够,是因为下限漏了。

三行结果里,pin 那行是零坏。 这不是「锁定就不会坏」,是「锁定之后坏了也跟你无关」——你用的还是老版本,它当然不会坏。 代价是拿不到新功能,这个取舍要自己认。 fork 那行坏两处,但原因跟接口无关。 pull 冲突把 <<<<<<< 标记写进了 cli.py,整个文件语法错。 这就是「坏几处」这个指标的盲区:它数的是失败次数,不是失败原因。 模板那段 diff 只有加三行删两行。 这个数小得有点出乎意料,但它说明模板设计得好:它把「你必须改的」压缩到了三处。 如果一个模板要改二十行,说明它预设了太多别人的环境。 最后两张表,左边的五行是可执行的检查,右边的五行是判断顺序。 左边的会过期,右边的不会。 所以每次工具升级,跑一遍左边,别去重读整本书。 全书到这里收尾。 这一节没有新技术,只有一句:把会变的和不会变的分开,然后只花时间在会变的那一半。

30 秒实验

  1. 打开你正在用的配套仓库,看它是 pin 还是跟 main。 是跟 main 的话,改成 pin 到今天这个 commit。
  2. 把你项目的 AGENTS.md 和模板 diff 一次。 差异超过十行,就有一半是你不该改的。
  3. 把「会过时的」五行抄进 AGENTS.md,加上「升级时照着走一遍」。 这五行比任何教程都耐用。

常见误区

  1. 「跟 main 才能拿到最新修复。」 最新修复和新破坏是同一批提交带过来的。 跟 tag 是折中:拿到版本,不拿未发布的改动。
  2. 「模板要按自己习惯改一遍。」 先按原样跑通再改。 没跑通就改,出了问题分不清是模板的问题还是你的问题。
  3. 「书里的命令跑不通,说明书过时了。」 先跑一次 --help 看参数还在不在,再判断是过时还是拼错。 这两种情况的处理方式完全不同。
自测三问(点开对答案) 1. pin 到 commit 零坏,为什么还说它有代价? —— **零坏的代价是拿不到上游的修复和新功能。** **锁定把「什么时候升」变成可选项,但可选项也得有人选。** 2. 为什么「fork 后自己改」那行坏两处,不能算作接口破坏的证据? —— **因为失败来自冲突标记,不是来自接口变更。** **文件里被写进了 `<<<<<<<`,整个模块导不进来。** 3. 「会过时的」和「不会过时的」怎么分? —— **看它描述的是「某个工具现在的样子」还是「做事的顺序」。** **前者一定过时,后者不会。**

全书到这里结束。下一步不是学更多工具,是把这 66 节里的任意一条,在自己项目里跑通一遍。

相关笔记