# contracts/ —— 绘境AI 八类契约单一事实源(Day-0 / M0) > **定位**:本目录是跨三仓(game-cloud 后端 / game-admin 管理端 / game-studio 产品端)与五工位(WS1-WS5)共享的**契约单一事实源**。 > **纪律**:任何接口 / 数据结构 / 事件 / SDK 签名变更,**先改本目录、再写代码**,并通知相关方(见 [`.agents/skills/contract-first-development.md`](../.agents/skills/contract-first-development.md))。 > **里程碑**:Day-0(6/9 上午)全员锁定下列契约并 git 提交 = **M0**。锁定后各工位 mock 对方接口并行开发,集中联调 Day11 起。 --- ## 一、八类契约清单与 owner | # | 契约 | 路径 | owner(主笔) | 消费方 | |---|---|---|---|---| | 1 | API OpenAPI | `api-schemas/*.yaml` | WS1 lead(全员 review) | 前端 mock / 各模块互调 | | 2 | DB 迁移 | `db-schemas/V*.sql` | WS1 | 后端各模块 | | 3 | SDK 接口 + postMessage 协议 | `sdk-interface.d.ts` | WS3 SDK 负责人 | game-studio 宿主 / 游戏侧 | | 4 | GamePackage 运行清单 + 对象存储索引 | `game-package.schema.json` + `game-artifact-manifest.schema.json` + `game-source-archive.schema.json` | WS3 + WS2 | 生成→编译→源归档→制品存储→预览→发布→运行全链路 | | 5 | telemetry 事件 | `events.schema.json` | WS5 | 前端埋点 / SDK 上报 / 看板 | | 6 | ~~Dify workflow I/O~~ ⚠️ 降级远期未部署 | `dify-workflow-io.json`(见 [`DEPRECATED-dify-workflow-io.md`](./DEPRECATED-dify-workflow-io.md)) | WS2 | ~~aigc Java 壳 ↔ Dify~~(现行=new-api 网关,C2/HJ-GEN-001;JSON 本体保留作历史/远期) | | 7 | 广告位配置 | `ad-slot.schema.json` | WS5 | ad 模块 / SDK Plugin.Ad | | 8 | Prompt Registry | `prompts/`(独立目录) | 各 prompt owner 工位 | aigc / 生成链路(见 [`prompt-governance`](../.agents/skills/prompt-governance.md)) | > **M0 八类契约已锁**(JSON/YAML/Schema 语法校验通过):#1 project.yaml · #2 V1.0.0__…sql · #3 sdk-interface.d.ts · #4 game-package · #5 events · #6 dify-workflow-io · #7 ad-slot · #8 prompts/。 > **#4 对象存储伴随契约(2026-07-29)**:`game-artifact-manifest.schema.json` 只描述素材、运行包、证据对象及源修订身份,不是宿主读取的 GamePackage;`game-source-archive.schema.json` 单独描述引擎无关源码归档。生产 `gameId/versionId` 只接受 project 数据库正整数 ID;Tier2 字符串版本只进入 Tier2 `sourceRevision.revisionId`,LittleJS/Canvas 等游戏使用 `game_source_archive` provider,不得伪装成 Phaser Tier2。发布状态继续由 `game_runtime_package.status` 管理,不写入不可变对象清单。 > **Wave1 脊柱 4 模块契约已补并锁**(aigc/runtime/feed/telemetry,2026-06-08):经契约先行起草 + 一致性评审 + 收口(§2.1)+ 主 agent 校验(YAML 语法/裸 select* 0/错误码段 101-104 独占/Flyway V2-5 唯一)。 > **Wave2 变现契约已补并锁**(ad/trade,2026-06-08):`ad.yaml`+`trade.yaml`(API #1)+ `V6.0.0`/`V7.0.0`(DB #2),消费既有 #7 ad-slot / #5 events 不重造;经主 agent 校验(YAML 语法/错误码 111·106 独占/Flyway V6-7 唯一/金额用「分」/资金幂等键+状态机/ad↔trade Feign seam 一致);ad 计费 `uk_trace` 由主 agent 收紧为 `(trace_id,event_type,tenant_id)` 防 reward 被 impression 静默吞掉。**pay=复用 huijing-pay 后置**(收单 P1)。 > **Wave3 跨主线收口(进行中)**:新增 `studio`(创作主链路最小版编排,错误码 112 / Flyway V8)+ `compliance`(锁风门 Gate,发布前合规扫描)两模块契约。Phase A 已收口 project 侧:publish 唯一化(返回 admitted+gates 门禁聚合)、ProjectApi seam 定稿(getCurrentVersionId GAP-3 / createProject 写类 RPC)、GAP-4 把 `events.schema.json` 信封 envelope/user 由 snake_case 统一为 camelCase(与 telemetry.yaml/前端 SDK 对齐)。compliance gate 在 project.submitPublish 内仅留 Phase C 接入 seam(TODO 注释),尚未接 ComplianceGateApi。其余模块(community/ip/biz)待后续波次补。 > > **游戏宿主装载契约(指针登记,不折进上表跨仓 8 类)**:Runner v2 P1 新立 additive 第 9 类契约,**落 `game-runtime/src/core/game-host.d.ts`**(与 `api.d.ts` 同目录,**非**本目录)。理由:它是 game-runtime 内部「host↔游戏工厂」接线面,消费方只在 game-runtime(host boot + 生成 agent),落同目录 import 方向顺(`./api.d.ts`);落本目录会让跨仓 SSOT 反向相对 import `../game-runtime/src`(拆仓即断)。消费方=host boot(装游戏)+ 生成 agent(产出靶);与受控面 6 项 additive(受控面零改)。详见 `docs/agent-specs/2026-06-13-P1-王蓝莓上引擎-execution.md` §5/§12-A1。 > > **判分闭环两契约(指针登记,additive 立位)**:生成引擎判分闭环的 PlaySpec 考卷(C5)与 VerdictFeedback 判卷反馈(C6),落 [`play-loop/`](./play-loop/)(README + 两份 schema + 零依赖校验器 + 正负样本套件)。它们把至今散在代码里的隐形约定钉成显式契约——考卷说清「怎么玩我以便判我」(驱动器族选择依据、起局仪式、赢/输可观测量、与源工程的 `sourceHash` 派生绑定),反馈说清「哪道门没过、卡在哪个 phase、往哪修」(一等字段 `phaseNow` 堵死 `gate_judge.py:100-102` 丢字段缺陷)。两档同一份 schema,不编码 tier 枚举、靠能力字段与 `ext` 扩展段表达档位差异(Δ9③)。消费方=W-S1 修复三单 + tier2 F-1 对齐;状态=schema 已立、生产接线在途。与本目录 v1 `agent-loop/verdict`(上代 clicker 终判)、`trace/`(观测事件)划清界限,见 play-loop/README。裁决记录见 `docs/agent-specs/2026-07-03-生成引擎agentic架构-第一性重推演与差量-设计.md` §5(Δ1)。 > > **门金标判例库(指针登记,additive 立位)**:验收门的误杀/漏放判例回归集,落 [`gate-fixtures/`](./gate-fixtures/)(manifest 登记 11 条判例 + 3 条待补产物 + 零依赖运行器 `run.mjs`)。判据散在 4 处 2 语言(九门/latch 于 play.cdp.cjs、形状/check 门于 amodel-gen、tier2 gate_judge、cheap_gates),故判例库落跨端等距的本目录;已有家的判例原地登记不搬(单一事实源),唯一新增真身=latch 终态同义词回归(读真源抽谓词字面量重建,删任一同义词即红)。**门判据改动必过全量判例**(挂载方案见其 README)。裁决记录同上 §5(Δ4)。 > > **tier2 自有受治理 schema(指针登记,不参与 huijing Flyway 对账)**:tier2 富游戏源工程存储的落库 manifest 表 `tier2_source_project_version`,DDL 权威声明落 [`tier2/config/schema/tier2_source_project_version.sql`](../tier2/config/schema/tier2_source_project_version.sql)(**非**本目录 `db-schemas/`)。**owner = tier2 生成线**,落 tier2 独立逻辑库(`tier2/config/infra.yaml` `mysql.database=tier2`,与 game-cloud 业务库隔离),走自建 DDL + `ALTER` 受治理迁移、**不走 game-cloud 的 Flyway、无执行副本**。故它明确**不参与** `db-schemas/` 那条「须与 game-cloud 执行副本保持 diff 一致」的授权源硬语义——那目录治的是 huijing 库,跨库塞是类别错误。in-code DDL(`tier2/gen-worker/worker/store.py` 的 `_DDL_SOURCE_PROJECT_VERSION` + `_ALTER_ADD_STATUS_COLUMN`)与该 `.sql` 双源,由 `tier2/gen-worker/tests/test_store_ddl_reconcile.py` 规范化对账钉成机器门。执行拆段见 `docs/plans/2026-07-05-001-feat-asset-src-源工程存储-plan.md` §4 T2 / §5。 ``` contracts/ ├── README.md # 本文件 ├── api-schemas/ # #1 OpenAPI 3.0(每模块一个 yaml) │ ├── project.yaml # 黄金模块 project(已落地) │ ├── aigc.yaml # Wave1 生成(已锁) │ ├── runtime.yaml # Wave1 预览/试玩/包服务(已锁) │ ├── feed.yaml # Wave1 游戏流/双轨专区(已锁) │ ├── telemetry.yaml # Wave1 遥测/聚合回灌(已锁) │ ├── ad.yaml # Wave2 广告引擎(已锁;含 ad↔trade Feign seam) │ ├── trade.yaml # Wave2 分账/结算/提现(已锁) │ └── studio.yaml # Wave3 创作主链路最小版(编排 project/aigc/runtime) ├── db-schemas/ # #2 Flyway 迁移(本目录=授权源;执行副本在 game-cloud/huijing-server/src/main/resources/db/migration/,Flyway 校验和敏感须保持 diff 一致) │ ├── V1.0.0__create_game_project.sql │ ├── V2.0.0__create_game_aigc.sql # aigc(每模块独占主版本号) │ ├── V3.0.0__create_game_runtime.sql │ ├── V4.0.0__create_game_feed.sql │ ├── V5.0.0__create_game_telemetry.sql │ ├── V6.0.0__create_game_ad.sql # ad(广告位 + 收入台账,Wave2) │ ├── V7.0.0__create_game_trade.sql # trade(账户 + 流水 + 提现,Wave2) │ ├── V8.0.0__create_game_studio.sql # studio(创作主链路编排状态,Wave3) │ └── V34.0.0__create_game_artifact_storage.sql # runtime/storage(对象清单 pending/committed 状态) ├── game-package.schema.json # #4 GamePackage 清单(已落地) ├── game-artifact-manifest.schema.json # #4 运行包/素材/证据对象索引(不替代 GamePackage) ├── game-source-archive.schema.json # #4 引擎无关源工程归档索引(独立 source 桶) ├── events.schema.json # #5 telemetry 事件 v1(已落地) ├── sdk-interface.d.ts # #3 已锁(SDK API + postMessage 协议) ├── dify-workflow-io.json # #6 ⚠️ 降级远期未部署(见 DEPRECATED-dify-workflow-io.md;JSON 保留作历史,现行=new-api 网关) ├── ad-slot.schema.json # #7 已锁(广告位配置) └── prompts/ # #8 已锁(README + registry.yaml + 01-safety 示例 + 8 阶段) ``` ## 二、版本与兼容规则(硬约束,来自工程规范 §5) - **API**:URL Path 版本,新增字段不算 breaking;删除/重命名字段 = 升版本;旧版本保留 ≥ 3 个月,废弃用 `Deprecation: true` + `Sunset: `。 - **事件**:每事件带 `schema_version`(如 `game_play_start.v2`);新增字段给默认值、老消费者忽略未知字段;不兼容变更用新事件名并行消费。 - **DB**:`V{版本号}__{描述}.sql`;已合入的迁移**禁止修改**,回滚写新补偿迁移;CI 跑 `flyway validate` 阻断不合规。 - **契约对齐顺序**:后端**先写 `-api` 包的 VO/DTO**,前端据此定义 TS 类型。 ### 2.1 跨模块对齐约定(Phase A 评审收口,HJ-BUILD-FIX) - **两个 `qualityScore` 不同量纲、不可互相回灌**:aigc=生成质量分(0-1,对齐 Dify #6);telemetry/feed=运营质量分(0-100)。两者来源与计算口径不同,禁止跨模块直接赋值或换算回填。 - **`game_version.package_url`/`checksum`/`bundle_size` 权威写者=runtime**(编译成功后回写);aigc 只回填 `version_id` 与生成元数据,不得写入编译产物字段。 - **`play_count` 权威源=telemetry `game_play_start` 事件聚合**;runtime session 仅作时长/质量观测,不作为播放计数源;`sessionId` 透传至 telemetry `session_id` 用于对账。 ## 三、端与鉴权(API 契约共同前提,来自工程规范 §4) ``` /app-api/** → 产品端(game-studio),用户 Token + DataPermission(创作者只见自己数据) /admin-api/** → 管理后台(game-admin),管理员 RBAC ``` URL 格式:`/{端前缀}/{模块}/{资源}/{动作}`。端前缀 `/app-api`·`/admin-api` 沿用 huijing 默认,由框架按 `controller.app`·`controller.admin` 包名**自动添加**(Controller 内 `@RequestMapping` 只写 `/{模块}`,不含端前缀)。权限在网关 + 注解双重校验,前端不可作为唯一边界。 ## 四、错误码段(每模块独占,来自工程规范 §1.3) `1-{模块段}-{业务}-{细分}`:project=100 / aigc=101 / runtime=102 / feed=103 / telemetry=104 / pay=105 / trade=106 / community=107 / ip=108 / compliance=109 / biz=110 / ad=111 / studio=112。新增模块在 `-api` 错误码常量类登记,禁止重叠。