games-development-ai/docs/agent-specs/_archive/2026-06-12-T1b-β引擎真接线与Runner-v2-review.md
zizi 7f24a344d0 docs(agent-specs): B2 归档——64 个闭线工作记录移入 _archive/,热目录顶层 90→26
承接目录治理:上轮只压缩内容未减文件数,闭线工作记录仍平铺致目录看着仍一堆(创始人指出)。本次执行 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>
2026-06-16 13:26:19 +00:00

35 KiB
Raw Blame History

T1b-β · 引擎真接线 + Runner v2 生产化 · 评审版(HJ-T1B-B-001)

状态:开工令已下(创始人 2026-06-13「β execution」)——扩裁(裁决②)并入 execution 版落地;Q3 按默认口径(outcome 随 Runner v2 落注记)推进。 配对 execution 版 = 2026-06-13-T1b-β引擎真接线与Runner-v2-execution.md。 裁决②(2026-06-13 扩裁,Opus 同类误判复查):Q4 剃刀复查逮出裁决①外同类误判 4 类——见下 §2.5;纠正 §2 非目标「collision/gamefeel 引擎缺件审计已确认」一刀切误判。证据=spike 实测导入 file:line + 引擎源(context7 /killedbyapixel/littlejs)互证。 R1 对抗评审(Codex Xhigh)11 条全采纳整改(3P0/6P1/2P2),2026-06-12:防 demo 兜底假阳性 / 真接线门三件套防名义接线 / 后端发布主链补依赖 / 并行口径改「契约可并行·验收串行」/ srcdoc→URL 四项兼容矩阵 / storage 三套形状收敛 等,逐条落 §3-§9。 R2 主裁(主会话)过,2026-06-12:P0/P1 关键证据 file:line 抽五处全与实码相符(GamePlayer demo 兜底+硬编码 sandbox / sdk-interface 无 storage / inject CSP connect-src none / bridge postMessage '*')。 上游:T1b-α 收口报告(§4 后续归属)| Runner 与双层模板 review v2.1(§5 Runner v2/outcome 契约、§9 波次切分)| 引擎终裁包| 自研偏误全链审计报告(盘点表行 1/3、R6)| build-vs-buy.md R1-R7。 范围权威源:docs/mvp/MVP作战清单.md T1b-β 行(六项一一对应,不增删)。


1. 背景

