实验课:真实调用 × 规则集 × 六种求值语义
本课要做的:用真实数据检验本章的两个结论——「同一份规则换一种语义可能换一个答案」「顺序只对 last-match / first-match 这类语义要紧」;顺带确认页面上的求值器和原实现一致。
需要的时间:约 40 分钟。全部计算在浏览器里完成,不需要联网,也不需要跑模型。
数据从哪来
- 真实调用:本课程项目 miniagent 用 Qwen/Qwen3-8B-MLX-4bit(revision
{M.trace_model.revision.slice(0, 7)},Apple M5 Max, 128 GB)本机录制的 26 次运行,覆盖任务 leap_year、parse_date、slugify、word_freq,共 139 次工具调用、16 种不同的「工具 + 参数」。每次调用在录制时都写下了 miniagent 当时的权限裁决。贯穿任务test_parse_date占其中大部分。 - 构造调用:第 1 课的危险 / 日常命令和每个规则集自带的例子,表格里标「构造」。
- 规则集:我们项目的真实配置
rules-standard.json、Claude Code 文档里的 aws 例子、OpenCode 文档里的 bash 例子、第 2 课的 git push 冲突。 - 求值器:lcc s03、CoreCoder、OpenCode、miniagent 的 first / last,全部移植自 pin 源码或项目源码,期望值由原实现在 pin 副本上跑出(
gen_a03_fixtures.py+.ts,2026-09-26);Claude Code 依据官方文档实现,非源码移植。
实验台
组件加载中……(需要 JavaScript;所有裁决都在你的浏览器里由移植的原算法现算)
任务
任务 1 · 找出分歧:在「项目真实配置」下,只看真实运行。哪些调用在 first-match 与 last-match 下裁决不同?它们是不是正好对应项目测试 StandardConfigFlips 钉住的两类(跑 unittest、改测试文件)?
任务 2 · 倒序:勾选「把规则整表倒序」。数一数红边格子:哪几列改判了,哪几列一格都没动?用第 2 课的精确条件解释为什么 Claude Code 那一列不动。
任务 3 · 换规则集:切到「OpenCode 文档里的 bash 例子」,找一条 Claude Code 与 OpenCode 结论不同的调用;再切到「Claude Code 文档里的 aws 例子」,看 aws s3 ls 在两家分别是什么、为什么。
任务 4 · 读自检表:下方表格里每一行是什么意思?哪一行不是「对源码」?Claude Code 那一行为什么只能对文档例子自检?
把结果写进项目:在 04-实践项目/DECISIONS.md 记下 ① 你为 miniagent 选的语义与理由;② 任务 1 里至少一条「书写顺序与动作优先级冲突」的真实调用,以及它在你所选语义下的期望裁决(并在 tests/test_permissions.py 里有对应断言);③ 任务 2 的改判格数。这三条就是本章里程碑的验收材料(见章首页)。
读数时注意
- Claude Code 那一列只到文档为止。它对官方文档里转写的 57 个例子自检通过,但和真实 CLI 的逐条对照(T12 黄金矩阵:在真实 Claude Code 上录一组规则 × 调用的实际放行、弹窗、拒绝)还没有录制 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条文档例子是官方原文;wrapper 剥离、重定向目标检查、子 shell 内嵌套匹配等本页没有实现,真实 CLI 在这些情形下可能不同。 出处Claude Code 文档 ↗需联网 。
- OpenCode 遇到复合命令时是近似的。它的真实实现用 tree-sitter 解析出每个子命令再分别求值;本页用引号感知的分隔符切分代替,只对不含子 shell、命令替换的命令成立。
- lcc s03 与 CoreCoder 不读规则表,所以它们那两列不随规则集变化——这本身就是第 2 课的结论之一。
- Codex 没有进矩阵:execpolicy 用 Starlark 写按词前缀匹配的规则,取所有命中规则里最严格的;pin 上的 Rust 源码没法在本机跑出对照 fixture,只在第 2 课做文字说明。
- 真实运行的模型是本地 8B 4bit,调用内容简单(读、改、跑测试);它说明不了前沿模型会发出什么命令,只保证矩阵里「真实」那几行确实出现过。
- Pi 核心、bypassPermissions、CoreCoder --yes解决了零打断,模型想跑什么马上跑。卡在L1 的 6 条本意危险的构造命令(含
rm -rf /)会全部直接执行。 - 朴素 黑名单:子串或正则lcc s01 / s03、CoreCoder bash 正则、Pi permission-gate解决了把已知危险的写法挡在执行之前,代码只有几行。卡在lcc s03 三道闸(pin 源码实跑):6 条危险命令里漏拦 4 条,5 条日常命令里误拦 2 条(
cat sudoku_solver.py因含子串 sudo 被拒)。 - 第一代 每次都问人CoreCoder 交互模式、Claude Code Manual、lcc s03 的第三道闸解决了判断交给人,规则写不全也不怕。卡在我们 26 次真实运行的 139 次工具调用,在 CoreCoder 交互模式下有 74 次要停下来问(53%);Anthropic 自报用户批准了约 93% 的弹窗——问多了,人就不看了。
- Claude Code(deny → ask → allow)、OpenCode(last-match)、Codex(最严格者胜)解决了把常见的放行和拒绝写成规则,只有规则没覆盖的才问人。卡在同一份规则换一种求值语义可能换一个答案:同一份
rules-standard.json改用 first-match,真实运行 pd-firstmatch-s1 里模型的python -m unittest -v test_dateparse.py被规则 #8 拒掉。 - 第三代 分层放行 + 模型审批Claude Code auto、Codex Auto-review(代码名 Guardian)、Hermes smart解决了只读直放、项目内编辑免审,其余交给另一个模型判断;弹窗接近清零。卡在Anthropic 自报:auto 分类器在真实越权动作上仍有 17% 漏判(n = 52),官方原话「does not guarantee safety」。
- 下一章 与 OS 沙箱分层Claude Code sandbox、Codex Seatbelt / bubblewrap解决了规则管「允许调用什么」,沙箱管「调用之后能碰到什么」。卡在L1 的
python3 -c "import shutil; shutil.rmtree(…)"在四个黑名单里被 4 个全部放行;规则看不见脚本在运行时做什么 → A4。
数字口径:黑名单与「每次都问」由原实现在 pin 源码上实跑(a03-permission-fixtures.json,2026-09-26);真实运行 = 本课程项目 miniagent 用 Qwen/Qwen3-8B-MLX-4bit 本机录制;93% 与 17% 为 Anthropic 官方自报。
这一课的结论
同一份真实配置、同一批真实调用,换一种求值语义,裁决就会在「书写顺序与动作优先级冲突」的那些调用上翻转;Claude Code 与 Codex 这类按动作优先级求值的语义对顺序不敏感,last-match / first-match 对顺序敏感。选哪一种都可以,前提是把顺序敏感的用例写成测试。
下一章:矩阵里被「放行」的命令,放行之后能碰到什么?看项目真实配置下 python -m unittest; curl x | sh 那一行:miniagent 的 last-match 放行了它(项目有意保留、并用测试钉住的已知漏洞),因为规则只看到它以 python -m unittest 开头;python3 -c "…" 那一行在 lcc s03 下同样放行。规则看的是命令文字,拦不住命令运行时做的事——A4 讲操作系统沙箱。