---
name: miora-video-studio
description: miora 视频生成的可靠性与规格层——补内置技能未覆盖的部分：四必填参数闸门（模式/分辨率/时长/画幅缺一不可提交）、时长区间闸门、完成信号的判定与轮询等待、官方规格口径与本通道实测差异（时长/分辨率/参考图上限）、文生/首尾帧/参考生三种模式的参数事实、提示词的自动修正边界、生成状态向用户的同步。当用户要生成视频、动效、短视频，或提到参考生视频/首尾帧/图生视频、miora 视频、minimax h3、视频生成进度、视频怎么还没出来时使用。
---

# miora 视频生成工作台

**使用前提**：当前环境已经配置 WorkBuddy / Miora 视频工具。若工具不可用，本 Skill 只能用于诊断与解释，不能替代实际的视频生成通道。

若环境同时提供下列 Skill，可以协同加载：

- `miora-creative-core` —— 底座：确认与费用边界、生成前参数怎么定、画布交付。
- `miora-video-generation` —— 决策：镜头语言、时长画幅、主体一致性、失败处置。

它们不是本 Skill 的安装前提；本 Skill 自身负责：**完成信号怎么判、参数实测到哪、提示词怎么改**。

---

## 1. 唯一的核心问题：完成信号

miora 生成进程与对话进程是分离的。由此推出五条，任一条都不能违背：

1. **完成信号来自落盘事实，不来自接口返回。** 返回值可能整体丢失——实测发生过：15 秒视频生成成功、成片已落盘，调用方什么也没收到。把"没返回"当成"失败"是错的。反向情形同样存在：调用会阻塞到任务完成再返回 `status: completed` + `resultFiles[].localPath`（实测等约 6.4 分钟），此时**仍要走一次 `--wait` 核验**——用文件头读规格，不采信自报值。
   - 返回值里**带了 `localPath` 时，那个绑定优先于文件扫描**：立刻 `--wait --claim <localPath> --job <作业名>` 落账（见第 4 节；`--claim` 不是独立动作，必须和 `--submit`/`--wait`/`--poll`/`--poll-all` 之一同时给，否则 argparse 直接报错退出）。别让启发式扫描有机会把并发作业的成片算到你头上。
2. **提交之前先登记作业**，再发起生成。顺序颠倒就失去跨轮追溯能力。
3. **生成后立刻轮询**，不靠用户再发一句话。视频要 6 ~ 21 分钟，单轮等得完。
4. **规格以文件头为准**，时长 / 分辨率 / 音轨自己读出来，不采信自报值。
5. **不重复提交。** 状态不明不等于失败；重复提交会重复计费，且已提交的任务无法取消。

配套脚本 `scripts/miora_watch.py` 实现上述判定。

调用前需 `connect_cloud_service` 取会话凭据，把 `clientTempToken` 作为 `tempKey` 传给视频工具。**凭据有效期不稳定**——实测出现过同一 token 在同一分钟内第二次使用就被拒（`AUTH_INVALID_TEMP_KEY`）。所以：报 `AUTH_*_TEMP_KEY` 就重新取一次再重试；**连续重试时干脆每次重取**，比猜有效期省事。凭据内容不得展示给用户。

### 1.1 第 0 步：先查工具在不在

**每次开工都查，不要凭上次的经验跳过**——同一台机器上不同会话的可用性可能不同（实测过：同一台机器，一个会话里 `mcp__miora__*` 正常可用并成功出片，另一个新会话里完全没有注册）。

开工第一步确认当前会话的工具清单里有没有 `mcp__miora__*`。

**判定分三步，顺序不能颠倒**——两种"缺失"形态容易混判。

**第一步：先看主工具清单。** 如果 `mcp__miora__miora_reference_to_video` / `mcp__miora__miora_text_to_video` / `mcp__miora__miora_write_canvas` 这些**直接出现在当前会话的可调用工具清单里，那就是可用，直接开工。** 无需再做任何探查——它们不在 deferred 索引里，`ToolSearch` 天生搜不到它们。

**第二步（仅当主清单里看不到 `mcp__miora__*` 时）：** `ToolSearch` 用 `queries: ["miora"]` 搜。这里的结果只用于识别"server 条目在、子工具一个都没注册"的空壳状态：`available_deferred_tools` 里列着 `mcp__miora`，但对比 `mcp__agent-mail` / `mcp__sheetagent` 能看到人家的子工具名都展开了，miora 没有。

**第三步（二次确认）：** 用 `DeferExecuteTool` 探 `mcp__miora__miora_reference_to_video`——报 `Tool "..." not found in the deferred tools index` 才是决定性证据。

**第四步（只在确诊缺失后做，用于分清"没配"还是"没启用"）：** 三处落盘证据一起看，给用户的结论才具体。

