{
  "schemaVersion": 1,
  "slug": "truncated-video-reject-and-retry",
  "locale": "zh",
  "evidenceClass": "executed-local-fixture-not-provider-generation",
  "providerModelTest": false,
  "productionTaskRun": false,
  "runCommand": "node run-recipe.mjs --out ./my-run",
  "environment": {
    "nodeVersion": "v24.18.0",
    "ffmpeg": {
      "version": "ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers",
      "binarySha256": "a90e3db6a3fd35f6074b013f948b1aa45b31c6375489d39e572bea3f18336584"
    }
  },
  "title": "拒绝截断视频，只重取交付文件",
  "description": "本机文件端点先返回半份 MP4，再返回完整文件；实际执行全解码、绑定校验和与零生成请求验收。",
  "goal": "把文件交付恢复与生成恢复分开。HTTP 200 下载也可能是损坏视频；本离线夹具只重取同一个已知交付文件身份。",
  "preparation": [
    "准备 Node.js 与 FFmpeg。原创源片为两秒、320×180、二十帧；大小与预期 SHA-256 写入 artifact-manifest.json。",
    "查看 truncated.mp4：它真实取自源文件的前半段字节，不是虚构错误标签；首次本机下载实际返回这份损坏文件。",
    "使用全新目录。请求仅指向 127.0.0.1 临时端口的同一文件 URL，设三秒超时、2MB 响应上限，并在 finally 关闭服务；不调用生产任务。"
  ],
  "steps": [
    {
      "title": "01. 保持原任务与文件身份",
      "body": "读取 local-paid-once 与 /artifact/local-paid-once 清单。夹具提供一个刻意禁止的 /generate 路由，只用于统计误提交，成功流程从不调用。本地名字不代表实际付费任务。"
    },
    {
      "title": "02. HTTP 成功仍要拒绝坏媒体",
      "body": "首个响应虽然是 HTTP 200，实际仅17775字节，为35550字节源文件的一半。FFmpeg 使用 -xerror 与 explode 错误检测执行完整视频解码，真实失败日志保留在负向回执。"
    },
    {
      "title": "03. 对同一文件 URL 只重试一次",
      "body": "第二次请求完全相同的交付文件身份，本机服务返回完整原创字节。先与清单核对 SHA-256，再完整解码二十帧，不只看网络状态。"
    },
    {
      "title": "04. 验收重取与生成之间的边界",
      "body": "确认下载次数恰为二、生成请求为零、临时服务已经关闭。此有界夹具没有退避、签名 URL 更新或提供商错误分类；真实下载器应使用其服务文档定义的恢复规则。"
    }
  ],
  "acceptance": [
    "首个 HTTP 200 实际包含截断字节前缀，SHA-256 不同于预期。",
    "截断文件全解码退出失败，实际错误已记录。",
    "第二次使用同一文件 URL，下载总数准确为二。",
    "第二份文件 SHA-256 与完整交付清单一致。",
    "恢复文件完整解码为二十帧 320×180。",
    "没有 /generate 请求，服务正常关闭，七项检查全部通过。"
  ],
  "troubleshooting": [
    {
      "symptom": "HTTP 返回200，但播放器打不开。",
      "change": "保留实际下载字节并运行完整解码，媒体检查失败后只重取同一交付文件。"
    },
    {
      "symptom": "第二份能播放，但校验和不同。",
      "change": "先只核对文件与清单绑定再接受；可读不代表它来自预期任务。"
    },
    {
      "symptom": "文件重试又产生了一次生成请求。",
      "change": "把重试目标改回已保存的文件 URL，再跑零生成断言；生成提交不能放在交付恢复循环内。"
    }
  ],
  "ending": "本机重放只证明这个截断 MP4 在保持文件身份下可恢复，不代表提供商重试承诺，也没有真实支付、生成或签名下载执行。",
  "assetCaption": "原创小型源片、真实截断与恢复文件、本机重放及文件重取图；没有生产或提供商生成。"
}
