fix(amodel-gen): reading 'w' 根因 footgun(host-config wiring)+ m3 timeout 300s

钻 reading 'w' 根因(minified 栈实锤):bootGameHost 读 i.viewport.w,而 buildTemplateHostConfig 返回的 viewport=undefined → M3 改 host-config 时破坏返回契约(漏 viewport 键/删 render.js export W/H)。非 minification、非产不出(两局当前 src 生产 min build 后 smoke PASS)。

更广模式:M3 游戏逻辑写得了(check+build 过),但反复搞坏插件 wiring——3 契约点:① host-config return shape(viewport)② registerOrder ③ game.js 取插件漏 .plugins 一层(createGame(opts.runtime) 后从 runtime 解构 → sceneFsm=undefined → reading 'define')。

本次改进:
- footgun ×2(prompt.mjs 红线 + littlejs skill ):buildTemplateHostConfig 必返 5 键+viewport{w,h};取插件走两层 opts.runtime.plugins。
- m3.mjs timeout 180→300s:M3 大上下文 turn 触发 thinking 单 turn 实测 ~215s(裸简单调用仅 1-3s);180s 误超时+重试更拖。实测效果:wfix3 从 read-thrash(63读0build)转为真写码(27write/check+build PASS)、viewport bug 未再现。

注:踩了 prompt.mjs 模板字面量反引号坑 2 次(node --check 拦下,未浪费 run)——红线:prompt.mjs 内禁反引号。

未达绿:amodel e2e 仍 0/1——wiring 错类是 whack-a-mole(footgun 一个、M3 露下一个),且 per-attempt 步数预算下难一次收口。下一步战略(待创始人定):结构性把 host-config + 工厂 glue 设为固定 plumbing(agent 只写游戏逻辑),根除 wiring 错类。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
lili 2026-06-22 07:54:13 -07:00
parent 054ebb0818
commit baedcd8153
3 changed files with 7 additions and 1 deletions

View File

