# 短剧流程、版本依赖与付费异步任务 ## 1. 不要只设计一张“任务状态”表 | 状态域 | 回答的问题 | 示例 | | --- | --- | --- | | 内容确认 | 这个剧本/镜头信息是否被人确认 | draft、confirmed | | 生成准备度 | 引用、参数、能力、价格是否齐备 | notReady、ready、stale | | 阶段运行 | 整集当前推进到哪个生产步骤 | script、assets、shots、audio、edit | | 任务 | 后台目前在做什么 | queued、waitingProvider、ingesting | | 远程提交 | 上游是否接受、ID 是什么 | prepared、accepted、outcomeUnknown | | 资金 | 用户积分是否冻结/结算 | reserved、settled、released | | 资产 | 文件是否入库、哪个版本被选用 | staging、ready、quarantined | “镜头已确认”不代表视频已生成;“上游完成”不代表已经交付;“任务失败”不一定能立即退款。 ## 2. 生产流程的阶段契约 | 阶段 | 冻结的主要输入 | 产物 | 人工关口 | | --- | --- | --- | --- | | 故事规划 | 创作简报、约束、目标 | StoryOutlineVersion | 确认故事方向与权利 | | 剧本 | 已确认大纲与人物设定 | ScriptVersion | 确认分场、对白和节奏 | | 资产准备 | 剧本版本、资产候选 | AssetVersion、ProjectBibleVersion | 合并角色、选参考图、锁定版本 | | 分镜 | 剧本、已确认资产 | ShotVersion、对白引用 | 检查准备度与每个媒体角色 | | 试拍 | 少量镜头与价格快照 | 样片/候选视频 | 确认视觉,再授权批量 | | 镜头生产 | 已批准批次计划 | 视频版本与任务记录 | 失败项单独处理 | | 音频 | 明确对白文本和音色 | AudioVersion、字幕候选 | 检查读音、权利和时间 | | 编辑 | 选定素材版本 | TimelineVersion | 预览与导出确认 | | 渲染 | 不可变时间线与渲染档位 | ExportVersion、素材包 | 交付质量检查 | Agent 只能提出计划与草稿。付费工具调用必须携带服务端 Grant,且 Grant 绑定输入摘要、额度、范围和有效期;不能把“帮我做个视频”当成无限预算。 ## 3. 不可变计划与用户授权 PlanSnapshot 包含明确资源版本、内容摘要、规范化参数、产品模型、binding 候选范围、价格版本、输出数量、约束、预留上限与 canonical input hash。 Quote 绑定该 Plan,不直接引用随时变化的“当前剧本”。确认时重新检查权限、版本、有效期和可用余额。输入、价格或未批准的路由变化都应返回新报价;不能在用户点确认后自动提高预算。 P0 默认逐操作确认;允许一次确认一个明确批次。P1 可提供按项目/集的预算 Grant,但仍限制能力、金额、次数、时间和模型范围。撤销 Grant 阻止未开始的付费动作,不倒退已经受理的执行。 ## 4. 任务状态与允许转换 | 状态 | 含义 | 主要后继 | | --- | --- | --- | | `queued` | 已持久化、等待领取;尚未跨提交边界 | running、cancelled | | `running` | Worker 已领取并检查执行身份 | waitingProvider、ingesting、failed、needsReconciliation | | `waitingProvider` | 已有明确上游任务 ID,等待同一任务 | ingesting、failed、needsReconciliation | | `ingesting` | 上游有结果,正在安全转存与登记 | succeeded、needsReconciliation | | `needsReconciliation` | 受理、结果或交付事实需要核对,非普通终态 | waitingProvider、ingesting、succeeded、failed | | `succeeded` | 可交付产物已登记,或文本结果已持久化 | 终态;财务可暂为 settlementPending | | `failed` | 有充分事实确认失败且无交付,附结构化原因 | 终态;显式新生成走新 Execution | | `cancelled` | 用户在排队阶段取消,无远程生成副作用 | 终态 | 创建前校验失败不一定需要 Task。P0 用户取消只对 `queued` 开放;已经开始提交/等待上游时只能停止尚未开始的下游任务,不承诺省回已受理费用。 ## 5. ProviderAttempt 的提交边界 | 状态 | 持久事实 | 是否允许重新 POST | | --- | --- | --- | | `prepared` | 输入/渠道/协议/凭据版本已冻结,还没跨发送 fence | 仅唯一持有者可首次发送 | | `submitStarted` | 已取得唯一发送权;请求可能已到上游 | 默认不允许,崩溃后进入核对 | | `accepted` | 明确 external ID 或已收到同步结果 | 不允许,查询/入库原结果 | | `rejectedBeforeAcceptance` | adapter 按契约保存未受理证据 | 仅按批准策略执行,不从状态码推断 | | `outcomeUnknown` | 无法确认上游是否受理 | 不允许自动重发或换渠道 | | `completed` | 上游终态与结果/失败证据已保存 | 不允许重新生成 | `submitStarted` 必须在实际 HTTP 前提交到数据库。它不能与远程服务构成原子事务,所以“拿到 fence 后、实际发送前崩溃”也可能进入保守核对;这是防重复费用的有意取舍,不谎称完美 exactly once。 ## 6. 创建与出队事务 ### T1:用户确认 锁定钱包与报价;校验幂等 key 与 hash;创建 Execution、Task、Reservation 和 Outbox;同一数据库事务提交。提交失败全部回滚,没有“已扣费但任务没创建”的可见半态。 ### T2:队列投递 dispatcher 读取 Outbox,使用稳定 Job ID 投递 BullMQ。发布后更新 Outbox 的发送状态;任意崩溃都可能造成重复投递,因此消费者必须幂等。Redis 队列去重是优化,不是最终正确性来源。 ### T3:领取与发送 Worker 用条件更新领取 Task,获取递增 lease token。生成 Attempt;数据库原子认领 submit fence。外部请求前再次检查 lease/fence;失去 lease 的旧进程不能创建第二次执行。 若 SDK/代理层有自己的 POST 重试必须关闭。网络 fence 只能控制本平台发起次数,不能控制未知上游自身的重试行为,因此还需供应商协议核验。 ### T4:接受与恢复 收到 external ID 后立即持久化渠道版本、请求身份、句柄与查询检查点,再调度 Poll。写库失败不能假装“未受理”;记录事故并进入核对。可使用受控持久诊断收据辅助救援,但不能把 key 或完整请求媒体放日志。 ## 7. 轮询与回调 - 轮询任务是短运行 job,一次查状态后退出,下一次延迟调度;不在 Worker 里睡几十分钟占并发槽。 - query 根据同一 ProviderJob 恢复,独立于创建请求重试预算。 - 区分查询网络错误、上游排队、生成失败、结果过期和未识别状态。 - 轮询间隔遵循供应商建议与配额,加入抖动;时间上限只是触发核对,不证明远程失败。 - 回调有官方签名时校验原始 body、时间戳与事件 ID;没有可靠鉴别时仅作唤醒提示,再主动 query。 - 回调和轮询都以版本条件写入,同一终态/资产/结算只生效一次;迟到消息不回退终态。 - 回调不得提供新的任意下载域名;结果仍经出站策略与媒体校验。 ## 8. 交付与资金结算顺序 上游完成、结果可下载、转存成功、AssetVersion 登记是不同事实。先发布可交付的不可变产物,再以稳定业务身份请求结算。登记成功但结算暂时失败时,产物保留,资金为 `settlementPending`,账本重试,不重新调用上游。 如果上游成功、暂存失败,保持 `needsReconciliation` 并只恢复交付。超过公示交付期限仍无法交付时,由平台规则释放/补偿用户费用,平台承担其自身交付事故的上游成本;后续迟到结果不能悄悄再次扣费。 ## 9. 重试分类 | 操作 | 自动恢复策略 | 必须避免 | | --- | --- | --- | | 输入检查、价格解析 | 本地纠正后新计划 | 在 Worker 才发现可以前置阻止的问题 | | Outbox 投递 | 稳定身份重投 | 把 Job 重试当成外部 POST 重试 | | 已知任务 query | 有界退避 | query 超时重新创建视频 | | 结果下载与探测 | 同一结果身份、受控临时文件 | 重新生成媒体 | | 账本结算 | 业务唯一 key 幂等重试 | 重扣或把结算失败伪装成生成失败 | | POST 受理未知 | 核对,不自动重发 | 根据 429/5xx/异常文本猜测没收费 | | 用户不满意 | 明确新执行、新报价 | 把“再生成一次”叫作免费恢复 | | 内容拒绝 | 修正内容或申诉 | 自动换渠道绕过限制 | ## 10. 重启与多实例恢复 Task 有 owner、lease token、expiresAt 和 heartbeat。恢复程序只处理过期且所有权可合法接管的任务;不能仅因本机没有内存协程就认定整个集群任务已死亡。 - 没有 submit fence:可重新排队,不产生远程重复费用。 - 已有 fence,无接受事实:进入核对;若上游支持经验证的幂等查询,可恢复同一身份。 - 有 external ID 与合法 checkpoint:继续查询原任务。 - 有同步响应暂存但尚未登记:继续 Ingest。 - 有已登记产物,资金未结:继续结算。 - 检查点缺失/损坏或渠道身份无法解析:停止自动动作并报警,不能从当前默认渠道猜测。 Redis 持久性损失后的恢复扫描依据数据库,且只重投调度事件,不重置提交身份。数据库损坏或从较旧备份恢复后,涉及旧提交窗口的任务必须核对,不能全量重跑。 ## 11. 批次与依赖失效 批次一次批准总上限,每项有稳定 item ID、独立预留和输出。成功项不重跑;失败项的“继续”必须判断是恢复原远程查询/交付,还是用户明确批准新生成。 剧本、参考图、对白或时间线变化形成新版本。依赖关系记录具体版本与用途:修改角色参考图只影响引用该版本的镜头,不让全项目无差别过期。系统提示过期,用户决定是否重做;旧版本仍可用于历史成片。 ## 12. 时间线与渲染任务 RenderPlan 冻结素材版本、片段范围、速度、音轨、字幕、渲染模板与输出档位。输入尚未就绪或存在越权、负时长、非法比例时禁止报价。渲染结果登记与 AI 结果使用同一资产系统,但渲染重试不触发 AI。 同一导出请求重复提交返回原 RenderJob;用户改变画幅或内容后是新请求。超大文件和超长素材根据服务端探测限制,不能从浏览器自报时长计算资源预算。 ## 13. 任务中心与诊断 用户看见阶段、项目/镜头、开始时间、可用操作和积分状态;不直接显示上游原始错误。详情回到对应业务页;任务中心不变成提示词和资源映射的巨大编辑器。 管理员看见脱敏失败码、attempt、external ID、版本、lease 和恢复动作。所有人工动作必须说明“只查询”“只转存”“重新生成(可能收费)”或“资金补偿”,不能都叫“重试”。 ## 14. 最小验收故障集合 发送前崩溃、发送后未收到响应、收到 ID 后写库失败、查询断线、未知上游状态、回调重复/乱序、下载中断、存储写成功但登记失败、结算失败、Redis 重启、双 Worker 争抢、配置发布、密钥撤销、迟到成功、用户重复点击与批次部分失败。每种情形都必须证明:没有未授权的新生成、没有重复账本效果、存在可解释的恢复路径。