{
  "$schema": "https://bestaiskill.com/schemas/agent-install/2.json",
  "skill": "openclaw-model-switch",
  "built": "2026-10-26",
  "control_level": 4,
  "control_level_label": "L4 高权限",
  "capabilities": [
    "execute_command",
    "network",
    "write_file"
  ],
  "required_controls": {
    "agent": [
      "sandbox_recommended",
      "graded_authorization"
    ],
    "admin": [
      "approval_process",
      "rollback_support",
      "full_audit"
    ]
  },
  "evidence": [
    {
      "file": "scripts/",
      "summary": "Executes local script or command: python3 scripts/switch-model.py <model-id> [--provider NAME] [--config PATH"
    },
    {
      "file": "网络端点",
      "summary": "Declares external network access: Script itself: zero network calls (no urllib/requests/socket/httpx, no URL constants)"
    },
    {
      "file": "本地工作目录",
      "summary": "File I/O and artifact output: <each discovered openclaw.json> (overwritten in-place, indent=2 + ensure_ascii=False + trailing newline)"
    }
  ],
  "verification": {
    "method": "第二遍换角度重做，不沿用第一遍任何结论：①重新 raw 读 scripts/switch-model.py 全 240 行，按「发现→备份→改模型→写 meta→保存→重启」逐阶段核对顺序，并单独找破坏性操作（删除/覆盖）的每一条；②对脚本做反向 token 扫描：urllib|requests.|socket|http.client|httpx|curl |wget → 零命中；os.environ|getenv|apiKey → 零命中（结果与第一遍相反之处在于：凭证面确实存在，但不是脚本读的，而是文档让 agent 从配置里取出后用于 curl，已改写到 credential_reads 而非留空）；③对三条 SKILL.md/README 声明做「文档 vs 代码」逐条对质：'syncs mirror files'、'Model validation against provider's model list'、以及 Step 2/Step 4 是否由脚本执行（见 second_pass 的 discrepancy 条）；④用脚本对全部 evidence.quote 做逐字子串比对（quote in file.read()），22 条全部命中后才落盘；⑤用 find -type f 确认 skill 目录仅 4 个文件（无隐藏脚本、无 hooks、无插件清单）；⑥git rev-parse HEAD 复核工作副本 == pin commit d5c4678。",
    "second_pass": [
      {
        "item": "文档称脚本 'syncs mirror files'（SKILL.md Step 3）是否等于内容同步",
        "status": "discrepancy",
        "detail": "代码只对每个发现的文件各自施加同一处修改（循环里 load→backup→改 provider/默认模型→save），从不把主配置内容复制到其它文件；因此若两份 openclaw.json 原本就有差异，改完仍然有差异，只是「默认模型」这一处一致了。SKILL.md 的 'syncs mirror files' 与脚本实际的 'edit all of them identically' 不是一回事，属措辞夸大（脚本自己的打印也是 'will edit and sync all'）。"
      },
      {
        "item": "README 声称 openclaw-model-switch 有 'Model validation against provider's model list'",
        "status": "discrepancy",
        "detail": "脚本里没有校验门禁：模型不在 provider 的 models 里时只做 model_exists → 若内置 KNOWN_MODELS 也没有该 id，仅打印 Warning（'Model X is not defined in config and not in built-in known models.'）然后照常写入并返回 0。SKILL.md 自身并未这样宣称（它靠 Step 2 探针 + Step 4 验证兜底），所以是 README 层面的描述与代码能力不符。"
      },
      {
        "item": "「Step 2 端点探针 / Step 4 端到端验证」是否由 skill 代码实现",
        "status": "ok",
        "detail": "复核确认这不是代码能力而是文档纪律：grep 全脚本无任何 HTTP 客户端与 curl 调用，Step 2/Step 4 都是给 agent 的操作指令（curl 与 openclaw agent 两条命令）。本报告已在 how_it_works 末条、capabilities 与 external_deps 中统一标注为「文档指示、非脚本执行」，避免把文档承诺记成代码能力。"
      },
      {
        "item": "脚本是否发网络请求 / 读 env 里的 API key（用户指定的两个重点）",
        "status": "ok",
        "detail": "反向扫描 scripts/ 零命中：无 urllib/requests/socket/httpx/curl/wget；无 os.environ/getenv/apiKey 读取。附带发现 import os 在该文件中完全未被使用（无 os.* 调用），说明连标准库层面的环境访问都没接上——凭证交接 100% 发生在文档层（curl 头）而非代码层。"
      },
      {
        "item": "备份是否真的先于写入、且每份被改文件都有备份",
        "status": "ok",
        "detail": "循环体内顺序为 load_config → 解析 provider → backup_config（打印 '[path] backed up to: …'）→ add_model_definition → update_default_model → 写 meta → save_config，备份严格前置于任何 save_config；显式 --config 时不走 discover_configs 的多文件分支，只备份那一个文件，与文档一致。"
      },
      {
        "item": "别名清理的破坏范围（第一遍记录「删除 stale keys」，第二遍量化影响）",
        "status": "ok",
        "detail": "确认删除条件是 k.startswith(f\"{provider_name}/\")，粒度是整个 provider 前缀而非「旧模型」——同一 provider 下所有其它模型的别名映射条目都会被 del，随后只补回新模型的一条空对象（models_map[f\"{provider_name}/{model_id}\"] = {}）；若属性顺序上是先删后写，用户其它模型的显示名别名确实会永久丢失（备份可回滚）。已升级为 verdict.risks 首位。"
      },
      {
        "item": "多文件模式下的失败原子性",
        "status": "ok",
        "detail": "provider 缺失时在循环体内直接 sys.exit(1)，若第一个候选文件已成功写入而第二个文件里没有该 provider，进程会在中途退出：出现「有的文件改了、有的没改」的半改状态，且没有回滚逻辑（文档也未提示需人工核对全部镜像）。"
      },
      {
        "item": "SKILL.md 的故障知识是否能在 references 里落地（声明 vs 资产）",
        "status": "ok",
        "detail": "SKILL.md 表格里的 5 类症状与 references/troubleshooting-model-config.md 的 5 条 trap 一一对应（含 env KIMI_API_KEY 劫持、插件 binary thinking、canonicalModelId 解等级、relay 分组 503、改错文件），kimi-models.md 也确实给出 k3/k2p6/kimi-k2.7-code 的规格与配置片段；文档承诺的知识资产存在且自洽，无空头引用。"
      },
      {
        "item": "quote 逐字存在性（防伪自检）",
        "status": "ok",
        "detail": "写盘前用校验脚本把本 JSON 中每一条 evidence.quote 作为子串到其 evidence.file 原文里查找（含多行 quote 的空格与换行），22 条全部命中；未使用 paraphrase 冒充 quote，meta.official_desc 为 frontmatter description 的折行还原原文（未翻译未截断）。"
      }
    ],
    "level": 1,
    "level_label": "V1 已固定",
    "commit": "d5c4678cb5d4fd6acc9c922690df035dbd33d247",
    "sha256": "c53908d204b24a25ecb7f2846bc6f3f3b364c6820c99c4d5393bf9a185a748e3",
    "reviewed_by": null,
    "reviewed_at": null
  },
  "assessed_at": "2026-10-25",
  "method_version": "2.0",
  "mirror": {
    "archive": "https://skillpub.pages.dev/r2/v/2026-09-15/openclaw-model-switch.tar.gz",
    "sha256": "c53908d204b24a25ecb7f2846bc6f3f3b364c6820c99c4d5393bf9a185a748e3",
    "commit": "d5c4678cb5d4fd6acc9c922690df035dbd33d247"
  },
  "original": {
    "github": "https://github.com/daymade/claude-code-skills/tree/main/openclaw-model-switch",
    "path": "openclaw-model-switch",
    "commit": "d5c4678cb5d4fd6acc9c922690df035dbd33d247"
  }
}