@skillbuilder/miniapp-simulator 0.2.4 → 0.2.7

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.
@@ -1,422 +1,105 @@
1
- # 小工具体验评测 APM 数据采集与指标校准
1
+ # 小工具体验评测 APM 上报契约
2
2
 
3
- ## 1. 目标与边界
3
+ ## 1. 应用与点位
4
4
 
5
- Mars 审核队列中的评测数据全部进入现有 APM,不建设 `/simulator/audit/raw`、评测数据库或对象存储。
5
+ - 应用:`skillbuilder-miniapp`。
6
+ - 点位:`miniapp_simulator_event`。
7
+ - `event_name`:miniapp_audit_session、miniapp_audit_paint、miniapp_audit_incident、miniapp_audit_package、miniapp_audit_result。
6
8
 
7
- 每个队列项产生一组可关联的 APM 事件,用于:
9
+ ## 2. 显式上报字段
8
10
 
9
- - 监控评测覆盖率、异常率、分数分布和采集链路健康度;
10
- - 按评测形态和版本重建指标时序,回放候选阈值;
11
- - 分析指标分布、风险命中和采集完整性,为内部复测选取样本并校准阈值;
12
- - 二期按 `app_id + package_hash` 关联真机 OOM、崩溃和机型数据。
11
+ 每个业务上报位置直接指定公共数值字段。指标名是明确写出的业务名称,不通过字段名前后缀判断类型或单位。
13
12
 