T1b-α 主门已过(创始人亲玩「暖阳小卖部」判 passed,轮 1/3 即过;收口报告 §1)。但同期 NIH 自研偏误审计逮出第三案现行(审计报告盘点表行 1,判 🔴):终裁的 LittleJS 至今 0 字节进入运行路径。

  • 事实边界(可复核):game-runtime/host-dev/host.js:15「α 阶段不接 littlejsengine(裁定留痕)」、参考件 games/wanglanmei-ref/entry.js:9 同款裁定、三件 impl(particles-juice/impl.js:24、palette-post/impl.js:28)自供「不 import littlejsengine」、受控面铁律「禁直透 littlejsengine 裸对象」(src/core/plugin.js:21)。全仓 0 处生产代码 import littlejsengine(命中仅在 docs/agent-specs/*-spike/ 的 spike lane)——此为已验证事实。
  • 推断部分(审计报告原样标注):三件插件在裸 Canvas2D 上对引擎内建粒子/物理/后处理 shader「平行重造」(审计报告 :58 标「平行重造为推断」)、「QA 像素哈希确定性 → 受控面只给 Canvas2D → 引擎 WebGL 粒子被墙 → 自研粒子」的因果链(审计报告 :37 R4-(c) 标「因果链为推断」)。
  • 字节记账(来源待校):审计报告盘点行 1 引「25.9KB 引擎 + 13.3KB 插件双份记账(SIZES.md 实测)」——但 game-runtime/SIZES.md 现表仅列插件叠加增量(合计 gz ≈13.3KB),无「25.9KB 引擎」独立行(引擎本身从未进 bundle 故未量取)。25.9KB 系 spike 实测引用值(docs/agent-specs/2026-06-11-tier1-engine-spike/ engine-only 列),非 SIZES.md 行——标注为审计推断/spike 实测,复核命令见 §5 范围①完成判据;真值留执行版按「引擎+包装层」实测重锚。

这正是尽调里被否决的「自研+微库,形态终点=再造 LittleJS」路线换壳复活。

创始人裁决①(2026-06-12 拍):粒子/物理/后处理三件改引擎能力包装层,β 设引擎真接线门。本波即落地该裁决,并把 α 遗留的 Runner v2 产品化、1.x 退役、参考件入 feed、P7/P8 定夺、审计整改余项一并收口——解封链路③⑤真 UI 走查(W-CLEAN 后 feed 池空,③⑤走查全等参考件入池)。

2. 目标 / 非目标

目标(= 作战清单 T1b-β 行六项):

  1. 裁决①落地:三件改引擎能力包装层 + 真接线门 + 受控面透传通道 + SIZES 重锚 + e2e 像素口径适配 WebGL 读回。
  2. Runner v2 产品化(URL 化交付 + 强缓存,接 GamePackage 真实产出)。
  3. 1.x 退役三件套改写(srcdoc→URL、GamePlayer/inject/bridge 重写、CDP 走查门)。
  4. 参考件「暖阳小卖部」发布入 feed(解封链路③⑤真走查)。
  5. P7/P8 决策 + SDK StoragePlugin 契约补丁 + probe 注入时钟拆分。
  6. 审计整改余项:R6 尽调补录四件 + R3 存量红线血统回填五条。

非目标:W-G1 模型竞标(受 DS key 前置,可并行但不入本波完成线);插件库扩展 v2 四候选(缺口由 20 游戏矩阵定义,归扩展波);M4 变现真实化;collision/gamefeel 维持自研(引擎缺件,审计已确认,不在裁决①范围) 【裁决②纠正 2026-06-13:此「审计已确认缺件」是一刀切误判——collision/gamefeel/physics-lite 均为混合体,含引擎已有内建的重叠函数,须逐函数三分(见 §2.5),不再整体豁免;改入范围①重叠清单处置】;TPL 产品命名改名(属产品改名非清毒,W-G0 给创始人选项)。

2.5 裁决②:同类误判扩裁(2026-06-13,Opus 复查全采纳)

Q4 裁定后,以「引擎内建已有→走包装,引擎确无→才许补层,为 harness 便利平行重造引擎内建=违线」剃刀复查全部自研件。关键前提强化:LittleJS 0 字节进运行路径(game-runtime/ 无 package.json/node_modules,全仓零生产代码 import littlejsengine),引擎源码本机不在盘——能力断言取两路互证:① spike 实测导入(2026-06-11-tier1-engine-spike/lane-littlejs/src/{game.ts:25-38,shop.ts:22-42},littlejsengine@1.18.19 真跑过=硬证)② 引擎源(context7 /killedbyapixel/littlejs src_engineMath/engineObject/engineTileLayer.js)。逮出 4 类同类误判(execution 版逐件落地):

# 件 误判类型 引擎内建对应(证据) 现实现(file:line) 处置(execution 落地)
②-1 🔴 audio-music 平行重造(裁决①漏网) Sound/zzfx/zzfxM(game.ts:70-73,188 实跑) audio-music/impl.js:29-30,233-276 re-vendor ZzFX/ZzFXM 合成核+手搓 createBuffer 播放 纳入裁决①范围:合成/音序改调引擎 Sound/Music;保留路由/混音编排(引擎外组合层)
②-2 🔴 core 受控面 random/time 为取证确定性砌墙(Q4 正面打击) 全局 RandomGenerator(种子化 xorshift 可 reseed)/time/timeDelta(src_engineMath.js) core/plugin.js 桩自造 SeededRandom(mulberry32,:155)/HostDevTime(:200),docstring 自承「与 LittleJS RNG 无耦合/换引擎不影响确定性」 集成段改透传引擎 RandomGenerator/time;per-plugin 派生子流(FNV-1a)编排可留(引擎外);mock/取证按 Q4 在门侧用固定 seed 解决,不以「换引擎不影响确定性」为由墙引擎
②-3 🟠 particles-juice 的 juice 套件 重造(裁决①归类遗漏) timeScale(慢动作/hitstop)、engineAddPlugin+cameraPos 官方屏震范式(reference.md/llms) particles-juice/impl.js:582-593 自造 hitStop/getTimeScale、:602-615 自造 shakeScreen hitStop→引擎 timeScale;屏震→引擎 engineAddPlugin+cameraPos;并入裁决①重叠清单
②-4 🟡 collision/gamefeel/physics-lite 「维持自研」一刀切误判(混合体) collision: isOverlapping/isIntersecting/lineTest;gamefeel: lerp/smoothStep/percent/oscillate;physics-lite: EngineObject.updatePhysics/objectMaxSpeed collision aabbVsAabb(:326)/raycastAabb(:489);gamefeel easing linear/smoothstep;physics-lite 抛体/clampSpeed/friction 逐函数三分:引擎有内建的→调引擎;引擎确无的(SpatialHash/SAT/MTV/圆射线/弹簧+解耦运动学/InputBuffer/coyote/combo/elastic-back 缓动)→ 补层合规保留

R3 复审整改(2026-06-13):上表「包装」类裁定非冻结——须经「能力同一性」测试(引擎候选的签名/返回语义/坐标系须满足插件现有契约,否则即缺件)。执行版 R3 复审已逮出多条初判「包装」实为缺件:collision isOverlapping→boolean 满足不了 aabbVsAabb→MTV/法线、audio 引擎 Sound(世界音频)不兼容受控面 PCM 播放层——这些降为「缺件补层」或「合成包装+播放补层」混合。最终逐函数裁定见 执行版 §1.5 + §7(Phase 0 抽引擎真实签名后填定)。 render.js 口径(参考件游戏侧绘制):属 agent 生成域(合规,非插件重造引擎),但 β 接引擎后绘制底座应切引擎 drawTile/drawText(CJK 已 spike 验)/drawRect/Color,作为「经引擎绘制画游戏」拔高样板——与插件包装层是两个层次,都不留裸 Canvas2D。 存疑项(execution 须以引擎 .d.ts 正面复核):postProcess WebGL shader 精确导出名、medal 系统——本次未在引擎源正面核到;palette-post 补层判据待此复核后定。

3. β 内部依赖序

flowchart TD
  CT["契约冻结(先行)<br/>PluginContext 引擎能力透传 API<br/>+ GamePackage Runner URL 字段<br/>+ SDK storage 根契约"] --> A
  CT --> E
  CT --> J
  A["①裁决① 包装层改造<br/>(受控面开透传通道 → 三件接 littlejsengine)"] --> B["真接线门三件套<br/>metafile 留存+probe 调用ID+负向扫 Canvas2D fallback"]
  A --> C["SIZES 重锚<br/>(引擎+包装层,消双份记账)"]
  A --> D["e2e 像素口径<br/>适配 WebGL 读回"]
  E["②Runner v2<br/>(URL+强缓存,接 GamePackage)"] --> F["③1.x 退役三件套改写<br/>(srcdoc→URL;GamePlayer/inject/bridge)"]
  F --> G["CDP 真 UI 走查门<br/>(同一参考包联验)"]
  subgraph BE["④参考件入 feed 硬依赖=后端发布主链"]
    direction LR
    BE1["submitPublish<br/>(ProjectServiceImpl)"] --> BE2["admin review<br/>(reviewProject 审核通过即发布)"]
    BE2 --> BE3["PublishOrchestrationService<br/>.publish"]
    BE3 --> BE4["runtimePackageApi.publish<br/>(翻包 0→1)"]
    BE4 --> BE5["feedApi.upsertRank<br/>(PUBLISH_BASELINE)"]
    BE5 --> BE6["feed stream<br/>(二次过滤 status=PUBLISHED 才出流)"]
  end
  E --> BE
  BE --> G
  G --> I["链路③⑤解封真走查"]
  J["⑤P7/P8 决策 + StoragePlugin 契约补丁 + probe 时钟拆分"]
  K["⑥审计整改余项<br/>(R6 尽调补录×4 / R3 血统回填×5)"]

依赖关键(接口契约可并行,实现验收串行——P1-3 改写):

  • 先冻结三组契约:①受控面 PluginContext 引擎能力透传 API;②GamePackage 的 Runner URL 字段(game-package.schema.json);③SDK storage 根契约。契约冻结前不放②③④实现下场。
  • 契约冻结后①与②③互不阻塞可并行写实现;③(1.x 退役 srcdoc→URL)依赖②(Runner v2 URL 化先就绪)。
  • 实现验收串行:②③④三件不各自单独过门,最终在**同一参考包(暖阳小卖部)**上联验 CDP 走查门 G——防两个半成品(Runner URL 化、1.x 退役、参考件入 feed)在 CDP 门集中爆炸、互相归责。
  • ④参考件入 feed 的硬依赖=后端发布主链(非前端单点):submitPublish →admin reviewProject(D-PUB=α 审核通过即发布,无常驻 APPROVED)→PublishOrchestrationService.publish(翻包 0→1 / 翻版本态 / 翻项目态 PUBLISHED(4) / 写 feed 基线)→feedApi.upsertRank →feed stream 二次过滤 project.status==PUBLISHED(4) 才出流。证据:ProjectServiceImpl.java(/service/project/,reviewProject 行 ~208-243 调 publishOrchestrationService.publish)/ PublishOrchestrationServiceImpl.java:63-97(五步编排)/ FeedServiceImpl.java:119-159(filterByProjectPublished 强制 PUBLISHED)。⑤⑥相对独立顺手做。

4. 裁决①前后架构对比

flowchart LR
  subgraph 现状["α 现状(审计盘点行1=🔴)"]
    G1[游戏代码] --> P1["三件插件<br/>裸 Canvas2D 重造"]
    P1 -.绕过.-> E1["littlejsengine<br/>(0 字节进运行路径)"]
  end
  subgraph 目标["β 目标(裁决①)"]
    G2[游戏代码] --> CS["受控面<br/>(开包装能力透传通道)"]
    CS --> P2["三件=引擎能力包装层"]
    P2 --> E2["littlejsengine 内建<br/>(粒子/物理/后处理 shader)"]
  end

要点:受控面仍不直透 littlejsengine 裸对象(R5(c) 安全边界保留),而是新开包装能力透传通道——游戏经包装层 API 调用引擎内建能力。collision/gamefeel 维持自研(引擎缺件)。

5. 推荐方案(逐项:做法 + 取舍 + 完成判据)

范围① 裁决①落地(核心)

  • 推荐做法:受控面 PluginContext 新增「引擎能力透传通道」(仍封装、禁裸对象);particles-juice / physics-lite / palette-post 三件 impl 改为调用 littlejsengine 内建(粒子系统/街机物理/后处理 shader);先出「插件×引擎内建能力重叠清单」逐件标「包装 or 有意替代」。
  • 取舍 1(已被 Q4 裁定收窄,2026-06-13):包装层 vs 有意替代(带砍预算)——创始人裁「自研内容是引擎外的层,不是对引擎本体的替代」,「有意替代」路关闭:引擎内建能力一律包装;确定性取证诉求在 harness/门侧解决(见 §9-Q4);重叠清单裁定空间=「包装 / 引擎缺件补层」两类。另注:手搓 Canvas2D 从未对比实测过优于引擎内建(审计断案=为像素哈希确定性砌墙的推断因果,非性能/效果优势;引擎 WebGL 批渲染+shader 上限更高,裸 Canvas2D 还把渠道/平台渲染差异揽成自有债)。
  • 取舍 2:WebGL 读回 vs Canvas2D 哈希的确定性——审计盘点行(c)指出「取证像素哈希确定性 → 受控面只给 Canvas2D → 引擎 WebGL 粒子被墙」的因果链(标注为推断)。接引擎 WebGL 后像素读回路径改变,e2e 哈希断言须适配 WebGL 读回(readPixels),并重验双开确定性是否仍成立。
  • 完成判据:
    • 真接线门三件套(P0-3 防名义接线):单纯 grep littlejsengine 可被一行死 import / 注释 / 字符串骗过——恰是 R6 要消灭的「名义采用」。故门改为三件套全过才算接线:
      1. esbuild metafile 证明引擎模块被保留进产物(--metafile 输出里 inputs 含 littlejsengine 且被三件 impl 的 chunk 真实引用,非 tree-shaken 掉)。
      2. 运行时 probe 记录三件包装层调用引擎能力的调用 ID(particles-juice / physics-lite / palette-post 各产出经透传通道调 littlejsengine 内建的调用证据 ID,证明运行期真走引擎)。
      3. 负向扫描禁止保留等价 Canvas2D 自研 fallback(grep pattern 清单扫三件 impl,确认旧裸 Canvas2D 粒子/物理/后处理实现已删除——防「引擎接上但自研双轨仍在」的双轨残留)。
    • SIZES 按「引擎+包装层」重锚,消除双份记账(R3 血统:重锚口径带来源/失效条件/复审触发)。复核命令:scripts/size.mjs 在集成段重跑,引擎进 bundle 后 engine 列与插件列单口径合并;旧 25.9KB 来源核对 docs/agent-specs/2026-06-11-tier1-engine-spike/ engine-only 实测。
    • e2e 像素门适配 WebGL 读回后,vfx 像素哈希 ×N 仍 PASS、双开确定性过(沿 game-e2e-cdp-harness 四件套口径)。
    • 重叠清单产出,每件有「包装/替代」裁定。

范围② Runner v2 产品化

  • 推荐做法:带版本 URL + immutable + brotli + feed 预热(Runner review §5);接 GamePackage 真实产出(非 demo 兜底)。
  • 取舍:强缓存 immutable vs 版本更新可达性——带版本 URL(内容寻址/版本号)保证 immutable 强缓存命中(享 HTTP+编译双缓存,终裁包冷开优势的兑现路径),但版本切换须靠 URL 变更,不可就地覆盖;GameConfig 数据走热发、游戏代码随版本整包(HJ-CH-001 口径)。
  • 完成判据(防 demo 兜底假阳性,P0-2):现状 GamePlayer.vue:128-168 存在多处 demo fallback——取包失败、manifest 校验失败、无 manifestUrl、versionId 非法均静默回退 demo 兜底(注释明示「可恢复场景不向上 emit error」)。故 Runner v2 加载成功的判据不能只看「画布有东西在跑」(demo 也能跑),须满足:
    • Network 捕获的 manifest checksum 与发布版本一致,且 gameId/versionId 匹配(证明加载的是真包非 demo);
    • 捕获 game_loaded 与 game_end(completed===true)事件(证明真游戏跑完一局);
    • demo 兜底路径触发即判门不过(probe/console 捕获到 [GamePlayer] ...回退 demo 兜底 即 fail)。
    • feed 首屏预热生效;带版本 URL immutable 缓存命中实证。

范围③ 1.x 退役三件套改写

  • 推荐做法:inject.ts 的 srcdoc 源码内联(startRuntime.toString())切换为 Runner v2 URL 加载;GamePlayer/inject/bridge 三件套运行时行为(沙箱注入时序/存档桥/CSP)重写;GamePlayer 2b(无 warn 版)并入。退役=架构级改写,非删码。
  • srcdoc→URL 兼容矩阵(P1-1,四项必须随改写一并收编,否则 URL 化即破链):
    1. sandbox 属性收编:GamePlayer.vue:528-533 硬编码 sandbox="allow-scripts allow-same-origin",而 backend 已下发 sandboxAttr(runtime.yaml(实际路径 contracts/api-schemas/runtime.yaml)SandboxPolicyVO 行 253-261,含 sandboxAttr/allowOrigins 字段)现未被消费——URL 化须改为消费后端下发的 sandboxAttr,消除前端写死与契约下发的双源。
    2. 父子双向 origin 校验:inject.ts:81-91 子 iframe 的 message handler 只校验 channel/direction,不校验 ev.origin;bridge.ts:201-220 宿主→游戏 postMessage 用 targetOrigin='*'(注释自承「仅适用 srcdoc/blob origin=null」)。URL 化后 iframe 有真实 origin,父子两侧都须按 allowOrigins 白名单做精确 origin 校验。
    3. URL Runner 的 CSP/headers:inject.ts:52-53 现 CSP connect-src 'none'(meta 行 53),会阻断 URL 加载的引擎/资源出站请求——URL 化须放开 connect-src/script-src 到 Runner URL 与 OSS/CDN 来源(与 SandboxPolicyVO.allowOrigins 一致),否则真包 fetch 被自身 CSP 拦死。
    4. 跨源 package/asset 的 CORS 与 credentials 策略:OSS/CDN 取包的 CORS(SandboxPolicyVO 注记已要求 AllowedOrigin 含宿主 origin、AllowedMethod=GET/HEAD、ExposeHeader=ETag)与 credentials 策略须落定,否则跨域 fetch manifest 被拦。
  • 取舍:srcdoc 内联 vs URL 加载的沙箱形态变化——srcdoc/blob 注入文档 origin 为 'null';切 URL 加载后 iframe origin 变为真实同源/跨源,上述四项须随之收紧/放开。这是隐藏依赖(Runner review 风险4:grep+build 门不足以兜底)。
  • 完成判据:CDP 真 UI 走查门必做(build 门不足)——/play 与 /preview 路由真 UI 走查通过;上述兼容矩阵四项 + 沙箱注入时序/存档桥回调/CSP 运行时行为实证无回归(且不落 demo 兜底,判据同范围②)。

范围④ 参考件入 feed

  • 推荐做法:「暖阳小卖部」经后端发布主链入 feed(解封链路③⑤——W-CLEAN 后池空,③⑤走查全等内容);IP gate 照旧(构建产物零「王蓝莓」字样,对外用占位原创美术/名称)。
  • 硬依赖=后端发布主链(P0-1,非前端单点点亮):参考件出现在 feed 流,须走完整后端链——submitPublish(ProjectServiceImpl)→admin reviewProject 审核通过(D-PUB=α 审核即发布)→PublishOrchestrationService.publish(翻包 0→1 / 翻版本态 game_version.status=3 / 翻项目态 project.status=PUBLISHED(4) / 写 feed 基线 PUBLISH_BASELINE)→feedApi.upsertRank→feed stream 二次过滤 project.status==PUBLISHED(4) 才出流。任一环未真翻态(如只在 feed_rank 写一条而 project.status 未到 4),feed 出流二次过滤会把它剔除——故验收不能只看 feed 列表有卡片,须验各环真翻态。
  • 取舍:参考件作为 feed 内容 vs 仅作样板——参考件入 feed 后即真实可玩内容(解封③⑤走查),但其 mmx 资产/占位美术须过 IP gate 产物扫描(α 执行版 §4 IP gate 口径)。
  • 完成判据(API/DB/CDP 联合验收,P0-1+P0-2):
    • API:发布链各接口返回成功(submitPublish→review→publish 链路无异常回滚);
    • DB:project.status==PUBLISHED(4) ∧ game_version.status==3 ∧ game_runtime_package.status==1 ∧ feed_rank 有该 gameId 行(status=1)——四态实查一致;
    • CDP:feed 流真出现该卡片 → /play 实玩加载真包(manifest checksum 匹配、捕获 game_loaded+game_end completed===true、不落 demo 兜底);链路③(分享/OG)⑤(真走查)借此内容闭合(与③联动判据见范围③ CDP 门)。

范围⑤ P7/P8 决策 + StoragePlugin 契约补丁 + probe 时钟拆分

  • P7/P8 决策(P2-1 固定清单判定,无命中默认留 v2):P7=sprites-anim(图集/动画状态机/九宫格);P8=pathfind-ai(A*/流场/转向行为)。不靠主观「感觉用没用到」,按固定清单逐项判——逐项检:①参考件代码 grep/import 是否命中该插件;②取证字段是否含该能力产物;③资产格式是否需该插件(注:sprite 静态资产 ≠ P7 动画插件,仅有 sprite 图不构成 P7 升必入);④玩法需求是否要该能力。任一硬命中→升必入;全不命中→默认留 v2。现状参考件 LOOP-LOG.md:28-30 记插件用法无 P7/P8 命中,sprite 资产为静态非动画——据此默认二者留 v2(待执行版按固定清单复核确认)。
    • 完成判据:P7/P8 各出固定清单逐项判定结果(四项命中/未命中表)+ 升必入/留 v2 裁定,带实证依据(参考件代码行/取证清单)。
  • SDK StoragePlugin 契约补丁(P1-5 三套形状收敛):现状 storage 契约形状漂移三套——①根契约 contracts/sdk-interface.d.ts:29-43 现只有 ad/pay 插件,无 storage(事实:SDK 根对象未声明 storage API);②host 副本 game-studio/src/host/contract.ts:118-144 已自行定义 StorageSet/Get/ResultPayload;③inject.ts:106-170 自建一套 storage bridge(makeStorageView/storagePending,P9 本地 adapter)。三套各自演化将持续漂移。β 须先定义根 SDK storage API(contract-first,补进 sdk-interface.d.ts),再同步 contract.ts 副本与 inject.ts 自建 bridge 收敛到根契约形状。
    • 完成判据:contracts/sdk-interface.d.ts 新增 storage 根契约(WanxiangGameSDK 挂 storage 插件);contract.ts/inject.ts 三套形状收敛一致;P9 由本地 adapter 切真 SDK storage 通道;验收=一个会真实 save/load 的游戏包端到端(写存档→重载读回值一致,防三套形状漂移导致读写不通)。
  • probe 注入时钟拆分:α P10 RuntimeProbe 锚点 t_boot→t_plugins_ready→t_game_init→t_first_paint→t_input_bound→t_game_start(α 执行版 §3);β 随 1.x 退役(srcdoc→URL)注入时序改变,时钟锚点须拆分适配新注入路径。
    • 完成判据:probe 锚点哈希链在 URL 加载形态下仍单调可验(verify 命令通过)。