| 文件 | 看到什么 | 说明 |
|---|---|---|
| `~/.workbuddy/mcp.json` | 有 `mcpServers.miora` 条目（`command: node` + `args` 指向 `miora-mcp/dist/cli.cjs`，`defer_loading: false`） | 配置在，不是"没配" |
| `~/.workbuddy/mcp-approvals.json` | 内容是 `{}` | 没有任何 MCP 被信任/批准 → 服务未启用 |
| `~/.workbuddy/plugins/data/mcp-miora/miora-media` 下最新 `.mp4` | mtime 是几分钟前 | 通道此前正常，产物都在 |

同时比对 `available_deferred_tools`：miora 只以**光秃秃的 `mcp__miora`** 出现、子工具名不展开，而 `mcp__agent-mail` / `mcp__sheetagent` 的子工具名都列全了——**这个不对称本身就是空壳签名**。加上 `defer_loading: false`（本该进主清单）却不在主清单里，两点互证。

据此可讲的三件事：① 这是**会话级未启用/未注册**，不是插件损坏（`miora-mcp/dist/cli.cjs` 仍在、历史成片仍在）；② 需求规格本身没问题；③ 最小解阻动作是到连接器管理右上角"自定义连接器"里信任 miora 服务、重启会话。**不要**自己去跑 `dist/cli.cjs` 或改 `mcp-approvals.json` 伪造信任。

> ⚠️ **踩过的坑（2026-09-16 实测）**：`ToolSearch` 只索引 deferred 工具，**搜不到 `mcp__miora__*` 不等于没注册**。那次 `queries: ["miora"]` 只回了 `connect_cloud_service`，看着像"未注册"，但 `mcp__miora__miora_reference_to_video` 本来就在主清单里，直接调用一次成功出片（15s / 768P / 4 张参考图，约 6.8 分钟）。**判断依据是"主清单里有没有"，不是"ToolSearch 搜不搜得到"**——按后者办会把能用的通道误判成不可用，白白拦下一次交付。

**确诊缺失后要回滚已登记的占位标记。** 探查时若顺手跑了 `--submit`，那是个永远不完成的作业，会污染 `--poll-all` 列表；用 `os.remove` 删掉 `~/.workbuddy/miora-jobs/<作业名>.json`（只删本次自己刚建的那一个）。

**给用户一条落盘证据更有说服力**：读 `~/.workbuddy/plugins/data/mcp-miora/miora-media` 下最新 `.mp4` 的 mtime，能说出"最近一次成功出片就在几分钟前"。实测过媒体目录里有约 7 分钟前刚出的 `miora_reference_to_video-*.mp4`，而新会话里工具完全未注册——据此可讲清这是**会话级注册问题**，插件本体、历史成片、参考素材都还在，素材和产物都没丢。

**没有就停下说明，不要找替代品。** 本机 miora-mcp 处于产品层隐藏状态：`workbuddy-builtin/mcps/miora-mcp/HIDDEN.md` 记录了它已从 marketplace 注册中移除、运行时不会被加载。此时据实告知用户：

- 插件本体、历史成片、参考素材都还在，但当前**没有任何可用的 miora 通道**；
- 需求规格本身没问题（比如 9 秒落在 4–15 秒的合法区间内），阻塞点只在工具缺失；
- 未做任何环境改动。

**不许改用的替代工具**：内置的 `VideoGen`（混元）只吃 1 张首帧 + 1 张尾帧，不支持多张参考图，也没有时长参数——做不出参考生视频的等价结果。换用它就是静默降级。

停在这一步，不要登记作业、不要提交生成。

---

## 2. 三种模式

| 手上有什么 | 模式 | 工具 |
|---|---|---|
| 只有文字 | 文生视频 | `mcp__miora__miora_text_to_video` |
| 有图，要它当起始画面（可另给结束帧） | 首尾帧生视频 | `mcp__miora__miora_frame_to_video` |
| 有图，要它锚定主体或风格 | 参考生视频 | `mcp__miora__miora_reference_to_video` |

两条硬规则：

- **有素材就绝不走纯文字工具。** 参考图、已确认的锚点、上一轮的定稿都是硬约束；退化成文字描述，拿到的是"像但不是同一个"的东西，而且这次无效生成要用户付费。
- **多图必须写明角色。** 提示词开头补一行"图1=角色主体，图2=场景，图3=道具"。用户用 `@image#N` 引用时，补编号映射表让编号可解析——这是结构性补充，不算改动用户原文。

---

## 3. 规格事实

口径来源：MiniMax 官方文档 `platform.minimax.cn/docs/guides/video-generation`（H3 / H3 Max），2026-09-16 核对；加「本机实测」的条目是本通道跑出来的实际行为。

### 3.1 闸门一：四个必填参数 —— 缺一个都不许提交

**模式、分辨率、时长、画幅**这四项**必须由用户声明**。四项里缺任意一项，**都不要调用 miora**，也不要替他猜。

