@skillbuilder/miniapp-simulator 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/docs/assets/audit-auto-stop-config-2026-10-21.jpg +0 -0
  2. package/docs/assets/audit-balanced-panel-2026-10-16.jpg +0 -0
  3. package/docs/assets/audit-lcp-input-2026-10-20.jpg +0 -0
  4. package/docs/assets/audit-paint-game3d-2026-10-16.jpg +0 -0
  5. package/docs/assets/audit-paint-webgl-2026-10-16.jpg +0 -0
  6. package/docs/assets/audit-paint-webgl-apm-excerpt-2026-10-16.json +397 -0
  7. package/docs/assets/audit-poetry-2026-10-16.jpg +0 -0
  8. package/docs/assets/audit-remaining-results-2026-10-16.json +2749 -0
  9. package/docs/assets/miniapp-audit-risk-review-2026-10-13.png +0 -0
  10. package/docs/assets/miniapp-audit-runtime-hung-2026-10-13.png +0 -0
  11. package/docs/audit-data-collection.codex.md +422 -0
  12. package/docs/audit-local-validation.codex.md +165 -0
  13. package/docs/audit-score-design.codex.md +221 -0
  14. package/docs/audit-score-design.md +885 -0
  15. package/docs/audit-score-tech-plan.md +448 -0
  16. package/docs/audit-tech-design.codex.md +468 -0
  17. package/docs/electron-review.md +223 -12
  18. package/docs/quality-evaluation-redoc.xml +163 -0
  19. package/lib/client-BDt3WDu_.mjs +1118 -0
  20. package/lib/{index-D5AYVv8s.mjs → index-7MeYFlk_.mjs} +210 -182
  21. package/lib/index.js +1254 -1115
  22. package/lib/remote-client.js +2 -2
  23. package/lib/types/host/shadow-host.d.ts +10 -0
  24. package/lib/types/injection/registry.d.ts +5 -0
  25. package/lib/types/remote/audit-controller.d.ts +56 -0
  26. package/lib/types/remote/audit-leave-monitor.d.ts +12 -0
  27. package/lib/types/remote/audit-telemetry.d.ts +23 -0
  28. package/lib/types/remote/audit-watchdog.d.ts +14 -0
  29. package/lib/types/remote/client.d.ts +25 -1
  30. package/lib/types/remote/load-timing.d.ts +5 -0
  31. package/lib/types/remote/protocol.d.ts +151 -1
  32. package/lib/types/remote/runtime.d.ts +2 -0
  33. package/lib/types/remote-client.d.ts +2 -2
  34. package/lib/types/sw/service-worker-host.d.ts +15 -0
  35. package/lib/types/tracker/default-tracker.d.ts +8 -0
  36. package/lib/types/types/options.d.ts +24 -0
  37. package/lib/workbench.js +1 -1
  38. package/package.json +1 -1
  39. package/lib/client-_vNHVHSm.mjs +0 -775