范围⑥ 审计整改余项(顺手做)

  • R6 尽调补录四件(审计盘点表对应行):
    1. CDP harness(行3 ⚠️):补 puppeteer-core/playwright 排除理由落档(蓝图选 Playwright,实现层被纪律改手搓;puppeteer-core 仅 connect 既有 :9222 不冲突机器红线);两份实现(browser-evidence.cjs 448 行 / orchestrator/player_cdp.py 1637 行)收敛单一权威 + 登记 Doc B 正式 T-id。
    2. ajv(行4 ⚠️):game-runtime/scripts/validate-manifest.mjs:7-10 文件头自供「不引 ajv=零依赖纪律——违纪」;校验挪集成段用 ajv 做权威门(集成段本就跑 npm,ajv 零成本),本机手写版降级开发期快检或删除。
    3. prompt registry(行8 ✅边缘):contracts/prompts/ + prompt-governance.md 补三行 why-not(LangSmith/PromptLayer/Langfuse)入 registry README。
    4. weapp-adapter(行14 ✅ spike 内):β 内仅补「为何不直接 vendor 官方 weapp-adapter」轻量一行(官方仅 wx 单端、本件 wx/tt 双端);完整转正尽调归 W-CH 波(审计明文落点,已采纳口径=§9-Q1,作战清单 β ⑥ 措辞随 execution 版同步更正)。
  • R3 存量红线血统回填五条(每条带来源/失效条件/复审触发;现落点已 grep 定位):
