codex xhigh 契约评审 FREEZE-WITH-FIXES(零 P0 破坏)。逐条收口: - P1 payload 必填 + mode×target.kind 锁定映射(后端可信边界校验,不用 oneOf 保 mock/codegen 简单) - P1 target path/id anyOf 强制至少其一 - P1 payload value/intent 按 mode 必填(后端校验) - P2 AssetContextItem 补 provider + 后端派生 assets[].id 说明 - P2 idempotency 语义(同 userId+op+key 命中返既有 taskChain/缺省不去重/TTL 24h) - P2 execution §5.6 JSON 指针示例纠错 /gameDefinition/config/speed→/config/speed(config 顶层,对齐 keystone) 复验:YAML 绿、14 $ref 零悬空、六类对齐 keystone、现有端点/VO 零破坏。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
56 KiB
固定游戏架构 + SAA agentic studio — execution 版
类型:execution 版(供两开发线实现)。日期:2026-06-17 · 起草:Opus(effort=高)。 上游(权威,勿翻旧账):
2026-06-17-固定游戏架构与SAA-agentic-studio-review.md—— 以 §1.5(已定决策)+§10(深析并入) 为权威;§4 旧 agent 表已被 §10.1 取代。2026-06-17-生成主线-游戏生命周期项目管理-review.md—— modify=改源不改打包产物 v2 口径权威;manifest 可寻址 diff 已废、不采用。- 命名/状态/分层规范见
.agents/rules/engineering-conventions.md§10;收口走.agents/skills/wave-close-checklist.md。 状态:ACTIVE。契约先行——本档锁定的 8 契约 + 拓扑表是两开发线开工前必须齐的单一事实源;契约未冻结前两线不得独立开工。
0. 结论先行(TL;DR)
- 范式:Opus 设计固定游戏架构(轻量声明式领域模型 + profile 三维),cheap 模型在 SAA agentic studio 里填槽;游戏 = 源项目,生命周期 create/modify/extend/build/release/maintain;改源不改打包产物(GamePackage 产物 schema、宿主
window.__GameBundle.bootGameHost、feed 全不变)。 - 8 契约(本档 §5 逐个给字段级 schema/签名):①源项目 schema ②源项目 DB(独立
game_source_project表)③GamePackage 源/产物分离 ④SAA state key 全表 ⑤asset 产消 ⑥modifyPatch ⑦唯一确定性构建 API ⑧trace+cost 字段。 - 拓扑(§6):现 11 节点 SAA 图 → 演进为 render·classify(新)·design·scaffold·logic/repair(一个核心代码 agent 两面)·config/balance·asset(新)·build·QA(九门)·modify(新) + 条件激活 narrative-designer-reviewer + 离线 skill-curator(MVP 只做 Debug Skill);救场阶梯 = cheap→连续 5 次九门失败→升档(stage1→stage2)→再 3 次失败→放弃,
recursionLimit按 5+3 重算。 - 两线切分(§8):后端线(6c6g 编辑 / mini-desktop 构建)锁源项目 schema+DB、SAA state/拓扑/救场路由、studio 编排、trace+cost、modifyPatch;引擎+前端线(Mac)锁 2D 适配器(游戏定义→LittleJS)、asset 产消、唯一构建实现、九门 QA、前端创作/修改/预览 UI。交汇=本档 8 契约。
- 开工前待解 → ✅ 全部收口(创始人 2026-06-17「按推荐」):①源项目表归属=studio 模块 ②后端 RuntimeBuild 只落包(构建留 worker/SAA build.mjs)③缓存透传 ✅ spike 绿(76-93%)+ classify ✅ 绿(tickModel 100%)④classify→archetype 映射表=引导非校验 ⑤narrative
needsRepair=true等价一次九门失败计入 failCount ⑥studiocreate=draft+generate 一步式封装。契约冻结进行中:keystonesource-project.schema.json已落;V18/ALL_KEYS/trace = 后端线 module 实现(V18 入 game-cloud 模块迁移,非 stale 的 contracts/db-schemas)。
1. 目标与范围边界
1.1 目标(本期 execution 要交付什么)
把"固定架构 + SAA agentic studio"由 review 决策落成可被验证的契约与实现切分,使两条开发线(后端 / 引擎+前端)能契约先行、各自独立开工,最终合流出:一句话 → studio(cheap 填固定架构槽) → 源项目 → 确定性构建 → 九门真玩过门 → 现 GamePackage 产物 → feed 真玩 的全链,且支持 modify(改源不改产物,出新预览版,走发布审核)。
1.2 范围内(In Scope)
- 固定游戏定义模型 schema(实体/组件/行为/场景/规则 + profile 三维)+ 2D 适配器(LittleJS)。
- 源项目工件契约 + 独立 DB 存储(
game_source_project)+ 源/产物分离。 - SAA 图扩展:新增 classify/asset/modify 节点 + narrative 分支 + 救场升档阶梯 + 完整观测/dump。
- 唯一确定性构建 API(化解构建权威分裂)。
- 三段式 prompt 缓存策略 + 版本化 Prompt Registry 资产(冻结 system+few-shot)。
- trace+cost 契约扩展(modelTier/escalationEvents/缓存命中两套字段/giveupDumpPath)。
- modify 生命周期(确定性编辑 / LLM 重生成单模块)。
1.3 范围外(Out of Scope,本期不做)
- 3D 适配器(Cocos):定义格式留前向兼容,适配器本身 Phase 2。
- Template Skill(骨架萃取晋升):MVP 只做 Debug Skill(冷路径)。
- per-creator 计量计费:沿用现 new-api logs.quota 权威对账,不拆到人(对齐 memory
newapi-billing-plane-integration)。 - 渠道线(小游戏)引擎:另行竞标(HJ-CH-001),本架构不动 feed 终裁。
- 打包产物 schema / 宿主 / feed 改动:零改(blast radius 收窄铁律)。
1.4 不可破坏的硬约束(回归红线)
| 约束 | 出处(已核码) |
|---|---|
GamePackage 产物 schema 不变(schemaVersion:"1.0",additive 新字段不升版本) |
contracts/game-package.schema.json:10-13 |
宿主装载契约不变:window.__GameBundle.bootGameHost({canvas,seed}) + iife 全局名 __GameBundle |
game-studio/src/host/inject.ts:202,241-248 |
回调唯一写入路径不变:DifyCallbackService.handleCallback(succeeded 建版本→组包→落包→回填三表同事务) |
SaaGraphDispatcher.java:251、DifyCallbackReqVO.java:13-17 |
| 九门 harness(serve-and-play.sh/play.cdp.cjs/build.mjs)子进程复用·禁重写 | SaaGenNodes.java:37、run.py:45-72 |
| Flyway 已合入禁改,只新增:新表走 V18.0.0(接 V17 之后) | V17.0.0__aigc_task_add_source.sql:19(头注铁律) |
| 错误码段:studio=1-112-、aigc=1-101-、runtime=1-103-*** | V8.0.0__create_game_studio.sql:14 |
2. 前置条件
- 上游决策已定:review §1.5 + §10 全部已定(领域模型轻量声明式+三维 profile、Phase1 仅 2D、agent 列表、救场带限额、narrative 留 MVP、MVP 只 Debug Skill、写码+修 bug=一个核心代码 agent)。
- 现行底座可用且已核码:
- SAA 全图 11 节点已建并生产收口(
SaaStudioGraph.assemble),checkpoint(MysqlSaver)/observation/trace split-brain 已闭合(703e462c)。 - W-G1 worker 闭环可跑(generate→validate→build→play 九门),救场 stage1/stage2 在
models.yaml。 - 宿主引擎包路(P2)已真接:
bootGameHost引擎掌帧 + game_loaded/game_end 桥接已 e2e。 game-module-studio编排层已建(session/taskchain/asset,/studio/{draft,generate,task,regenerate})。
- SAA 全图 11 节点已建并生产收口(
- 机器分工(memory
internal-build-infra-servers):后端编辑 6c6g、权威构建/e2e 门 mini-desktop、基建 mini-infra;6c6g 禁起浏览器(九门真玩在 mini-desktop)。 - 子代理模型分流(memory
opus-subagents-critical-tasks):实现派 opus、机械活派 haiku、最高复杂度终裁用 opus 兜(本环境 fable 子代理不可用)。
3. 涉及模块与文件路径
3.1 后端线(game-cloud,com.wanxiang.huijing)
| 关注点 | 路径 |
|---|---|
| 源项目 schema(新契约) | contracts/agent-loop/source-project.schema.json(新建) |
| 源项目 DB(新 Flyway) | game-cloud/huijing-server/.../db/migration/V18.0.0__create_game_source_project.sql(新建)+ 同名副本入对应模块 db/migration/(与 V8/V17 同模式,两处一致) |
| SAA 图布线唯一源 | game-cloud/.../aigc/saa/SaaStudioGraph.java(扩节点/边/recursionLimit) |
| SAA 编排节点 + state key | game-cloud/.../aigc/saa/SaaStudioNodes.java(ALL_KEYS 扩、新 classify/asset/modify NodeAction) |
| SAA 生成流水节点 | game-cloud/.../aigc/saa/SaaGenNodes.java(validate/scaffold/build/play) |
| 派发器(job↔state↔回调桥) | game-cloud/.../aigc/saa/SaaGraphDispatcher.java(buildInputs/buildCallbackReqVO/extractTraceQuietly 扩) |
| 回调入参 VO | game-cloud/.../aigc/.../vo/DifyCallbackReqVO.java(trace 字段扩 cost/modelTier/cacheHit) |
| studio 编排层 | game-cloud/game-module-studio/.../service/studio/StudioServiceImpl.java(+ create/modify/extend 编排) |
| studio 路由 | game-cloud/.../studio/controller/app/studio/AppStudioController.java(+ /studio/{create,modify,extend}) |
| 确定性构建权威 | game-cloud/game-module-runtime/.../service/build/RuntimeBuildServiceImpl.java(桩转真 / 或定义构建实现归属) |
| 执行器配置(救场旋钮) | game-cloud/.../aigc/service/executor/AigcExecutorProperties.java(saaMaxRepairs=5/saaMaxPlayerRounds=1 已在;补 stage/升档阈值) |
3.2 引擎+前端线(Mac)
| 关注点 | 路径 |
|---|---|
| 2D 适配器(游戏定义→LittleJS) | game-runtime/src/(新增 adapter 层;scripts/build.mjs 不动=唯一构建脚本) |
| 唯一构建脚本(共用) | game-runtime/scripts/build.mjs(worker 与 SAA build 节点共调,--global-name=__GameBundle) |
| 九门 harness(禁重写) | game-runtime/games/_wg1-gen/_shared/{serve-and-play.sh,play.cdp.cjs,entry-bundle.template.js,index.template.html} |
| 宿主装载契约 | game-studio/src/host/{inject.ts,contract.ts,runtime/index.ts}(消费源不变,零改) |
| 前端创作/修改/预览 UI | game-studio/src/(创作工作坊接 /studio/create、修改接 /studio/modify、预览复用 GamePlayer) |
| Prompt Registry(缓存前缀资产) | contracts/prompts/(冻结 system+few-shot 为版本化资产,CI 卡 byte 不变) |
3.3 worker(wg1,Python,引擎线复用)
| 关注点 | 路径 |
|---|---|
| 生成编排闭环 | wg1/gen-worker/worker/run.py、wg1/gen-worker/worker/agent_loop/studio.py |
| prompt 上下文包(缓存前缀来源) | wg1/gen-worker/worker/prompt.py(SYSTEM 常量 + _few_shot() 现从文件读=字节不稳,要固化) |
| 校验门 | wg1/gen-worker/worker/validate.py |
| 模型路由(救场阶梯) | wg1/gen-worker/worker/models.yaml(stage1/stage1_mmx/stage2) |
| 成本折算(缓存命中字段) | wg1/gen-worker/worker/cost.py(现不计缓存折扣,cache_ratio 已在 /api/pricing,要落命中 token) |
4. 数据流与依赖
4.1 全链数据流(create / build / modify)
flowchart TB
subgraph FE["前端线(Mac)"]
U["创作者一句话+六类素材"] -->|POST /studio/create| ST
U2["改一处(换美术/调参/改关卡/改玩法)"] -->|POST /studio/modify| ST
PV["预览(GamePlayer)<br/>window.__GameBundle.bootGameHost"]
end
subgraph BE["后端线(6c6g/mini-desktop)"]
ST["studio 编排层<br/>create/modify/extend"] -->|job(brief/素材/mode/baseVersion/target)| DISP
DISP["SaaGraphDispatcher<br/>job→state"] -->|invoke| G
G["SAA 固定架构图<br/>(§6 拓扑)"] -->|源项目 sourceProject| SRC
SRC[("game_source_project<br/>独立表 · 源 JSON/url")]
SRC -->|确定性构建 API<br/>sourceProject+buildProfile| BUILD
BUILD["唯一确定性构建<br/>esbuild → __GameBundle"] -->|engineBundle/checksum/bundleSize| CB
CB["DifyCallbackService.handleCallback<br/>(唯一写入路径·不变)"] -->|建版本→组包→落包| PKG
PKG[("game_version + game_runtime_package<br/>GamePackage 产物(schema 不变)")]
end
PKG -->|/app-api/runtime/package/{versionId}/manifest| PV
PKG -->|发布审核(B1 链)| FEED["feed 真玩(不变)"]
4.2 关键依赖与边界
- 源项目 = 新增 additive 存储面(
game_source_project);GamePackage 产物 = 既冻产物面。二者解耦:源落库成功 → 触发构建 → 构建成功才建 preview package;构建失败 → 源标孤儿、不建包(§5.2 事务)。 - 生成侧(new-api)/收益侧(trade)硬边界不变(memory
newapi-billing-plane-integration):缓存命中 token 只落成本台账(token 计量),不接收益结算。 - modify 不动 currentVersion、不自动入 feed:产物=新预览版,仍走发布审核;失败=不建新版、base 不动(对齐 v2 review §3.2 / 待确认⑤)。
- classify→archetype 映射表依赖现
contracts/templates/*.schema.json(8 个:clicker/dodge/match/runner/idle/merge/tycoon/generic)作为品类 profile 锚(§5.5)。
5. 接口/数据契约(8 契约逐个给 schema/签名)
原则:契约 schema 具体到字段,但不预写无法验证的实现代码。所有 schema 与现行代码兼容性已逐条核对。
5.1 契约①:源项目 schema(新 contracts/agent-loop/source-project.schema.json)
cheap agents 在固定架构上填的唯一结构化产物;Opus 设计、长期版本化升级。
{
"$id": "https://wanxiang.ai/contracts/agent-loop/source-project.schema.json",
"title": "SourceProject",
"type": "object",
"required": ["schemaVersion", "sourceHash", "profile", "gameDefinition"],
"additionalProperties": false,
"properties": {
"schemaVersion": { "const": "1.0" }, // 源项目契约版本(独立于 GamePackage 版本)
"sourceHash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, // 源 JSON 规范化后 sha256(可寻址/幂等键)
"buildInputHash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, // sha256(sourceHash + buildProfile);构建缓存命中键
"profile": { // 维度无关三维(review §10.2,否则剧情/TRPG 绷断)
"type": "object",
"required": ["tickModel", "inputModel", "progressModel"],
"additionalProperties": false,
"properties": {
"tickModel": { "enum": ["realtime", "turn-based", "event"] },
"inputModel": { "enum": ["continuous", "discrete-choice", "text-command"] },
"progressModel": { "enum": ["metric", "narrative"] } // narrative → 走 narrative-reviewer 质量门(§5.9)
}
},
"gameDefinition": { // 轻量声明式领域模型(非 AAA ECS:无 system 调度器/无 archetype 存储/无 query DSL)
"type": "object",
"required": ["entities", "scenes", "rules"],
"additionalProperties": false,
"properties": {
"entities": { "type": "array", "items": { "$ref": "#/$defs/entity" } },
"components": { "type": "array", "items": { "$ref": "#/$defs/component" } }, // 组件定义(声明式属性:渲染/碰撞/物理)
"behaviors": { "type": "array", "items": { "$ref": "#/$defs/behavior" } }, // 行为模块(逻辑,维度无关,读参数操作实体)
"scenes": { "type": "array", "items": { "$ref": "#/$defs/scene" } }, // 关卡构成(数据驱动)
"rules": { "type": "array", "items": { "$ref": "#/$defs/rule" } } // 胜负条件(数据驱动)
}
},
"assets": { "type": "array", "items": { "$ref": "#/$defs/assetSpec" } }, // 六类资产规格/引用(§5.5 asset 契约写入)
"config": { "type": "object" } // 平衡参数(数值/难度/速度)——数据驱动,确定性 modify 改这里免 LLM
},
"$defs": {
"entity": { // 实体:transform(2D 用 xy/z=0,3D 用 xyz,同字段两维成立)+ 组件引用
"type": "object", "required": ["id", "transform"], "additionalProperties": false,
"properties": {
"id": { "type": "string", "minLength": 1 },
"transform": { "type": "object", "required": ["position"], "properties": {
"position": { "type": "object", "required": ["x", "y"], "properties": {
"x": {"type":"number"}, "y": {"type":"number"}, "z": {"type":"number","default":0} } },
"rotation": { "type": "number" }, "scale": { "type": "number", "default": 1 } } },
"components": { "type": "array", "items": { "type": "string" } } // 引用 components[].id
}
},
"component": { "type": "object", "required": ["id", "kind"], "additionalProperties": true,
"properties": { "id": {"type":"string"}, "kind": { "enum": ["render","collision","physics","custom"] } } },
"behavior": { "type": "object", "required": ["id", "trigger"], "additionalProperties": true,
"properties": { "id": {"type":"string"}, "trigger": { "enum": ["init","update","input","collision","timer"] } } },
"scene": { "type": "object", "required": ["id", "entityRefs"], "additionalProperties": true,
"properties": { "id": {"type":"string"}, "entityRefs": { "type": "array", "items": {"type":"string"} } } },
"rule": { "type": "object", "required": ["id", "condition", "outcome"], "additionalProperties": true,
"properties": { "id": {"type":"string"}, "condition": {"type":"string"}, "outcome": { "enum": ["win","lose","score","advance"] } } },
"assetSpec": { "$ref": "#/$defs/assetSpecBody" },
"assetSpecBody": { "type": "object", "required": ["id", "category", "ref"], "additionalProperties": false,
"properties": {
"id": { "type": "string" },
"category": { "enum": ["sprite","character","effect","scene","ui","music"] }, // 六类(对齐 v2 review C5)
"ref": { "type": "string" }, // 平台 assetId/ref 为主(url 只读镜像)
"url": { "type": "string", "format": "uri" },
"provider": { "type": "string", "default": "mmx-cli" } // provider 可插拔(§5.5)
} }
}
}
诚实边界:
gameDefinition.behaviors是声明式模块描述,真逻辑代码仍由核心代码 agent(logic)产出并经构建编译进__GameBundle;源项目存"可维护的结构化定义",非裸 iife。MVP 最小集(对齐 v2 review 待确认①)= profile 三维 + 单 behavior + config + assets 引用,复杂结构随品类迭代。
5.2 契约②:源项目 DB 存储(新 Flyway · 独立 game_source_project 表)
勿塞 game_version(架构 review §10 明令);源项目是 additive 新存储面。
-- V18.0.0__create_game_source_project.sql(Flyway 只新增,接 V17 之后;头注铁律:已合入禁改,回滚写 V18.0.1 补偿)
CREATE TABLE `game_source_project` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '源项目工件 ID',
`game_id` BIGINT NOT NULL COMMENT '所属游戏 ID(project.game_project.id)',
`version_id` BIGINT NULL COMMENT '关联产物版本 ID(project.game_version.id);构建成功建包后回填,失败留 NULL=孤儿',
`source_json` LONGTEXT NULL COMMENT '源项目工件 JSON(SourceProject schema;M0 走 DB,大资产经 ref 外置)',
`source_url` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '源项目对象存储 URL(切对象存储后用,与 source_json 二选一)',
`source_hash` CHAR(64) NOT NULL DEFAULT '' COMMENT '源规范化 sha256(可寻址/幂等;= SourceProject.sourceHash)',
`schema_version` VARCHAR(16) NOT NULL DEFAULT '1.0' COMMENT '源项目契约版本',
`build_profile` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '构建画像(目标引擎/优化档;= buildProfile,影响 buildInputHash)',
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '源态:0 草稿 1 已构建 2 孤儿(构建失败) 3 已发布',
`base_version_id` BIGINT NULL COMMENT 'modify 血缘:本源派生自的 base 版本(create 时 NULL)',
`creator` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建者(Yudao 审计列)',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除',
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户 ID',
PRIMARY KEY (`id`),
KEY `idx_game` (`game_id`, `id`) COMMENT '按游戏查源项目历史',
KEY `idx_version` (`version_id`) COMMENT '按产物版本反查源',
KEY `idx_source_hash` (`source_hash`) COMMENT '可寻址/幂等去重'
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '游戏源项目工件表(改源不改产物;与 game_version 解耦)';
事务边界(关键,化解孤儿):
① studio 编排 → 图产源项目 → 源落库(status=0)成功
② 触发确定性构建(§5.7)
③ 构建成功 → 建 preview package(走 handleCallback 唯一写入路径)→ 回填 version_id + status=1
④ 构建失败 → 源 status=2(孤儿),不建 package,不动 currentVersion
源落库与建包不同一大事务(构建数十秒级,长事务=连接池杀手,对齐 SaaGraphDispatcher.java:55-57 既有纪律);用 status 机器态串联,而非分布式事务。
归属待解见 §12-①:
game_source_project物理归 studio 还是 project 模块(都引用 game_id/version_id),DB review 曾提"game_version 双存",与本独立表口径冲突,本档采架构 review 的独立表口径,归属在 §12 收口。
5.3 契约③:GamePackage 源/产物分离(game-package.schema.json 维持产物-only)
不改 game-package.schema.json。明确边界:
| 面 | 存储 | schema | 可变性 |
|---|---|---|---|
| 源项目(可维护) | game_source_project(新) |
source-project.schema.json(新,§5.1) |
cheap 填、确定性 modify 改 |
| 打包产物(可玩) | game_version + game_runtime_package |
game-package.schema.json(既冻,additionalProperties:false) |
构建产出、宿主消费,不变 |
engineBundle仍是 GamePackage 的 additive 可选产物字段(game-package.schema.json:94-97),由构建写入、handleCallback落包;源项目不进 GamePackage。additionalProperties边界:GamePackage 顶层additionalProperties:false→ 源项目字段禁止塞进 GamePackage;源项目经独立表存,经provenance(可选)只挂sourceHash做溯源(若需)。
5.4 契约④:SAA state key 全表(SaaStudioNodes.ALL_KEYS 扩)
现 ALL_KEYS(已核码 SaaStudioNodes.java:96-106)+ 新增键。全 ReplaceStrategy(节点 return 覆盖写)。
现有键(保留,不动语义):brief, enriched, designText, gatespec, gatespecParseError, playSpec, factorySrc, gameId, role, repairCount, playerRound, feedback, playerFeedback, validateOk, buildOk, playPass, verdict, playerPanel, tokensIn, tokensOut, tokensByModel, attempts, status, failureReason, engineBundle,+ SaaGenNodes 内部键 gameDir, validateErrors, buildLog,+ 参数化 port, cdpPort, runId。
新增键(本档锁定):
| key | 类型(state 内存形态) | 写节点 | 读/消费 | 语义 |
|---|---|---|---|---|
archetype |
String | classify | design/scaffold,映射表 | 品类原型(§5.5 枚举);填错品类比写错码更致命 |
tickModel |
String | classify | logic/QA(选质量门机制) | realtime/turn-based/event(profile 三维之一) |
inputModel |
String | classify | logic | continuous/discrete-choice/text-command |
progressModel |
String | classify | playerRouter / narrative 路由 | metric/narrative;narrative→走 reviewer 门 |
sourceProject |
String(JSON 串) | scaffold/logic/config/asset | build/emit/落库 | SourceProject 工件 JSON(§5.1);新核心产物 |
assetSpec |
String(JSON 串) | asset | logic/scaffold | 六类资产规格/引用(§5.5) |
modifyMode |
String | render(modify 入口) | modify 路由 | "deterministic"|"regenerate-module"(§5.6) |
modifyPatch |
String(JSON 串) | modify | logic(regenerate)/scaffold(deterministic) | 改一处寻址+载荷(§5.6) |
baseVersionId |
String | render | modify/emit | modify 的 base 版本(create 时空) |
failCount |
int | playRouter/各失败回边 | okElseRepairOrGiveup/升档判据 | 连续九门失败计数(锚 verdict.pass=false) |
modelTier |
String | render(初 stage1)/升档节点 | generate/repair 选模型 | "stage1"|"stage2";救场升档作用面 |
escalationEvents |
String(JSON 数组串) | 升档节点 | trace/dump | [{tierBefore,tierAfter,atFailCount,ts}] |
giveupDumpPath |
String | giveup | trace/Opus 离线读 | 放弃前完整 dump 落盘路径 |
narrativeReviewVerdict |
String(JSON 串) | narrative-reviewer | playerRouter/repair 路由 | narrative 质量门裁决(§5.9) |
兼容性:严格 additive——存量节点不读新键则零影响;
extractTraceQuietly(SaaGraphDispatcher.java:448)best-effort 抽取,新键缺则省略,trace_json 字节兼容(键集仍为_extract_trace输出超集时需同步扩 worker 侧_extract_trace,见 §8 后端线步骤)。
5.5 契约⑤:asset 产消(asset 节点写 assets[],下游消费)
- 生产:asset 节点据
archetype/gameDefinition产六类资产规格,写state.assetSpec(JSON 串)→ merge 进sourceProject.assets[](§5.1assetSpec形态)。 - 消费:logic/scaffold 读
sourceProject.assets[].ref,构建时解析为 GamePackageassets[](game-package.schema.json:34-50,类型 image/audio/...);宿主经assets[].url走<img>/drawImage(inject.ts CSP img-src 已放行)。 - provider 可插拔:
assetSpec.provider默认mmx-cli(memorymmx-asset-pipeline:王蓝莓投资人版默认走 mmx-cli,音乐"记谱→合成"两步);切 provider 只改 asset 节点,不动消费侧。 - 六类枚举一次定死(对齐 v2 review C5,四处同引):
sprite/character/effect/scene/ui/music。 - MVP 边界:asset 节点 v0 可只产规格(spec)不真生图(用 canvas 几何兜底,对齐现 prompt.py 硬规则 7"资产容错"),真资产生成 provider 接入为 additive 升级;但
assets[]产消通道必须打通(否则 v2 review §2 "assets[] 空"缺口未补)。
5.6 契约⑥:modifyPatch(modify 节点输入/输出)
modify = 在固定结构上改一处 + 重构建;对齐 v2 review §3.2(改源不改产物)。
// modifyPatch(state.modifyPatch JSON 串;modify 节点产)
{
"baseVersionId": "string", // 改谁(base 版本;对应 game_source_project.base_version_id)
"mode": "deterministic | regenerate-module", // 确定性编辑 | LLM 重生成模块
"target": { // 寻址源项目部件
"kind": "asset | config | level | behavior", // 换美术=asset / 调参=config / 改关卡=level(scene) / 改玩法=behavior
"path": "string", // 源项目内 JSON 指针(如 /config/speed、/assets/0、/gameDefinition/scenes/2;config/assets 为顶层,scenes 在 gameDefinition 下,对齐 keystone)
"id": "string" // 或按部件 id 寻址(behaviors[].id / assets[].id)
},
"payload": { // mode=deterministic:新值(直接覆写,免 LLM);mode=regenerate-module:重生成意图(喂 LLM)
"value": {}, // deterministic 用:确定性新值
"intent": "string" // regenerate-module 用:改玩法逻辑的自然语言意图(只重生成那一个 behavior 模块)
}
}
modify 口径(锁定,对齐 v2 review):
- 换美术 / 调参 / 改关卡 =
mode=deterministic:确定性编辑源文件→重构建→新预览版,免 LLM、秒级。 - 改玩法逻辑 =
mode=regenerate-module:LLM 只重生成那个 behavior 模块(非全量重出),其余部件不动。 - 产物:新预览版(
game_version新行 status=2 预览就绪),不动 currentVersion、不自动入 feed,仍走发布审核(B1 链)。 - 失败:不建新版、base 不动(
game_source_project不新增行 / 新增行标孤儿)。 - manifest 可寻址 diff 已废:不采用(v2 review supersede)。
5.7 契约⑦:唯一确定性构建 API(化解构建权威分裂)
输入 sourceProject + buildProfile → 输出 engineBundle + checksum + bundleSize + buildLog。
// 构建 API 契约(语言无关签名;Java 侧 RuntimeBuild、worker 侧 build.mjs 同一实现)
buildSource(input) -> output
// input:
{ "sourceProject": { /* SourceProject §5.1 */ }, "buildProfile": "default" }
// output:
{
"ok": true,
"engineBundle": "string", // iife bundle 全文,顶层全局名 __GameBundle(契约冻结)
"checksum": "string", // 整包 sha256(hex);= GamePackage.manifest.checksum
"bundleSize": 123456, // raw 字节(B1 入场券:raw≤1.5MB,见 generic.schema.json)
"bundleGzBytes": 12345, // gz 字节(B1 入场券:gz≤350KB)
"buildLog": "string" // 失败回喂用;ok=false 时载错因
}
构建权威化解(本档裁定,见 §12-②):
- 推荐构建实现留 worker/编排器侧 esbuild(
game-runtime/scripts/build.mjs--global-name=__GameBundle,现已真跑、九门验过),SAA build 节点与 worker 共调同一scripts/build.mjs(SaaGenNodes.buildNode/run.py:build已是同脚本同参,已天然统一,无需第二实现)。 - 后端
RuntimeBuildServiceImpl= 落包+manifest 权威(非第二构建器):接收构建产物(engineBundle/checksum/bundleSize)→ 经handleCallback落game_runtime_package+ 回填game_version三字段。当前它是桩(RuntimeBuildServiceImpl.java:51TODO),本期不要求它自己跑 esbuild,只要求它消费构建产物落包——构建执行权在 worker/SAA build 节点,落包权在后端,职责单一、不分裂。 - 确定性:同
buildInputHash(sourceHash+buildProfile)→ 字节等价产物(v2 review M0 验收"非一次性"=从源重新构建出字节等价 bundle);锁引擎版本/依赖(game-runtime/package.json+ esbuild 锁参)。
5.8 契约⑧:trace+cost 字段(扩 DifyCallbackReqVO.trace + SAA trace 抽取)
现 trace(9d 账本,DifyCallbackReqVO.java:68-75,落 game_aigc_task.trace_json)扩字段:
// trace(扩;snake/camel 与现 _extract_trace 口径一致;additive,缺则省略键)
{
// —— 现有(保留)——
"pass": true, "repairs": 0, "wallS": 12.3, "models": {}, "attempts": [],
"gameId": "", "stage": "saa", "gatespec": {}, "sevenGateVerdict": {}, "tokens": { "prompt": 0, "completion": 0 }, "player": {},
// —— 新增(本档锁定)——
"modelTier": "stage1", // 终态模型档(救场升档后为 stage2)
"escalationEvents": [ // 升档事件(state.escalationEvents)
{ "tierBefore": "stage1", "tierAfter": "stage2", "atFailCount": 5, "ts": "ISO8601" }
],
"cacheHit": { // 缓存命中(成本台账;命中 token 落账)
"promptCacheHitTokens": 0, // 取 max(DeepSeek prompt_cache_hit_tokens, MiniMax prompt_tokens_details.cached_tokens)
"source": "deepseek | minimax | none" // 命中来源(字段口径见下)
},
"giveupDumpPath": "string", // 放弃前完整 dump 落盘路径(state.giveupDumpPath;Opus 离线读)
"cost": { // F3 折¥(SAA 路现只 token,本期补折¥见 §8;非阻断)
"totalRmb": 0.031, "gateRmb": 0.15, "byModel": {}
}
}
缓存命中检测(兼容两套字段,锚 review §1.5):
- DeepSeek:
usage.prompt_cache_hit_tokens。 - MiniMax:
usage.prompt_tokens_details.cached_tokens。 - 取 max 落
cacheHit.promptCacheHitTokens;命中 token 进成本台账(cost.py现不计缓存折扣cost.py:10-12,本期补:读/api/pricing的cache_ratio+ 命中 token 折真实 quota,落 trace.cost,不阻断、仅观测)。
5.8.1 缓存策略(三段式 prompt + Prompt Registry 资产)
- 三段式(review §10.3,spike 已证绿):固定前缀(契约/few-shot/能力面,永不变)→ 共享中段(GDD)→ 可变后缀(brief/反馈)。现
prompt.py:SYSTEM已是固定前缀骨架,但_few_shot()从文件读 → 字节不稳(缓存命中要求前缀 byte 完全一致)。 - 动作(本档锁定):把
SYSTEM+ few-shot 冻结为版本化 Prompt Registry 资产(contracts/prompts/,现有registry.yaml+ 04-config/07-fix 等),CI 卡 byte 不变(few-shot 从文件读改为读已固化的版本化常量,字节固定)。 - L1 架构契约前缀先做(review §1.5:最大块,第二款起省~90% input)。
- ✅ 缓存透传已 spike 证绿(2026-06-17):deepseek-v4-flash / MiniMax-M3 / M2.7 经 new-api 网关前缀缓存全部透传,第二款起命中 76-93%;检测兼容两套字段(DeepSeek
prompt_cache_hit_tokens/ MiniMaxprompt_tokens_details.cached_tokens取 max)。缓存策略坐实、风险解除;实施只剩"冻结 few-shot 字节稳 + 落命中台账"工程动作(B9/E5)。
5.9 narrative 子系统(创始人裁定保留 MVP · 条件激活)
progressModel=narrative 分支由 narrative-designer-reviewer 当质量门(替代九门——九门确定性测不了叙事连贯)。
// narrativeReviewVerdict(state.narrativeReviewVerdict JSON 串;narrative-reviewer 产)
{
"problems": [ "string" ], // 叙事连贯/设计问题列表
"needsRepair": true, // 是否需回 repair(true→走 repair 路,消费同 playerFeedback 范式)
"founderFinal": false // 终判留创始人(false=未终审;质量门按品类换机制,叙事类终判人工)
}
接入(锁定):
- 路由:
progressModel=narrative→ play 节点后不走九门 playRouter,改走 narrative-reviewer;needsRepair=true→ repair(同repairNode自增 repairCount + role=fix);needsRepair=false→ emit。 - 失败计入救场 failCount(§12-⑤ 收口点):九门对 narrative 失效,故 narrative 的
needsRepair=true等价一次"九门失败"计入failCount(同 5+3 阶梯:连续 5 次 needsRepair→升档、再 3 次→giveup);recursionLimit同口径重算。 - follow-up:产品需求清单需补一条 narrative P-id 与验收(标注待补,见 §11)。
6. 最终拓扑表(无孤儿节点 · recursionLimit 按救场 5+3 重算)
6.1 拓扑图(SAA 固定架构图)
flowchart TB
START([START]) --> render
render --> classify
classify --> design
design --> generate["generate(logic 写 / role=fix 时 repair 修=同一核心代码 agent 两面)"]
generate --> validate
validate -->|ok| scaffold
validate -->|fail & failCount<5| repair
validate -->|fail & 升档窗| escalate
scaffold --> asset
asset --> build
build -->|ok| play
build -->|fail| repair
play -->|metric & 九门 pass| player
play -->|narrative 路| nreview["narrative-reviewer"]
play -->|fail & failCount<阈| repair
player -->|无体验问题/轮尽| emit
player -->|有体验问题| repair
nreview -->|needsRepair=false| emit
nreview -->|needsRepair=true & 轮未尽| repair
repair --> generate
escalate["escalate(升档 stage1→stage2)"] --> generate
emit --> END([END])
giveup["giveup(完整 dump)"] --> END
play -.->|failCount≥5 & 已 stage2 再失败 3| giveup
modify["modify(确定性编辑/regenerate-module)"] -.->|确定性路| build
modify -.->|regenerate-module 路| generate
6.2 逐节点拓扑表(入边/出边/读写 state/消费者/路由条件)
| 节点 | 入边 | 出边(路由条件) | 读 state | 写 state | 消费者 |
|---|---|---|---|---|---|
| render | START / modify 入口 | →classify(create)/→generate(modify regenerate)/→build(modify deterministic) | brief, modifyMode, baseVersionId | role=code, repairCount=0, playerRound=0, failCount=0, modelTier=stage1, tokensIn/Out=0 | classify/modify |
| classify(新) | render | →design | brief | archetype, tickModel, inputModel, progressModel | design/scaffold/logic/QA;映射表 |
| design | classify | →generate | brief, archetype | designText, enriched, playSpec, gatespec, gatespecParseError | generate |
| generate(logic+repair 两面) | design / repair / escalate | →validate | role, modelTier, enriched, feedback | factorySrc, sourceProject(填 behaviors/config), feedback, tokensByModel, attempts | validate |
| validate | generate | ok→scaffold;fail→repair(failCount<5)/escalate(升档窗) | factorySrc | validateOk, validateErrors, feedback | scaffold/repair |
| scaffold | validate(ok) | →asset | gameId, factorySrc, playSpec, sourceProject | gameDir, sourceProject(落盘结构) | asset/build |
| asset(新) | scaffold | →build | archetype, sourceProject | assetSpec, sourceProject.assets[] | build/logic;provider=mmx-cli |
| build | scaffold/asset / modify(确定性) | ok→play;fail→repair | gameId, gameDir, sourceProject, buildProfile | buildOk, buildLog, engineBundle, checksum, bundleSize | play/emit |
| play(QA 九门) | build(ok) | metric&pass→player;narrative→nreview;fail→repair/giveup | gameId, port, cdpPort, playSpec, progressModel | playPass, verdict, feedback, failCount(++) | player/nreview/repair |
| player(软门) | play(metric pass) | 无问题/轮尽→emit;有问题→repair | gameId, brief, verdict | playerPanel, playerFeedback | playerRouter/emit |
| nreview(narrative,条件) | play(narrative 路) | needsRepair=false→emit;true&轮未尽→repair | brief, sourceProject, verdict | narrativeReviewVerdict, failCount(++) | emit/repair |
| repair | validate/build/play/player/nreview 失败回边 | →generate | repairCount, playerFeedback | role=fix, repairCount++, playerRound++(软门), feedback | generate |
| escalate(新) | 失败回边(failCount 命中升档阈) | →generate | failCount, modelTier | modelTier=stage2, escalationEvents+= | generate |
| emit | player/nreview(收口) | →END | gameId(bundle), sourceProject | status=succeeded, engineBundle | handleCallback |
| giveup | 救场耗尽(stage2 再失败 3) | →END | feedback, attempts(全), sourceProject | status=failed, failureReason, giveupDumpPath(完整 dump) | handleCallback/Opus 离线 |
| modify(新) | render(modify 入口) | 确定性→build;regenerate-module→generate | modifyPatch, baseVersionId, sourceProject(base) | sourceProject(改一处), modifyMode | build/generate |
6.3 救场阶梯 + recursionLimit 重算
- 锚:
verdict.pass=false(确定性九门,非主观;SaaGenNodes.playNode:409rc==0 ∧ verdict.pass)。 - 阶梯:cheap(stage1)→连续 5 次九门失败 → escalate 升档(stage1→stage2)→ stage2 再 3 次失败 → giveup。
- state 驱动:
failCount在每次九门(及 narrativeneedsRepair)失败 +1;okElseRepairOrGiveup/playRouter判据改为:failCount < 5→ repair(stage1);failCount == 5 ∧ modelTier==stage1→ escalate(升 stage2,failCount 续计或重置由实现定,建议续计:stage2 阈 = 5+3=8);failCount ≥ 8(stage2 再 3 次)→ giveup。
- recursionLimit 重算:现
recursionLimitFor(maxRepairs) = (maxRepairs+1)*7+78(SaaStudioGraph.java:221)。救场总轮 = 5(stage1)+3(stage2)=8 主轮,每轮主链 ≈ 9 节点(render→classify→design→generate→validate→scaffold→asset→build→play),+ 升档/repair 回环。新公式建议:recursionLimitFor = (5+3+1)*10 + 余量≈90+余量,确保正常收口不误触超步(余量保守取 ≥30)。AigcExecutorProperties.saaMaxRepairs由 5 升为可配,新增saaStage2ExtraRepairs=3。 - 全程留存(硬观测,非可选):每编辑步 + 日志留存;
giveup前完整 dump(所有 attempts 源码/verdict 整包落盘 →giveupDumpPath),喂 Opus 离线分析。
6.4 classify→archetype 映射表(避免孤儿分类,锚 review §10.1)
archetype 枚举把"消除族"拆细(review 明令);映射到现 contracts/templates/*.schema.json 品类 profile:
| archetype | tickModel | inputModel | 品类 profile 锚(现模板 schema) |
|---|---|---|---|
clicker |
event | discrete-choice | templates/clicker.schema.json |
dodge |
realtime | continuous | templates/dodge.schema.json |
runner |
realtime | continuous | templates/runner.schema.json |
bubble(瞄准发射) |
realtime | continuous | templates/match.schema.json(瞄准变体) |
match3/line-clear(点选) |
turn-based | discrete-choice | templates/match.schema.json |
merge |
event | discrete-choice | templates/merge.schema.json |
idle |
event | discrete-choice | templates/idle.schema.json |
tycoon |
turn-based | discrete-choice | templates/tycoon.schema.json |
generic(兜底) |
* | * | templates/generic.schema.json |
- 物理优先分类(OpenGame Physics-First,review §10.5):classify 先定 tickModel(spike 已证 100%)→ 再定 archetype(93%);可选 DeepSeek 副模型双跑兜底。
- 映射表是契约:classify 出 archetype 必落到此表的一行(否则=孤儿分类);新增 archetype 必须同时补本表 + 对应 profile 锚。
7. 关键实现步骤(按两线)
顺序:先冻结 8 契约 → 两线并行。契约冻结前任一线不得开工(契约先行铁律)。
7.0 契约冻结(联合,开工门)
- 写
contracts/agent-loop/source-project.schema.json(§5.1)。 - 写
V18.0.0__create_game_source_project.sql(§5.2,两处副本)。 - 扩
SaaStudioNodes.ALL_KEYS新键(§5.4)。 - 扩
DifyCallbackReqVO.trace字段口径(§5.8)。 - 收口 §12 五个待解项(尤其①归属、②构建权威、⑤narrative failCount)。
- 两轮评审已过(review 版),实现版按 memory
impl-review-one-opus-round单轮 opus 评审。
7.1 后端线(6c6g 编辑 / mini-desktop 构建)
| # | 步骤 | 文件 | 验证 |
|---|---|---|---|
| B1 | 源项目 schema + DB | source-project.schema.json、V18.0.0__*.sql |
Flyway 启动迁移绿(mini-desktop) |
| B2 | SAA 图扩 classify/asset/modify/escalate/nreview 节点 + 边 + recursionLimit 重算 | SaaStudioGraph.java、SaaStudioNodes.java |
SaaStudioGraphTest 回归绿 + 拓扑无孤儿 |
| B3 | state key 全表落地(新键 + KeyStrategy 注册) | SaaStudioNodes.java:ALL_KEYS |
单测:全键 ReplaceStrategy 注册 |
| B4 | 救场阶梯 failCount/modelTier 路由 + giveup 完整 dump | SaaStudioNodes.java(playRouter/okElseRepairOrGiveup/giveupNode) |
单测:5 失败升档、8 失败 giveup + dump 落盘 |
| B5 | trace+cost 扩(modelTier/escalationEvents/cacheHit/giveupDumpPath)+ worker 侧 _extract_trace 同步扩 |
SaaGraphDispatcher.java:extractTraceQuietly、service.py:_extract_trace |
字节兼容:ReadinessScorer 两路同读 |
| B6 | studio 编排 + /studio/{create,modify,extend} | StudioServiceImpl.java、AppStudioController.java |
单测 + 编译绿;modify 出新预览版不动 currentVersion |
| B7 | modifyPatch 契约接线(确定性编辑路 / regenerate-module 路) | StudioServiceImpl.java、SaaStudioNodes.modifyNode |
单测:确定性免 LLM、regenerate 只重一模块 |
| B8 | 源落库事务边界(源→构建→建包,失败标孤儿) | StudioServiceImpl.java / 落库服务 |
单测:构建失败源 status=2、不建包 |
| B9 | 缓存命中字段落账(cache_ratio + 命中 token 折¥) |
cost.py、SaaGraphDispatcher |
单测:两套字段取 max、落 trace.cost |
7.2 引擎+前端线(Mac)
| # | 步骤 | 文件 | 验证 |
|---|---|---|---|
| E1 | 2D 适配器(游戏定义→LittleJS 渲染):SourceProject.gameDefinition → 可玩 | game-runtime/src/(adapter 层) |
单测:实体→sprite、behavior→逻辑 |
| E2 | 唯一构建实现核对(SAA build 节点与 worker 共调 scripts/build.mjs) |
game-runtime/scripts/build.mjs(不动) |
同源同参:__GameBundle 产出一致 |
| E3 | asset 产消(asset 节点 spec → assets[] → 宿主消费)+ provider=mmx-cli 插桩 | game-runtime/ + worker asset 角色 |
九门:assets[] 非空、宿主加载 |
| E4 | 九门 QA harness 复用(禁重写)+ narrative 路质量门接 reviewer | _shared/*(harness 不动)+ reviewer 角色 |
九门真玩绿(mini-desktop) |
| E5 | Prompt Registry 冻结 few-shot(byte 稳)+ CI 卡 byte | contracts/prompts/、prompt.py |
CI:few-shot byte 不变 |
| E6 | 前端创作(接 /studio/create)/ 修改(接 /studio/modify)/ 预览 UI | game-studio/src/ |
真机 UI 走查(mini-desktop CDP) |
7.3 缓存透传 spike ✅ 已完成(绿)
- 结果(2026-06-17):deepseek-v4-flash / MiniMax-M3 / M2.7 经 new-api 网关前缀缓存全部透传成立,第二款起命中 76-93%。
- 落地口径:检测兼容两套字段(DeepSeek
prompt_cache_hit_tokens/ MiniMaxprompt_tokens_details.cached_tokens,取 max);命中 token 落成本台账。 - 结论:缓存策略(三段式 + Prompt Registry 冻结)坐实,不再是前置阻断项;实施只剩"冻结 few-shot 字节稳(B9/E5)+ 落命中台账(B9)"。
8. 两线切分与交汇(谁锁谁)
graph LR
subgraph 契约交汇["8 契约(开工前冻结=两线交汇面)"]
C1["①源项目 schema"]; C2["②源项目 DB"]; C3["③源/产物分离"]; C4["④SAA state 全表"]
C5["⑤asset 产消"]; C6["⑥modifyPatch"]; C7["⑦唯一构建 API"]; C8["⑧trace+cost"]
end
BE["后端线(6c6g/mini-desktop)<br/>锁:C1·C2·C4·C6·C8 + SAA 拓扑/救场/studio 编排"] --> 契约交汇
EN["引擎+前端线(Mac)<br/>锁:C1(消费)·C5·C7(构建实现)·C3(产物消费) + 2D 适配器/九门 QA/前端 UI"] --> 契约交汇
- 后端线主锁:①②④⑥⑧(源项目 schema/DB、SAA state/拓扑/救场路由、studio 编排、modifyPatch、trace+cost)。
- 引擎+前端线主锁:①(消费)⑤⑦(构建实现)③(产物消费)+ 2D 适配器、asset 产消、九门 QA、前端创作/修改/预览 UI。
- 共锁:① 源项目 schema(后端写、引擎消费)、⑦ 构建 API(引擎实现 esbuild、后端落包)。
- 并行边界 = 模块边界(memory
prefer-parallel-over-serial):零共享可变态,worktree 隔离,只对真独占资源(九门端口 4320/9222)串行。
9. 边界失败路径
| 失败 | 处置 | 出处 |
|---|---|---|
| 源落库成功但构建失败 | 源 status=2(孤儿),不建 package,不动 currentVersion | §5.2 事务 |
构建产 bundle 缺 __GameBundle 全局名 |
emit 判 failed(bundle_missing_global_name),不落坏包 |
SaaStudioNodes.emitNode:666 |
| LLM 调用超时/429/5xx | 单次 180s 超时 + ≤3 重试,超限不裸退图(写 feedback) | SaaStudioNodes.callWithTimeoutAndRetry:154 |
| 九门连续失败 | failCount++ → 5 升档 → 8 giveup + 完整 dump | §6.3 |
| narrative needsRepair 连续 true | 同九门 failCount 阶梯(§5.9/§12-⑤) | §5.9 |
| 缓存前缀不透传(spike 已证透传,仅理论兜底) | 命中字段缺则按 miss 计价、生成不阻断(仅成本回退) | §7.3 ✅ |
| modify 失败 | 不建新版、base 不动 | §5.6 |
| classify 出未知 archetype | 落 generic 兜底 + 告警(不污染下游) | §6.4 |
| trace 抽取异常 | best-effort 吞+warn,trace_json 留 NULL,不阻断生成 | SaaGraphDispatcher.java:497 |
| 图终态空(超步等) | 兜底 failed(llm_error) 回调,真因留日志 | SaaGraphDispatcher.java:376 |
10. 验证方法(含两线各自验收门)
10.1 后端线验收门
- 编译 + 单测绿:
SaaStudioGraphTest(图布线回归)、SaaStudioNodesRegressionTest、新 classify/asset/modify/救场单测。 - Flyway 迁移绿(mini-desktop):V18 迁移成功,
game_source_project建表。 - 救场阶梯单测:5 失败升档(escalationEvents 落)、8 失败 giveup(giveupDumpPath 落盘+完整 dump)。
- trace 字节兼容:
ReadinessScorer在 SAA 路与 worker 路同读pass/gatespec.driver/sevenGateVerdict.guards/repairs(SaaGraphDispatcher.java:424口径)。 - modify 局部性单测:确定性编辑免 LLM、regenerate-module 只重一 behavior、不动 currentVersion。
10.2 引擎+前端线验收门
- 2D 适配器单测:SourceProject.gameDefinition → 可玩(实体→sprite、behavior→逻辑)。
- 九门真玩绿(mini-desktop,端口 4320/9222):cheap 在固定架构填出过九门游戏,
verdict.pass=true。 - asset 产消门:
sourceProject.assets[]非空 → GamePackageassets[]→ 宿主加载(非空 assetContext)。 - 构建确定性门(v2 review M0):同
buildInputHash→ 字节等价 bundle(从源重新构建可复现)。 - 前端真机 UI 走查(memory
frontend-link-ui-walk-publish-fix:编排器旁路掩盖 UI 缺陷 → 真 UI 走查唯一手段):create/modify/预览闭环。
10.3 联合 spike 门(决定架构成不成立)
- 缓存透传 spike ✅ 已绿(§7.3):deepseek-v4-flash/M3/M2.7 经 new-api 透传成立(76-93% 命中)。
- classify 准确率 spike ✅ 已绿(§6.4):M3 tickModel 100%/archetype 93%、$0.003/次,便宜分类不污染下游;唯一改进=archetype 枚举拆"消除族"(bubble vs match3/line-clear)。
- 端到端门(待实施后验):一句话 → studio 填固定架构 → 源项目 → 构建 → 九门过门 → GamePackage → feed 真玩;成功率(对齐 MVP ≥80%)+ 单款 < $1(¥0.15 门)+ modify 局部性。
11. 完成条件(Definition of Done)
- 8 契约全冻结(schema/DB/state/构建 API/trace 全落地且评审过)。
- 后端线:SAA 固定架构图扩节点全绿(单测+Flyway),救场阶梯/giveup dump/trace+cost 可验,studio create/modify/extend 编排通。
- 引擎+前端线:2D 适配器可把游戏定义渲成可玩,九门真玩绿,asset 产消通,构建确定性(字节等价),前端创作/修改/预览真机走查过。
- 联合 spike 三门过:缓存透传成立、classify 准确、端到端成功率+成本+modify 局部性达标。
- 无孤儿设计(AGENTS §7):每节点有入边/出边/消费者(§6.2);每新数据结构有产消通道。
- follow-up 登记:
- 产品需求清单补 narrative P-id 与验收(§5.9)。
- 3D 适配器(Phase 2)、Template Skill(冷路径晋升)登记为远期。
game_source_project物理归属模块最终落定(§12-①)。
- 知识回写(AGENTS §7):新增 skill
fixed-architecture-saa-studio(固定架构填槽+救场阶梯+缓存前缀+classify 映射),更新.agents/README.md索引;收口走 wave-close-checklist 8 步。
12. 开工前待解(诚实列出 · 现行代码与设计未解冲突)
以下是我判断现行代码/文档与本设计存在未解冲突或需创始人/两线收口的点,不糊过去。开工门(§7.0)须逐条收口。
✅ 全部待解经创始人 2026-06-17「按推荐」确认收口(本节转为已收口记录):① 源项目表归属 = studio 模块(create/modify 编排入口在此;project 仍管 game_version 产物权威)· ② 后端
RuntimeBuildServiceImpl本期只接"落包",不自驱 esbuild(构建留 worker/SAAbuild.mjs)· ③ 缓存透传 ✅ spike 已证绿(76-93%)· ④ classify→archetype 映射表语义 = 引导(品类预设)非校验(对齐"玩法模板未废、游戏模板已废")· ⑤ narrative 失败 =needsRepair=true等价一次九门失败计入failCount(reviewer 自身抖动也计,防卡死)· ⑥ studiocreate=draft+generate一步式封装(additive,不破现两步路)。契约冻结进行中:keystonecontracts/agent-loop/source-project.schema.json已落;V18 SQL + ALL_KEYS 扩 + trace 扩 = 后端线 module 实现(V18 入 game-cloud 模块迁移,非 stale 的contracts/db-schemas/〔已停于 V9〕)。
① 源项目存储权威归属(DB review 与架构 review 口径冲突)
- 冲突:v2 生命周期 review §5 说"
game_version内容从打包产物升级为源项目工件+构建产物双存";架构 review §10 + 本档定"独立game_source_project表,勿塞 game_version"。两者矛盾。 - 本档裁定:采独立表(改源不改产物的关键=源/产物物理解耦,塞 game_version 会破 GamePackage 产物纯净 + 既冻 schema)。
- 待收口:
game_source_project物理归 studio 模块(它是编排层、已持 game_id/version_id 引用,V8 错误码段 112)还是 project 模块(版本台账权威)?倾向 studio 模块(create/modify 编排入口在此,源项目是其编排产物;project 仍管 game_version 产物权威)。需创始人/两线拍。
② 构建权威分裂(worker 私有 esbuild vs 后端 RuntimeBuild 桩)
- 现状(已核码):worker
run.py:build/SAASaaGenNodes.buildNode已共调game-runtime/scripts/build.mjs(同脚本同参,已天然统一);后端RuntimeBuildServiceImpl.triggerCompile是桩(:51TODO,只落排队不跑编译)。 - 本档裁定(§5.7):构建执行权 = worker/SAA build 节点的
scripts/build.mjs(已真跑、九门验过,不另造第二实现);后端 RuntimeBuild = 落包+manifest 权威(消费构建产物落game_runtime_package+ 回填game_version,不要求它自跑 esbuild)。 - 待收口:
RuntimeBuildServiceImpl桩的 TODO 是否本期转真?建议本期只接"消费构建产物落包"路(经 handleCallback 已通),不强求它自驱 esbuild 执行引擎(那是渠道线/未来 CI 化才需)。需确认范围。
③ 缓存前缀经 new-api 网关透传 ✅ 已 spike 证绿(已解除,非待解)
- 结果(2026-06-17 spike):deepseek-v4-flash/M3/M2.7 经 new-api 网关前缀缓存全部透传,命中 76-93%;检测兼容两套字段(DeepSeek
prompt_cache_hit_tokens/ MiniMaxprompt_tokens_details.cached_tokens)。 - classify 准确率 spike 同绿:M3 tickModel 100%/archetype 93%、$0.003/次。
- 剩工程动作(非待解):冻结 few-shot 字节稳(B9/E5)+ 命中 token 落账(B9)。
④ classify→archetype 映射表必须与现 8 模板 schema 对齐(否则孤儿分类)
- 现状:
contracts/templates/现有 8 schema(clicker/dodge/match/runner/idle/merge/tycoon/generic),但语义已变(generic.schema.json注:P3 走引擎 bundle 路,校验 bundle 形态而非 GameConfig 玩法字段)。 - 待收口:§6.4 映射表把 archetype 锚到这些 schema 作"品类 profile 引导",但旧模板 schema 校验对象(GameConfig)在 bundle 路已退场——映射表用它们做引导 prompt/脚手架预设(玩法模板=品类框架,非 pre-built 代码,对齐 memory
tiered-engine-cocos-decision2026-06-17 术语纠偏:废的是"游戏模板"、"玩法模板未废"),非填参执行器。需确认映射表语义=引导而非校验。
⑤ narrative 失败如何计入救场 failCount(九门对它失效)
- 冲突点:救场阶梯锚
verdict.pass=false(九门),但 narrative 路不走九门(走 reviewer)。若不定义,narrative 路无升档/giveup 终止条件 → 可能死循环。 - 本档裁定(§5.9):narrative
needsRepair=true等价一次九门失败计入 failCount(同 5+3 阶梯);recursionLimit同口径。 - 待收口:确认此口径(narrative reviewer 的 needsRepair 作为 failCount 源);+ narrative reviewer 自身失败(LLM 调用失败)是否也计 failCount(建议计,避免 reviewer 抖动卡死)。
⑥ studio 路由 create/modify/extend 部分净新(现只有 draft/generate/task/regenerate)
- 现状(已核码):
AppStudioController现有/studio/{template/list,draft,generate,task/{id},task/{id}/regenerate};无/create(统一入口)//modify//extend。 - 待收口:v2 review C3 的
/studio/{create,modify,extend}是净新增;create与现draft+generate关系=统一入口归一(generic 缺省,对齐7534bdf9一句话入口),还是并存?建议create=draft+generate的一步式封装(additive,不破现有两步路)。
13. 回滚策略
| 变更 | 回滚 |
|---|---|
Flyway V18(game_source_project) |
写 V18.0.1 补偿迁移 DROP TABLE(不改 V18,头注铁律);additive 表删除不影响 GamePackage 产物链 |
| SAA 图新节点(classify/asset/modify/escalate/nreview) | 新节点 additive;SaaStudioGraph.assemble 布线唯一源,删新节点+边即回现 11 节点图;state 新键不读则零影响 |
| 救场阶梯(failCount/升档) | AigcExecutorProperties 开关:saaStage2ExtraRepairs=0 → 退回单档 5 轮(现行);recursionLimit 回旧公式 |
| trace+cost 扩字段 | additive(DifyCallbackReqVO.trace Map):删字段口径,缺则省略键,trace_json 字节回旧 |
| modify 编排 + /studio/{create,modify,extend} | 新路由 additive;下线路由即回现 draft/generate/regenerate;modify 不动 currentVersion=天然安全 |
| 缓存 Prompt Registry 冻结 | few-shot 回从文件读(_few_shot());缓存命中字段不落账=现行(cost 不计缓存折扣) |
| 2D 适配器 | 引擎线产物;现 worker 直产 iife 路保留=回退路 |
核心安全垫:GamePackage 产物 schema / 宿主装载契约 / 回调唯一写入路径 / 九门 harness 全不变 → 任一新增失败,生成主线可回退到现 W-G1 worker 直产 bundle + 现 11 节点 SAA 图,B1 发布链/feed 真玩零回归。
14. 知识回写(收口时执行,AGENTS §7)
- skills/:新增
fixed-architecture-saa-studio.md(固定架构填槽范式 + 救场 5+3 阶梯 + 三段式缓存前缀冻结 + classify→archetype 物理优先映射 + modify 改源不改产物);更新saa-graph-orchestration.md(新节点/state 键/recursionLimit 重算)。 - knowledge/:
tech-decisions.md补"固定游戏架构=轻量声明式领域模型(非 AAA ECS)+ 2D 适配器(LittleJS)/ 3D Phase2";glossary.md补 SourceProject/archetype/profile 三维/救场阶梯/escalate。 - rules/:补红线"源项目独立
game_source_project表,勿塞 game_version;GamePackage 产物 schema 不变"。 - 更新
.agents/README.md索引 +docs/agent-specs/_index.md活地图(本档登记 ACTIVE)。