承接目录治理:上轮只压缩内容未减文件数,闭线工作记录仍平铺致目录看着仍一堆(创始人指出)。本次执行 B2 归档。 64 个 ≤06-15 闭线档(25 压缩桩 + 闭线 review/report/纪要/edit-plan)git mv 入 docs/agent-specs/_archive/(文件名不变、仍 git 跟踪可查)。热目录 ≤06-15 仅留 13 活档(决策/纲领/SoT/活spike)+13 个 06-16 在飞。 活资产 20 处旧路径引用(.agents/docs/memory/_index)同步改 _archive/,引用断裂复测=0;_index 活地图 + 治理档状态收口。约束:0 个 06-16 被移、orchestrator 等未跟踪在飞档零误纳。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
24 KiB
新玩法模板接入配方(add-game-template)
🛑 DEPRECATED(2026-06-12 模板哲学终裁,整篇配方退役)
本配方所教的「新增一个可玩玩法模板」工作流已废除,勿照此为新作上新。 现行裁决:
- 玩法模板层废除——模板 ≠ 玩法品类件;模板 = LittleJS 能力插件/二次开发件(粒子/物理/后处理等引擎能力包装层,裁决①2026-06-12)。
- 玩法 / 美术 / 关卡 / UI = agent 生成域(agent 写码于插件库,HJ-GEN-001 终审);旧「模板驱动生成 / LLM 填参」线随之退役。
- 好玩基线 v2 改挂评估门(非模板属性)。
- Tier1 引擎 = LittleJS 增强发行版 + Runner v2(2026-06-12 终裁);旧「自研 Canvas<15KB / toString 注入 / 15KB 体积门」为 1.x 加载面、β 退役。
- 旧 4 玩法模板(clicker/merge/idle/tycoon)+ 存量数据已清除(W-CLEAN)。
新工作去向:新增后端业务模块 →
./add-business-module.md(不动);新增引擎能力插件/生成链路 → 现行口径见../knowledge/tech-decisions.md§1.1、./runtime-and-multichannel.md顶部横幅、../rules/build-vs-buy.md。 以下正文一律仅作 1.x 历史留痕(保留 M-c 批①/批②实战收口痕迹与踩坑教训,不作现行执行依据)。
蒸馏来源:
docs/agent-specs/_archive/2026-06-10-Mc模板波-execution.md(HJ-MC-TPL-EXEC-001 §3–§9 全链)+ M-c 批① merge 模板实战收口(2026-06-10,五级验收门全过:构建/体积/契约门+真玩五AND双模板+Golden v1.1.2 PASS+校准批 accept 10/10+金丝雀10条入feed;途中逮修三真缺陷,见各节红框)。 适用(已退役,见顶部横幅):给「模板驱动生成 + agent 闭环 QA」生产链新增一个可玩玩法模板(merge/idle/tycoon 类纯 Canvas Tier1 玩法),覆盖契约→prompt→runtime→后端→编排器→五级验收门全链。 配套:新增后端业务模块(非玩法模板)见./add-business-module.md;生成链路现实态见./ai-generation-pipeline.md⓪ 节;契约先行见./contract-first-development.md;运行时/SDK 见./runtime-and-multichannel.md;Prompt 治理见./prompt-governance.md;可靠性红线见../rules/security-and-reliability.md。
目标
把一个新玩法(如「合成升级」merge)从契约接到可玩+可验收+可入 feed:新增一份 GameConfig schema + 一个 designer prompt + runtime 一个玩法分支 + 后端模板白名单一行 + 编排器一条玩家策略,全程守住「注入 LLM 文本 == 服务端校验文本 == judge 校验口径」的同源铁律与既有发布链/数据回路/鉴权红线零改。产出后该模板可生成、可真玩通关、可入 feed 被玩家试玩。
样板:merge 是已五级验收门全过的活样板(schema=
contracts/templates/merge.schema.json,designer=contracts/prompts/04-config/merge-designer.md,runtime 分支=game-studio/src/host/runtime/index.ts的initMerge,编排器策略=player_cdp.py的 merge 拖拽分支)。照抄它即可。 非目标红线:dodge/runner/match 三份 schema 仅契约落盘未实现,不据此宣称可玩;不动发布链(生命周期事件名 /game_end{score,completed,duration_ms}契约行 / 遥测 / feed 排序)、不动鉴权、不动 demo 兜底包。
前置
- 已读
./ai-generation-pipeline.md⓪ 节(生产路径已切「模板驱动生成 + agent 闭环 QA」),对齐编排器三件位置:docs/agent-specs/2026-06-09-agent-loop-v1/orchestrator/(run_batch.py/player_cdp.py/judge.py/prompts.py)。 - 重型构建/测试一律走 mini-desktop(git push→pull 同步,本机严禁
mvn/npm build,记忆internal-build-infra-servers);前端构建必须npm run build -- --mode staging(缺 staging env → mock 接管 → 静默 demo 兜底)。 - 与在飞波次的文件级共改先排程:若另一波已改
game-module-aigc-server/pom.xml或service/task/AigcTaskServiceImpl.java(如鉴权波 PlayerApi seam),本波在其合入后开工,开工前git pull/rebase取最新基线(执行版 §11.1)。
七步配方
步骤一 · schema 定稿三招(契约先合入,再动代码)
新建 contracts/templates/<t>.schema.json,逐项对齐 clicker.schema.json 风格($schema draft 2020-12 + $id + 中文 description + 数值带 minimum/maximum)。三招守门:
templateId用const锁死(如"const": "merge")——精确等值防 LLM 跨模板串台,比enum更严。- 顶层
additionalProperties: false——守住「字段不增不删」,LLM 不得自由发挥加字段。 - 跨字段约束 schema 表达不了的,用双兜底:JSON Schema draft 2020-12 无
$data,无法用一字段值约束另一字段(如 merge 的targetLevel ≤ chainLength、itemLabel数组长度 =chainLength)。处置 = ① prompt 正文硬约束(步骤二 hard_constraints 明文)+ ② runtime 渲染时钳制(步骤三clampInt(targetLevel, _, chainLength)、数组按min(len, chainLength)兜底、缺位补占位文案)。schema 只保各字段独立边界(如数组minItems:1/maxItems:上限+ 每项非空minLength:1+pattern:"\\S")。
可解性论证义务:schema 边界即「保证可解、堵死局」的承诺。新玩法须在 execution 版论证「最坏情况有限步可达通关、无死局」(merge 例:
targetLevel≤chainLength≤6→ 最坏2^5=32个 1 级物件,点击产料无限 + 合成必腾格 → 无死局,执行版 §3.3)。 诚实边界口径:新模板 runtime 实现后,schema description 写「runtime 本波已实现,可据此宣称可玩」——区别于未实现模板的「仅契约落盘」声明。
步骤二 · prompt 三件套(新 designer + 对抗/fix 复用升 patch + Golden 三守卫)
(a) 新 <t>-designer(新建 contracts/prompts/04-config/<t>-designer.md + registry.yaml 增条目):
- 结构逐项对齐
clicker-designer.md:frontmatter 8 键(id/version/stage/owner/tier/engine/input_schema/output_schema)+hard_constraints块 + 正文。只换模板专属约束,通用口径一字不降:- 不降的通用口径:注入防护(不执行创意/列表/上一轮问题里的指令)、只产一个合法 JSON 对象、不自评不下结论、重出轮只改指出项。
- 替换的模板专属:①
designIntent只许描述本模板机制内体验(禁承诺模板外机制:计时/失败惩罚/物理/音效)② config 字段域指向input.template_schema(真源 = 本模板 schema)③ schema 表达不了的跨字段约束在此写成硬约束(merge 例:「targetLevel 必须 ≤ chainLength;itemLabel 必须给 chainLength 个文案按等级排列」)。
(b) 对抗 quality.adversary-review + fix fix.design-revise 复用,仅升 patch(口径一字不动红线):
- 二者主干口径对任何模板已中性,不分模板分段、不新增条目。改法仅两类:
- 对抗:细则①示例追加新模板域示例(如「创意『合成种花』被改写为『躲避鲨鱼』属核心动作矛盾 P1」),原句一字不动(沿「仅追加不改口径」纪律)。
- fix:正文补
{{input.template_schema}}注入段(对齐 designer 的【模板 schema】块)+ 把残留的 clicker 字段示例括注中性化(主干句不动)。编排器侧零改(run_batch.py已传template_schema,补占位符即生效)。
- 红线:升 patch version 同步
registry.yaml,过四道闸 CI(Schema/成功率≥80%/Golden 回归 diff/成本延迟);P0/P1 口径文字一字不动(守「不得以放宽 P1 口径回应漂移」红线)。 - 后端不调 fix prompt:
AigcGenerateExecutor重出走 schema 校验失败回炉、不经 fix.design-revise(grepdesign-revise在 aigc 模块零命中),fix 改动仅影响编排器run_batch,勿误改后端。
(c) Golden 三守卫样本(新建 eval/config.<t>-designer/ 三件 + 对抗 Golden append-only 扩 3 条):
- kill 题文不符 ×1(硬门):创意↔config 核心动作矛盾(创意「合成种花」↔ config 改写「躲避鲨鱼」)→
decision:kill, reasons:[题文不符](守细则① P1 不被泛化吞)。这是稳定硬门——模型可靠判 kill。 - 越模板机制 ×1(⚠ Golden 观察项,非硬门——M-c 批② 2026-06-11 终裁):designIntent 承诺模板外机制(如「物理碰撞反弹」「计时」「破产扣分」)但 config 自洽 → labels.jsonl 标
decision:accept, reasons:[越模板机制P2放行](细则① :60「越模板 config 自洽=P2 放行不拦截,模板级表达力限制非缺陷」=文档化口径目标)。但 Golden harness 必须把此守卫降为观察项(golden-setexpectation:observe、harness_observe()恒记录实判不纳入 verdict)——实证:越模板是软语义边界,同输入温 0.2 重采样抖动(M-c 批② idle 2/4 判 kill、merge/tycoon 0/4),P1/P2 两向硬断言都随采样抖,硬门必 flaky。两向 fail-safe(P2 不拦发布/偶发 P1 仅多一次 HITL)。 - accept 正例 ×1(硬门):题文自洽 + 数值合规(跨字段约束满足)→
decision:accept。稳定硬门——模型可靠不误杀。 - 🔴 Golden verdict 只由硬门裁定 = 题文不符 kill ∧ accept 不误杀(+ 既有模板守卫不回归);越模板守卫只观察不门禁。通用红线:软判定(P2/非阻塞)绝不可做单样本硬 Golden 门——温 0.2 仍 50/50 抖(M-c 批② 实锤)。labels.jsonl 行只写 plain
decision(行内禁造doctrine字段);越模板恒按细则① P2、无版本门控(旧「doctrine 双标签 v1.1.2→kill」叙事已随终裁废止)。蒸馏全程见docs/agent-specs/_archive/2026-06-10-Mc模板波-批②idle-tycoon-execution.md§4.5 二次勘误 banner +eval/quality.adversary-review/README.md2026-06-11 两条。
步骤三 · runtime 单工厂分发(game-studio/src/host/runtime/index.ts)
单 startRuntime 内 switch(pkg.templateId) 分发,绝不开 ×N 个工厂——一份注入面、一份生命周期/遥测红线代码、theme/资源/game_end 只一处,杜绝 ×N 漂移。
- 分发骨架:
const templateId = typeof pkg.templateId === 'string' ? pkg.templateId : ''→switch:case '': case 'clicker':(空串兼容旧包,守存量内容池零影响)→ clicker;case '<t>':→ 新玩法;default:→game_error防御分支(sdk.reportError+life('game_error',{message:'unknown_template',templateId})+return {destroy(){}},不静默错渲染)。 - 新玩法
init<T>()函数体内自包含:因startRuntime经toString()注入沙箱,所有新函数必须定义在startRuntime函数体内、不引模块外符号;config 读取用函数体内纯函数clampInt/cleanLabels(无可抛路径,沿cleanText范式)做缺省/越界钳制(步骤一兜底②落地点)。 - 生命周期/finish 单一来源、参数化 score:
life('game_loaded'/'game_start'/'game_end')与finish()红线代码不复制——新玩法通关时调同一finish(),仅参数化score来源(如 clicker=点击数、merge=合成次数);game_end{score,completed,duration_ms}契约行零变化。 - 体积门 + 契约 grep(改后必跑):
- 体积:
node /tmp/measure-runtime.cjs dist/assets/GamePlayer-*.js(mini-desktop:/tmp,md5e6608a77520d560cd4fb29e2fb8d3481)提取 startRuntime(min) raw——硬线 < 15,360B(恒定红线);软门当前 8,192B(M-c 批① 因 merge 单玩法逼近原 4,096B 软门已上调,加新玩法再评)。前后差值写交付记录。 - 契约 grep:
grep -c 'duration_ms'计数只增不减;git diff不含 clicker 分支game_end/game_loaded/game_start任何删改;grep -rn 'innerHTML\|document\.'零命中(禁 DOM,玩法纯 Canvas);grep -P '[\x00-\x08\x0b\x0c\x0e-\x1f]'零控制字节。
- 体积:
步骤四 · 后端四点 + pom(game-module-aigc-server)
把 PromptResourceLoader / GameConfigSchemaValidator 从「单模板常量」改「templateId→资源 Map」,守同源铁律零分叉。四点 + pom:
PromptResourceLoader:资源路径常量 →Map<templateId, (promptVersion,promptBody,schemaText)>,构造时逐模板装载缓存;render/getTemplateSchemaText/getPromptVersion全加templateId参数;某模板资源缺失只禁用该模板不污染其他。新模板 = Map 加一行。GameConfigSchemaValidator:构造入参String→Map<templateId,schemaText>,逐个编译缓存Map<templateId,JsonSchema>;validate(configNode)→validate(templateId, configNode)。校验逻辑本身零新码(仍schema.validate(node)),守「不手写字段校验、不双源」精神。AigcExecutorProperties.supportedTemplates白名单常量加项(List.of("clicker","merge",...))+AigcExecutorConfigurationBean 装配传 Map +AigcGenerateExecutor调用点全部按task.getTemplateId()取参。AigcTaskServiceImpl:getTemplateList()加一条(templateId/name/description/examplePrompt);validateTemplateExists()接同源白名单(与supportedTemplates同一来源,避免「提交时通过、执行时 no_template_match」割裂;用独立配置/常量不强依赖 executor@ConditionalOnProperty装配)。- pom maven-resources-plugin —— 已一次性解决,勿再手改:
pom.xml的copy-wanxiang-contractsincludes 已改通配prompts/04-config/*.md+templates/*.schema.json(实读 :138-139),新模板两资源自动进 classpath。曾踩坑:原 includes 仅复制 clicker 两单文件 → 新模板资源静默漏复制 →readClasspathResource返 null → 该模板自禁用。现已通配,新增模板无需再动 pom。
测试随生产签名同步重写、不得删测(同源铁律的回归守卫):单值→Map 改造后,
GameConfigSchemaValidatorTest/PromptResourceLoaderTest/AigcGenerateExecutorTest旧签名调用点全部编译失败——必须随之重写、validate/render/getTemplateSchemaText全加templateId、保留原断言语义(不放宽、不删用例规避编译错),mvn -pl game-module-aigc/game-module-aigc-server test全绿。
步骤五 · 编排器参数化(run_batch / player / judge)
run_batch.py --template已通用:--template(default=clicker,保既有调用零改)+--prompt-designer(default 按 template 推导config.{t}-designer),TEMPLATE_ID/schema 路径自动联动。- player 按
(templateId, config)分发,新增_play_<t>_once策略:player_cdp.py的play/_play_once改按(templateId, config)接参,内部分发到各模板策略(避免每加模板改形参)。新玩法策略用 config 字段 + iframe 几何 + 布局公式推导确定性帧序列(取证纪律:真实输入事件、禁 evaluate 篡改/读游戏内部状态,仅读布局几何/文案/自注入缓冲)。merge 例 =_dispatch_drag(CDPInput.dispatchMouseEventpress-move×N-release)按「点满料→逐对合成」推进;降级预案:拖拽通关率 <60% → 切「点选两格合成」(runtime+player 输入层同步小改,玩法/schema/prompt 不动)。 - judge 子集若引入新 JSON 形态须先补分支 + 红样本单测:
judge.py的validate_config_against_schema覆盖 JSON Schema 子集,新形态须先补——merge 引入array即在 integer 分支后补elif expect_type=="array"(minItems/maxItems + 逐元素套 items 子 schema),补后口径 == 后端 networknt SchemaValidator(同源),越界单测含该维度红样本(如 array 空数组/非字符串项/超上限三条)。
🔴 实战逮修缺陷 ②(模板专属字段一律
.get/分流取参):design["config"]["target"]是 clicker 专属直取(merge schema 无target,直取 KeyError 整批熔断)。两处实证:①run_batch.py:772附近design_target=design["config"]["target"](spec 点名修,按 templateId 分流取参)②run_batch.py:735附近_verify_package的expected_target=design["config"]["target"](spec 枚举漏列、merge-cal-10 首跑实测熔断逮获,修法改.get("target"),commit 55bcdf6)。配方铁律:模板专属字段一律.get取或按 templateId 分流,绝不裸下标直取——逐处 grepdesign["config"]["排查。
步骤六 · 承重接口纪律(runtime ↔ player 共享公式逐字符对齐)
runtime 与 player 若共享一套公式(如 merge 的棋盘布局:cols=ceil(sqrt(boardSize))、rows=ceil(boardSize/cols)、格中心 cellCenterInternalX/Y 几何式),该公式即承重接口:runtime(canvas 内部像素算)与 player(按比例映射 cssX=rect.x+(cellCenterInternalX/W)*rect.w,规避直读 dpr)必须字面同一套,全部参数钉死——含 topPad 这类散文易漏项。收口时主 agent 逐字符比对两侧公式,任一侧改公式即破取证。
步骤七 · 取证环境三铁律 + 五级验收门
取证环境三铁律(批跑前置,缺一即静默 demo 兜底、五条 AND 全假绿):
--frontend http://localhost:4173:宿主 manifest 校验用crypto.subtle,仅安全上下文(localhost)可用;走 IP 访问永走 demo 兜底。npm run build -- --mode staging构建 game-studio:缺 staging env → mock 中间件接管 → 宿主静默 demo 兜底。- 🔴 实战逮修缺陷 ①(取证导航前注 localStorage 登录态):鉴权波
/create/preview路由meta.requiresAuth=true,前端守卫仅认 localStoragewanxiang_token存在性——取证导航前须先注入登录态,否则被守卫重定向/login、状态条永不出现(M-c 级2④ 实测逮获,commit 831c9cb)。修法 = 导航前Page.addScriptToEvaluateOnNewDocument注localStorage.wanxiang_token="test1";player_cdp.py已内置UI_LOGIN_TOKEN(:103-104,:747-752 先于页面脚本注入),新模板取证直接复用。 - 批跑前关执行器互斥窗:
AIGC_EXECUTOR_ENABLED=false重启(避免执行器与编排器对同一 staging 任务源双跑烧钱),批末还原。
五级验收门顺序表(精简自 execution 版 §9,逐级全过才算 done):
| 级 | 动作 | 通过判据 |
|---|---|---|
| 1 入册 | schema 落 contracts/templates/ + registry 增条目 + 后端 Map 接入 + judge 补分支单测 + 三测试同步重写 + 新模板两资源 classpath 非 null + aigc-server 构建绿 |
judge 补丁+三测试重写全绿 + 资源 classpath 非 null + 构建绿 + registry/schema/后端三处同源(注入文本==校验文本,grep 比对) |
| 2 真玩 | runtime 分发改本机→镜像 mini-desktop(md5 对账)→ build --mode staging 绿 + 体积/契约门 + 落一个新模板包 + player 策略五条 AND 全绿 + clicker 回归同窗五绿 + 浏览器实玩截图 |
新模板五 AND + clicker 回归五绿 + 体积/契约门全过 + 截图留档 |
| 3 QA 闭环 | 对抗 Golden 扩三守卫 + Golden 回归跑(kill 守卫被判 kill、accept 不误杀)+ 批内查重对新模板生效 | 守卫样本全中 + 查重生效 |
| 4 校准批 | 10 条校准批全自动流完零 infra 中断 | 全流完零 infra;accept 不设硬门、不计 M2 口径(M2 ≥80% 已由 clicker 收口、不受本波回退影响),accept 为校准观测值 |
| 5 入 feed | 金丝雀 ≤10 条直发入 feed + 浏览器实玩通关截图 | feed 可见新模板卡片(走 meta.title 不感知模板差异)+ 实玩通关截图 |
校准批口径(执行版拍板 3):10 条校准批不设硬门(暴露系统性问题则 designer 升 minor 加约束、对抗/fix 误判则升 patch,过四道闸再开第二轮);收敛后 20 条正式批 accept ≥80% 量级验收。新模板冷启动无老模板积累,首批 accept 可能落 50-70%(预期管理,非承诺)。 边界失败路径:CDP 超时/通关率不达归 infra 信号(不混入 accept 分母);未知 templateId 灌包走
game_error防御;config 越界由后端 SchemaValidator 拦截(两轮重出)+ runtime clampInt 兜底纵深。
回滚
- runtime 分发回退:改动集中在
runtime/index.ts(switch + init + 防御分支),还原单文件重建重部署即回退(无数据/契约迁移,低代价)。 - 白名单摘除即回退:
supportedTemplates去掉该模板 → 生成请求走no_template_match失败桶;getTemplateList 去该条 → Create 页不展示。后端 Loader/Validator Map 保留新模板资源无害(不被认领即不用)。 - feed 零影响:feed 卡片走
meta.title不感知模板差异;已入 feed 的金丝雀走既有下架编排;存量内容池零影响(空串 templateId 兼容 + 回归五绿)。 - prompt 回滚:新 designer 是新增条目,去 registry 条 + 删 md 即回退;对抗/fix 的 patch 改动若引回归,revert 到前一 version(版本化双标签 Golden 守卫可定位回归)。
常见坑(实战收口版)
| 坑 | 后果 | 正确做法 |
|---|---|---|
模板专属字段裸下标直取 config["x"] |
新模板无该字段 → KeyError 整批熔断(merge-cal-10 实测) | 一律 .get 或按 templateId 分流取参;逐处 grep design["config"][" 排查(缺陷②) |
| 取证导航前未注 localStorage 登录态 | requiresAuth 守卫重定向 /login,状态条永不出现、五 AND 全假 | 导航前 addScriptToEvaluateOnNewDocument 注 wanxiang_token(player_cdp 已内置,缺陷①) |
走 IP 访问 / 漏 --mode staging |
crypto.subtle 不可用 / mock 接管 → 静默 demo 兜底、AND 全假绿 | --frontend localhost:4173 + build --mode staging(取证三铁律) |
| 开 ×N 个 runtime 工厂 | 生命周期/遥测/game_end 红线代码 ×N 漂移 | 单 startRuntime 内 switch 分发,红线代码单一来源、参数化 score |
| 新玩法函数引模块外符号 | toString() 注入沙箱后 ReferenceError | init 全部定义在 startRuntime 函数体内、纯函数自包含 |
| schema 跨字段约束硬塞 schema | draft 2020-12 无 $data,judge 子集不支持,双源漂移 | prompt 硬约束 + runtime 钳制双兜底,schema 只保单字段边界 |
| 改生产签名不同步重写测试 | 编译失败,或删测规避破坏同源守卫 | 三测试随签名同步重写、保留原断言语义、不删用例 |
| judge 未补新 JSON 形态分支 | 数组/新形态字段静默不校验,与后端口径分叉 | 先补 judge 分支 + 红样本单测,再开批(与后端 SchemaValidator 同源同判) |
| 把 M2 ≥80% 口径套到新模板校准批 | 冷启动新模板首批必红、误判回退 | 校准批不设硬门不计 M2;正式批 ≥80% 量级;M2 由 clicker 收口不受影响 |
| 对抗/fix 改示例时顺手动 P1 口径 | 漂移、违「不得放宽 P1 口径」红线 | 仅追加示例升 patch,P0/P1 口径文字一字不动,过四道闸 |
| 把软判定(越模板机制 P2/非阻塞)做成单样本硬 Golden 门 | 同输入温 0.2 仍 50/50 抖(M-c 批② idle 2/4 实锤),Golden 随机红/绿、误导口径 | 软判定降 Golden 观察项(expectation:observe+_observe() 不纳入 verdict);硬门只留稳定的题文不符 kill + accept 不误杀 |