{
  "$schema": "https://bestaiskill.com/schemas/agent-install/2.json",
  "skill": "audiogram",
  "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": "Local script or command execution: (Verification loop explicitly listed in SKILL.md) `npx remotion still Audiogram out/f-{start,mid,end}.png -`"
    },
    {
      "file": "网络端点",
      "summary": "External network access declared: `npx remotion …` and `@remotion/media-utils`: Initial package retrieval via official npm channels (registry.npmjs.or)"
    },
    {
      "file": "本地工作目录",
      "summary": "File I/O and artifact output: Remotion project constructed by the agent according to this skill and out/audiogram.mp4 (out/clip-square.mp4 for 1:1)"
    }
  ],
  "verification": {
    "method": "第二遍独立重读（只读 pin commit f3df381d65abe5078f5ed410bbc3ed72e7cb92bd）：① 目录清单 `find skills/audiogram -type f` 返回 SKILL.md、references/waveform-render.md 与 0 字节 README.md；② 逐行打开 waveform-render.md，核对 SKILL.md 的每条主张是否在实现与参数表里成立——镜像 bars、示波波形、五层 Audiogram 组件（含封面/标题/进度条/<Audio> 混流）、参数速查表、零依赖 canvas 变体，逐项可定位；③ 对全目录 grep `process.env|api[_-]?key|token|cookie|https?://` 确认 0 命中；④ 回读仓库根 scripts/{contact-sheet.sh,probe-mp4.sh} 确认只调 ffmpeg/ffprobe；⑤ 专项比对「禁止实时分析」这一铁律在 reference 两条路线里是否都成立（Remotion 路线用 useAudioData，canvas 路线离线解码为每帧 RMS）；⑥ 专项检查同名参数 windowInSeconds 在两处的归属（发现文档表述不一致）。",
    "second_pass": [
      {
        "item": "「禁止实时 analyser」是否在 reference 的两条实现路线里都成立（防第一遍只信开头那句）",
        "status": "ok",
        "detail": "Remotion 路线：Bars 组件用 `useAudioData(staticFile(src))` + `visualizeAudio({ audioData, frame, fps, numberOfSamples, smoothing: true })`，值是 frame 的纯函数。canvas 路线：reference 明写 `No Remotion. Decode the file once to a per-frame amplitude array (RMS per frame), then a deterministic loop draws each frame`，并在末尾注明实时 AnalyserNode 只能用于实时预览——`//   but never use it to drive a deterministic/offline render.`。两条路线都守住了铁律，且都点名了不得使用实时分析。"
      },
      {
        "item": "windowInSeconds 参数在两处的语义是否一致（第一遍漏检）",
        "status": "discrepancy",
        "detail": "SKILL.md 在「长文件」小节把 windowInSeconds 用在 `useWindowedAudioData(staticFile(\"full-episode.mp3\"), fps, /* windowInSeconds */ 10)`——语义是「HTTP range 抓取窗口」；而 reference 的参数速查表写 `| windowInSeconds | visualizeAudioWaveform | small (≈1/fps) tracks per-frame amplitude |`——语义是「逐帧幅度分析窗口」，且 §参数示例里 `windowInSeconds: 1 / fps` 出现在 visualizeAudioWaveform 调用中。两个 API 确实各有同名参数，但文档未区分说明，读者极易把「抓取窗口」与「分析窗口」混为一谈（设成 1/fps 去抓长音频，或设成 10 去分析都会出问题）。属对 pin commit 有效的表述出入，非能力虚假。"
      },
      {
        "item": "「80% 静音观看」「加字幕显著提升留存」是否有据",
        "status": "unlocatable",
        "detail": "SKILL.md 写 \"the captions carry the message for the 80% who watch on mute\" 与 \"subtitled video holds attention far longer\"，仓库内无引用来源与数据文件；只读侦查不验证，仅记为文档声明。"
      },
      {
        "item": "跨包字幕委派会不会造成「只装本包即能力缺失」",
        "status": "discrepancy",
        "detail": "SKILL.md 把词级字幕机制交给 `caption-animation`，但该 skill 位于**另一个仓库** iart-ai/tiktok-video-skills（本包目录树内不存在）。youtube 包的 .claude-plugin/plugin.json 只声明本包两个 skill，README 也未提示这一跨包依赖。结论：只安装 youtube 包时，本 skill 的「captions carry the message」这一层需要用户自行补装另一包，SKILL.md 未说明——属真实的安装面缺口（不影响档位）。"
      },
      {
        "item": "HEAVY tier 的「离线烘焙」要求是否与 reference 的实现一致",
        "status": "ok",
        "detail": "SKILL.md 要求「Bake the amplitude/waveform samples into props (or decode once via useAudioData) offline — never analyse audio at render time」，reference 的两条路线恰好各对应一半：Remotion 路线在一次解码后按帧取值，canvas 路线预先把整轨解码为每帧 RMS 数组。要求与实现一致，不是空头约束。"
      },
      {
        "item": "一稿多幅与真实音频长度对齐是否落实",
        "status": "ok",
        "detail": "reference §Full audiogram composition 末尾给出 1x1 与 9x16 两个 `<Composition>` 注册示例，并写 `Set durationInFrames from the actual clip length: Math.round(audioData.durationInSeconds * fps), or read it ahead of time with getAudioDurationInSeconds() and feed it via calculateMetadata.`；批量命令 `npx remotion render Audiogram-1x1 …` / `Audiogram-9x16 …` 亦给出。"
      }
    ],
    "level": 1,
    "level_label": "V1 已固定",
    "commit": "f3df381d65abe5078f5ed410bbc3ed72e7cb92bd",
    "sha256": "77694b043f16eba0f83ac5ac486a799e7af30f5974ef46c2f5940d9e5923fdc1",
    "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-28/audiogram.tar.gz",
    "sha256": "77694b043f16eba0f83ac5ac486a799e7af30f5974ef46c2f5940d9e5923fdc1",
    "commit": "f3df381d65abe5078f5ed410bbc3ed72e7cb92bd"
  },
  "original": {
    "github": "https://github.com/iart-ai/youtube-video-skills/tree/main/skills/audiogram",
    "path": "skills/audiogram",
    "commit": "f3df381d65abe5078f5ed410bbc3ed72e7cb92bd"
  }
}