红线 现落点(grep 实证) 回填动作
SDK<8KB contracts/sdk-interface.d.ts:6、.agents/rules/engineering-conventions.md:89、.agents/knowledge/glossary.md:18、product-and-architecture.md:166 补三件套血统(来源=SDK 首屏负担约束/失效条件/复审触发)
B1 350KB docs/brainstorms/2026-06-11-tier1-runtime-constraints-requirements.md:21,41(KD2/R6)、tech-decisions.md:14 补三件套(来源=引擎预算放宽档 KD2/KD3)
「本机零 npm 依赖」 .agents/rules/engineering-conventions.md:88(SDK 零依赖)、build-vs-buy.md:17 补血统并标注适用面=lane 源码,不及工具链(审计 Q4-R3 明示)
「标准库优先」 仅 build-vs-buy.md:17 待回填表列出,未在 rules 正文找到独立落点(待查证:疑散落 orchestrator/README:8-9) 补血统 + 定落点
harness RSS≤2G 仅 build-vs-buy.md:17 待回填表列出,未在 rules/skills 正文找到独立落点(待查证) 补血统 + 定落点
  • 完成判据:R6 四件各有尽调记录/收敛动作落档;R3 五条各带三件套血统、grep 可验;回填后活文档残毒残扫零(wave-close 第三步 R3 48h 回填子项)。

