miora-video-studio · git:20260918.a827ccc · 2026-09-18 · sha256 3b4441ecce74b4c8

miora-video-studio git:20260918.a827cccA

Immutable. This exact content is served forever at /api/v1/blob/3b4441ecce74b4c8.

---
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. 两条边界

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