14
- APM 中不上传 ZIP 文件内容、完整文件清单、DOM、输入内容、屏幕坐标、网络正文、完整错误堆栈或截图二进制。静态包只上报评分所需的聚合指标;截图继续使用现有附件链路,自动截图关闭不影响评测数据上报。
15
-
16
- ## 2. APM 事件模型
17
-
18
- 所有事件沿用现有:
19
-
20
- ```text
21
- measurement_name = miniapp_simulator_event
13
+ ```ts
14
+ { name: 'zip_size', size: pkg.zipBytes, score: zipScore, weight: zipWeight }
15
+ { name: 'unpacked_size', size: unpackedBytes }
16
+ { name: 'fcp', time: paint.fcpMs }
17
+ { name: 'peak_heap', memory: metrics.peakHeapBytes }
18
+ { name: 'fps_median', value: metrics.fpsMedian, unit: 'fps' }
22
19
  ```
23
20
 
24
- 通过 `event_name` 区分评测数据:
25
-
26
- | `event_name` | 频率 | 内容 |
27
- | ------------------------------ | ---------------: | -------------------------------------------------- |
28
- | `miniapp_audit_session` | 每个阶段一次 | 会话启动、探针就绪、采集开始、刷新失效、结束和中断 |
29
- | `miniapp_audit_sample` | 采集期间 1 Hz | 单个原始指标快照 |
30
- | `miniapp_audit_paint` | 首屏值变化及收口 | guest FCP、LCP 候选与收口,不等待预热 |
31
- | `miniapp_audit_incident` | 事件发生时 | context lost、JS fatal、熔断、失联和探针饱和 |
32
- | `miniapp_audit_package` | 每个评测会话一次 | 包体和静态能力聚合指标 |
33
- | `miniapp_audit_result` | 每个评测会话一次 | 三态报告、得分、覆盖度、硬风险和关键派生指标 |
34
-
35
- 每条 `measurement_data` 都是扁平标量,只使用 string 和 number,不把 timeline 或报告数组序列化成一个大 JSON 字符串。布尔语义统一编码为 number:`1` 表示 true/是,`0` 表示 false/否。1 Hz 样本逐点进入 `miniapp_audit_sample`,现有 tracker 再按 10 条或 10 秒合并为 APM 批量请求。
36
-
37
- 按最长 120 秒评测估算,每个会话约产生 120 条 sample、4~10 条会话/异常/结果事件,对应约 13 个批量请求。上线前需要根据 Mars 日审核量确认 APM 事件配额和保留周期。
38
-
39
- ## 3. 会话标识
40
-
41
- | 字段 | 生成方 | 生命周期 | 用途 |
42
- | ---------------------- | -------------- | ------------------ | ---------------------------- |
43
- | `review_task_id` | Mars | 一个审核队列项 | 关联队列项及其评测证据 |
44
- | `audit_session_id` | Runtime | 一次评测 | 关联全部评测 APM 事件 |
45
- | `attempt_no` | Runtime | 一次 guest Realm | 区分手动刷新、重试和失效时序 |
46
- | `simulator_session_id` | Remote Client | 一个远程模拟器连接 | 关联加载性能与评测数据 |
47
- | `app_id` | Mars | 应用 | 聚合同一应用的历史表现 |
48
- | `package_version` | Mars | 被审核包版本 | 对齐审核产物 |
49
- | `package_hash` | Client/Runtime | ZIP 或文件表内容 | 防止版本名复用,关联真机结果 |
50
-
51
- `audit_session_id` 使用 UUID,不能只使用时间戳。所有评测事件都携带以上标识;`attempt_no + sample_seq` 在会话内唯一。
52
-
53
- 审核员 ID 沿用 APM 的 `context_userId`,不重复写入 `measurement_data`。审核员昵称和自由文本备注不进入 APM。
54
-
55
- ## 4. 公共字段
56
-
57
- 所有评测事件都携带:
21
+ | 公共字段 | 类型 | 固定语义 |
22
+ | --- | --- | --- |
23
+ | name | STRING | 指标或事件名称 |
24
+ | time | FLOAT64 | 耗时或相对时间,毫秒 |
25
+ | memory | FLOAT64 | 内存,字节;保留 P95 插值精度 |
26
+ | size | FLOAT64 | 包体、文件和资源体积,字节 |
27
+ | score | FLOAT64 | 得分 |
28
+ | weight | FLOAT64 | 生效权重 |
29
+ | ratio | FLOAT64 | 比例,coverage 为 0~1 |
30
+ | count | INT64 | 次数、数量、会话阶段序号或事故序号;布尔标记使用 0/1 |
31
+ | value | FLOAT64 | 需要额外单位的观测值,与 unit 同时明确赋值 |
32
+ | unit | STRING | value 的单位,如 fps、MB/min |
33
+ | result | STRING | scored/unscorable/loadFailed、采集状态、风险码或框架分类值 |
34
+ | stage | STRING | 会话阶段、采样阶段、首屏收口状态或停止原因 |
35
+ | duration | FLOAT64 | 事件距评测启动的毫秒数 |
36
+ | source | STRING | 事故来源 |
37
+ | message | STRING | 有界诊断 JSON;事故摘要最多 200 字符;框架数量、证据条数和单条长度分别限制 |
58
38
 
59
- ```ts
60
- interface AuditApmCommonFields {
61
- business_line: 'mars';
62
- review_task_id: string;
63
- audit_session_id: string;
64
- attempt_no: number;
65
- simulator_session_id: string;
66
- app_id: string;
67
- package_version: string;
68
- package_hash: string;
69
- app_type: 'tool' | 'game2d' | 'game3d' | 'video';
70
- policy_version: string;
71
- rules_version: string;
72
- probe_version: string;
73
- runtime_version: string;
74
- sdk_version: string;
75
- }
76
- ```
39
+ 无实测值时省略数值字段。零是有效数值,不代替缺失。清理函数只过滤缺失和非有限数值,不生成字段映射。布尔标记由业务调用处显式转换为 0/1。
77
40
 
78
- 会话 ID、任务 ID、应用 ID 和包哈希只用于单次追踪与数据关联,不作为 APM 看板的 group-by 维度。看板只按状态、形态、版本、风险类型和结构化原因码聚合。
41
+ ## 3. 公共上下文与登记
79
42
 
80
- ### 4.1 APM 字段登记
43
+ 公共上下文固定为 audit_session_id、attempt_no、simulator_session_id、app_type、policy_version、rules_version、probe_version、review_task_id、package_version、package_hash、runtime_version。
81
44
 
82
- 沿用 APM 已有顶层信封字段,不新增 measurement:
45
+ tracker 补充 event_name、timestamp、business_line、sdk_version、renderer、app_id;审核员沿用顶层 context_userId。任务和包版本由接入方提供时记录;ID 和哈希只用于精确查询,不用于看板分组。
83
46
 
84
- - `measurement_name = miniapp_simulator_event`;
85
- - `clientTime`、`context_sdkSessionId`、`context_pageSessionId`、`context_sdkSeqId`;
86
- - `context_nameTracker`、`context_platform`、`context_accountGeographicZone`;
87
- - `context_artifactName`、`context_artifactVersion`、`context_feSdkVersion`、`context_userId`;
88
- - `context_route`、`context_matchedPath`、`context_userAgent`。
47
+ APM 现有 28 个基础字段可以复用。固定新增登记项共 18 个:
89
48
 
90
- 需要在 `measurement_data` 登记的 string/keyword 字段:
49
+ - FLOAT64:time、memory、size、score、weight、ratio、value。
50
+ - INT64:attempt_no。
51
+ - STRING:unit、audit_session_id、simulator_session_id、app_type、policy_version、rules_version、probe_version、review_task_id、package_version、package_hash。
91
52
 
92
- ```text
93
- event_name, business_line, renderer, app_id, simulator_session_id,
94
- review_task_id, audit_session_id, package_version, package_hash,
95
- runtime_version, sdk_version, app_type, policy_version, rules_version, probe_version,
96
- stage, phase, reason_code, stop_reason, kind, source, detail,
97
- declared_app_type, detected_app_type,
98
- status, failure_code, primary_blocking_code, truncated_reason_code,
99
- fcp_status, lcp_status, paint_finalize_reason, paint_timing_source,
100
- paint_finalize_event, lcp_element_tag
101
- ```
53
+ 新增指标使用现有公共数值字段,并在业务上报位置明确赋值。诊断信息不上传代码、输入内容、坐标、完整错误堆栈、任意文件路径清单或截图。
102
54
 
103
- 需要登记的 0/1 number 标志字段(`1 = true/是`,`0 = false/否`):
55
+ ## 4. 事件与频率
104
56
 
105
- ```text
106
- automatic, complete, sufficient, probe_saturated,
107
- blocking_passed, enforced, tag_mismatch,
108
- has_webgl, has_canvas2d, has_wasm, has_worker, has_video,
109
- lcp_finalized
110
- ```
57
+ | event_name | 上报方式 |
58
+ | --- | --- |
59
+ | miniapp_audit_session | 每阶段一条,name/stage 为阶段,count 为序号,result 为原因码,message 记录计划时长、预热和离开倒计时等会话信息 |
60
+ | miniapp_audit_paint | FCP 首次实测立即上报;LCP 收口后上报一次;stage=finalized 且 result=measured 的 LCP 才进入首屏分布统计 |
61
+ | miniapp_audit_incident | 事故发生时一条,name/result 为事故类型,source 为来源,message 为摘要 |
62
+ | miniapp_audit_package | 每会话一个记录组,体积直接放入 size,文件数量和能力标记放入 count |
63
+ | miniapp_audit_result | 每会话最多 20 条。每个指标在同一条记录中显式携带实测值、得分和权重;total_score 同时记录总分、覆盖率、有效时长、风险数量及诊断 JSON |
111
64
 
112
- 需要登记的 number 字段:
65
+ 本地保持完整 1 Hz 采集,评分和峰值/P95/增长速率使用完整样本。运行期样本只在本地参与评分和交互观察。完整终态分别上报纹理、缓冲、WASM 和 Worker 等派生指标。终态包含 16 个评分指标、heap_p95、buffer_watermark、fps_p5,以及一条 total_score 摘要,合计最多 20 条;只有缺失数值、得分和权重时省略该指标。
113
66
 
114
- ```text
115
- timestamp, attempt_no, stage_seq, sample_seq, incident_seq,
116
- session_elapsed_ms, collecting_elapsed_ms, evaluation_duration_ms, arming_ms, auto_stop_on_leave_ms,
117
- heap_bytes, tex_bytes, buf_bytes, canvas_bytes, img_bytes, wasm_bytes, workers,
118
- fps, long_task_count, long_task_max_ms, js_error_count, net_pending, interaction_count,
119
- zip_bytes, unpacked_bytes, file_count, largest_image_bytes,
120
- largest_uncompressed_js_bytes, wasm_file_count, worker_file_count, media_file_count,
121
- score_total, score_memory, score_stability, score_performance, score_experience, score_package,
122
- coverage_ratio, effective_ms, sample_count, first_interaction_ms,
123
- reload_count, infrastructure_error_count, blocking_failure_count,
124
- peak_heap_bytes, heap_growth_mb_per_min, tex_watermark_bytes, buf_watermark_bytes,
125
- max_workers, fps_median, fps_p5, js_error_total,
126
- score_fps, score_long_task, score_js_error, weight_fps, weight_long_task, weight_js_error,
127
- fcp_ms, lcp_ms, score_fcp, score_lcp, fcp_threshold_ms, lcp_threshold_ms,
128
- lcp_finalized_at_ms, lcp_element_size
129
- ```
67
+ tracker 满 10 条或等待 10 秒触发发送,每个请求最多 10 条,50 条分为 5 个请求,尾批按实际条数发送。同一 SDK 模块内的 tracker 共用有序发送队列,每批完成(含重试)后发送下一批;每次请求尝试最多等待 5 秒,网络错误、超时及 5xx 最多尝试三次,4xx 结束该批。FCP 首次实测和 LCP 收口及时 flush,终态在最后一条记录统一 flush,然后发布业务报告。
130
68
 
131
- `detail` 只用于故障明细检索,不建立 group-by 索引;最大 200 字。ID 和哈希字段只用于精确查询和关联,不做高基数聚合。金额、输入内容、文件路径、完整堆栈和截图内容不登记。
69
+ 阈值校准优先使用完整终态派生指标,并按运行环境、形态和策略版本分组。Runtime 失联时,宿主发送失败终态并冲刷已收到的数据;缺失指标不视为零风险。
132
70
 
133
- ### 4.2 请求格式示例
71
+ ## 5. 请求示例与查询
134
72
 
135
- 单次 HTTP 请求是数组批次,Header 固定为 `Content-Type: application/json`、`Biz-Type: apm_fe`、`Batch: true`。终态会立即 flush,其他事件达到 10 条或等待 10 秒发送。以下为字段结构示例,数值不作为真实包实测结果。
73
+ 请求 Header 为 Content-Type: application/json、Biz-Type: apm_fe、Batch: true;请求体是 metric 数组,顶层信封由 tracker 统一生成。
136
74
 
137
75
  ```json