6. 对外影响面(被动方,四象限重列)

象限 被动对象 影响
契约 contracts/events.schema.json(completed,line 61)/ contracts/agent-loop/verdict.schema.json outcome×completed 裁定:completed 仍是闭环达成权威判据;outcome:'win'|'lose' 仅作 action 类可选 additive 字段;关系写契约注记(Runner review §5)。评估门以 completed 为准
契约 contracts/game-package.schema.json(Runner URL 字段)/ contracts/api-schemas/runtime.yaml(SandboxPolicyVO:sandboxAttr/allowOrigins) 范围②③:URL 化交付字段冻结先行;前端改为消费下发的 sandboxAttr/allowOrigins(消双源)
契约 contracts/sdk-interface.d.ts(storage 根契约新增 + R3 血统注记) 范围⑤ contract-first 先行;范围⑥ 注记类不改语义值
backend game-cloud runtime(RuntimePackageService 翻包 0→1)/ project(ProjectServiceImpl.reviewProject→PublishOrchestrationService 五步编排)/ feed(FeedServiceImpl 二次过滤 PUBLISHED) 范围④ 发布主链全程被动;Runner v2 包 URL 产出对接
studio host 四件 game-studio/src/host/{inject.ts,bridge.ts,GamePlayer.vue,runtime/index.ts} + src/host/contract.ts(storage 形状副本收敛) 范围③ 架构改写(srcdoc→URL;sandbox/origin/CSP/CORS 四项矩阵)+ 范围⑤ 三套形状收敛
studio src/views/{play/Play.vue,create/Preview.vue} + 分享链路(api/types.ts shareUrl→/play/:gameId/:versionId、feed.ts getShareMeta) 两路由消费 GamePlayer + 分享落地是 1.x 改写后必须保活链路(§7-1),CDP 走查覆盖
admin 审核台(AdminProjectController review 动作)/ feed 精选池运营位 范围④ 参考件须经 admin 真审核过链路②;精选池若引用 gameId 随入池联动
staging feed 服务(:4173)/ Runner v2 交付面(URL+immutable headers)/ mini-desktop CDP 门 范围②③④ 联验场地;缓存命中/headers 实证在此取证
工作区 game-runtime/(SIZES.md / 三件 impl / scripts/validate-manifest.mjs / probe) 范围①⑤⑥ 改造

