导入提交:Submit 必须冻结 Revision 与 PlanDigest
自动关联目录:导入提交:Submit 必须冻结 Revision 与 PlanDigest
核心判断:导入按钮提交的不是“当前草稿 ID”,而是一次不可变执行意图;只有同时冻结草稿 Revision、源文件指纹、计划摘要和工具能力版本,异步 Cook 才不会消费后来变化的内容。
一、业务冲突
模型检查、节点选择、材质补图和目标平台配置都可能在 UI 中继续变化。若运行任务只保存草稿 ID,排队后再读取草稿,就可能出现预览的是 A、Cook 的却是 B,重试时又变成 C。最终产物即使成功,也无法回答它对应哪次确认。
二、实际实现
实际导入合约把草稿与运行任务分开。命令携带 expectedRevision;提交批次同时提交各草稿 Revision 和 planDigest。运行记录保存 frozenDraftRevision,并落盘一份紧凑的冻结计划,包含源输入指纹、绑定指纹、Schema、选择、参数、目标平台、产品图和兼容能力快照。执行前再次验证计划字节与摘要一致。
三、值得保留
这套设计把“用户仍可编辑的配置”与“已经进入执行的事实”分离了。运行任务不会因检查结果刷新而漂移;测试还明确修改提交后的检查数据,证明既有任务继续使用冻结计划。这比锁死整个 UI 更符合创作体验。
四、结构性缺陷
冻结事实分散在 Revision、多个 fingerprint、planDigest 和 capability 字段中,调用方若漏比一个就会形成局部一致。计划摘要能证明字节未变,却不能单独证明源快照、工具链和目标制品属于同一执行世代。
五、目标设计
struct ImportIntent {
IntentId id;
DraftRevision draft;
Hash sourceSnapshot;
Hash normalizedPlan;
Hash capabilitySnapshot;
Array<TargetId> targets;
};
RunId Submit(DraftId draft, Revision expected, Hash expectedPlan) {
DraftSnapshot s = LoadAndCompareExchange(draft, expected);
Require(HashOf(s.plan) == expectedPlan);
return PersistRun(FreezeIntent(s));
}后续每个 Stage 只接受 IntentId,产物 Manifest 反向记录全部冻结摘要。重试复用同一 Intent;用户修改配置只能创建新 Intent,不能改写旧运行。
六、取舍与验证
代价是额外快照空间、摘要计算和“旧任务不能顺手使用新配置”的产品解释成本。验证要覆盖提交与编辑竞争、源文件替换、工具升级、目标平台变化和进程重启,最终断言运行输入与产物证明始终闭环。下一次应先定义“提交冻结什么”,再设计按钮和队列。