| 必填参数 | 合法取值 |
|---|---|
| 模式 | 文生视频 / 首尾帧生视频 / 参考生视频 |
| 分辨率 | `768P` / `2K` |
| 时长 | 4 ~ 15 秒的整数 |
| 画幅 | `16:9` / `9:16` / `1:1` 等 |

缺项时的标准动作：

1. **停下，不提交**，明确告诉用户还缺哪几项；
2. 缺的项**一次性列全**（不要一项问一轮），说明"四项填齐后才能提交生成"；
3. 可以给**建议值**帮用户决策，但**建议不等于默认**——用户没点头就不许写进参数里。

**禁止的四件事**：

- 拿"合理默认值"填上就投——本 skill **不再为这四项设任何自动默认**；
- 用文字描述蒙过去（比如不给 `duration`，指望模型自己定）；
- 只问一部分、先把任务投出去；
- 声称"我按你的意思补了默认值"——你没这个权力。

**不算法定缺项的一种情况**：用户声明了某一项，但取值不合法（例如分辨率说 `720p`）。这算**已声明**——属于取值澄清，不是参数缺失——按合法等价档映射并披露（`720p` → `768P`，见 3.2）。

模式这一项还要和素材对齐：手上有参考图就必须走参考生视频或首尾帧生视频，**不许退化成文生视频**（见第 2 节）。

四项齐了就直接视为已确认，不要再问一遍；其余参数（提示词内容、参考素材取舍）按第 2 节和第 6 节走。

**与 `miora-creative-core`「生成前必须 AskUserQuestion 确认」的冲突裁决**：当四参数齐全、且规格**全部由用户自己声明**（没有任何一项是模型填的默认值）、参考素材也已明确时，**不再重复提问**，直接提交——规格本就是用户给的，重复确认只增加一轮往返；用户把脚本写到分镜秒级时间轴这一层时，更是明确的定稿信号。需要重新提问的情形只有：产出规模变化、参数实质变化、用户要求重做。core 的确认环节若确实要做，也要装进"产出什么 / 规格 / 素材"的实质信息，不要做成空泛的"确认继续吗"。

### 3.2 输出规格

| 项目 | MiniMax H3（本通道在用） | MiniMax H3 Max |
|---|---|---|
| 模型名 | `MiniMax-H3` | `MiniMax-H3-Max` |
| 输出分辨率 | `768P` / `2K` | `480P` / `768P` |
| 输出时长 | **4 ~ 15 秒，仅整数** | 5 ~ 15 秒，仅整数 |

- 本机实测：`resolution` **只接受 `768P` / `2K`**，传 `720p` / `1080p` 被上游拒——`unsupported video resolution: 720p, supported values: [768P 2K]`。用户说 `720p` 时按 `768P` 投（16:9 原生档即 1344×768，等价档、不是降级），并在交付说明里写明；用户想要更高档时用 `2K`。
- 16:9 输出 **1344×768**；**24 FPS**；成片**带原生立体声音频轨**（32 kHz）。
- 本机实测（2026-09-16）：**15 秒 + 768P + 4 张参考图**一次通过，文件头读到 **15.08 秒 / 1344×768 / `has_audio: true`**。**4 张正好是通道上限的合法边界值**，不必为"以防万一"留余量。
- **成片时长会略长于请求值**：请求 9 秒 → 文件头 `mvhd` 读到 **9.42 秒**（帧对齐所致）；同一批实测还有 11 秒 → **11.54 秒**、12 秒 → **12.25 秒**、13 秒 → **13.67 秒**（两次一致）、15 秒 → **15.08 秒**。核验时按 **±1 秒**容忍（实测最大偏差 +0.67 秒），不要因为差这零点几秒判成规格不符，更不要因此重投。
- 从提交到落盘 **1.7 ~ 55 分钟，波动很大**（实测五次：13 秒档 1.7 分钟、6 分钟，15 秒档 6.8 分钟、20.8 分钟、**55.3 分钟**）。轮询预算按 **60 分钟以上**给——单段 `--timeout 1800` 也未必够，长任务要分段续挂（见第 5 节）；官方推荐轮询间隔 10 秒。
  - 最新一次（2026-09-17，15 秒 + 768P + 4 张参考图）：提交 12:14:59 → 落盘 13:10:16，**55.3 分钟**，文件头 15.08 秒 / 1344×768 / `has_audio: true`，与同规格历史实测完全一致。中途约 40 分钟时本地无任何文件、上游 `query_task` 仍报 `pending`（附带 `Request failed with status code 400`），**但最终正常出片**。
  - **结论：耗时长不能作为判定失败或重投的依据。** 唯一完成信号仍是落盘文件（见第 1 节）。
  - 补充实测（2026-09-17，同规格 15 秒 + 768P + **3** 张参考图）：提交 13:31:24 → 落盘 13:39:41，**8.2 分钟**，文件头 15.08 秒 / 1344×768 / `has_audio: true`。当日两次同规格作业分别为 55.3 分钟与 8.2 分钟，进一步说明耗时离散度极大（约 1.7 ~ 55 分钟），**不能靠历史耗时预估本次**。
  - 补充实测（2026-09-17，15 秒 + 768P + **4** 张参考图）：提交 14:12:29 → 落盘 14:24:11，**11.7 分钟**，文件头 15.08 秒 / 1344×768 / `has_audio: true`；生成调用前台阻塞至完成并返回 `status: completed` + `resultFiles[].localPath`，`--wait --claim` 绑定后 probe 与自报值一致。同日另一件 15 秒 + 4 图作业为 55.3 分钟——**同规格同素材数，11.7 分钟与 55.3 分钟并存，耗时离散度不因规格相同而收窄**。
  - 补充实测（2026-09-17，**11 秒** + 768P + 3 张参考图）：提交 13:45:12 → 落盘 13:50:37，**5.4 分钟**，文件头 11.54 秒 / 1344×768 / `has_audio: true`；本次生成调用在前台阻塞至完成并返回 `status: completed` + `resultFiles[].localPath`（第 1 节"仍要 `--wait --claim` 核验"的情形），`--claim` 落账后 probe 与自报值一致。
