Codex 教程
按顺序阅读,循序渐进掌握相关 AI 工具与实战方法。
dsh 仓库把每一次“不该出现却出现了”的 bug 都写成事故复盘(postmortem),并留下测试、文档与规则层面的防护。一个 bug 的价值不在那行修复,而在于为什么流程放过了它、新增了什么防护让同类问题下次明确报错。每篇复盘回答四问:什么坏了(三十秒能读完的摘要)、机制是什么(直白说清根因,不归咎个人)、为什么每道安全网都没拦住(找测试、工具、约定的缺口)、新增了什么防护(测试、AGENTS.md 规则、ADR)。只有同时满足隐蔽、系统性、重新发现代价高三个条件的 bug 才值得写复盘。
| 复盘 | 问题与机制 | 新增防护 |
|---|---|---|
| 0001 | 插件多写 export default apply,Loader 的 unwrapExports 取到裸函数、丢掉 inject;178 个绿测加 100% 行覆盖率全用手动 ctx.plugin(...) 挂载,绕过了真实 Loader |
删除 default export;补真实 Loader 冒烟测试;规则“测真实入口路径,行覆盖率不等于行为覆盖率” |
| 0002 | disabled: !!js ... 是 truthy 对象(Cordis 只在插件 config 内部求值),七个文件系统场景返回 UNKNOWN_TOOL;快照刷新把“确定性回放”误当“行为正确” |
改用显式 overlay;静态配置守卫拒绝 Loader 配置项元数据中的表达式节点;快照框架拒绝 UNKNOWN_TOOL 结果 |
| 0003 | Web agent 把裸 Vite 的 HTTP 200 当成功(实际白屏),验收了替代服务器;组合未向模型提供当前 GUI、规范 URL 与运行模式的身份信息 | 启动器发布规范环回 URL 与模式;独立 Vite 模式拒绝启动;分层真实路径测试覆盖 CLI、提示词、运行时事实与浏览器 HMR |
| 0004 | 旧 Landlock ABI 上 ripgrep 退出码 1 的正常结束被误判为 SANDBOX_UNAVAILABLE——子串匹配把无害的 partial enforcement 通知与非零退出组合成 runner 失败 |
RunnerFailureRule 携带允许退出码、逐行致命签名与精确排除行;文件搜索改用 ctx.subprocess 跑打包的 ripgrep |
共同经验:测试必须走真实入口路径——手动挂载、mock 一切、把快照刷新当验收,都会让“单元全绿、产品却坏了”成为可能。
| 层级 | 命令 | 抓什么 |
|---|---|---|
| 单元测试 | pnpm run test |
边界、错误路径、事件顺序、并发竞态 |
| 覆盖率门禁 | pnpm run test:coverage |
按文件 100% 覆盖,未覆盖行往往是死代码 |
| 真实 API e2e | pnpm run test:e2e |
带密钥调真实提供方;缺密钥自动跳过,keyless CI 保持绿色 |
| 快照 | pnpm run test:snapshot / test:web |
无密钥预期输出覆盖对外行为,浏览器快照用 Chromium 回放比较 |
几条原则:推理在 DeepSeek 自己的仓库里很便宜,不要吝惜真实 API 测试——无密钥测试只证明底层通路,带密钥运行才能证明 agent 能对接真实模型;价值最高的是冒烟测试(启动真实示例、发提示词、检查外部世界);行覆盖率是必要条件而非充分条件;断言要验证外部世界而非自我报告,未修改的文件应逐字节一致。
verify-type-equiv 门禁用 TypeScript 解析器提取类型声明的符号与 JSDoc,断言文档代码块同时匹配两者,保证文档与源码永不漂移。另一条纪律是一个事实一个家:每个事实只在一个文件维护,其余引用它;中英文档双语配对,更新时先跑 pnpm run gen-doc-graphs 更新英文再同步中文。复盘开头的三十秒摘要公式:坏什么 → 直白说根因 → 为什么逃逸 → 可长期沿用的教训。
系列至此收官,真正带走的是一套思考方式:模型负责聪明,Harness 负责可靠;一切皆插件,把策略放在扩展点上;真实入口路径胜过一切 mock;故障不可怕,可怕的是不知道为什么——复盘文化把一次事故变成一套防护。