P0整改:①新增§1.5『能力同一性』原则(引擎『有』须签名/返回语义/坐标系兼容,否则缺件)+三分判定测试;②§7改方法论+待P0验签假设表(裁定不冻结,Phase0抽签名后填)——collision isOverlapping→boolean满足不了aabbVsAabb→MTV=降缺件补层/audio Sound世界音频不兼容PCM播放层=合成包装+播放补层;③random/time拆条,引擎主循环接管(A0)列地基显式步,probe墙钟与引擎time解耦;④Runner URL复用后端packageUrl(撤『backend零改写』),OSS非空分支or DB-manifest带版本降级二选一待拍;⑤audio三分细化 P1:消『双份记账』伪命题(引擎首次入bundle非消重)/CSP放行扩script-src+default-src/storage上提contract.ts定稿对象形态(不回退string)/outcome落game_play_end props 待二轮对抗复审+待确认A(OSS二选一)拍定后冻结开工 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
35 KiB
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作战清单.mdT1b-β 行(六项一一对应,不增删)。
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-β 行六项):
- 裁决①落地:三件改引擎能力包装层 + 真接线门 + 受控面透传通道 + SIZES 重锚 + e2e 像素口径适配 WebGL 读回。
- Runner v2 产品化(URL 化交付 + 强缓存,接 GamePackage 真实产出)。
- 1.x 退役三件套改写(srcdoc→URL、GamePlayer/inject/bridge 重写、CDP 走查门)。
- 参考件「暖阳小卖部」发布入 feed(解封链路③⑤真走查)。
- P7/P8 决策 + SDK StoragePlugin 契约补丁 + probe 注入时钟拆分。
- 审计整改余项: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→adminreviewProject(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 要消灭的「名义采用」。故门改为三件套全过才算接线:- esbuild metafile 证明引擎模块被保留进产物(
--metafile输出里inputs含littlejsengine且被三件 impl 的 chunk 真实引用,非 tree-shaken 掉)。 - 运行时 probe 记录三件包装层调用引擎能力的调用 ID(particles-juice / physics-lite / palette-post 各产出经透传通道调 littlejsengine 内建的调用证据 ID,证明运行期真走引擎)。
- 负向扫描禁止保留等价 Canvas2D 自研 fallback(grep pattern 清单扫三件 impl,确认旧裸 Canvas2D 粒子/物理/后处理实现已删除——防「引擎接上但自研双轨仍在」的双轨残留)。
- esbuild metafile 证明引擎模块被保留进产物(
- 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 四件套口径)。
- 重叠清单产出,每件有「包装/替代」裁定。
- 真接线门三件套(P0-3 防名义接线):单纯
范围② 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 缓存命中实证。
- Network 捕获的 manifest checksum 与发布版本一致,且
范围③ 1.x 退役三件套改写
- 推荐做法:
inject.ts的 srcdoc 源码内联(startRuntime.toString())切换为 Runner v2 URL 加载;GamePlayer/inject/bridge 三件套运行时行为(沙箱注入时序/存档桥/CSP)重写;GamePlayer 2b(无 warn 版)并入。退役=架构级改写,非删码。 - srcdoc→URL 兼容矩阵(P1-1,四项必须随改写一并收编,否则 URL 化即破链):
- 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,消除前端写死与契约下发的双源。 - 父子双向 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 校验。 - URL Runner 的 CSP/headers:
inject.ts:52-53现 CSPconnect-src 'none'(meta 行 53),会阻断 URL 加载的引擎/资源出站请求——URL 化须放开connect-src/script-src到 Runner URL 与 OSS/CDN 来源(与SandboxPolicyVO.allowOrigins一致),否则真包 fetch 被自身 CSP 拦死。 - 跨源 package/asset 的 CORS 与 credentials 策略:OSS/CDN 取包的 CORS(
SandboxPolicyVO注记已要求 AllowedOrigin 含宿主 origin、AllowedMethod=GET/HEAD、ExposeHeader=ETag)与 credentials 策略须落定,否则跨域 fetch manifest 被拦。
- sandbox 属性收编:
- 取舍: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)→adminreviewProject审核通过(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 尽调补录四件(审计盘点表对应行):
- CDP harness(行3 ⚠️):补 puppeteer-core/playwright 排除理由落档(蓝图选 Playwright,实现层被纪律改手搓;puppeteer-core 仅 connect 既有 :9222 不冲突机器红线);两份实现(
browser-evidence.cjs448 行 /orchestrator/player_cdp.py1637 行)收敛单一权威 + 登记 Doc B 正式 T-id。 - ajv(行4 ⚠️):
game-runtime/scripts/validate-manifest.mjs:7-10文件头自供「不引 ajv=零依赖纪律——违纪」;校验挪集成段用 ajv 做权威门(集成段本就跑 npm,ajv 零成本),本机手写版降级开发期快检或删除。 - prompt registry(行8 ✅边缘):
contracts/prompts/+ prompt-governance.md 补三行 why-not(LangSmith/PromptLayer/Langfuse)入 registry README。 - weapp-adapter(行14 ✅ spike 内):β 内仅补「为何不直接 vendor 官方 weapp-adapter」轻量一行(官方仅 wx 单端、本件 wx/tt 双端);完整转正尽调归 W-CH 波(审计明文落点,已采纳口径=§9-Q1,作战清单 β ⑥ 措辞随 execution 版同步更正)。
- CDP harness(行3 ⚠️):补 puppeteer-core/playwright 排除理由落档(蓝图选 Playwright,实现层被纪律改手搓;puppeteer-core 仅 connect 既有 :9222 不冲突机器红线);两份实现(
- 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.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)。
- admin 侧 = 零半径:
- 真接线后确定性回归风险:接 littlejsengine WebGL 后,e2e 像素哈希读回路径变(Canvas2D→WebGL readPixels),双开确定性须重验——若引擎渲染含不可控浮点/时序,确定性门可能不稳,需在重叠清单内逐件评估(取舍 2)。
- 包装层能力缺口风险:个别引擎内建能力(如确定性取证所需)若不满足生成约束,可能反逼「有意替代+砍预算」——届时须创始人书面裁定(R7 抽象墙审计:墙内重造项须单独过 R1+R2)。
- 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 | β 内仅做「补一行 why-not」轻量动作,完整转正尽调归 W-CH 波(避免两波重复);作战清单 β ⑥措辞随 execution 版同步更正 | |
| Q2 | 执行版先定位权威源头+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 | 「有意替代」豁免关闭:自研只许做引擎外的层(包装层/引擎缺件补层——collision/gamefeel 属引擎没有的能力,即「引擎外补层」,与此一致);引擎内建能力一律走包装;确定性取证等诉求在 harness/门侧解决(如 probe 调用断言替代像素哈希、固定 seed readPixels),不得以此为由替代引擎内建。重叠清单裁定空间随之收窄为「包装 / 引擎缺件补层」两类 |
裁决类:除上述 Q1-Q4 外,均沿既有裁决(裁决①/引擎终裁 LittleJS/Runner v2 形态/outcome×completed/R1-R7)。
篇幅自律线 ≤250 行;配对 execution 版待两轮评审通过后另出(须含:包装透传通道接口契约、三件 impl 改造步骤、重叠清单模板、CDP 走查门脚本形制、SIZES 重锚命令口径、契约补丁字段、R6/R3 逐条落点与回填文本)。