- `duration` 只吃整数，小数会被拒。

**时长下限有两套口径，别混说**：官方文档写 H3 是 **4 秒**起；本机历史实测只验证过 **5 秒**可用，4 秒这一档没验证过。要 4 秒时按"文档允许、本机未验证"如实说明，不要断言一定能做，也不要为了验证它花钱试探。

**没有自动默认值。** 时长和画幅都是闸一的必填项，用户没给就停下索取。可以给建议（单镜头从 5 秒起，多分镜按分镜数 × 3~6 秒估算），但**建议必须经用户采纳才能写进参数**。

### 3.3 输入素材上限

模型口径（H3 全能参考入口）：

| 素材 | 上限 | 附加条件 |
|---|---|---|
| 图片 | **≤ 9 张** | 单张 ≤ 30 MB；JPG / JPEG / PNG / WEBP / HEIC / HEIF |
| 视频 | ≤ 3 段 | 单段 2–15 秒、总 ≤ 15 秒；单段 ≤ 50 MB；H.264/H.265，内含音频 AAC/MP3 |
| 音频 | ≤ 3 段 | 单段 2–15 秒、总 ≤ 15 秒；单段 ≤ 15 MB；WAV/MP3；需搭配图片或视频 |
| 混合合计 | ≤ 12 个文件 | API 请求体 ≤ 64 MB |
| 图片尺寸 | 宽高均在 [256, 5760] | 宽高比 5:2 ~ 2:5 |

**通道口径（本机实测，比模型严）**：miora 通道对参考图做 **≤ 4 张** 校验，超了直接返回

```
UPSTREAM_ERROR: input.reference_images must contain no more than 4 elements (10005)
```

- 这是**提交层校验失败，不产生生成任务、不计费**，可以放心重投。
- **差异在通道侧，不在模型侧**：绝不能说"模型只支持 4 张"——官方是 ≤ 9 张，用户一核对就穿帮。
- 超 4 张时按主体优先级取 4 张（主角 / 场景 / 关键道具 / 主要对手），落选素材的设定**降级写进提示词文字描述**，交付时逐条披露。
- **取舍的真正标准是"文字还原难度"，不是照抄上面那句列举顺序**：机械道具（车辆、武器等精密结构）、角色身份最依赖参考图，**优先保留**；环境最容易靠文字承载（地表材质、光线、远景元素都可写清），可**最先舍弃**。实测案例：8 张素材里同时有摩托与折叠钢刀两个机械道具时，舍场景图保两张道具图，比分给场景一票更划算。
- **加一条判据：看这个元素在分镜里出镜多少、离镜头多近。** 全是近身中景 / 特写时，环境只是背景纹理，场景图首先舍；反过来有大远景、环境即主体的镜头，场景图就值得占一席。同理，末镜只有远景剪影的怪物，属"角色身份"仍优先于环境，但取全身三视图而不是头部特写——远景用不上头部细节。实测：一件四镜全为近身格斗的片子，舍场景图、保"主角 / 武器 / 近身对手 / 远景巨兽轮廓"四张最划算。
- **加一条判据：同一角色有多个形态（换装 / 变身 / 前后期形态）时，只保留本单元实际出现的那一个形态。** 形态切换发生在**同一个单元内**时才需要两张同留——因为"从 A 形态变到 B 形态"这个过程需要模型同时看到起点和终点。反之，单元全程是 B 形态、A 形态 0 出镜时，占一张 A 的槽位就是浪费。实测（2026-09-17）：同一角色素材里有"基础服三视图"与"战斗装甲三视图"，前一单元是装甲自脊柱向全身延展的展开过程 → 两张都留；后一单元全程装甲形态、基础服 0 出镜 → 舍基础服，把槽位让给对手的头部特写（该单元有两处怼头部的关键表现：抬头咆哮、脑后贯穿），取舍正确。
- **先核对「声明的形态」是否真的对应到文件，别照抄附件路径。** 实测（2026-09-17）：用户用 `@image#1` / `@image#2` 分别声明「岚·基础战斗服」与「岚·战斗装甲形态」，但两次附的是**同一个文件**（`岚基础三视图.jpg` 出现两遍），而素材目录里存在语义对应的 `战斗装甲三视图.jpg`（Read 该图目视确认为同一角色的全装甲形态）。这是**附件滑档**，不是用户想拿同一张图当两个形态。处置：① 先去素材目录按形态语义找同名 / 近名文件，用 Read 目视确认是不是同一角色的那一形态；② 确认后按形态语义替换进槽位——**槽位有冗余时（唯一素材数 < 4）替换不挤占任何素材**，因此不必停机回问，但必须在交付说明里显著披露"改用了哪张、为什么、声明的原路径是什么"；③ 若槽位无冗余（替换会挤掉别的素材）或找不到语义匹配的独立文件，回问，不许替用户决定。判据是"有没有把人原本要的素材挤出去"，不是"有没有动过路径"。
- 想把更多素材塞进 4 个槽位，唯一可行办法是**离线拼参考板**（本地 PIL 拼接，不重新生成、不损失像素），例如"怪兽全身三视图 + 头部特写"拼成一格。这改动了用户素材，**必须先问用户**。