@ -133,6 +133,8 @@ export default function createGame(opts) {
- ❌ 工厂里用 `opts.ctx` / `opts.boot` 取受控面 → ✅ 受控面在**实例 `init(boot)``boot.ctx`**(`boot.ctx.time` / `boot.ctx.random` / `boot.ctx.getInput()` / `boot.ctx.getEngine()`);工厂入参 `opts` **只有** `runtime:{plugins,bundle}`,**没有 ctx**。
- ❌ 修 bug 时图省事写 `Math.random()` / `Date.now()` / `setTimeout()` → ✅ `boot.ctx.random.next()` / `boot.ctx.random.range(a,b)``boot.ctx.time.nowMs()``timer-scheduler.after(ms,cb)`(红线 check 必拦;**越改越要守,thrash 时尤其别引入**)。
- ❌ `sessionScore.add(n)` 等臆测名 → ✅ 先 `read_file``session-score/api.d.ts`(实为 `addScore(d)`);**任何方法名拿不准都先读对应 api.d.ts**。
- ❌ 改写 `host-config.js``buildTemplateHostConfig` 的 return 丢了 `viewport` 键 / 删了 render.js 的 `export const W/H`(致 `templateViewport` 失值) → ✅ **return 必须是全 5 键 `{factory, plugins, registerOrder, viewport, buildFactoryOpts}` 且 `viewport={w,h}`**(host 的 `bootGameHost` 启动读 `viewport.w`)。漏 viewport → **boot 崩 `Cannot read properties of undefined (reading 'w')`、一局起不来**(HJ-AGI-003 e2e 实测高频:重写 host-config / 改 render.js 导出时最易踩;改完务必核 return 5 键 + viewport 仍接 W/H)。
- ❌ 工厂里把 `opts.runtime` 当插件集直接解构 / 传给内层:`export default (opts)=>createGame(opts.runtime)``createGame({sceneFsm,...})` —— 插件在 **`opts.runtime.plugins`** 下、不在 `opts.runtime` 下,这样 `sceneFsm` 取到 undefined → **boot 崩 `Cannot read properties of undefined (reading 'define')`**(或其它插件方法名)。✅ **取插件一律 `const { plugins, bundle } = opts.runtime; const { sceneFsm, sessionScore, hudUi, timerScheduler } = plugins;`**(先 `.runtime``.plugins` 两层;`bundle``runtime` 下、与 plugins 平级)。HJ-AGI-003 e2e 实测高频:M3 漏掉 `.plugins` 这一层。
---

View File

@ -37,7 +37,9 @@ const KEY = getKey();
* @returns {Promise<{message:object, usage:object, finishReason:string}>}
*/
export async function chat(messages, tools, opt = {}) {
const { maxTokens = 16000, temperature = 0.3, timeoutMs = 180000 } = opt;
// timeout 300s:M3 在大上下文/代码生成 turn 会触发服务端 thinking、单 turn 实测达 ~215s(裸简单调用仅 1-3s)
// 180s 会误超时→重试(反而拖长:180s 等 + 再来一轮)。300s 让 thinking turn 一次完成、不浪费重试(HJ-AGI-003 实测)。
const { maxTokens = 16000, temperature = 0.3, timeoutMs = 300000 } = opt;
const body = { model: MODEL, messages, tools, tool_choice: 'auto', max_tokens: maxTokens, temperature };
let lastErr;
for (let attempt = 0; attempt < 3; attempt++) {

View File

@ -81,11 +81,13 @@ A 读手册(1-2) → B 按 brief 定玩法(核心循环 / 胜负 / 计分 / 数
红线(check 会拦,违反则 done 被拒)
- game.js 默认导出工厂**零引擎 import**;host-config.js **保留导出名 buildTemplateHostConfig**(只改插件集/wiring,别改函数名)
- **buildTemplateHostConfig 的返回对象必须含全部 5 factory / plugins / registerOrder / viewport / buildFactoryOpts, viewport 必须是 {w,h}(数字)**host bootGameHost 启动时读 viewport.w,漏了/改名/置空 viewport(常见: render.js 时删了 export const W/H或重写 return 时丢掉 viewport ) **boot Cannot read properties of undefined (reading 'w')一局起不来**(M3 实测高频踩坑) host-config 后务必核对 return 仍是这 5 viewport 仍接 render.js W/H
- 游戏源(game/core/render)**零裸** Math.random / Date.now / setTimeout / requestAnimationFrame / new AudioContext / addEventListener 时间随机经 boot.ctx,定时经 timer-scheduler,输入经 ctx.getInput
- game.js update(dt) **必须调 opts.runtime.bundle.tick(dt)**(否则插件 onFrame 不推进timer 永不到期一局不结束)
- **受控面 ctx 在实例 init(boot) 入参的 boot.ctx**(nowMs/random/getInput/getContext2d 全经它);**工厂入参 opts 只有 runtime:{plugins,bundle}别在 opts 上找 ctx**(常见错:写成 opts.ctx)五法 = init(boot)/update(dt)/render(g)/destroy()(+可选 _forensicsView)
- **插件方法名一律以 api.d.ts 为准别按常见库套路臆测**(M3 实测幻觉:scene-fsm 写成 defineScenes define)拿不准先 read 该插件 api.d.ts;skill M3 实测易犯的幻觉 API一节逐条列了
- 插件由 host 拥有 opts.runtime.plugins 注入;游戏只**** new register;插件键名与 host-config plugins 对象一致
- **取插件必须走两层 opts.runtime.plugins**: const {plugins, bundle} = opts.runtime; const {sceneFsm, sessionScore, hudUi, timerScheduler} = plugins;**别把 opts.runtime 当插件集直接解构**(常见错:createGame(opts.runtime) 后从 runtime 解构 sceneFsm .plugins 一层 sceneFsm=undefined boot reading 'define')bundle runtime plugins 平级
完成判据 + 停机纪律(重要)
- 判据 = check PASS + build PASS( spike **不跑** README 里的 node --test)**一旦 check build PASS,立即调 done**(summary 一句话)