7. 风险与兼容

  1. 1.x 退役兼容爆破半径(grep 实证):
    • admin 侧 = 零半径:grep -rn "GamePlayer\|srcdoc\|/play/\|inject" game-admin/src 未查到任何 1.x 运行时引用(唯一命中 useConfigGlobal.ts:4 的 inject('configGlobal') 是 Vue 依赖注入,与宿主无关)→ admin 预览不引用 1.x 路径,推断零半径。
    • 分享链接 = 活消费方:game-studio/src/api/types.ts:92,97(shareUrl + GAP-3「立即玩」携 versionId 跳 /play/:gameId/:versionId)+ feed.ts:73,77(getShareMeta /app-api/feed/share/{gameId})→ 分享落地页经 /play 路由 → GamePlayer 是 srcdoc→URL 改写后必须保活的链路。这是 CDP 走查门的核心覆盖点。
    • 存量游戏包 = 无包袱:W-CLEAN 已清旧 4 模板 + 存量 1022 行(已归档 mini-desktop:/root/backups/w-clean-20260612/),1.x 无存量双轨包袱(Runner review §5)。
  2. 真接线后确定性回归风险:接 littlejsengine WebGL 后,e2e 像素哈希读回路径变(Canvas2D→WebGL readPixels),双开确定性须重验——若引擎渲染含不可控浮点/时序,确定性门可能不稳,需在重叠清单内逐件评估(取舍 2)。
  3. 包装层能力缺口风险:个别引擎内建能力(如确定性取证所需)若不满足生成约束,可能反逼「有意替代+砍预算」——届时须创始人书面裁定(R7 抽象墙审计:墙内重造项须单独过 R1+R2)。
  4. Runner v2 缓存与版本风险:immutable 强缓存命中依赖版本 URL 正确性;版本切换不可就地覆盖,发布流须保证 URL 唯一变更(与 GameConfig 热发解耦)。