### 3.4 提示词与参数

- 提示词上限 **7000 字符**。
- 关键描述后可用 `[运镜]` 指令引导镜头调度——官方推荐的精度控制手法，写镜头语言的段落可以用它。
- H3 **自带原生音频输出，没有关音频的参数**。所以"无配乐 / 无字幕"这类要求只能写进提示词去压，交付时如实说明这是提示词层面的约束，不是参数保证。
- **对白（人声）：没有台词输入通道。** 能把"有人在说话"生成出来，但**不保证按你写的句子咬字**，也没有逐字配音的可控手段。处理办法：把台词写进提示词时明确标成**表演提示**（谁在说、什么语气、停顿在哪、口型要有开合），并写明"不做字幕、不做文字叠加"；不要去承诺台词会念对。
- **混音类的描述（"对白期间压低环境声、保留空间底噪"）是后期工序，生成端做不到**。照原文写进提示词可以（它会往那个方向靠），但交付时必须说清这是后期的事，别让用户以为生成端已经做了。用户脚本里带这类注记时，通常意味着他本来就有后期配音/混音流程——照投，别为它停工。
- **参数名对照**（解读上游报错时用）：miora 的 `aspect_ratio` = API 的 `ratio`；miora 的 `references` 到上游是 `input.reference_images`；图生视频模式下 `ratio` 恒为 `adaptive`，画幅由首帧图决定，不能另行指定。

### 3.5 闸门二：时长区间 —— 先说，不许先试

时长参数（闸一必填项）落在合法区间之外时，**不要调用 miora**，直接用文字向用户说明做不到并给出原因。

H3 的合法区间是 **4–15 秒**（整数）。但 4 秒这一档本机没有验证过（见 3.2），所以：

- 要 **< 5 秒** → 说明本通道实测可用下限是 5 秒；文档写的下限是 4 秒但本机未验证，**要不要按 4 秒试一次由用户决定**，不要自己替他决定，也不要自己花钱去探。
- 要 **单次 > 15 秒** → 说明单次最长 15 秒，明确做不到。

**不许主动帮用户拆分提示词，也不许分镜分批提交生成。** 拆分与否是用户的决定，不是你的补救手段：用户明确要求分批时再照做。

同样不许的三种"假装满足"：

- 把参数写成用户要的值，指望模型自己截断或拉长；
- 把超限需求悄悄做成多条，交付时宣称"完成了"；
- 事后把规格不符说成已实现。

**两道闸门都在作业流程之前**：先过闸一（四参数齐否）→ 再过闸二（时长在区间内否）→ 才走第 4 节。任一不过就停在原地向用户说明，不许提交。

### 3.5.1 上游 `context ir` 报错（实测 2026-09-17）

提交后立即返回 `status: failed`，`errorMessage` 为：

```
1033: system error, MiniMax-H3 context ir (status_code=2000)
```

含义与处置：

- `context ir` 指官方的提示词增强环节，失败发生在上游处理链路上，**不是参数非法**——本次四参数（参考生视频 / 768P / 15s / 16:9）与 4 张参考图全部合法。
- 先用 `miora_query_task` 复核，别凭猜：本次复核返回同为 `failed`，确认不是 pending 假象，可以放心重投。
- 实测：约 2400 字中文提示词首投失败 → 压缩到约 1800 字、其余参数与素材全部不变，**重投一次成功**（15.08s / 1344×768 / 有音轨，约 9.7 分钟落盘）。
- **因果未证实**：无法排除上游瞬时抖动，所以不要写成"提示词超长必然触发"。但压缩提示词是低成本的差异化重试手段，优先于原样重投（没有新证据不原样重试）。
- **反向数据点（2026-09-17）**：约 **1900 字**中文提示词 + 3 张参考图，**首投即通过**（8.2 分钟落盘）。所以 1900 字档是已验证可过的量级——用户分镜脚本落在这一档时**直接逐字提交即可，不必预先压缩**；压缩只留作首投失败后的差异化手段。
- 失败任务不产生成片、无 `resultFiles`，重投属于新的一次生成，须向用户说明。