@@ -0,0 +1,221 @@
1
+ # 小工具体验评测与准入设计
2
+
3
+ ## 目标与边界
4
+
5
+ 小工具是开发者自带构建产物的 Web 内容,形态包括工具、2D/3D 游戏和音视频。评测需要在 Mars 远程模拟器中识别内存增长、图形资源高水位、运行异常、主线程卡顿和包体问题,并给审核员可解释、可复核的证据。
6
+
7
+ 一期采用 Web 侧动态采集,默认 `enforce: false`,用于观察和人工复核。它不能等价替代真机 OOM 结论:浏览器 JS 堆不包含原生 RSS/PSS、GPU 驱动、媒体解码器和系统内存压力。二期将 Web 风险信号与真机进程、崩溃和机型数据关联后再校准自动卡口。
8
+
9
+ ## 审核队列模型
10
+
11
+ 审核员在队列中逐个处理小工具,每个队列项都创建独立会话并完整重载模拟器:
12
+
13
+ ```text
14
+ 队列项进入
15
+ → Mars Runtime 建连,按需加载独立评测插件
16
+ → 审核员开始审核
17
+ → document-start 探针先注册,小工具后加载
18
+ → 审核员真实操作主要功能并检查结果
19
+ → 离开整个模拟器容器(含留白与评测面板) 30 秒后自动结束并上报,或点击“停止评测”
20
+ → 最长 2 分钟自动结算
21
+ → 保存报告并完整重载模拟器
22
+ → 下一队列项
23
+ ```
24
+
25
+ 平均处理时间约为 1 分钟,不是固定时限。策略默认最低有效时长 30 秒、最低 30 个快照、至少 1 次真实输入、覆盖度不低于 0.6;正常完整采集且无基础设施异常时可出分,最长会话时钟为 120 秒。审核员可随时停止评测,证据不足时保留数据和原因,不为等待出分延长队列处理时间。OOM、泄漏和晚发异常风险较高的内容可安排专项复测。
26
+
27
+ 交互计数只记录实际到达 guest 的输入事件,不保存输入文本和屏幕坐标。审核员按 SOP 检查主要功能或结果,游戏需进入主循环并实际操作。离开整个模拟器容器(含留白与评测面板) 30 秒自动结束;倒计时内移回取消,区域外仍有真实输入时延后,手机、内部留白与面板间移动不结束。面板保留“停止评测”按钮,Apollo 通过 `autoStopOnLeaveMs` 调整延迟,0 表示关闭。自动结束和上报由模拟器内部完成,不要求 Mars 接口。停止不表示功能或审核通过,也不伪造业务完成证据;提前刷新按中断处理,上报失败不阻塞队列。
28
+
29
+ ## 报告状态与消费顺序
30
+
31
+ | 状态 | 含义 | 审核处理 |
32
+ | ------------ | ----------------------------------------- | -------------------------------- |
33
+ | `scored` | 采集完整,时长、采样、交互和覆盖度均满足,且无基础设施异常 | 查看风险、分项和总分,保留体验反馈 |
34
+ | `unscorable` | 证据不足,或采集被资源熔断/失联截断 | 人工复核,不可按分数放行 |
35
+ | `loadFailed` | ZIP 无法启动,或 Runtime/guest 主线程卡死 | 展示结构化失败码并进入下一队列项 |
36
+
37
+ 消费顺序固定为:
38
+
39
+ ```text
40
+ status === scored
41
+ → quality.complete === true
42
+ → blocking.passed === true
43
+ → 再消费总分和分项建议
44
+ ```
45
+
46
+ 只要命中硬性风险,面板显示红色“需复核”,总分同步使用风险色,并提示“不能仅按分数放行”。`enforce: false` 只表示不自动拒绝,不表示风险通过。
47
+
48
+ ## 采集指标
49
+
50
+ 面板分类汇总与指标明细的展示顺序为:运行性能 → 包体积 → 稳定性 → 内存。稳定性当前包含 JS 异常,内存分类只展示内存和资源占用指标;硬风险单独提示。
51
+
52
+ ### 运行期
53
+
54
+ | 指标 | 口径 | 权重 | 当前用途 |
55
+ | ----------- | -------------------------------------------------------- | ---: | ------------------------------- |
56
+ | 峰值 JS 堆 | `performance.memory` 稳定期峰值相对会话基线 | 6 | 分数;识别异常高占用 |
57
+ | 堆增长速率 | 稳定期样本最小二乘斜率,MB/min | 7 | 分数 + 硬风险,默认阈值 8MB/min |
58
+ | 显存水位 | WebGL texture/buffer/renderbuffer 存活字节配对记账的 P95 | 6 | 分数 + profile 硬风险 |
59
+ | Canvas 缓冲 | 存活 canvas 像素后备缓冲峰值 | 3 | 分数 |
60
+ | 解码图片 | 存活图片像素字节峰值 | 4 | 分数 |
61
+ | WASM 内存 | `WebAssembly.Memory` 已分配页峰值 | 3 | 能力存在时计分 |
62
+ | Worker 数 | 存活 Worker 峰值 | 2 | 能力存在时计分 |
63
+ | JS 异常 | `error` 与 `unhandledrejection` 计数 | 0.5 | 低权重风险信号;默认不触发硬卡口 |
64
+ | FCP | guest 导航到首次内容绘制 | 4 | 首屏分数 + 独立 APM 观测 |
65
+ | LCP | guest 导航到最大内容绘制,交互或结束时收口 | 10 | 首屏分数 + 独立 APM 观测 |
66
+ | 帧率 | rAF 采样窗口 FPS 中位数;P5 单独上报 | 5 | 流畅度评分,结合实际操作解释 |
67
+ | 长任务 | 采集期最长一次主线程 Long Task | 1 | 低权重;500ms以内不扣分,3000ms为0分 |
68
+ | 上下文丢失 | `webglcontextlost` 任意发生 | — | 硬风险 |
69
+ | guest crash | guest 崩溃/失联 | — | 硬风险或结构化失败 |
70
+
71
+ 不适用项明确标为 N/A,不进入总分分母。探针记账达到上限时设置 `probeSaturated`,受影响的显存和 Canvas 项降级为 N/A,不使用偏低读数出分。
72
+
73
+ ### 首屏评分与观测
74
+
75
+ FCP/LCP 使用 Lighthouse mobile 的对数正态评分曲线作为种子曲线,单项满分 100:
76
+
77
+ | 指标 | 良好边界,约 90 分 | 50 分控制点 | 默认权重 |
78
+ | --- | ---: | ---: | ---: |
79
+ | FCP | 1800ms | 3000ms | 4 |
80
+ | LCP | 2500ms | 4000ms | 10 |
81
+
82
+ 依据:[FCP](https://web.dev/articles/fcp)、[LCP](https://web.dev/articles/lcp)、[Lighthouse 评分机制](https://developer.chrome.com/docs/lighthouse/performance/performance-scoring)。曲线控制点见 Lighthouse 的 [FCP 实现](https://github.com/GoogleChrome/lighthouse/blob/main/core/audits/metrics/first-contentful-paint.js)与 [LCP 实现](https://github.com/GoogleChrome/lighthouse/blob/main/core/audits/metrics/largest-contentful-paint.js)。桌面模拟器使用这组用户体验参考值,不代表移动设备实测或完整 Lighthouse 得分。
83
+
84
+ 探针从 document-start 监听浏览器 Paint Timing,使用 buffered observer 补取启动记录,不等待 3 秒预热。时钟起点为小工具 guest 导航,不包含 ZIP 上传、解压和 Runtime 建连。LCP 候选在首次输入、滚动、页面隐藏、pagehide 或停止审核时收口;停止时排空 observer 待处理记录,插件最多等待 150ms 确认,未确认的候选不参与评分。
85
+
86
+ 不支持 API、首屏前已隐藏或没有合格绘制时显示 N/A,不以 0ms 补齐。Canvas/WebGL 画面不属于 LCP 主内容,游戏中的 DOM 标题也不能证明游戏核心场景已经可用;可玩性由审核员通过实际操作检查。FCP 首次实测和 LCP 收口独立触发 APM flush,即使有效时长不足,也保留首屏数据。看板按 `policy_version`、设备/环境和形态分组,使用已收口且实测的 LCP 计算 P75,不混入缺失或失效 attempt。
87
+
88
+ 运行过程相对权重为 FPS 5 > 长任务 1 > JS 异常 0.5。JS 异常完整累计并保留代表性事故证据,默认 `blocking.jsFatal: false`。错误数量不直接证明功能损坏;功能是否受影响需结合真实操作反馈、失联/崩溃等证据判断。APM 分别上报 `fps_median`、`fps_p5`,以及三项的实际得分和权重,按策略版本分析。
89
+
90
+ ### 静态包
91
+
92
+ | 指标 | 口径 | 权重 |
93
+ | ---------- | -------------------------- | ---: |
94
+ | 解压总体积 | ZIP 内全部文件解压后字节和 | 4 |
95
+ | 最大单图 | 单个图片文件最大字节数 | 3 |
96
+ | 未压缩 JS | 单个未压缩脚本最大字节数 | 3 |
97
+
98
+ 包体指标用于质量排序。无法解析或超过加载安全限制的 ZIP 由加载链路返回 `loadFailed`,不生成伪分数。
99
+
100
+ ## 采集与业务隔离
101
+
102
+ 探针在 guest document-start 注入,hook 先调用原始实现,再在隔离的 `try/catch` 中记账,保留业务函数的 `this`、参数、返回值和异常语义。WebGL 对象创建、覆盖上传和删除均配对记账;场景释放后水位可以下降。
103
+
104
+ 插件构建为独立浏览器 ESM。仅 `businessLine === mars` 动态加载,普通预览链路不请求探针、规则和面板资源。截图失败属于证据附件失败,不中断指标采集。
105
+
106
+ ## 卡死、熔断与队列恢复
107
+
108
+ 评测期间 Runtime 持续向宿主发送进度。宿主每次收到进度都重置 12 秒静默计时器;连续 12 秒没有进度时,立即发布:
109
+
110
+ ```text
111
+ status: loadFailed
112
+ loadFailure.code: RUNTIME_HUNG
113
+ source: host-watchdog
114
+ ```
115
+
116
+ 总时钟仍保留“策略最长时长 + 35 秒收口余量”,用于防止 Runtime 持续发空进度却不结算。评测模式的 guest 堆熔断线为 3GiB;触发时报告为采集中断,保留已观测到的硬风险。审核员对下一队列项执行完整页面刷新,避免复用卡死 Realm。
117
+
118
+ ## 默认 profile
119
+
120
+ 所有 profile 均保持 observe-only:
121
+
122
+ | profile | peakHeapMB | textureMB | canvasMB | imageMB | wasmMB | 包体 ideal / accept / max MB |
123
+ | -------- | ---------: | --------: | -------: | ------: | -----: | ---------------------------- |
124
+ | `tool` | 32 | 48 | 32 | 48 | 32 | 2 / 4 / 9 |
125
+ | `game2d` | 96 | 96 | 64 | 96 | 64 | 6 / 12 / 24 |
126
+ | `game3d` | 200 | 48 | 32 | 32 | 64 | 12 / 20 / 32 |
127
+ | `video` | 180 | 96 | 64 | 64 | 32 | 4 / 8 / 16 |
128
+
129
+ 形态由静态指纹和运行能力共同推断;申报形态不一致时保留 `tagMismatch` 供人工复核。`game2d` 和 `video` 样本不足,不开启自动卡口。
130
+
131
+ ## 策略配置
132
+
133
+ 服务端 key 为 `miniappSimulatorAuditPolicies`。每条 `strategy` 都必须是一份完整策略;可按 `businessLines`、`appIds`、`userIds` 命中,命中多条时选择 `priority` 最大的一整份,不做字段合并。服务端只校验外层 JSON、scope 和 priority 结构,不校验审核策略字段。
134
+
135
+ ```json
136
+ [
137
+ {
138
+ "priority": 0,
139
+ "scope": { "businessLines": ["mars"] },
140
+ "strategy": {
141
+ "policyVersion": "phase1-fps-priority-v6-2026-10-23",
142
+ "enforce": false,
143
+ "minCoverage": 0.6,
144
+ "defaultProfile": "tool",
145
+ "profiles": {
146
+ "tool": {
147
+ "peakHeapMB": 32, "textureMB": 48, "canvasMB": 32,
148
+ "imageMB": 48, "wasmMB": 32,
149
+ "size": { "idealMB": 2, "acceptMB": 4, "maxMB": 9 }
150
+ },
151
+ "game2d": {
152
+ "peakHeapMB": 96, "textureMB": 96, "canvasMB": 64,
153
+ "imageMB": 96, "wasmMB": 64,
154
+ "size": { "idealMB": 6, "acceptMB": 12, "maxMB": 24 }
155
+ },
156
+ "game3d": {
157
+ "peakHeapMB": 200, "textureMB": 48, "canvasMB": 32,
158
+ "imageMB": 32, "wasmMB": 64,
159
+ "size": { "idealMB": 12, "acceptMB": 20, "maxMB": 32 }
160
+ },
161
+ "video": {
162
+ "peakHeapMB": 180, "textureMB": 96, "canvasMB": 64,
163
+ "imageMB": 64, "wasmMB": 32,
164
+ "size": { "idealMB": 4, "acceptMB": 8, "maxMB": 16 }
165
+ }
166
+ },
167
+ "size": { "singleImageKB": 300, "uncompressedJsKB": 1024 },
168
+ "minSamplesForSlope": 30,
169
+ "minEffectiveMs": 30000,
170
+ "minSamplesForScoring": 30,
171
+ "minInteractionsForScoring": 1,
172
+ "evaluationDurationMs": 120000,
173
+ "autoStopOnLeaveMs": 30000,
174
+ "auditModeHeapLimitBytes": 3221225472,
175
+ "weights": {
176
+ "peakHeap": 6, "heapGrowth": 7, "texWatermark": 6,
177
+ "canvasBuffer": 3, "decodedImages": 4, "wasmMemory": 3,
178
+ "workerCount": 2, "jsError": 0.5, "fps": 5, "longTask": 1,
179
+ "fcp": 4, "lcp": 10,
180
+ "unpackedSize": 4, "singleImage": 3, "uncompressedJs": 3
181
+ },
182
+ "scoreRanges": {
183
+ "workerCount": { "good": 4, "bad": 12, "threshold": 4 },
184
+ "jsError": { "good": 0, "bad": 5, "threshold": 0 },
185
+ "fps": { "good": 50, "bad": 20, "threshold": 30 },
186
+ "longTask": { "good": 500, "bad": 3000, "threshold": 500 }
187
+ },
188
+ "loadingScoreRanges": {
189
+ "fcp": { "p10": 1800, "median": 3000 },
190
+ "lcp": { "p10": 2500, "median": 4000 }
191
+ },
192
+ "blocking": {
193
+ "heapGrowthMBPerMin": 8,
194
+ "textureWatermark": true,
195
+ "contextLost": true,
196
+ "jsFatal": false,
197
+ "crash": true
198
+ }
199
+ }
200
+ }
201
+ ]
202
+ ```
203
+
204
+ 外层 JSON、scope 或 priority 结构无法解析时继续使用 Apollo 的 last-known-good;`strategy` 内的审核字段不做业务校验。
205
+
206
+ 规则包内置一份完整的 `enforce: false` 默认策略。Apollo 未命中或没有取得 audit 配置时使用本地默认;只要服务端返回了 audit 配置,Runtime 就整份直接采用,不校验策略字段,也不与本地默认逐字段拼接。评分公式、采集方式和指标 ID 固定在规则包,profile 预算、评分区间、权重、证据门槛和卡口开关由 Apollo 调整。
207
+
208
+ ## 一期交付与二期输入
209
+
210
+ 一期交付:
211
+
212
+ - Mars 独立插件与常驻侧栏;
213
+ - document-start 动态采集与静态包指标;
214
+ - 真实交互次数、首次操作时间和采集完整性;
215
+ - 三态报告、N/A 覆盖度与硬风险“需复核”;
216
+ - 12 秒进度静默看门狗、3GiB 熔断和会话中断收口;
217
+ - 20 个本地 ZIP 的逐包真实交互结果,详见 [audit-local-validation.codex.md](./audit-local-validation.codex.md)。
218
+
219
+ 一期接入 Mars 队列时,模拟器内部采集的评测数据统一上报 APM:审核任务、应用、包版本、策略/规则/探针版本、开始/首次操作/结算时间、1 Hz 指标时序、FCP/LCP 首屏事件、包体摘要、交互次数、三态终态和硬风险。事件契约、异常收口和指标校准流程详见 [audit-data-collection.codex.md](./audit-data-collection.codex.md)。
220
+
221
+ 二期输入:真机 RSS/PSS、GPU 驱动内存、媒体解码内存、系统内存告警、进程终止与崩溃原因、机型/系统/WebView 版本。通过同包同脚本的 Web 与真机对照,计算误报/漏报和分机型阈值,再决定哪些硬风险可以从“需复核”升级为自动卡口。