feat(wg1-gen): gate-H 推广 = design agent 自产 gate-spec + reframe 决策锁定

P1(gate-H 推广多游戏):确定性门从手写 brief 升级为 design agent 自产,适用任意游戏。
- roles.py:DESIGN_SYSTEM 末尾产机器可读 gatespec 块(exportState/driver/controlCheck/
  assertAfterPlay/expectLatch);ballPath 明确为水平 x。
- studio.py:_extract_gatespec 抽取(json_repair 兜)+ 合入 play_spec + 安全归一
  (paddle-intercept 的 ballPath .y→.x 兜底);结果记 gatespec。
- 实证:flash design agent 对 breakout 产出结构合法 gate-spec,studio 抽取合入成功
  (唯一内容误差 ball.y 已由 prompt + 归一双修)。

reframe 锁定(WG1 review §8,创始人亲玩校准后):确定性 gate-H = 可玩性真值/地板;
player = 主观层(消费 gate-H、判不出手感、须人锚校准);创始人/人锚不可替代;
生产三层 = 确定性门 + 便宜 player + 创始人抽检(无 Claude)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
lili 2026-06-14 05:16:04 -07:00
parent c5df28f2e2
commit 405394d451
3 changed files with 62 additions and 1 deletions

View File

@ -169,3 +169,9 @@ graph TD
**架构守护栏(working 解读,待创始人纠正):**
- "改进 agent scope" = 改进**我方 agent 层**(任务协议 / 状态模型 / 工具接口 / 循环模板 / 门禁 / 自修复逻辑 / judge 校准——GC9 明列的"要固化"项),**AgentScope 框架本身保持可替换**(不 fork 其内核,保留换轨 LangGraph 选项,遵 XC3/GC9 框架可替换铁律)。
- 便宜模型仍是**生产 in-loop 角色**(生成 / 自修复 / judge);**Opus = builder / teacher / calibrator,建好即退,不进生产环**(否则"生产无 Claude"前提破)。
**质量评估架构 reframe(2026-06-14 创始人亲玩校准后拍定):**
- **确定性 gate-H = 可玩性真值 / 地板(Claude-free)**:九门(七门假绿守卫 + H 机制/latch + I 控制手感)+ 适配性真玩 driver(读 state 接球,解盲打假阴性)。手感尽量**拆成确定性门**(latch 终态驻留 / 控制跟手 / 碰撞穿透[门 J 规划]);拆得掉的全自动判。
- **player panel = 主观层,消费 gate-H,有结构性天花板**:便宜 player(M3 静态截图 + flash 数据)**判不出物理/碰撞/控制的交互手感**——实证创始人把碰撞有问题的件判 fix、两 player 均高估(fun=4),text 还漏控制 bug。故 player 只判**拆不掉的主观**好玩/美术/节奏,且须人锚校准(`calibrate.py` vs 创始人 `labels.json`)。
- **创始人 / 人锚不可替代**(现阶段):是 gate-H 假阴性(盲打)+ player 漂移的最终纠偏。**Opus 退场后,生产 = 确定性门 + 便宜 player + 创始人抽检 三层**,无 Claude。
- **gate-H 推广 = design agent 自产 gate-spec**(exportState / driver / controlCheck / assertAfterPlay / expectLatch)→ 确定性门适用**任意游戏**,不再手写 brief(已建:`roles.py` 产 spec、`studio.py` 抽取合入;实证 design agent 能产合法 spec)。

View File