#### 3.5.2 提交返回 `MIORA_UNAVAILABLE` / `ENOTFOUND`（实测 2026-09-17）

提交调用可能返回：

```json
{"code":"MIORA_UNAVAILABLE","message":"Miora /api/ai/workbuddy-proxy/video/query-task unreachable: ENOTFOUND.","upstreamTaskId":"v89618551-..."}
```

含义与处置：

- 这是**提交已受理、结果回传通道断了**（`query-task` 域名 DNS 解析失败），**不是提交失败**。返回值带 `upstreamTaskId` = 上游确实收了任务。
- 按 `resumeHint`：**不要重投**（重复计费，且两份成片归属互相干扰）。先 `miora_query_task` 复核，再靠第 4 节的本地落盘等待收结果。
- 复核时大概率先撞 `AUTH_INVALID_TEMP_KEY`——重新 `connect_cloud_service` 取一次再查即可（与第 1 节的凭据不稳描述一致）。
- 实测链路：提交报 ENOTFOUND → 复核 pending → 本地等待正常出片（15.08s / 1344×768 / 有音轨）。**这条路上"接口不可达"从不等于"生成失败"。**
- `query_task` 返回 `pending` 时附带的 `Request failed with status code 400` **不改变 pending 这个结论**，也不是任务出错的证据；本地无文件就是没成品，继续等。

## 3.6 官方有、本通道没暴露的能力

用户问到这些时，如实说是通道没开，不要承诺：

| 官方能力 | 本通道情况 |
|---|---|
| **MiniMax H3 Max**（480P/768P、生成更快、时长 5–15s） | 没有模型选择参数，调不到。用户要"更快"或"480P"时说明做不到 |
| **视频再生成**（拿已有 768P 成片 + 原 `content` 重跑出 2K） | 没有对应工具。想要 2K 只能**直接以 `2K` 重新生成一条**，那是新的一次计费生成，须先经用户同意 |
| **H3-Context-IR**（只返回增强提示词、不生成视频） | 没有对应工具。提示词增强由本 skill 第 6 节自己做 |
| **参考视频 / 参考音频输入** | miora 的参考生视频只收图片，没有视频、音频通道。用户想用参考视频驱动动作或配参考音频时，说明通道不支持 |
| **取消 / 删除任务** | 提交后无法取消 |

---

## 4. 作业流程

先过两道闸门：**闸一（3.1）四个必填参数是否齐** → **闸二（3.5）时长是否在区间内**。任一条不过就停下向用户说明，不许提交。

```
① 登记   python scripts/miora_watch.py --submit --job <作业名>
② 生成   mcp__miora__miora_*_video（tempKey + 参数）
          ↑ 返回值丢失属正常，不因此重发
②.5 认领 返回值带了 localPath → --wait --claim <localPath> --job <作业名>
          ↑ --claim 是修饰项，必须挂在一个动作上。实测 2026-09-16：单独跑 --claim 报
            "one of the arguments --submit --wait --poll --poll-all is required"
          ↑ 有绑定就用绑定；没返回就跳过，走 ③ 的扫描
③ 等待   python scripts/miora_watch.py --wait --job <作业名> --timeout 1800
④ 核验   从 ③ 的 probe 读时长/分辨率/音轨，与确认过的规格对照
```

**作业名撞车是会真实发生的**：同一台机器上多个会话可以同时在生成，时间窗一重叠，"since 之后最早落盘的文件"就不一定属于你。实测过一次：并发作业 22:42:22 提交、本作业 22:44:49 提交，前者的成片 22:49:09 落盘，被本作业的 `--wait` 认成了自己的结果；本作业真实的成片 22:50:46 才落盘。
两个防线：

- 脚本扫描时**跳过其他作业标记里已登记的 file**（`claimed_by_others`），避免认领别人已经拿走的产物；
- 仍存疑时**用返回值里的 `signedUrl` 做指纹对账**：下载它，与本地候选文件比 md5。实测这一招能唯一确定归属（signedUrl 与本地文件字节一致）。signedUrl 有效期短，要趁早；它只用于核对，**不要交给 `present_files`**。

**别把并发作业的成片交出去**：两份片子若参数相同、时长相同，靠 probe 分辨不出来，只能靠提交时刻 + 指纹归属。归属没定之前不要写画布、不要 present。

作业名用有意义的名字（`lan-15s`、`shot-03`），不要随机串。三个动作都必填 `--job`，脚本会拒绝空名——空名会生成一个名为 `.json` 的伪作业污染列表。

