fix(saa): 包级 assets 接通源 sourceProject.assets[]——闭合产消断链(兑现 engine-E2/E3 消费侧 TODO)
gen-done 出包历史上把包级 assets 硬置空(setAssets(emptyList)),丢掉源
gameDefinition 已落库的六类源资产(game_source_project.source_json 顶层
assets[6]),造成产(asset 节点写源)→消(组包)断链。
改 SaaGraphDispatcher.buildCallbackReqVO(in-JVM SAA 路,即 generic/engine
任务真实落包路):新增 extractSourceAssets(s,traceId) 从图终态 K_SOURCE_PROJECT
抽顶层 assets[] 忠实映射进 reqVO.assets;DifyCallbackTxService.buildGamePackage
读 reqVO.getAssets() 即自然带进 GamePackage.assets。
- 形态:源 assetSpec={id,category,ref,provider}(source-project.schema.json
#/$defs/assetSpec),运行时 gd-runtime 经 gdef.assets 同形消费;geom:<cat> ref
系几何占位资产引用,原样透传,不伪造包契约 strict AssetSpec 的
type/url/hash/bytes/mime(无真图/真 sha256,伪造即脏数据)。
- best-effort 非阻断(严格 additive):源缺失/空白/非 JSON/无 assets 键/非数组/
异常一律回退空集,绝不外抛、绝不打断 SAA 生成;存量无源回调字节零变化。
- 复用既有 parseTrace + TRACE_MAPPER(只读,无共享可变状态),不引新依赖。
不动 AigcGenerateExecutor:440:该处为进程内 clicker/merge 旧路(generic/engine
经 dispatchGeneric 早返,不达此行;worker 回调由独立 reqVO 驱动),作用域无
sourceProject,改它即凭空伪造,故按现状保留(对齐 run_batch.py assets:[])。
验证:mvn -o clean install -pl game-module-aigc-server -am 编译 BUILD SUCCESS;
DifyCallbackServiceImplTest+AigcGenerateExecutorTest 41 tests 0 fail(含
in-process 路 getAssets().isEmpty() 断言仍过,确认未回归)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9d463f0873
commit
490dc6293d
@ -609,7 +609,14 @@ public class SaaGraphDispatcher implements GenerationDispatcher {
|
||||
DifyCallbackReqVO reqVO = new DifyCallbackReqVO();
|
||||
reqVO.setTraceId(traceId);
|
||||
reqVO.setTemplateId(templateId);
|
||||
reqVO.setAssets(java.util.Collections.emptyList());
|
||||
// ── U2/B8 消费侧(§5.2 产消接通):忠实取已落库源 assets[](六类源资产)填充包级 assets,替代历史硬置空。 ──
|
||||
// 兑现 SaaStudioNodes 处自标的「engine-E2/E3 消费侧本期不做」TODO:源 asset 节点已产 assets[6]
|
||||
// (schemaVersion+gameDefinition+顶层 assets,落 game_source_project.source_json),此处把同批源 assets
|
||||
// 忠实带进 GamePackage.assets(DifyCallbackTxService.buildGamePackage 读 reqVO.getAssets()),闭合产消断链。
|
||||
// 形态注记:源 assetSpec={id,category,ref,provider}(source-project.schema.json #/$defs/assetSpec,运行时
|
||||
// gd-runtime 经 gdef.assets 同形消费);geom:<cat> ref 为几何占位资产引用,原样透传不伪造 type/hash/bytes/mime。
|
||||
// 空/缺/非数组源 assets → 回退空集(不抛):严格非破坏,存量无源回调字节零变。
|
||||
reqVO.setAssets(extractSourceAssets(s, traceId));
|
||||
// gameConfig 最小合法占位(engine 路游戏逻辑全在 engineBundle,gameConfig 仍不可空:GamePackage required)。
|
||||
Map<String, Object> gameConfig = new LinkedHashMap<>();
|
||||
gameConfig.put("templateId", templateId); // 须与包级 templateId 一致(一致性校验)
|
||||
@ -763,6 +770,55 @@ public class SaaGraphDispatcher implements GenerationDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* U2/B8 消费侧(§5.2 产消接通):从图终态 {@code K_SOURCE_PROJECT} 抽顶层 {@code assets[]} 映射为包级 assets。
|
||||
*
|
||||
* <p><b>兑现 TODO</b>:源 asset 节点已把六类源资产写入 {@code sourceProject} 顶层 {@code assets}
|
||||
* ({@code source-project.schema.json #/$defs/assetSpec},形态 {@code {id,category,ref,provider}}),历史上组包侧
|
||||
* 硬置空集导致产消断链;本方法把<b>同一批</b>源 assets 忠实搬进 {@link DifyCallbackReqVO#getAssets()},
|
||||
* 由 {@code DifyCallbackTxService.buildGamePackage} 落进 {@code GamePackage.assets}。运行时 {@code gd-runtime}
|
||||
* 经 {@code gdef.assets}(同 source assetSpec 形态)消费,故<b>原样透传不重塑</b>:{@code geom:<cat>} 为几何占位
|
||||
* 资产引用,不伪造包契约 strict AssetSpec 的 {@code type/url/hash/bytes/mime}(无真图、无真 sha256,伪造即脏数据)。
|
||||
*
|
||||
* <p><b>best-effort 非阻断(严格 additive)</b>:源缺失/空白/非 JSON/无 assets 键/assets 非数组/任意异常 →
|
||||
* 一律返回<b>空集</b>(绝不外抛、绝不打断 SAA 生成),与历史「恒空集」对存量无源回调字节零变化。
|
||||
*
|
||||
* @param s 图终态(可能 null)
|
||||
* @param traceId 贯穿键(仅日志)
|
||||
* @return 源 assets 映射出的 {@code List<Map<String,Object>>}(忠实透传字段);无/异常时空集(非 null)
|
||||
*/
|
||||
private static java.util.List<Map<String, Object>> extractSourceAssets(OverAllState s, String traceId) {
|
||||
if (s == null) {
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
try {
|
||||
// 复用 best-effort 宽松解析(null/空白/非法 JSON → null);源串即 §5.2 落库的 source_json。
|
||||
JsonNode root = parseTrace(s.value(SaaStudioNodes.K_SOURCE_PROJECT, String.class).orElse(""));
|
||||
if (root == null) {
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
JsonNode assets = root.path("assets");
|
||||
if (!assets.isArray() || assets.isEmpty()) {
|
||||
// 无 assets 键 / 非数组 / 空数组 → 回退空集(不抛,存量无源回调字节零变)。
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
// 逐项忠实映射为 Map(保 {id,category,ref,provider} 等全部源字段;geom: ref 原样);非对象项跳过(防御脏数据)。
|
||||
java.util.List<Map<String, Object>> out = new java.util.ArrayList<>(assets.size());
|
||||
for (JsonNode a : assets) {
|
||||
if (a != null && a.isObject()) {
|
||||
out.add(TRACE_MAPPER.convertValue(a, new com.fasterxml.jackson.core.type.TypeReference<Map<String, Object>>() {}));
|
||||
}
|
||||
}
|
||||
// 可追溯日志:接通了几个源 assets(0 表示源里确无对象项,等价历史空集,不告警)。
|
||||
log.info("[saa-dispatch] 包级 assets 接通源 assets[] 共 {} 个(产消接通,兑现 engine-E2/E3 消费侧 TODO)traceId={}", out.size(), traceId);
|
||||
return out;
|
||||
} catch (Exception e) {
|
||||
// 命门:抽取/映射异常一律吞 + warn 返空集,绝不打断 SAA 生成(生成成败由 status/engineBundle 既有逻辑决定)。
|
||||
log.warn("[saa-dispatch] 源 assets 抽取失败,包级 assets 回退空集(不阻断生成)traceId={}", traceId, e);
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 派生 models 并集:{@code K_TOKENS_BY_MODEL} 的 model 名键集 ∪ {@code K_ATTEMPTS[].{role:model}},组同形 {role:model} map。
|
||||
*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user