现状
bin/lc 已经 1137 行、16 个命令,但 ci.yml 的断言只钉住其中 4 个:
有门禁
sync(配置生成器输出)、doctor(tool calling 探测,test-doctor-probe.sh)、export(打包内容,test-export.sh)、code(仅 --help 能跑)
没有任何断言
init、add、ls、use、rm、up、down、status、logs、test、e2e、migrate
对没覆盖的那 12 个,CI 唯一能保证的是 py_compile 过得去——语法对,行为完全没验证。
为什么现在提
这个仓库的改动很大比例由 issue-agent 自动产生。它遵守「CI 覆盖不到的不自动合并」这条规则,所以覆盖缺口会直接变成吞吐瓶颈 :碰到没门禁的命令,它只能开 PR 然后停下来等人工审核。
反过来,覆盖不足时「CI 全绿」会给出虚假的安全感。这个坑已经踩过一次:PR #9 在版本比对零断言的情况下被合并,agent 把「没破坏既有断言」误读成「新代码被验证」。
优先级建议
第一梯队(写坏了会静默毁掉用户配置或泄密)
init / add —— 交互式写入 .env 和 registry.json。要断言:密钥只进 .env 从不进 registry;headers 的值走 KEY_*_HEADER_* 变量名而不是明文(这是 团队场景:registry.json 被 gitignore,导致每个人都要重新 lc init #4 的成果,现在没有任何东西防止它回归);.env 权限是 0600
rm —— 要断言删上游时对应的 KEY_* / KEY_*_BASE / header 变量一并从 .env 清掉,不留孤儿密钥
migrate —— 迁移逻辑写错会破坏已有用户的配置,且不可逆
第二梯队(错了会浪费排查时间但不致命)
use —— 切换后 codex/config.toml 的默认 model 真的变了
ls —— 不泄漏密钥值到 stdout(现在只显示 base URL,但没有断言防止有人「顺手」把 key 也打出来)
status / up / down —— 至少断言参数拼装正确、网关不可达时给干净报错而不是 traceback
第三梯队
test / e2e —— 本身就是测试入口,断言它们在网关不可达时干净失败即可
logs —— 薄封装,优先级最低
实现约束
不引入第三方依赖 。pytest 也不要——用 scripts/test-*.sh + python3 标准库,和现有的 test-doctor-probe.sh / test-export.sh 保持一致
不碰开发机的真实配置 。现有两个测试脚本都在临时目录里造假 registry.json / .env,沿用这个模式
交互式命令需要喂输入 。init / add 走 input(),用管道喂或者加一个 --non-interactive 入口,后者更好测也更适合脚本化使用,可以顺带做掉
每条断言都要做变异测试 。参考 test-export.sh 的做法:故意把代码改坏,确认断言真的变红。写了抓不到东西的断言比没有断言更糟——它制造虚假安全感
分批交付
一次性写 12 个命令的测试太大,PR 会没法 review。建议按上面的梯队分三个 PR,每个 PR 只动一个梯队,并在描述里列出 ci.yml 需要加的行(agent 推不了 .github/,那几行由人工补)。
一个额外收益
做这件事的过程中大概率会发现现存缺陷——写测试逼着你想清楚边界条件。发现了就单独开 issue,不要夹带在测试 PR 里。
现状
bin/lc已经 1137 行、16 个命令,但ci.yml的断言只钉住其中 4 个:sync(配置生成器输出)、doctor(tool calling 探测,test-doctor-probe.sh)、export(打包内容,test-export.sh)、code(仅--help能跑)init、add、ls、use、rm、up、down、status、logs、test、e2e、migrate对没覆盖的那 12 个,CI 唯一能保证的是
py_compile过得去——语法对,行为完全没验证。为什么现在提
这个仓库的改动很大比例由 issue-agent 自动产生。它遵守「CI 覆盖不到的不自动合并」这条规则,所以覆盖缺口会直接变成吞吐瓶颈:碰到没门禁的命令,它只能开 PR 然后停下来等人工审核。
反过来,覆盖不足时「CI 全绿」会给出虚假的安全感。这个坑已经踩过一次:PR #9 在版本比对零断言的情况下被合并,agent 把「没破坏既有断言」误读成「新代码被验证」。
优先级建议
第一梯队(写坏了会静默毁掉用户配置或泄密)
init/add—— 交互式写入.env和registry.json。要断言:密钥只进.env从不进 registry;headers的值走KEY_*_HEADER_*变量名而不是明文(这是 团队场景:registry.json 被 gitignore,导致每个人都要重新 lc init #4 的成果,现在没有任何东西防止它回归);.env权限是 0600rm—— 要断言删上游时对应的KEY_*/KEY_*_BASE/ header 变量一并从.env清掉,不留孤儿密钥migrate—— 迁移逻辑写错会破坏已有用户的配置,且不可逆第二梯队(错了会浪费排查时间但不致命)
use—— 切换后codex/config.toml的默认 model 真的变了ls—— 不泄漏密钥值到 stdout(现在只显示 base URL,但没有断言防止有人「顺手」把 key 也打出来)status/up/down—— 至少断言参数拼装正确、网关不可达时给干净报错而不是 traceback第三梯队
test/e2e—— 本身就是测试入口,断言它们在网关不可达时干净失败即可logs—— 薄封装,优先级最低实现约束
pytest也不要——用scripts/test-*.sh+python3标准库,和现有的test-doctor-probe.sh/test-export.sh保持一致registry.json/.env,沿用这个模式init/add走input(),用管道喂或者加一个--non-interactive入口,后者更好测也更适合脚本化使用,可以顺带做掉test-export.sh的做法:故意把代码改坏,确认断言真的变红。写了抓不到东西的断言比没有断言更糟——它制造虚假安全感分批交付
一次性写 12 个命令的测试太大,PR 会没法 review。建议按上面的梯队分三个 PR,每个 PR 只动一个梯队,并在描述里列出
ci.yml需要加的行(agent 推不了.github/,那几行由人工补)。一个额外收益
做这件事的过程中大概率会发现现存缺陷——写测试逼着你想清楚边界条件。发现了就单独开 issue,不要夹带在测试 PR 里。