138
- [
139
- {
140
- "clientTime": 1791958348000,
141
- "context_sdkSessionId": "<tracker-session-uuid>",
142
- "context_pageSessionId": "<page-session-uuid>",
143
- "context_sdkSeqId": 52,
144
- "context_nameTracker": "wapT",
145
- "context_platform": "PC",
146
- "context_accountGeographicZone": "cn",
147
- "context_artifactName": "skillbuilder-miniapp",
148
- "context_artifactVersion": "0.1.10",
149
- "context_feSdkVersion": "1.3.13",
150
- "context_userId": "<reviewer-id>",
151
- "measurement_name": "miniapp_simulator_event",
152
- "measurement_data": {
153
- "event_name": "miniapp_audit_result",
154
- "timestamp": 1791958348000,
155
- "business_line": "mars",
156
- "sdk_version": "0.1.10",
157
- "renderer": "iframe-service-worker",
158
- "app_id": "playground-test-app",
159
- "simulator_session_id": "<simulator-session-uuid>",
160
- "review_task_id": "playground-review-task",
161
- "audit_session_id": "c179ed94-806f-46b1-8a2e-0da05c8361c8",
162
- "attempt_no": 1,
163
- "package_version": "playground-sample-v1",
164
- "package_hash": "<sha256>",
165
- "runtime_version": "development",
166
- "app_type": "tool",
167
- "policy_version": "phase1-fps-priority-v3-2026-10-19",
168
- "rules_version": "1.2.0",
169
- "probe_version": "1.1.1",
170
- "status": "scored",
171
- "blocking_passed": 1,
172
- "score_total": 100,
173
- "coverage_ratio": 1,
174
- "effective_ms": 47000,
175
- "sample_count": 48,
176
- "interaction_count": 1,
177
- "peak_heap_bytes": 3222161,
178
- "heap_growth_mb_per_min": 0.4698531312,
179
- "fps_p5": 120,
180
- "long_task_count": 0,
181
- "js_error_total": 0
182
- }
76
+ {
77
+ "context_artifactName": "skillbuilder-miniapp",
78
+ "measurement_name": "miniapp_simulator_event",
79
+ "measurement_data": {
80
+ "event_name": "miniapp_audit_result",
81
+ "business_line": "mars",
82
+ "app_id": "<app-id>",
83
+ "audit_session_id": "<audit-session-uuid>",
84
+ "attempt_no": 1,
85
+ "policy_version": "<policy-version>",
86
+ "app_type": "tool",
87
+ "name": "peak_heap",
88
+ "memory": 104857600,
89
+ "result": "scored",
90
+ "stage": "manual"
183
91
  }
184
- ]
185
- ```
186
-
187
- ## 5. 事件字段
188
-
189
- ### 5.1 `miniapp_audit_session`
190
-
191
- | 字段 | 类型 | 说明 |
192
- | -------------------- | ------- | ----------------------------------------------------------------------------------------------------- |
193
- | `stage` | string | `started`、`probe_ready`、`collecting`、`attempt_invalidated`、`stop_requested`、`finishing`、`finished`、`interrupted` |
194
- | `stage_seq` | number | 会话阶段递增序号 |
195
- | `session_elapsed_ms` | number | 相对评测启动时间 |
196
- | `reason_code` | string | 刷新、中断、失败或停止的稳定原因码;自动结束为 `pointer_leave_timeout`,手动为 `manual`,最长时限为 `duration_limit` |
197
- | `auto_stop_on_leave_ms` | number | `started` 携带本次离开自动结束延迟,默认 30000;0 表示关闭 |
198
- | `interaction_count` | number | 到达 guest 的真实操作累计值 |
199
- | `reload_count` | number | 本会话刷新次数 |
200
-
201
- 同一队列项中手动刷新时,发送 `attempt_invalidated`,随后 `attempt_no + 1`。不同 Realm 的样本不能拼接;失效 attempt 仍保留在 APM,供分析刷新原因和启动风险。
202
-
203
- ### 5.2 `miniapp_audit_sample`
204
-
205
- 每秒发送一个扁平样本:
206
-
207
- ```ts
208
- interface AuditSampleApmFields {
209
- sample_seq: number;
210
- session_elapsed_ms: number;
211
- phase: 'arming' | 'collecting';
212
- collecting_elapsed_ms?: number;
213
- heap_bytes?: number;
214
- tex_bytes: number;
215
- buf_bytes: number;
216
- canvas_bytes: number;
217
- img_bytes: number;
218
- wasm_bytes: number;
219
- workers: number;
220
- fps?: number;
221
- long_task_count: number;
222
- long_task_max_ms: number;
223
- js_error_count: number;
224
- net_pending: number;
225
- interaction_count: number;
226
92
  }
227
93
  ```
228
94
 
229
- `performance.memory` 不可用时省略 `heap_bytes`,不能写成 0。arming 与 collecting 都上报;评分只消费 collecting,分析可以单独查看启动尖峰和启动期 OOM。
230
-
231
- ### 5.2.1 `miniapp_audit_paint`
232
-
233
- | 字段 | 类型 | 说明 |
234
- | --- | --- | --- |
235
- | `fcp_ms` / `lcp_ms` | number | 相对 guest 导航的毫秒;缺失时省略,不填 0 |
236
- | `fcp_status` / `lcp_status` | string | pending、measured、unsupported、hidden;终态无探针证据时为 not_reported |
237
- | `lcp_finalized` | number | 1 已收口,0 仍是候选 |
238
- | `paint_finalize_reason` | string | interaction、hidden、pagehide、audit-stop |
239
- | `paint_finalize_event` | string | 触发 LCP 收口的输入事件:touchstart、pointerdown、mousedown、keydown、input、change、click、scroll;非输入收口时省略 |
240
- | `lcp_finalized_at_ms` | number | 首次收口相对 guest 导航的毫秒;后续操作或停止评测不延长截止时间 |
241
- | `lcp_element_tag` | string | 候选元素标签,例如 img、p、h1;不包含文本、选择器或 URL |
242
- | `lcp_element_size` | number | 浏览器报告的候选可见面积,单位为平方 CSS 像素;缺失时省略 |
243
- | `paint_timing_source` | string | guest-navigation |
244
- | `session_elapsed_ms` | number | 当前事件相对评测启动时间,与导航绘制时钟区分 |
245
-
246
- 首个实测 FCP 和 LCP 收口要求 tracker 立即 flush,LCP 候选变化按现有批量策略发送,observer 的相同快照去重。停止时 guest 再返回一次收口确认。首屏数据独立于 3 秒预热与 30 秒有效采样门槛,短会话或 unscorable 也可观测。停止时最多等待 150ms 排空探针待处理记录;未确认收口的 LCP 不计分。
247
-
248
- `miniapp_audit_result` 同时携带这些字段,另带 `score_fcp`、`score_lcp`、`fcp_threshold_ms`、`lcp_threshold_ms`,用于按策略版本分析曲线与总分影响。运行过程上报 `fps_median` 与 `fps_p5`,并记录 `score_fps`、`score_long_task`、`score_js_error` 和 `weight_fps`、`weight_long_task`、`weight_js_error`。权重取自实际报告,包括 Apollo 生效后的数值;本地默认依次为 5、1、0.5。JS 异常数量和事故证据完整上报,默认不因单条 JS 异常触发硬卡口。以上新增 measurement 字段均为数值,缺失时省略。
249
-
250
- 探针 `1.1.1` 在捕获阶段处理首次输入,包括模拟器转发的 `input/change`,先固定 LCP 截止时间,再排空截止前的候选;搜索、分类切换和分页后的候选不进入首屏评分。`miniapp_audit_paint` 与 `miniapp_audit_result` 共用上述绘制字段,用于核对采集值、收口依据与最终分数。
251
-
252
- 看板以最终有效 attempt 的 result 为去重入口,FCP 筛选 measured,LCP 筛选 measured 且 `lcp_finalized = 1`,再计算 P50/P75/P95 和缺失率,避免把候选事件重复计入分布。按策略、规则、探针版本、形态和浏览器/设备环境分组。初始良好边界为 FCP ≤1800ms、LCP ≤2500ms,约 90 分;控制点 3000/4000ms 为 50 分。桌面模拟器不代表移动端 field Web Vitals;Canvas/WebGL 不属于 LCP,游戏核心可用性仍需交互确认。
253
-
254
- ### 5.3 `miniapp_audit_incident`
255
-
256
- | 字段 | 类型 | 说明 |
257
- | -------------------- | ------ | --------------------------------------------------------------------------------------- |
258
- | `incident_seq` | number | 会话内递增序号 |
259
- | `session_elapsed_ms` | number | 相对评测启动时间 |
260
- | `phase` | string | `arming` 或 `collecting` |
261
- | `kind` | string | `contextLost`、`jsFatal`、`infraError`、`guestLost`、`simulatorGuard`、`probeSaturated` |
262
- | `source` | string | `app`、`simulator-sdk` 或 `audit-probe` |
263
- | `detail` | string | 最多 200 字的脱敏摘要 |
264
-
265
- JS 异常累计值仍在 sample/result 中上报;incident 只保留首三次代表性错误,避免同一异常刷爆 APM。
266
-
267
- ### 5.4 `miniapp_audit_package`
268
-
269
- 静态包只上报当前评分和阈值分析需要的聚合值:
270
-
271
- - `zip_bytes`、`unpacked_bytes`、`file_count`;
272
- - `largest_image_bytes`、`largest_uncompressed_js_bytes`;
273
- - `wasm_file_count`、`worker_file_count`、`media_file_count`;
274
- - `has_webgl`、`has_canvas2d`、`has_wasm`、`has_worker`、`has_video`,均为 0/1 number;
275
- - `declared_app_type`、`detected_app_type`。
276
-
277
- 不逐文件上报路径和大小。APM 可以重放已有静态指标的阈值,但无法用历史数据新增依赖完整文件清单的规则;新增这类规则时需要先补对应聚合字段,再积累样本。
278
-
279
- ### 5.5 `miniapp_audit_result`
280
-
281
- | 分类 | 字段 |
282
- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
283
- | 终态 | `status`、`failure_code`、`blocking_passed`、`enforced`、`stop_reason`、`auto_stop_on_leave_ms` |
284
- | 分数 | `score_total`、`score_memory`、`score_stability`、`score_performance`、`score_experience`、`score_package` |
285
- | 质量 | `coverage_ratio`、`effective_ms`、`complete`、`sufficient`、`sample_count`、`interaction_count`、`first_interaction_ms`、`reload_count`、`probe_saturated` |
286
- | 关键指标 | `peak_heap_bytes`、`heap_growth_mb_per_min`、`tex_watermark_bytes`、`buf_watermark_bytes`、`canvas_bytes`、`img_bytes`、`wasm_bytes`、`max_workers`、`fps_median`、`fps_p5`、`long_task_count`、`long_task_max_ms`、`js_error_total` |
287
- | 流畅度与稳定性评分 | `score_fps`、`score_long_task`、`score_js_error`;实际权重 `weight_fps`、`weight_long_task`、`weight_js_error` |
288
- | 风险 | `blocking_failure_count`、`primary_blocking_code`、`infrastructure_error_count`、`truncated_reason_code` |
289
-
290
- 分类分统一换算为 0~100:`got / max * 100`;分类没有适用项时省略该字段,不能按 0 分上报。逐项数组和 N/A 文本不进入 APM,改为稳定的计数、原因码和关键指标字段。
291
-
292
- `stop_reason` 区分 `manual`、`pointer_leave_timeout`、`duration_limit`、`interrupted`。正常 Runtime 终态携带该字段;宿主生成的失联/销毁失败报告仍通过 `failure_code` 判断,不把缺失的停止原因当作手动结束。按停止方式关联有效时长、样本数和证据不足率,可评估 30 秒是否合适。自动结束不伪造输入次数或功能完成状态,短会话仍上报 `unscorable`。
293
-
294
- `score_stability` 为独立的稳定性分类,当前仅包含低权重 JS 异常。面板展示顺序为运行性能、包体积、稳定性、内存。长任务默认按 500ms 满分、3000ms 零分的线性曲线评分,权重为 1;原始次数和最长时长继续保留,单次几百毫秒阻塞不作为硬风险。
295
-
296
- ## 6. 上报链路
297
-
298
- ```text
299
- guest 探针
300
- → Runtime AuditSession
301
- → MessageChannel 发送扁平 audit telemetry
302
- → Remote Client 宿主 tracker
303
- → APM 批量上报
304
- ```
305
-
306
- 评测样本由宿主 tracker 发送,不由 Runtime 直接发送。宿主与 guest/Runtime 不共用被测主线程:Runtime 卡死后,宿主仍可把已经收到但尚未满批的 sample 冲刷到 APM,并发送 `RUNTIME_HUNG` 终态。
307
-
308
- 现有 tracker 的 10 条/10 秒批量策略保持不变:
309
-
310
- - 收到终态、页面隐藏或模拟器销毁时立即 `flush()`;
311
- - 使用 `fetch(..., { keepalive: true })` 保全页面离开前的批次;
312
- - 检查 HTTP `response.ok`,网络错误和 5xx 最多进行 3 次内存重试;
313
- - 重试使用短退避且不阻塞审核结算;
314
- - 每个批次完成后通过 `onTrackerDelivery({ ok, status, attempts, eventCount })` 暴露投递回执,回调不包含事件正文;
315
- - 队列进入下一项前先提交当前会话终态,再完整重载模拟器;
316
- - APM 关闭、拒绝或最终重试失败时静默降级,不改变审核结果。
317
-
318
- 不建设跨页面补传库。APM 作为唯一数据通道时,必须确认评测事件不被服务端采样、字段可检索、保留周期覆盖指标校准周期,并有足够事件配额。否则丢失的数据无法从其他存储恢复。
319
-
320
- ## 7. 队列内时序
321
-
322
- ```text
323
- Mars 进入队列项
324
- → 传入 review_task_id / app_id / package_version
325
- → Remote Client 计算 package_hash,创建 simulator_session_id
326
- → Runtime 创建 audit_session_id
327
- → miniapp_audit_session(stage=started)
328
- → 探针 document-start 安装
329
- → arming / collecting 样本按 1 Hz 发给宿主并进入 APM
330
- → 审核员真实操作主要功能并检查结果
331
- → 异常实时发送 miniapp_audit_incident
332
- → 离开整个模拟器容器(含留白与评测面板) 30 秒、点击“停止评测”,或达到最长时钟
333
- → miniapp_audit_package + miniapp_audit_result
334
- → 宿主 flush APM 批次
335
- → 完整重载模拟器,处理下一队列项
336
- ```
337
-
338
- 自动截图关闭时,以上时序不变。截图失败或缺失不影响六类评测 APM 事件。
339
-
340
- 停止仅结束采集,`complete` 表示正常收口,不表示主要功能已完成或审核通过。使用证据记录真实输入次数、首次操作时间、有效采集时长和样本数;主要功能是否完成由审核员按 SOP 判断。六类事件及离开自动结束均由模拟器内部处理,不要求 Mars 提供人工审核结论或调用停止接口。倒计时内移回模拟器容器内会取消,区域外持续真实输入会延后;到期生成报告后宿主立即 flush。若先刷新或销毁,则按中断链路尽力上报已收到的数据,不保证完整终态送达;上报失败不阻塞审核流转。
341
-
342
- ## 8. 指标校准
343
-
344
- ### 8.1 数据重建
345
-
346
- 通过 `audit_session_id + attempt_no` 查询 `miniapp_audit_sample`,按 `sample_seq` 排序即可重建时序。使用 `miniapp_audit_result` 确认当时的版本、终态和证据质量,并关联同一会话的首屏、包体和事故事件。
347
-
348
- 进入阈值分布的样本必须满足:
349
-
350
- - `status = scored`;
351
- - 真实操作数、有效时长与样本数满足策略;
352
- - 采集完整、覆盖度达标、版本字段齐全;
353
- - 同一分析批次使用兼容的 probe/rules 口径。
354
-
355
- `unscorable` 和 `loadFailed` 单独分析,不混入正常分数分布,也不能从故障率中删除。
356
-
357
- ### 8.2 调整步骤
358
-
359
- 1. 按 app type 计算关键指标的 P50、P75、P90、P95、P99 和缺失率;
360
- 2. 按高低分、风险类型和证据不足原因选取内部复测样本,实际操作并检查功能与体验;
361
- 3. 从 APM 导出 sample 事件,用候选策略离线重算;
362
- 4. 对比候选策略的分数分布、风险命中、缺失率和有效采集时长;使用有明确复测结论的内部样本检验误报和漏报;
363
- 5. 生成新的 `policyVersion`,以 `enforce: false` 灰度到指定业务线或 app;
364
- 6. 覆盖一个完整校准周期后,再决定是否扩大试跑范围;一期保持观察,不作为审核强卡口。
365
-
366
- 样本量不足的 profile 只展示分布,不自动调整阈值。指标分布和评分不能代替真实功能结论,也不能单独证明误报率或漏报率;内部复测结论需由分析人员整理,不由模拟器自动推断。分析任务只能产出候选策略,不能直接写 Apollo。
367
-
368
- ### 8.3 首批看板
369
-
370
- - 每日评测量、三态比例、有效采集率;
371
- - 评测会话耗时、有效采集时长、首次操作时间、真实交互次数和零交互占比;
372
- - 各 app type 的关键指标分位数和缺失率;
373
- - 硬风险命中率、风险类型分布和分数分布;
374
- - JS 异常、context lost、Runtime hung 和资源熔断趋势;
375
- - `policy_version / rules_version / probe_version` 覆盖情况;
376
- - APM 请求成功率、批量大小、重试率和丢弃事件数。
377
-
378
- ## 9. 代码落点
379
-
380
- | 位置 | 改造内容 |
381
- | ----------------------------------------------------------- | -------------------------------------------------------------------- |
382
- | `packages/miniapp-audit-plugin/src/collector/session.ts` | 保留 arming/collecting 样本;为 sample、incident 和 attempt 分配序号 |
383
- | `packages/miniapp-audit-plugin/src/index.ts` | 增加逐样本、事件和阶段的 telemetry 回调 |
384
- | `packages/miniapp-simulator/src/remote/audit-controller.ts` | 生成 UUID、会话字段和 package 扁平摘要 |
385
- | `packages/miniapp-simulator/src/remote/runtime.ts` | 通过 MessageChannel 把 audit telemetry 发送给宿主 |
386
- | `packages/miniapp-simulator/src/remote/client.ts` | 消费 telemetry、扁平化 result 并交给 APM;看门狗发送卡死终态 |
387
- | `packages/miniapp-simulator/src/remote/load-timing.ts` | 从只支持 load stage 扩展为内部通用自定义点位上报 |
388
- | `packages/miniapp-simulator/src/tracker/default-tracker.ts` | 检查响应、有限重试和终态 flush |
389
- | Mars 接入层 | 传入队列/包身份,消费评测报告 |
390
-
391
- 模拟器服务端不新增评测数据接口和存储,只继续提供 Runtime、插件与动态策略。
392
-
393
- ## 10. 验收标准
394
-
395
- - 使用 `audit_session_id` 能在 APM 查到 session、sample、paint、incident、package 和 result;
396
- - 六类评测事件由模拟器内部产生和上报,不依赖人工审核结论回调;
397
- - 连续处理多个队列项时,样本、attempt、包版本和评测结果不会串包;
398
- - 手动刷新后的新 Realm 使用新的 `attempt_no`,时序不与失效 attempt 拼接;
399
- - Runtime 卡死后,宿主仍会冲刷已收到的样本并发送 `RUNTIME_HUNG` result;
400
- - 关闭自动截图后,全部评测 APM 事件仍正常产生;
401
- - APM 中没有大 JSON、文件清单、输入内容、错误全文或截图二进制;
402
- - 从 APM 导出的 sample 能使用指定策略版本重算,并与原 result 对账;
403
- - APM 的事件配额、无采样配置、字段检索和保留周期满足一次完整校准;
404
- - APM 上报失败不阻塞审核队列,成功率、重试和丢弃量可监控。
405
-
406
- ## 11. 当前实现状态
407
-
408
- 模拟器已实现以下数据链路:
409
-
410
- - arming 和 collecting 的 1 Hz 原始样本、异常、会话阶段、包体摘要和三态结果通过 MessageChannel 送到宿主;
411
- - 宿主 tracker 分别上报 `miniapp_audit_session`、`miniapp_audit_sample`、`miniapp_audit_paint`、`miniapp_audit_incident`、`miniapp_audit_package` 和 `miniapp_audit_result`;
412
- - `auditContext` 接收 `reviewTaskId`、`packageVersion` 和可选制品哈希;未传哈希时由 Remote Client 对 ZIP 或稳定排序后的文件表计算 SHA-256;
413
- - 终态立即 flush,Runtime 卡死、会话销毁和老 Runtime 无内部 telemetry 时由宿主补终态;
414
- - APM 请求检查 HTTP 状态,网络错误和 5xx 最多尝试三次,4xx 不重试;
415
- - `onTrackerDelivery` 返回批次是否成功、HTTP 状态、尝试次数和事件数,Playground 会把回执显示在事件区;
416
- - 模拟器服务端没有评测数据接口或存储。
95
+ - 首屏:按 name=fcp/lcp 查询 time;LCP 仅统计 paint 事件中 stage=finalized、result=measured 的记录。
96
+ - 包体:name=zip_size/unpacked_size,size 为原始字节数;score/weight 为对应评分及权重。
97
+ - 内存:name=peak_heap/heap_p95 查询 memory;name=heap_growth 查询 value,unit=MB/min。
98
+ - 流畅度:name=fps_median/fps_p5 查询 value,unit=fps;name=long_task_max 查询 time。
99
+ - 摘要:name=total_score 的 score 为总分、ratio 为覆盖率、time 为有效采集毫秒数、count 为风险数量;message.result_record_count 为该终态预期记录条数;message.quality 记录样本数、交互数、完整性、证据充足和探针饱和等状态。
100
+ - 事故和分类:total_score 的 message.failure_code 为主要风险码,message.classification 为引擎、框架、置信度和有界证据,message.category_scores 为分类得分。
101
+ - 证据:正常 Runtime 与宿主失败补报均直接使用公共字段;同一 audit_session_id + attempt_no 关联记录,终态去重并整组冲刷。
417
102
 
418
- 业务接入和数据运营需要完成:
103
+ ## 6. 发送端与版本核对
419
104
 
420
- - Mars 创建模拟器时传入真实队列项和包版本,并消费评测报告;
421
- - 确认六类事件在 APM 侧关闭采样、字段可检索、配额和保留周期满足校准周期;
422
- - 建设 APM 数据导出、时序重建、阈值回放、请求成功率和分析看板。
105
+ 评测采集和记录生成由 Runtime 执行;APM 网络发送由宿主 SDK 执行。Runtime 发布与宿主 SDK 升级分别生效。核对发送行为时检查 sdk_version,核对采集和记录结构时检查 runtime_version。APM 仅有请求发出或 HTTP 成功不能证明完整入库;按 context_sdkSessionId + context_sdkSeqId 检查连续性,按 audit_session_id + attempt_no 检查摘要及核心指标是否齐全。
@@ -150,7 +150,7 @@ WebGL 包已核对真实发送路径的 APM 请求体:`measurement_name=miniap
150
150
  | 有效使用 | 至少 1 次输入到达 guest;审核员按 SOP 检查主要功能,静态无交互包不出分 |
151
151
  | 异常收口 | Runtime 12 秒无进度产生 `loadFailed:RUNTIME_HUNG`;熔断和失联产生 `unscorable` 或结构化失败 |
152
152
  | 结论显示 | 硬风险统一为“需复核”,总分红色显示,不允许只按分数放行 |
153
- | APM 上报 | 上报任务、应用、包版本、策略版本、1 Hz 时序、FCP/LCP、包体摘要、操作证据、三态终态和风险 |
153
+ | APM 上报 | 上报任务、应用、包版本、策略版本、终态派生指标、FCP/LCP、包体摘要、操作证据、三态终态和风险 |
154
154
  | Mars 集成 | 在真实审核队列完成连续 20 包回归,确认切换、超时、刷新和结果保存不阻塞审核员 |
155
155
  | 策略状态 | 保持 `enforce: false`,完成真机相关性与阈值回放后再评估自动卡口 |
156
156