8. 验收标准(汇总,可验证门)

量化口径形状要求(P2-2):每道门在执行版必须给「唯一命令 / 输入版本(SHA) / 样本数 / 输出文件 / fail 条件」五件,证据可复跑(沿参考件 FORENSICS 四件套复跑口径);评审版此表只定门的形状。

# 门 判据(形状)
1 真接线门三件套(R6 硬门,防名义接线) ①esbuild metafile:littlejsengine 入产物且被三件 impl chunk 真实引用(非 tree-shaken)②运行时 probe:三件包装层各产出调用引擎能力的调用 ID 证据 ③负向扫描:grep pattern 清单证旧裸 Canvas2D 实现已删(防双轨)。单纯 bundle grep 不算过门。另:插件×引擎重叠清单产出,每件有「包装/替代」裁定
2 SIZES 重锚 「引擎+包装层」单口径(scripts/size.mjs 集成段重跑,固定 SHA),双份记账消除;R3 血统三件套齐
3 e2e 像素门(WebGL) 固定 seed/frame 的 readPixels 哈希 ×N(样本数执行版定)PASS + 双开确定性过(清档同存档态口径)
4 Runner v2(防 demo 假阳性) Network 捕获 manifest checksum=发布版本 ∧ gameId/versionId 匹配 ∧ 捕获 game_loaded+game_end(completed===true) ∧ demo 兜底路径触发即 fail;immutable 缓存命中=CDP Network timing 实证(二开 fromCache/304)+ feed 预热实证
5 1.x 退役 CDP 走查门 /play /preview 真 UI 走查过;兼容矩阵四项(sandboxAttr 消费/双向 origin 校验/CSP 放行/CORS)+ 注入时序/存档桥/CSP 运行时无回归;不落 demo 兜底(build 门不足以替代)
6 参考件入 feed(API/DB/CDP 联合验收) API:发布链接口全成功;DB:project.status==4 ∧ game_version.status==3 ∧ runtime_package.status==1 ∧ feed_rank 行存在 四态实查;CDP:feed 卡片→/play 加载真包(判据同门 4);链路③⑤借此闭合
7 P7/P8 决策 固定清单四项判定表(代码 grep/取证字段/资产格式/玩法需求)+ 裁定;无命中默认留 v2
8 StoragePlugin 契约补丁 根契约 sdk-interface.d.ts 落 storage;contract.ts/inject.ts 三套形状收敛一致;端到端=真实 save→重载→读回一致的游戏包
9 probe 时钟拆分 URL 加载形态下锚点哈希链单调可验(verify 命令通过,固定 SHA)
10 R6 尽调补录 CDP harness/ajv/prompt registry 三件落档+收敛动作;weapp-adapter 仅轻量 why-not 一行(完整尽调归 W-CH,已采纳口径见 §9-Q1)
11 R3 血统回填×5 各带三件套血统;先列权威源头文件+grep pattern 再验残扫零(无独立落点两条按 §9-Q2 口径就地补)
12 收口 wave-close 七步(含 R3 48h 回填子项、R6 接线证据入收口报告)

