games-development-ai/docs/agent-specs/2026-06-17-固定游戏架构与SAA-agentic-studio-execution.md
zizi 38729ffdaa fix(contracts): studio.yaml 契约评审跟进——收紧 modifyPatch + idempotency 语义(单轮 codex 评审)
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>
2026-06-17 16:00:52 +00:00

56 KiB
Raw Blame History

固定游戏架构 + SAA agentic studio — execution 版

类型:execution 版(供两开发线实现)。日期:2026-06-17 · 起草:Opus(effort=高)。 上游(权威,勿翻旧账):


0. 结论先行(TL;DR)

  1. 范式:Opus 设计固定游戏架构(轻量声明式领域模型 + profile 三维),cheap 模型在 SAA agentic studio 里填槽;游戏 = 源项目,生命周期 create/modify/extend/build/release/maintain;改源不改打包产物(GamePackage 产物 schema、宿主 window.__GameBundle.bootGameHost、feed 全不变)。
  2. 8 契约(本档 §5 逐个给字段级 schema/签名):①源项目 schema ②源项目 DB(独立 game_source_project 表)③GamePackage 源/产物分离 ④SAA state key 全表 ⑤asset 产消 ⑥modifyPatch ⑦唯一确定性构建 API ⑧trace+cost 字段。
  3. 拓扑(§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 重算。
  4. 两线切分(§8):后端线(6c6g 编辑 / mini-desktop 构建)锁源项目 schema+DB、SAA state/拓扑/救场路由、studio 编排、trace+cost、modifyPatch;引擎+前端线(Mac)锁 2D 适配器(游戏定义→LittleJS)、asset 产消、唯一构建实现、九门 QA、前端创作/修改/预览 UI。交汇=本档 8 契约。
  5. 开工前待解 → ✅ 全部收口(创始人 2026-06-17「按推荐」):①源项目表归属=studio 模块 ②后端 RuntimeBuild 只落包(构建留 worker/SAA build.mjs)③缓存透传 ✅ spike 绿(76-93%)+ classify ✅ 绿(tickModel 100%)④classify→archetype 映射表=引导非校验 ⑤narrative needsRepair=true 等价一次九门失败计入 failCount ⑥studio create=draft+generate 一步式封装。契约冻结进行中:keystone source-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. 前置条件

  1. 上游决策已定:review §1.5 + §10 全部已定(领域模型轻量声明式+三维 profile、Phase1 仅 2D、agent 列表、救场带限额、narrative 留 MVP、MVP 只 Debug Skill、写码+修 bug=一个核心代码 agent)。
  2. 现行底座可用且已核码:
    • 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})。
  3. 机器分工(memory internal-build-infra-servers):后端编辑 6c6g、权威构建/e2e 门 mini-desktop、基建 mini-infra;6c6g 禁起浏览器(九门真玩在 mini-desktop)。
  4. 子代理模型分流(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.1 assetSpec 形态)。
  • 消费:logic/scaffold 读 sourceProject.assets[].ref,构建时解析为 GamePackage assets[](game-package.schema.json:34-50,类型 image/audio/...);宿主经 assets[].url 走 <img>/drawImage(inject.ts CSP img-src 已放行)。
  • provider 可插拔:assetSpec.provider 默认 mmx-cli(memory mmx-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:51 TODO),本期不要求它自己跑 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 / MiniMax prompt_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:409 rc==0 ∧ verdict.pass)。
  • 阶梯:cheap(stage1)→连续 5 次九门失败 → escalate 升档(stage1→stage2)→ stage2 再 3 次失败 → giveup。
  • state 驱动:failCount 在每次九门(及 narrative needsRepair)失败 +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 契约冻结(联合,开工门)

  1. 写 contracts/agent-loop/source-project.schema.json(§5.1)。
  2. 写 V18.0.0__create_game_source_project.sql(§5.2,两处副本)。
  3. 扩 SaaStudioNodes.ALL_KEYS 新键(§5.4)。
  4. 扩 DifyCallbackReqVO.trace 字段口径(§5.8)。
  5. 收口 §12 五个待解项(尤其①归属、②构建权威、⑤narrative failCount)。
  6. 两轮评审已过(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 / MiniMax prompt_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 后端线验收门

  1. 编译 + 单测绿:SaaStudioGraphTest(图布线回归)、SaaStudioNodesRegressionTest、新 classify/asset/modify/救场单测。
  2. Flyway 迁移绿(mini-desktop):V18 迁移成功,game_source_project 建表。
  3. 救场阶梯单测:5 失败升档(escalationEvents 落)、8 失败 giveup(giveupDumpPath 落盘+完整 dump)。
  4. trace 字节兼容:ReadinessScorer 在 SAA 路与 worker 路同读 pass/gatespec.driver/sevenGateVerdict.guards/repairs(SaaGraphDispatcher.java:424 口径)。
  5. modify 局部性单测:确定性编辑免 LLM、regenerate-module 只重一 behavior、不动 currentVersion。

10.2 引擎+前端线验收门

  1. 2D 适配器单测:SourceProject.gameDefinition → 可玩(实体→sprite、behavior→逻辑)。
  2. 九门真玩绿(mini-desktop,端口 4320/9222):cheap 在固定架构填出过九门游戏,verdict.pass=true。
  3. asset 产消门:sourceProject.assets[] 非空 → GamePackage assets[] → 宿主加载(非空 assetContext)。
  4. 构建确定性门(v2 review M0):同 buildInputHash → 字节等价 bundle(从源重新构建可复现)。
  5. 前端真机 UI 走查(memory frontend-link-ui-walk-publish-fix:编排器旁路掩盖 UI 缺陷 → 真 UI 走查唯一手段):create/modify/预览闭环。

10.3 联合 spike 门(决定架构成不成立)

  1. 缓存透传 spike ✅ 已绿(§7.3):deepseek-v4-flash/M3/M2.7 经 new-api 透传成立(76-93% 命中)。
  2. classify 准确率 spike ✅ 已绿(§6.4):M3 tickModel 100%/archetype 93%、$0.003/次,便宜分类不污染下游;唯一改进=archetype 枚举拆"消除族"(bubble vs match3/line-clear)。
  3. 端到端门(待实施后验):一句话 → studio 填固定架构 → 源项目 → 构建 → 九门过门 → GamePackage → feed 真玩;成功率(对齐 MVP ≥80%)+ 单款 < $1(¥0.15 门)+ modify 局部性。

11. 完成条件(Definition of Done)

  1. 8 契约全冻结(schema/DB/state/构建 API/trace 全落地且评审过)。
  2. 后端线:SAA 固定架构图扩节点全绿(单测+Flyway),救场阶梯/giveup dump/trace+cost 可验,studio create/modify/extend 编排通。
  3. 引擎+前端线:2D 适配器可把游戏定义渲成可玩,九门真玩绿,asset 产消通,构建确定性(字节等价),前端创作/修改/预览真机走查过。
  4. 联合 spike 三门过:缓存透传成立、classify 准确、端到端成功率+成本+modify 局部性达标。
  5. 无孤儿设计(AGENTS §7):每节点有入边/出边/消费者(§6.2);每新数据结构有产消通道。
  6. follow-up 登记:
    • 产品需求清单补 narrative P-id 与验收(§5.9)。
    • 3D 适配器(Phase 2)、Template Skill(冷路径晋升)登记为远期。
    • game_source_project 物理归属模块最终落定(§12-①)。
  7. 知识回写(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/SAA build.mjs)· ③ 缓存透传 ✅ spike 已证绿(76-93%)· ④ classify→archetype 映射表语义 = 引导(品类预设)非校验(对齐"玩法模板未废、游戏模板已废")· ⑤ narrative 失败 = needsRepair=true 等价一次九门失败计入 failCount(reviewer 自身抖动也计,防卡死)· ⑥ studio create = draft+generate 一步式封装(additive,不破现两步路)。契约冻结进行中:keystone contracts/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/SAA SaaGenNodes.buildNode 已共调 game-runtime/scripts/build.mjs(同脚本同参,已天然统一);后端 RuntimeBuildServiceImpl.triggerCompile 是桩(:51 TODO,只落排队不跑编译)。
  • 本档裁定(§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 / MiniMax prompt_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-decision 2026-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)。