忘了在生成前登记也没关系：`--wait` / `--poll` 会自动从当次调用时刻起算并补登记，链路不会断。

③ 返回码 2 表示超时，**不是失败**，转入第 5 节；`--wait` 被上层超时打断就改后台运行，用任务 id 收结果。

**脚本怎么调（Windows 本机实测）**：用 Python 绝对路径，脚本路径写 Windows 风格。

```bash
"/c/Users/<username>/.workbuddy/binaries/python/versions/3.13.12/python.exe" "C:/Users/<username>/.workbuddy/skills/miora-video-studio/scripts/miora_watch.py" --submit --job <作业名>
```

两个坑：① 脚本路径传 `/c/Users/...` 这种 Git Bash 形式会被错误转换成 `c:\c\Users\...`，报 `No such file or directory`——**脚本路径必须用 `C:/...`**；② 某些会话里 Bash 的 `ls` / `head` / `cat` / `which` 会 `command not found`（PATH 缺失），所以**脚本输出不要走管道**，直接读 stdout，文件探查改用 Glob / Read 或 Python 绝对路径。

两个补充（同样是实测踩到的）：

- **别把路径存进 shell 变量再展开**。`SK="/c/Users/.../miora_watch.py"; "$PY" "$SK"` 一样会被转成 `c:\c\Users\...`。路径一律写成 `C:/...` 字面量，不要中转。
- **本机可能没有 `curl`、没有 `ffmpeg`**。要下载返回值里的 `signedUrl` 做指纹对账时，用 Python `urllib.request`；要读视频头规格时，直接 `importlib` 加载本脚本复用它的 `probe()`，不必另装工具。

---

## 5. 状态同步

| 路径 | 命令 | 适用 |
|---|---|---|
| 同轮闭环 | `--wait` | **主力**。一次轮询就能等到，用户不用再说话 |
| 显式绑定 | `--wait --claim <localPath> --job <名>` | 生成调用返回值里带了 `localPath` 时**先跑这个**，再用 `--wait` 核验 |
| 跨轮兜底 | `--poll --job <名>`；新会话用 `--poll-all` 恢复现场 | 轮到点结束、应用重开后再回来 |

返回码是给上层判断的语义：`0` 已完成 ／ `2` 超时（≠失败）／ `3` 仍在生成。作业状态另有 `unknown`——标记缺失或损坏，**无法判定**，不等于完成。

**后台 `--wait` 被打断（实测 2026-09-17）**：放进后台跑的 `--wait` 可能被会话切换 / 应用重开 kill，返回 `status: killed` 且**无任何输出**，长任务尤其容易撞上。处置：

1. 跑一次 `--poll` 确认当前状态；
2. 再**重新挂一段 `--wait` 接着等**——`since` 已登记，续挂不丢上下文、不重复计费；
3. **killed 不是失败，更不是重投的理由。**

长任务建议**分段挂**（单段 `--timeout 900` ~ `1500`），比一次挂 1800 秒更抗打断。

**三条判定铁规**（都是踩过坑才定下来的，改脚本时别破坏）：

- **取 `since` 之后最早出现的文件，不取最新的。** 两个作业时间窗重叠时，取最新会把后提交作业的成片误认成前一个作业的结果——这是真实会发生的误报。
- **已被别的作业认领的文件要排除掉。** 只靠上一条仍会撞车：并发作业的成片先落盘时，会被后来的作业抢先认成自己的结果（实测过一次，且两份片子 probe 完全相同、无法用规格分辨）。脚本用 `claimed_by_others()` 实现，别删。
- **`since` 一旦登记就永不丢失。** 无法确定 `since` 的标记一律标 `unknown` 并跳过扫描，**绝不 fallback 到 0**；回退到 0 等于扫描全部历史文件，必然把上一轮的旧成片报成本次完成。

其余可靠性来源：

- **体积稳定判定**：连续两次读数一致才认定写完，排除半写文件误报完成。
- **文件头核验**：解 `mvhd` 读时长、`tkhd` 读分辨率、查 `mp4a` 判断音轨。
- **标记固定放用户级目录**，不随工作目录漂移，换目录、换会话都找得到。

路径：媒体目录 `~/.workbuddy/plugins/data/mcp-miora/miora-media`（可用 `--media-dir` 覆盖）；标记文件 `~/.workbuddy/miora-jobs/<作业名>.json`。作业名做成 `项目-用途-序号`（如 `lan-15s-2`）以便区分。

没有回调、没有反向唤起。用户不说话时的唯一自动路径是定时自动化——那是例外手段，不要为常规任务常驻。

---

## 6. 提示词构建与修正边界

**逐字透传的情形**：用户已给完整描述，或示意"就用我的原话"。不扩写、不改词，只允许补第 2 节说的编号映射。

**含糊则补全，且必补运动**——只写静态画面会得到一段几乎不动的视频。四件事说清：