9. 待确认项(待创始人/评审拍板)

# 事项 现状/默认
Q1 weapp-adapter R6 补录归属冲突 已采纳口径(R1 评审 P1-6):审计明文落点=「W-CH 转正 spec」(转正时重过尽调 Q4-R4) β 内仅做「补一行 why-not」轻量动作,完整转正尽调归 W-CH 波(避免两波重复);作战清单 β ⑥措辞随 execution 版同步更正
Q2 「标准库优先」「harness RSS≤2G」两条 R3 血统落点缺失 已采纳口径(R1 评审 P1-6):除 build-vs-buy.md:17 待回填表外正文无独立落点(疑散于 orchestrator/README) 执行版先定位权威源头+grep pattern;确无独立落点则在 build-vs-buy.md 待回填表就地补三件套,不为过门新增无效注记
Q3 outcome 字段是否本波落契约:events.schema 现仅有 completed(line 61),outcome 为 Runner review §5 提议的 additive 字段,contracts 内尚未落 默认建议:本波随 Runner v2 把 outcome 关系注记写入契约(additive,不破坏 completed 权威性)
Q4 裁决①个别能力「有意替代」豁免 已裁(创始人 2026-06-13):「自研内容是引擎外的层,不是对引擎本体的替代」 「有意替代」豁免关闭:自研只许做引擎外的层(包装层/引擎缺件补层——collision/gamefeel 属引擎没有的能力,即「引擎外补层」,与此一致);引擎内建能力一律走包装;确定性取证等诉求在 harness/门侧解决(如 probe 调用断言替代像素哈希、固定 seed readPixels),不得以此为由替代引擎内建。重叠清单裁定空间随之收窄为「包装 / 引擎缺件补层」两类

裁决类:除上述 Q1-Q4 外,均沿既有裁决(裁决①/引擎终裁 LittleJS/Runner v2 形态/outcome×completed/R1-R7)。


篇幅自律线 ≤250 行;配对 execution 版待两轮评审通过后另出(须含:包装透传通道接口契约、三件 impl 改造步骤、重叠清单模板、CDP 走查门脚本形制、SIZES 重锚命令口径、契约补丁字段、R6/R3 逐条落点与回填文本)。