📄 一句话概括
正常情况只能证明【能跑】,失败路径才证明【边界在】——故意让它越权,看它是不是真的越不了。
📝 本节和前面几节的关系
8.3.5 把输出定死,这一步收口:怎么知道这套预设真的成立。
一、四种该造的失败
- 让它改一个文件 → 期望改不动(工具表里没有写操作)。
- 让它跑一条命令 → 期望跑不了(执行类一件没装)。
- 让它审查不存在的目录 → 期望明说找不到(不能编报告)。
- 插件缺一个包 → 期望明确失败(不允许静默降级)。
四条都要主动制造,不能等它自己出现。
二、为什么正常情况不够
正常情况跑通,只说明这条路上没有东西挡着。
它证明不了:
- 边界在不在(没人试着越界,当然看不出)。
- 失效时会不会吭声(没制造失效,当然听不到)。
验证的本质是制造反例,不是复述正例。
三、两条老规矩在这里焊住
- 发现 ≠ 具备运行条件(5.4):包在树里不等于能用,缺条件时必须明确失败。
- 拒绝沉默的降级(5.3):不能悄悄退化成别的行为,要【明确的失效】。
这两条平时是设计原则,跑到失败路径上就变成了验收标准。
四、验收清单
把四条失败写进清单,跑一遍,每条都要有明确结果:
- 改不动:给出的是拒绝,不是执行后报错。
- 跑不了:工具表里找不到,而不是调用时报冲突。
- 找不到:如实说找不到,不生成一份【看起来像那么回事】的报告。
- 缺包:启动就明确报,不带病运行。
五、动手 Demo:用失败路径验证,不只测顺利情况
故意制造四种情况,看边界在不在:
cases = ["让它改文件", "让它跑命令", "审查不存在的目录", "缺一个插件包"]
expect = ["改不动", "跑不了", "明说找不到", "明确失败"]
for c, e in zip(cases, expect):
print(" %-12s -> %s" % (c, e))
print(" 正常情况只能证明能跑, 失败路径才证明边界在")
实跑输出:
--------------------------------------------------------------------
用失败路径验证,不只测顺利情况
--------------------------------------------------------------------
正常情况只能证明【能跑】;失败路径才证明【边界在】。
故意制造的情况 期望结果 据什么判断
-----------------------------------------------------------
让它改一个文件 改不动 工具表里没有写文件
让它跑一条命令 跑不了 执行类工具一件没装
让它审查不存在的目录 明说找不到 不能编一份报告
插件缺一个包 明确失败 不静默降级(5.4)
-----------------------------------------------------------
第 2/4 条正好焊住本课的两条老规矩:
**发现≠具备运行条件**;**拒绝沉默的降级**。
四条失败要主动制造——等是等不来的。 第二、第四条焊住本课两条老规矩:发现≠具备运行条件、拒绝沉默的降级。 验收的标准是【明确的回答】:拒绝、找不到、启动失败,都算过。
30 秒实验
- 给你的预设造四条失败,逐条记下结果。
- 如果某条失败【没反应】或者【安静地换了做法】,那就是没过。
- 把四条失败写进你项目的验收清单,以后每次改配置都跑一遍。
常见误区
- 错误:跑通一次正常流程就算验收完了。——纠正:正常流程证明不了边界——边界只在越界尝试时才现身。
- 错误:失败路径 = 看它报不报错。——纠正:安静地换一种做法更危险——要的是明确拒绝,不是悄悄降级。
- 错误:这四条是一次性的。——纠正:每次改配置都要重跑——配置是活的,今天不越界不代表改完之后还不越界。
自测三问(点开对答案)
1. 为什么要用失败路径验证? —— 因为**正常情况只能证明能跑,证明不了边界在**——验证的本质是制造反例(越权尝试)。 2. 四条该造的失败是什么? —— **改文件、跑命令、审查不存在的目录、插件缺包**——对应改不动、跑不了、明说找不到、明确失败。 3. 这里焊住了本课哪两条老规矩? —— **发现≠具备运行条件**(5.4)与**拒绝沉默的降级**(5.3)——在失败路径上它们变成了验收标准。- ☐ 下一节(8.4 不要把 Preset 当成权限系统)
相关笔记
- 不要把 Preset 当成权限系统 —— 失败路径里最重要的一条:权限
- 插件被发现,不等于已经具备运行条件 —— 缺包要明确失败
- Spatial Composability:当能力环境变化时,插件还能不能运行 —— 拒绝沉默的降级
- 🐳 DeepSeek Harness · 索引