@ -16,7 +16,20 @@ DESIGN_SYSTEM = r"""你是轻量 H5 小游戏的【设计 agent】。输入是
6. 画面要点背景铺满主要元素形状与颜色HUD分数等
7. 可观测进展点明"玩家在推进"的可量化信号如剩余目标数下降 / 分数上升 / 关卡推进并说明胜负如何切状态这是判"真有进展、非空心"的依据
约束控制在 ~200 字内聚焦"代码 agent 实现时需要的决策"不堆砌辞藻不写引擎/契约细节那是代码 agent 的事"""
约束设计正文控制在 ~200 字内聚焦"代码 agent 实现时需要的决策"不堆砌辞藻不写引擎/契约细节那是代码 agent 的事
末尾必附 gate-spec机器可读·harness 据此确定性验"能玩 + 手感"·这是 gate-H 推广到任意游戏的关键
设计正文之后另起一个 ```gatespec 代码块块内为 JSON声明本游戏怎样被确定性验证
```gatespec
{
"exportState": ["phase","score","remaining","progress","<关键实体位置:如 ball:{x,y,vx,vy}、paddle:{x,y,w};纯点击类可省位置>"],
"driver": {"type":"paddle-intercept","ballPath":"ball.x","paddleY":800},
"controlCheck": {"paddlePath":"paddle.x","tapXs":[50,340]},
"assertAfterPlay": [{"path":"remaining","op":"decreased","why":"击碎砖块→剩余下降"}],
"expectLatch": true
}
```
规则 `expectLatch` true游戏必须能真玩到 gameover 且驻留 "连续控制体(挡板/角色随手指平滑移动)"才给 `controlCheck`纯点击/无连续控制给 null 技巧类挡板接球/接物`driver.type="paddle-intercept"``ballPath`=**球的水平 x 坐标字段**挡板水平移动去对齐它几乎总是 `ball.x`**绝不要填 ball.y**`paddleY`=挡板所在 y纯点击类用 `{"type":"none"}` `assertAfterPlay` 至少一条"真有进展"断言op increased/decreased/changed/>/>=/</<=/==/inpath 用你让代码导出的字段名须与 exportState 一致"""
# 玩家 agent看截图 + 运行数据,像真玩家一样判完整度/好玩/问题。M3 视觉位用截图,文本位仅用数据。

View File

@ -13,6 +13,7 @@ import argparse
import asyncio
import base64
import json
import re
import sys
import time
from collections import defaultdict
@ -68,6 +69,39 @@ def _b64_data_url(png_path):
return "data:image/png;base64," + base64.b64encode(p.read_bytes()).decode()
def _extract_gatespec(design_text):
"""gate-H 推广:从设计稿抽 ```gatespec JSON 块(设计 agent 自产机制门 spec → 确定性门适用任意游戏)。
json_repair 兜脏 JSON无块/解析失败返回 None"""
m = re.search(r"```gatespec\s*(.+?)```", design_text or "", re.S)
if not m:
return None
raw = m.group(1).strip()
obj = None
if repair_json is not None:
try:
obj = repair_json(raw, return_objects=True)
except Exception:
obj = None
if not isinstance(obj, dict):
try:
obj = json.loads(raw)
except Exception:
obj = None
if not isinstance(obj, dict):
return None
# 轻校验assertAfterPlay 须 listexpectLatch 缺省补 True官方 latch 契约恒需)。
if "assertAfterPlay" in obj and not isinstance(obj["assertAfterPlay"], list):
obj["assertAfterPlay"] = []
obj.setdefault("expectLatch", True)
# 安全归一paddle-intercept 的 ballPath 须是水平 x便宜模型偶把 ball.y 当横向)→ .y 兜底改 .x。
drv = obj.get("driver")
if isinstance(drv, dict) and drv.get("type") == "paddle-intercept":
bp = drv.get("ballPath")
if isinstance(bp, str) and bp.endswith(".y"):
drv["ballPath"] = bp[:-2] + ".x"
return obj
def _parse_judge(raw):
"""容错解析玩家 agent 的 JSON 评判(json_repair 兜脏 JSON)。"""
obj = None
@ -180,6 +214,13 @@ async def run_studio(game_id, brief, play_spec, stage="stage1", max_repairs=5,
design_text, (di, do) = await _agent_reply("design", roles.DESIGN_SYSTEM, design_model, brief)
tin += di; tout += do; per_model[design_name][0] += di; per_model[design_name][1] += do
enriched = brief + "\n\n## 设计稿(设计 agent 产出)\n" + design_text
# gate-H 推广:设计 agent 自产 gate-spec → 合入 play_spec覆盖 brief 默认),使确定性门适用任意游戏(不再手写 brief
gatespec = _extract_gatespec(design_text)
play_spec = dict(play_spec or {}) # 拷贝,不改入参
if gatespec:
for k in ("exportState", "driver", "controlCheck", "assertAfterPlay", "expectLatch"):
if k in gatespec and gatespec[k] is not None:
play_spec[k] = gatespec[k]
feedback = None
passed = False
@ -257,6 +298,7 @@ async def run_studio(game_id, brief, play_spec, stage="stage1", max_repairs=5,
"game_id": game_id, "stage": stage, "pass": passed,
"repairs": len(attempts) - 1, "player_rounds_used": player_round_used,
"design_text": design_text,
"gatespec": gatespec, # gate-H 推广:设计 agent 自产的机制门 spec合入 play_spec 的来源)
"attempts": attempts,
"seven_gate_verdict": final_verdict,
"player": player_result["panel"] if player_result else None,