{
  "$schema": "https://bestaiskill.com/schemas/agent-install/2.json",
  "skill": "video-comparer",
  "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": "Execute local script or command: python3 scripts/compare.py <original> <compressed> [-o out.html] [--interva"
    },
    {
      "file": "网络端点",
      "summary": "Declare external network access: The generated report page loads https://unpkg.com/img-comparison-slider@8/dist/{styles.css,in via the browser"
    },
    {
      "file": "本地工作目录",
      "summary": "File read/write and artifact output: Writes HTML report to path specified by -o (default ./comparison.html): open(output_path, 'w', encoding='"
    }
  ],
  "verification": {
    "method": "第二遍独立复核（找茬视角）：①glob 清点目录全部文件（含隐藏）建立资产面；②以 raw 分段精读 compare.py（1036 行：常量段、校验段、ffmpeg 封装段、模板替换段、写盘段），逐项核实文档的三条安全声明与「self-contained / base64」声明；③做确定性反例检索：grep base64/b64encode/data:image、grep shell=True、grep urllib/requests/socket、grep vmaf、grep https://；④用 wc -l 核对 README 声称的行数；⑤把 README 架构清单、SKILL.md 的 reference 列表与文件系统实际内容三方对照；⑥核对模板的 CDN 引用与帧相对路径，确认产物形态；⑦git 核对 pin commit 与目录最后一次提交。",
    "second_pass": [
      {
        "item": "SKILL.md 的『frames 以 base64 内嵌进 self-contained HTML』声明是否成立",
        "status": "discrepancy",
        "detail": "不成立，是本次侦查发现的最重问题。SKILL.md 第 99 行：'The script extracts frames at specified intervals (default: 5 seconds), scales them to consistent height (800px) for comparison, and embeds them as base64 data URLs in self-contained HTML. Temporary files are automatically cleaned after processing.' 实际实现是把帧复制到 HTML 同级子目录：copy_frames_to_output 的 docstring 即 'Copy frames to a subdirectory next to the HTML output.'，dest_name = f\"frame_{i:03d}.png\"、shutil.copy2(frame_path, dest_path)，调用处为 copy_frames_to_output(original_frames, output_path, 'original') 与 (compressed_frames, output_path, 'wechat')。全目录 grep base64/b64encode/data:image 在 .py 与 .html 中零命中（仅出现在 README 的依赖清单与 configuration.md 的说明文字里）。模板侧确认用相对路径：<img slot=\"first\" id=\"originalImage\" src=\"original/frame_001.png\" ...>。即产物是「HTML + original/ + wechat/」一整个目录，不是单文件。"
      },
      {
        "item": "SKILL.md 的『Self-contained format (no server required, works offline)』是否成立",
        "status": "discrepancy",
        "detail": "不成立（两条独立原因）。SKILL.md 第 108 行原文：'- Self-contained format (no server required, works offline)'。①存在外部 CDN 依赖：template.html 第 7-8 行加载 https://unpkg.com/img-comparison-slider@8/dist/styles.css 与 .../index.js，断网时滑块组件不可用；②依赖同级帧目录（见上一条），单独拷走 HTML 会丢帧。值得注意的是 README 自己承认了 CDN 依赖（依赖清单写 'img-comparison-slider (loaded from CDN)'），却同时在架构说明里声称 template.html 具备 'Base64-encoded image embedding'——即 README 内部亦不自洽，且与 SKILL.md 的 offline 声明互相矛盾。"
      },
      {
        "item": "README 的『Architecture』信息是否与文件系统/实现一致",
        "status": "discrepancy",
        "detail": "三处不符：①行数——README 写 'compare.py # Main comparison script (696 lines)'，实测 wc -l = 1036 行；②架构清单只列 video_metrics.md 与 ffmpeg_commands.md 两份 reference，漏掉实际存在且被 SKILL.md 明确引用的 references/configuration.md；③把 template.html 描述为 'Base64-encoded image embedding'，与实现不符（见第 1 条）。"
      },
      {
        "item": "文档是否宣称了未实现的能力（VMAF 等）",
        "status": "discrepancy",
        "detail": "SKILL.md 层面是对的：它只说两个指标（PSNR、SSIM），与脚本一致（grep -i vmaf 在 compare.py 中零命中）。但 references/video_metrics.md（4 处 VMAF）与 references/ffmpeg_commands.md（3 处，含 'VMAF Calculation' 小节）都提供了 VMAF 的定义与 ffmpeg 命令。即参考材料覆盖了脚本未实现的第三指标——不是夸大声明（SKILL.md 未据此承诺），而是「参考材料超出工具能力」，使用者若按 reference 期待 VMAF 输出会落空。"
      },
      {
        "item": "三条安全声明（path validation / command injection prevention / resource limits）是否有代码对应",
        "status": "ok",
        "detail": "逐条核实成立：①path validation —— validate_video_file 内 Path(path).resolve()、exists()、is_file()、后缀白名单 ALLOWED_EXTENSIONS、os.access(R_OK)、体积上限 MAX_FILE_SIZE_MB=500；②command injection prevention —— run_ffmpeg_command 以参数列表调用 subprocess.run（docstring：'args: Command arguments as list (prevents shell injection)'），全文无 shell=True；③resource limits —— FFMPEG_TIMEOUT=300、FFPROBE_TIMEOUT=30，且 TimeoutExpired 有专门异常映射。声明未夸大。"
      },
      {
        "item": "是否存在未声明的网络/凭证行为",
        "status": "ok",
        "detail": "反例检索失败：compare.py 的 import 段为 argparse/json/logging/os/re/subprocess/sys/tempfile/time/pathlib/typing，无 urllib/requests/socket/http；全目录 grep token/secret/password/api_key/getenv/os.environ 零命中；无 base64 大块、无 >200 字符无空格长行。结论成立。"
      },
      {
        "item": "模板的『通用性』呈现与内容是否相符",
        "status": "discrepancy",
        "detail": "SKILL.md/README 把它呈现为通用的视频压缩对比工具，但 assets/template.html 的文案与路径是微信专用的：标签为「🎬 原始视频 (AVC)」与「📱 微信视频号 (HEVC)」、替换目标里有 '<div class=\"metric-subtitle\">微信重新编码</div>'、帧相对路径写死 'wechat/frame_001.png'，且 compare.py 的复制调用也写死 subfolder='wechat'（而非 'compressed'）。结论：工具可用，但默认产物带有上游使用场景的专用词汇；非微信场景需自行改模板与源码常量。"
      },
      {
        "item": "pin commit 与 skill.path 是否与任务书表格一致",
        "status": "ok",
        "detail": "git rev-parse HEAD = d5c4678cb5d4fd6acc9c922690df035dbd33d247，与任务书表格『库内 HEAD』逐字一致；目录位于仓库根，相对路径 video-comparer；本目录最后一次提交 878f947（2026-09-07）。GitHub API 复核 MIT / stars 1392 / pushed 2026-09-15T09:30:04Z。"
      },
      {
        "item": "evidence 逐字性是否经磁盘级复核",
        "status": "ok",
        "detail": "【evidence 逐字性校正】首稿有两条 quote 经磁盘级校验未逐字命中源文，已按 pin 源码重新逐字提取：①compare.py 的模板替换片段——首稿在 f-string 中把源码里的字面 `\\n` 误写成换行，且把跨行内容合并，现改为源码第 784 行原文 `        r'<div class=\"metric-value\">[\\d.]+ dB</div>\\s*<div class=\"metric-subtitle\">偏低</div>',`；②references/configuration.md 的标题——首稿写成 「# Script Configuration Reference / ## Contents / ## Adjustable Constants」三行连续，但源文件在 Contents 与 Adjustable Constants 之间还有 5 行目录列表，现改为真实连续的两段 `# Script Configuration Reference` + `## Contents`。两处的**结论均未改变**（模板正则替换与可调常量文档确实存在），属引用精度问题而非判断错误。"
      }
    ],
    "level": 1,
    "level_label": "V1 已固定",
    "commit": "d5c4678cb5d4fd6acc9c922690df035dbd33d247",
    "sha256": "f6f34839800154eddfd20fdc86fe55e3314a686c250ed21f9d827f4efb05f122",
    "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/video-comparer.tar.gz",
    "sha256": "f6f34839800154eddfd20fdc86fe55e3314a686c250ed21f9d827f4efb05f122",
    "commit": "d5c4678cb5d4fd6acc9c922690df035dbd33d247"
  },
  "original": {
    "github": "https://github.com/daymade/claude-code-skills/tree/main/video-comparer",
    "path": "video-comparer",
    "commit": "d5c4678cb5d4fd6acc9c922690df035dbd33d247"
  }
}