1. 主体在做什么（具体动作，不是"一个人站着"）；
2. 镜头怎么动（推 / 拉 / 摇 / 跟 / 环绕，**一个镜头只用一种运动**，叠加会乱）；
3. 光线与氛围（主光方向、软硬、色温 + 氛围词）；
4. 结束状态（镜头停在哪，不写结尾容易飘）。

写镜头的第 2 条时可用官方支持的 **`[运镜]` 指令**：在关键描述后面直接跟 `[运镜]`，引导镜头调度，比重述一遍自然语言更稳。

总长控制在 **7000 字符**以内（上限，见 3.4）。用户给的脚本本来就长时，优先保主体身份描述、镜头运动、物理动作和全局约束，压缩美术词藻。

### 6.1 允许自动改（改完必须在交付说明里逐条披露）

| 明显问题 | 处理 |
|---|---|
| 分镜时间轴重叠、越界、不连续 | 改为顺序衔接并披露 |
| 分镜时间轴合计 ≠ 声明的时长 | **以声明的时长为准**（它才是闸一必填项），但时间轴**原样保留、不拉伸、不慢放**。合计短于声明的 → 把差额写成"延续末镜收尾状态、不新增动作"（实测：10.5s 的分镜放进 13s，末段写"巨兽继续缓慢转身、尘土未落、主角保持跪姿"）；合计长于声明的 → 按比例压缩秒点（实测：14s 压缩到 13s）。两种都要在交付说明里点明冲突与处理方式，并给出"按另一个值重投"的选项。**禁止**用慢动作、补拍内容或反复切镜去填满时长。 |
| 只有静态描述、无任何运动信息 | 按上面四件事补齐 |
| 未声明参考图角色 / 素材顺序与 `@image#N` 不一致 | 补角色映射、按用户可见顺序对齐并披露 |
| 设定段里混着本单元并不出镜的条目（惯用固定模板时常见，如"本段有三只怪物缠斗"其实属于上一个单元、或已弃置的道具） | **不许删原文**，改为在提示词**开头加一段「入画依据」**，明确本单元画面里有谁、没有谁；落选者写"仅作世界观背景 / 不在画面内"。实测：一件只有主角与巨兽的单元里，人设仍带着上一单元的小怪条目与弃置摩托，靠「入画依据」段排除，比逐条删改原文更安全、也好披露。 |
| 拼写、标点、明显笔误、格式混乱 | 直接改，保持原意与用词风格 |
| 与显式全局约束冲突（如写了配乐，又要求"无配乐"） | 以显式约束为准并披露 |
| 缺模式 / 分辨率 / 时长 / 画幅中的任一项 | **不许补**。这是闸一缺项，停下向用户一次性列全索取（见 3.1） |
| 参考图超过通道上限 4 张 | 按主体优先级裁到 4 张，落选素材的设定改写进提示词文字描述，交付时逐条披露（见 3.3） |
| `resolution` 声明成 `720p` / `1080p`（已声明但不合法） | 按等价档 `768P` 投（用户要更高档时 `2K`）并披露（见 3.2） |
| 提示词超过 7000 字符 | 压到限内，优先保主体 / 运动 / 动作 / 全局约束，交付时说明压掉了什么 |
| 用户要求无配乐 / 无字幕 | 写进提示词（H3 无音频开关），并在交付时说明这是提示词层约束、需目视耳听确认 |

### 6.2 必须回问，不许自行决定

- 改动**主体身份特征、关键设定、台词内容或语气**这类用户固定的核心属性；
- 增删参考素材；
- 大幅改变产出规模（条数、时长档位跳变）；
- 用户明确说了"原封不动"的段落——只允许补编号映射，一个字都不许动。

判断不了就问。**例外：闸一的四个必填参数（模式 / 分辨率 / 时长 / 画幅）不适用"跳过提问就按默认执行"**——那四项属提交前提，用户不声明就一直停着，见 3.1。其余项用户跳过提问时按默认执行并明说。

---

## 7. 验收

- 产物真的拿到了：本地路径有效，不是失败占位。
- **实测时长 / 分辨率与确认过的规格一致** —— 读 probe 的值来对，不要复述提示词里写的。
- 用户固定的主体特征没被改掉；同一批成片在同一张画布上；画幅统一。
- **不断言"画面流畅""运镜到位""音效对白正确"** —— 文件头读不出来，如实标为需用户目视确认。
- 不合格不要自动重做，是否重做由用户决定。

交付动作（画布、`present_files` 的参数与顺序）以 `miora-creative-core` 为准。

---

## 8. 两条边界

- **多分镜塞进单次生成，模型会自由取舍**，不会严格按你写的秒数切镜头——要精确切分只能分条生成再拼。
- **严格跨条身份一致做不到。** 参考图只能逼近，多条之间必有可见差异。用户有硬要求时说明限制让用户决定，不要硬做后交一堆对不上的片子。
