ソースを参照

docs(perf): diagnose post-maintenance latency and plan optimization

彭峰 6 時間 前
親
コミット
81f8b442fe

+ 50 - 0
perf/recovery-performance-2026-11-14/BASELINE.md

@@ -0,0 +1,50 @@
+# 恢复后性能基线
+
+2026-11-14;仅诊断,未部署优化。完整口径、限制及方案见 PLAN.md;脱敏逐次样本见 baseline.json。
+
+## 绕过代理:主要结论
+
+测量时段 UTC:2026-11-14T03:56:17.821Z 至 2026-11-14T04:01:11.200Z(北京时间 +8 小时)。
+
+| 页面 | 成功加载 | p50 秒 | p75 秒 | p95 秒 | 外壳 p75 秒 | 长任务累计 p75 毫秒 |
+|---|---:|---:|---:|---:|---:|---:|
+| 老师首页 | 10/10 | 6.87 | 7.71 | 9.18 | 2.30 | 58 |
+| 学生首页 | 10/10 | 12.10 | 14.32 | 20.34 | 2.31 | 60 |
+| 老师当天课表 | 10/10 | 3.14 | 5.15 | 6.62 | 2.31 | 64 |
+| 学生当天课表 | 10/10 | 3.12 | 6.16 | 6.64 | 2.34 | 59 |
+
+## 系统代理:辅助复现,不能与直连组作优化 A/B
+
+测量时段 UTC:2026-11-14T03:50:51.064Z 至 2026-11-14T03:55:20.666Z(北京时间 +8 小时)。
+
+| 页面 | 成功加载 | p50 秒 | p75 秒 | p95 秒 | 外壳 p75 秒 | 长任务累计 p75 毫秒 |
+|---|---:|---:|---:|---:|---:|---:|
+| 老师首页 | 10/10 | 6.03 | 7.04 | 9.63 | 2.36 | 58 |
+| 学生首页 | 10/10 | 9.66 | 14.84 | 17.94 | 2.24 | 60 |
+| 老师当天课表 | 10/10 | 4.38 | 6.18 | 6.46 | 2.20 | 61 |
+| 学生当天课表 | 10/10 | 3.88 | 5.90 | 6.61 | 2.30 | 59 |
+
+## 直连业务接口
+
+接口耗时包含网络与响应读取,不能等同于 SQL 执行时间;首字节等待包含网关、服务和网络。
+
+| 页面 / 接口 | 样本数 | p75 秒 | p95 秒 | 发出请求至首字节 p75 秒 |
+|---|---:|---:|---:|---:|
+| 老师首页 / e_order_tongji | 10 | 5.28 | 6.50 | 5.02 |
+| 老师首页 / app_review_page | 10 | 4.47 | 6.97 | 4.16 |
+| 学生首页 / e_order_tongji | 10 | 3.10 | 7.24 | 2.84 |
+| 学生首页 / app_account_overview | 10 | 5.20 | 5.23 | 4.95 |
+| 学生首页 / app_review_page | 10 | 11.89 | 17.29 | 11.54 |
+| 老师当天课表 / app_companion_overview | 10 | 2.82 | 3.80 | 2.52 |
+| 学生当天课表 / app_companion_overview | 10 | 3.81 | 4.08 | 3.62 |
+
+学生复习同步状态计数:{"unavailable":1,"conflict":9}。HTTP 200 / 页面已显示数据不代表旧系统同步成功。
+
+## 网络对照与限制
+
+- xiaoshu 直连健康检查:10/10 HTTP 200;总耗时 p75 0.25 秒。
+- shared 直连健康检查:10/10 HTTP 200;总耗时 p75 0.24 秒。
+- 本机系统代理开启;代理路径曾出现约 5 秒的 URLError,没有取得服务端 HTTP 状态。不能据此宣称服务器又返回 503。绕过代理的页面仍慢,代理不是全部原因。
+- 冷启动所记录资源传输量约 0.58 MB;这是 Resource Timing 可见资源量,不含缺少跨域 Timing-Allow-Origin 的 API 字节,也不完整包含主文档。API 解码后响应大小另记,二者不可混称带宽用量。
+- 这不是设备端真实用户统计,没有 CrUX/RUM 的认证后页面数据;未做低端 CPU、热返回、开课或语音测量。
+- 页面样本全部完成与否按表列出;本脚本未完整收集 requestfailed 事件,不能用它宣布网络失败率为零。没有发布优化候选,因此没有优化收益百分比。

+ 54 - 0
perf/recovery-performance-2026-11-14/PLAN.md

@@ -0,0 +1,54 @@
+# 维护恢复后的性能诊断与优化方案
+
+日期:2026-11-14。状态:**诊断与方案,不包含上线批准。没有部署代码或修改生产配置。**
+
+## 测量口径与证据边界
+
+- 真实老师、学生会话,各覆盖首页与当天课表;一页一页访问,没有并发压测,没有操作开课、结课、取消预约、充值或扣费。
+- Chrome,390×844,Asia/Shanghai;每次新浏览器上下文,冷缓存,Fast 4G(增加 20ms 延迟、4Mbps 下行、3Mbps 上行),CPU 不限速。数字包含实际线路延迟,不等同于真实学生手机的 RUM。
+- “可用”要求关键统计、列表和刷新按钮加载完成,没有对应错误状态,统计/条数稳定 500ms;不以页面外壳或标题出现为终点。该 500ms 稳定窗口包含在报告耗时内。
+- 四种页面各十次,交替测量。先测系统默认代理路径,再绕过系统代理复测;两组不能当成优化前后 A/B,也不能将差额全部归因于代理,因为测量时段不同。
+- 分位数使用 nearest-rank:排序后第 ceil(n×p) 个值;n=10 时 p95 是该组最大值。失败单独统计,不作为快速样本。
+- 页面使用现有业务接口;学生复习的既有读取接口自身会执行旧系统同步,本次没有改写这一行为。未新增诊断云函数或修改公共服务。
+- 只覆盖两个账号的代表性页面。未进行全体账号、真实低端手机、课堂切词/语音、后台所有模块或高并发验收;不能据此宣布全系统性能已经达标。
+
+具体测量数值和脱敏原始样本见本目录 BASELINE.md、baseline.json。账号、token、接口原文保存在本机私有诊断目录,不入 Git。
+
+## 已证实的链路问题
+
+1. **学生首页复习读取依赖旧系统同步完成。** 回读当前生产网关,`appReviewPage` 先 `await syncLegacyReviews`,然后才能启动本地复习列表/统计查询。`performLegacyReviewSync` 先拉旧系统第一页 500 条,缺数时可继续拉页;单次旧接口请求的超时上限是 12 秒。随后 `applyLegacyReviewRecords` 开启事务、获取学员 advisory lock、比对记录并按需补写。即使已有记录,也需要完成旧系统请求及比对。这条依赖关系已确认,但本轮没有插入服务端计时,不能将接口总耗时全部算作旧系统网络等待。
+2. **一个页面读取会触发多项数据库汇总和版本查询。** 复习接口包含 summary、count、rows、可选 dates/students/income,以及 review/account 版本;学生端默认还取日期元数据。教师“今天”请求的列表限定今天,但汇总基于过滤今天之前的范围;每页又重复计算汇总/版本。课表也读取日期汇总、人员选项、总数、列表和版本。SQL 次数和范围是确定的优化对象,哪条 SQL 最慢仍需执行计划及阶段计时。
+3. **浏览器加载有固定成本,但不是多秒接口波动的充分解释。** 冷启动资源下载、路由模块加载在业务接口前;应优化首屏资源,同时避免把服务等待误判成动画或 CSS 问题。
+
+直连复测还捕获了学生复习的 `legacyReviewSync.state=unavailable`,以及多次 `conflict`(同一测试学生拉取 60 条、冲突 3 条、写入 0 条)。这是现有来源保护机制的结果,不能为了提速强行覆盖或删除冲突。当前学生首页没有展示该同步状态;因此“页面已显示已有数据”和“旧系统数据同步成功”必须分别计数、分别提示。应给冲突生成可核对的处理记录,避免每次打开首页都重复等待同一批比对。
+
+生产网关仍包含今早的运行环境兼容标记 `XIAOSHU_ISOLATED_RUNTIME_COMPAT_V1`,两条网关的 updatedAt 为 2026-11-14T00:38:27.640Z。本轮没有发现兼容补丁被覆盖。
+
+## 必须继续核实的运行环境因素
+
+今早事故记录曾捕获业务连接池 max=2、连接超时 5 秒,以及实际连接获取超时;这属于**维护完成前的证据**,不是现在的配置结论。维护方需要提供恢复后的:
+
+- 小树租户所在实例/worker 数量、重启与冷启动时间线,入口 upstream connect/header/response time;同一请求的 request ID。
+- 各实例数据库池 max、active/idle/waiting、获取连接耗时、超时数;数据库总连接预算、慢查询、锁等待和资源利用率。
+- 旧系统请求耗时,以及云函数中认证、旧系统同步、连接获取、SQL、序列化各阶段耗时。
+- 当前函数执行器是否每次请求重新创建函数作用域。今早 worker 快照使用 `new Function(...code...)`;若仍如此,网关顶层 Map 的 10 秒缓存不能可靠跨请求复用。当前运行语义需维护方确认。
+
+不要直接把连接池从 2 大幅调高。先核算“实例数×每实例连接数”的总预算,确认等待来自连接获取还是慢 SQL/锁,再小范围验证。不得改动其他租户服务。
+
+## 优化顺序
+
+| 优先级 | 工作 | 具体方案 | 正确性与验证 |
+|---|---|---|---|
+| P0 | 恢复后的稳定性与定位 | 维护方补齐上述阶段计时和连接池指标,区分入口、worker、数据库与旧系统 | 先消除连接超时/503;任何配置调整单独评审、回滚,不以健康检查 200 代替业务恢复 |
+| P1 | 学生复习读写解耦 | 首屏先读小树已同步数据;旧系统增量同步由有租约的任务承接,合并同一学员的同步请求并限制并发;新增可见的更新时间/同步状态 | 不能悄悄显示陈旧结果;完成复习、开结课、取消预约等写入以服务端最新状态核验,保留来源保护、冲突记录、事务和幂等键。未同步的新数据有明确状态与补偿重试 |
+| P1 | 减少查询数量及扫描范围 | 首页专用轻量读模型;今日任务统计按正确口径计算,分页后续页复用同一版本的统计;日期/人员元数据按需;合并 count/summary 或复用查询结果;版本查询改为可失效的轻量版本记录 | 先在隔离数据跑 EXPLAIN (ANALYZE, BUFFERS) 和结果对照,再决定索引;不得盲加索引或删掉学生需要的逾期/未来统计。验证任务总数、顺序、日期边界、收入与账本一致 |
+| P1 | 降低突发请求压力 | 按租户/接口限制数据库并发,合并相同读取;确认缓存生命周期并采用有界缓存;轮询增加抖动、隐藏页暂停、恢复事件合并、故障退避 | 保留跨设备排课更新;写入后精确失效;重试有总预算。已有首页缓存、隐藏暂停、并发限制不能当作本次新增成果 |
+| P2 | 冷启动与页面响应 | 分析首屏 bundle,延后非首页模块;优化 logo 等静态资源;检查版本化资源缓存;各面板独立可用,返回页面先展示明确标注的已有数据再校验 | 使用同一 ready 条件;不把旧数据冒充新数据,不隐藏接口错误;不通过延长超时或只改提示文案冒充提速 |
+
+## 验证与发布门槛
+
+1. 先在本地/隔离环境实施候选,一次只验证一个主要机制;同数据、同网络、同设备交替 A/B、B/A,每组至少 10 次,同时记录 p50/p75/p95、失败率、API 次数、SQL 次数、连接等待与长任务。
+2. 初步目标:核心四页面 Fast 4G 冷启动 p75 ≤3秒、p95 ≤5秒,热返回 p75 ≤1秒;关键轻量 API p75 ≤800ms、p95 ≤2秒。这是候选验收目标,**不是已达到或保证的收益**。数据新鲜度与跨设备一致性另设指标,不能用无限缓存换速度。
+3. 回归已授权真实身份的只读页面;隔离环境验证开课、结课、重复提交、预约取消、旧系统同步冲突、课时预留/释放、来源流水,保证没有重复扣课时或教师收入变化。
+4. 扩展到后台登录后加载、会员搜索、排课及批量操作结果核对,并补充多教师/多学生、低端手机、正常教学负载;不在生产做无边界压测。
+5. **等用户明确通知上线后**,再备份当前函数/静态版本、选择性发布、分批回读和业务验收;发现错误率上升、账务差异或 p95 退化立即回滚本批。当前只保存诊断与方案。

+ 3331 - 0
perf/recovery-performance-2026-11-14/baseline.json

@@ -0,0 +1,3331 @@
+{
+  "method": {
+    "runsPerCohort": 10,
+    "network": "Fast4G: added latency 20ms; download 4Mbps; upload 3Mbps",
+    "viewport": "390x844",
+    "cpu": 1,
+    "cache": "new context each sample",
+    "readyStabilityMs": 500,
+    "percentile": "nearest rank",
+    "scope": "presentation ready with existing data; source synchronization tracked separately"
+  },
+  "groups": {
+    "system-proxy": {
+      "rows": [
+        {
+          "cohort": "teacher-home",
+          "run": 1,
+          "at": "2026-11-14T03:50:51.064Z",
+          "ok": true,
+          "readyMs": 6026,
+          "shellMs": 2475,
+          "elapsedMs": 6033,
+          "longTaskMs": 57,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 1134,
+              "startMs": 2048,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 3457,
+              "startMs": 2049,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 1,
+          "at": "2026-11-14T03:51:06.172Z",
+          "ok": true,
+          "readyMs": 14843,
+          "shellMs": 1781,
+          "elapsedMs": 14848,
+          "longTaskMs": 61,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 536,
+              "startMs": 1723,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 3896,
+              "startMs": 1723,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 12608,
+              "startMs": 1724,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 1,
+          "at": "2026-11-14T03:51:09.354Z",
+          "ok": true,
+          "readyMs": 2921,
+          "shellMs": 2165,
+          "elapsedMs": 2927,
+          "longTaskMs": 59,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 594,
+              "startMs": 1826,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 1,
+          "at": "2026-11-14T03:51:15.101Z",
+          "ok": true,
+          "readyMs": 5503,
+          "shellMs": 2203,
+          "elapsedMs": 5508,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 3119,
+              "startMs": 1876,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 2,
+          "at": "2026-11-14T03:51:20.335Z",
+          "ok": true,
+          "readyMs": 4985,
+          "shellMs": 2156,
+          "elapsedMs": 4991,
+          "longTaskMs": 61,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 2673,
+              "startMs": 1798,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 2,
+          "at": "2026-11-14T03:51:27.202Z",
+          "ok": true,
+          "readyMs": 6459,
+          "shellMs": 2255,
+          "elapsedMs": 6463,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 4021,
+              "startMs": 1925,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 2,
+          "at": "2026-11-14T03:51:37.789Z",
+          "ok": true,
+          "readyMs": 10351,
+          "shellMs": 1769,
+          "elapsedMs": 10356,
+          "longTaskMs": 58,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 477,
+              "startMs": 1713,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 4357,
+              "startMs": 1714,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 8135,
+              "startMs": 1714,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 2,
+          "at": "2026-11-14T03:51:42.618Z",
+          "ok": true,
+          "readyMs": 4595,
+          "shellMs": 2211,
+          "elapsedMs": 4599,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 997,
+              "startMs": 1853,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 2215,
+              "startMs": 1854,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 3,
+          "at": "2026-11-14T03:51:49.218Z",
+          "ok": true,
+          "readyMs": 6365,
+          "shellMs": 2131,
+          "elapsedMs": 6370,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 413,
+              "startMs": 1762,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 4080,
+              "startMs": 1761,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 3,
+          "at": "2026-11-14T03:52:01.221Z",
+          "ok": true,
+          "readyMs": 11757,
+          "shellMs": 1802,
+          "elapsedMs": 11761,
+          "longTaskMs": 60,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_account_overview",
+              "ms": 380,
+              "startMs": 1748,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 568,
+              "startMs": 1748,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 9495,
+              "startMs": 1749,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 3,
+          "at": "2026-11-14T03:52:07.938Z",
+          "ok": true,
+          "readyMs": 6453,
+          "shellMs": 2189,
+          "elapsedMs": 6458,
+          "longTaskMs": 61,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 4116,
+              "startMs": 1845,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 3,
+          "at": "2026-11-14T03:52:11.075Z",
+          "ok": true,
+          "readyMs": 2901,
+          "shellMs": 2182,
+          "elapsedMs": 2905,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 442,
+              "startMs": 1942,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 4,
+          "at": "2026-11-14T03:52:15.228Z",
+          "ok": true,
+          "readyMs": 3884,
+          "shellMs": 3290,
+          "elapsedMs": 3890,
+          "longTaskMs": 59,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 386,
+              "startMs": 2978,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 4,
+          "at": "2026-11-14T03:52:18.271Z",
+          "ok": true,
+          "readyMs": 2803,
+          "shellMs": 2152,
+          "elapsedMs": 2809,
+          "longTaskMs": 59,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 530,
+              "startMs": 1772,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 4,
+          "at": "2026-11-14T03:52:33.900Z",
+          "ok": true,
+          "readyMs": 15409,
+          "shellMs": 2142,
+          "elapsedMs": 15414,
+          "longTaskMs": 58,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 366,
+              "startMs": 1760,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 4655,
+              "startMs": 1761,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 13134,
+              "startMs": 1761,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 4,
+          "at": "2026-11-14T03:52:40.889Z",
+          "ok": true,
+          "readyMs": 6685,
+          "shellMs": 2358,
+          "elapsedMs": 6689,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 1201,
+              "startMs": 1947,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 4232,
+              "startMs": 1947,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 5,
+          "at": "2026-11-14T03:52:46.513Z",
+          "ok": true,
+          "readyMs": 5388,
+          "shellMs": 1748,
+          "elapsedMs": 5392,
+          "longTaskMs": 59,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 1116,
+              "startMs": 1696,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 3184,
+              "startMs": 1697,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 5,
+          "at": "2026-11-14T03:52:55.735Z",
+          "ok": true,
+          "readyMs": 8986,
+          "shellMs": 2165,
+          "elapsedMs": 8990,
+          "longTaskMs": 58,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 1851,
+              "startMs": 1746,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 5248,
+              "startMs": 1745,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 6728,
+              "startMs": 1745,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 5,
+          "at": "2026-11-14T03:53:02.203Z",
+          "ok": true,
+          "readyMs": 6177,
+          "shellMs": 2124,
+          "elapsedMs": 6181,
+          "longTaskMs": 61,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 3874,
+              "startMs": 1790,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 5,
+          "at": "2026-11-14T03:53:05.190Z",
+          "ok": true,
+          "readyMs": 2753,
+          "shellMs": 2194,
+          "elapsedMs": 2757,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 360,
+              "startMs": 1888,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 6,
+          "at": "2026-11-14T03:53:11.390Z",
+          "ok": true,
+          "readyMs": 5904,
+          "shellMs": 2132,
+          "elapsedMs": 5910,
+          "longTaskMs": 61,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 3620,
+              "startMs": 1774,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 6,
+          "at": "2026-11-14T03:53:16.974Z",
+          "ok": true,
+          "readyMs": 5304,
+          "shellMs": 2147,
+          "elapsedMs": 5308,
+          "longTaskMs": 60,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 2953,
+              "startMs": 1835,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 6,
+          "at": "2026-11-14T03:53:24.582Z",
+          "ok": true,
+          "readyMs": 7385,
+          "shellMs": 2149,
+          "elapsedMs": 7390,
+          "longTaskMs": 58,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 469,
+              "startMs": 1730,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 2667,
+              "startMs": 1731,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 5141,
+              "startMs": 1732,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 6,
+          "at": "2026-11-14T03:53:29.209Z",
+          "ok": true,
+          "readyMs": 4365,
+          "shellMs": 1683,
+          "elapsedMs": 4369,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 1109,
+              "startMs": 1632,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 2206,
+              "startMs": 1632,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 7,
+          "at": "2026-11-14T03:53:36.476Z",
+          "ok": true,
+          "readyMs": 7035,
+          "shellMs": 2191,
+          "elapsedMs": 7039,
+          "longTaskMs": 57,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 507,
+              "startMs": 1743,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 4793,
+              "startMs": 1743,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 7,
+          "at": "2026-11-14T03:53:46.378Z",
+          "ok": true,
+          "readyMs": 9664,
+          "shellMs": 2242,
+          "elapsedMs": 9668,
+          "longTaskMs": 59,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_account_overview",
+              "ms": 3595,
+              "startMs": 1858,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 4880,
+              "startMs": 1858,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 7284,
+              "startMs": 1859,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 7,
+          "at": "2026-11-14T03:53:49.567Z",
+          "ok": true,
+          "readyMs": 2969,
+          "shellMs": 2134,
+          "elapsedMs": 2973,
+          "longTaskMs": 119,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 631,
+              "startMs": 1835,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 7,
+          "at": "2026-11-14T03:53:56.343Z",
+          "ok": true,
+          "readyMs": 6557,
+          "shellMs": 2273,
+          "elapsedMs": 6562,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 4040,
+              "startMs": 2016,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 8,
+          "at": "2026-11-14T03:54:03.197Z",
+          "ok": true,
+          "readyMs": 6607,
+          "shellMs": 2212,
+          "elapsedMs": 6611,
+          "longTaskMs": 59,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 4123,
+              "startMs": 1961,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 8,
+          "at": "2026-11-14T03:54:07.808Z",
+          "ok": true,
+          "readyMs": 4385,
+          "shellMs": 2321,
+          "elapsedMs": 4392,
+          "longTaskMs": 117,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 1887,
+              "startMs": 1994,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 8,
+          "at": "2026-11-14T03:54:14.490Z",
+          "ok": true,
+          "readyMs": 6447,
+          "shellMs": 2407,
+          "elapsedMs": 6452,
+          "longTaskMs": 59,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_account_overview",
+              "ms": 398,
+              "startMs": 2000,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 427,
+              "startMs": 1999,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 3930,
+              "startMs": 2000,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 8,
+          "at": "2026-11-14T03:54:23.920Z",
+          "ok": true,
+          "readyMs": 9209,
+          "shellMs": 2374,
+          "elapsedMs": 9215,
+          "longTaskMs": 57,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 6015,
+              "startMs": 1944,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 6737,
+              "startMs": 1944,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 9,
+          "at": "2026-11-14T03:54:33.791Z",
+          "ok": true,
+          "readyMs": 9631,
+          "shellMs": 1790,
+          "elapsedMs": 9636,
+          "longTaskMs": 57,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 5920,
+              "startMs": 1740,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 7382,
+              "startMs": 1739,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 9,
+          "at": "2026-11-14T03:54:42.719Z",
+          "ok": true,
+          "readyMs": 8698,
+          "shellMs": 2143,
+          "elapsedMs": 8703,
+          "longTaskMs": 59,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 397,
+              "startMs": 1699,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 5248,
+              "startMs": 1700,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 6493,
+              "startMs": 1701,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 9,
+          "at": "2026-11-14T03:54:48.117Z",
+          "ok": true,
+          "readyMs": 5156,
+          "shellMs": 2167,
+          "elapsedMs": 5161,
+          "longTaskMs": 60,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 2759,
+              "startMs": 1895,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 9,
+          "at": "2026-11-14T03:54:51.371Z",
+          "ok": true,
+          "readyMs": 3019,
+          "shellMs": 2318,
+          "elapsedMs": 3024,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 508,
+              "startMs": 2009,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 10,
+          "at": "2026-11-14T03:54:54.533Z",
+          "ok": true,
+          "readyMs": 2930,
+          "shellMs": 2303,
+          "elapsedMs": 2934,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 416,
+              "startMs": 2004,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 10,
+          "at": "2026-11-14T03:54:57.556Z",
+          "ok": true,
+          "readyMs": 2798,
+          "shellMs": 2197,
+          "elapsedMs": 2802,
+          "longTaskMs": 59,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 444,
+              "startMs": 1843,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 10,
+          "at": "2026-11-14T03:55:15.733Z",
+          "ok": true,
+          "readyMs": 17941,
+          "shellMs": 2391,
+          "elapsedMs": 17945,
+          "longTaskMs": 60,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_account_overview",
+              "ms": 4535,
+              "startMs": 1957,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 7197,
+              "startMs": 1956,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 15467,
+              "startMs": 1957,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": null
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 10,
+          "at": "2026-11-14T03:55:20.666Z",
+          "ok": true,
+          "readyMs": 4679,
+          "shellMs": 1795,
+          "elapsedMs": 4684,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 1064,
+              "startMs": 1740,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": null
+            },
+            {
+              "action": "app_review_page",
+              "ms": 2433,
+              "startMs": 1740,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": null
+            }
+          ]
+        }
+      ],
+      "summary": {
+        "teacher-home": {
+          "runs": 10,
+          "readySuccess": 10,
+          "p50": 6026,
+          "p75": 7035,
+          "p95": 9631,
+          "shellP75": 2358,
+          "longTaskP75": 58,
+          "resourceBytesP75": 586525
+        },
+        "student-home": {
+          "runs": 10,
+          "readySuccess": 10,
+          "p50": 9664,
+          "p75": 14843,
+          "p95": 17941,
+          "shellP75": 2242,
+          "longTaskP75": 60,
+          "resourceBytesP75": 586525
+        },
+        "teacher-course": {
+          "runs": 10,
+          "readySuccess": 10,
+          "p50": 4385,
+          "p75": 6177,
+          "p95": 6459,
+          "shellP75": 2197,
+          "longTaskP75": 61,
+          "resourceBytesP75": 579388
+        },
+        "student-course": {
+          "runs": 10,
+          "readySuccess": 10,
+          "p50": 3884,
+          "p75": 5904,
+          "p95": 6607,
+          "shellP75": 2303,
+          "longTaskP75": 59,
+          "resourceBytesP75": 579388
+        }
+      }
+    },
+    "direct": {
+      "rows": [
+        {
+          "cohort": "teacher-home",
+          "run": 1,
+          "at": "2026-11-14T03:56:17.821Z",
+          "ok": true,
+          "readyMs": 8619,
+          "shellMs": 2490,
+          "elapsedMs": 8626,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 2436,
+              "startMs": 2437,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": 945.049
+            },
+            {
+              "action": "app_review_page",
+              "ms": 5653,
+              "startMs": 2437,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": 4158.087
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 1,
+          "at": "2026-11-14T03:56:38.428Z",
+          "ok": true,
+          "readyMs": 20344,
+          "shellMs": 2924,
+          "elapsedMs": 20350,
+          "longTaskMs": 58,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 789,
+              "startMs": 2541,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": 385.823
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 5170,
+              "startMs": 2542,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": 4773.923000000001
+            },
+            {
+              "action": "app_review_page",
+              "ms": 17290,
+              "startMs": 2542,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40460,
+              "requestToFirstByteMs": 16878.01,
+              "reviewSync": {
+                "state": "unavailable",
+                "pulled": 0,
+                "written": 0
+              }
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 1,
+          "at": "2026-11-14T03:56:43.838Z",
+          "ok": true,
+          "readyMs": 5133,
+          "shellMs": 2305,
+          "elapsedMs": 5138,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 2649,
+              "startMs": 1982,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": 2390.3520000000003
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 1,
+          "at": "2026-11-14T03:56:46.954Z",
+          "ok": true,
+          "readyMs": 2876,
+          "shellMs": 2206,
+          "elapsedMs": 2882,
+          "longTaskMs": 57,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 463,
+              "startMs": 1905,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": 257.713
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 2,
+          "at": "2026-11-14T03:56:50.251Z",
+          "ok": true,
+          "readyMs": 3058,
+          "shellMs": 2317,
+          "elapsedMs": 3063,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 480,
+              "startMs": 2060,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": 256.789
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 2,
+          "at": "2026-11-14T03:56:53.615Z",
+          "ok": true,
+          "readyMs": 3098,
+          "shellMs": 2309,
+          "elapsedMs": 3102,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 520,
+              "startMs": 2088,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": 213.34799999999998
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 2,
+          "at": "2026-11-14T03:57:07.938Z",
+          "ok": true,
+          "readyMs": 14081,
+          "shellMs": 2259,
+          "elapsedMs": 14086,
+          "longTaskMs": 58,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 394,
+              "startMs": 1829,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": 144.891
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 5207,
+              "startMs": 1829,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": 4960.0019999999995
+            },
+            {
+              "action": "app_review_page",
+              "ms": 11739,
+              "startMs": 1830,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": 11469.488,
+              "reviewSync": {
+                "state": "conflict",
+                "conflicts": 3,
+                "pulled": 60,
+                "written": 0,
+                "sourceTotal": 60,
+                "complete": true
+              }
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 2,
+          "at": "2026-11-14T03:57:14.620Z",
+          "ok": true,
+          "readyMs": 6431,
+          "shellMs": 2319,
+          "elapsedMs": 6436,
+          "longTaskMs": 59,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 718,
+              "startMs": 2177,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": 431.51599999999996
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 3739,
+              "startMs": 2177,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": 3470.924
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 3,
+          "at": "2026-11-14T03:57:22.262Z",
+          "ok": true,
+          "readyMs": 7400,
+          "shellMs": 2259,
+          "elapsedMs": 7404,
+          "longTaskMs": 57,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 523,
+              "startMs": 1822,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": 237.68699999999998
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 5059,
+              "startMs": 1821,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": 4792.204
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 3,
+          "at": "2026-11-14T03:57:33.324Z",
+          "ok": true,
+          "readyMs": 10811,
+          "shellMs": 2314,
+          "elapsedMs": 10816,
+          "longTaskMs": 61,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_account_overview",
+              "ms": 405,
+              "startMs": 1938,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": 144.319
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 3095,
+              "startMs": 1938,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": 2836.44
+            },
+            {
+              "action": "app_review_page",
+              "ms": 8366,
+              "startMs": 1939,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": 8075.395,
+              "reviewSync": {
+                "state": "conflict",
+                "conflicts": 3,
+                "pulled": 60,
+                "written": 0,
+                "sourceTotal": 60,
+                "complete": true
+              }
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 3,
+          "at": "2026-11-14T03:57:39.976Z",
+          "ok": true,
+          "readyMs": 6412,
+          "shellMs": 2418,
+          "elapsedMs": 6419,
+          "longTaskMs": 117,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 3769,
+              "startMs": 2136,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": 3457.0350000000003
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 3,
+          "at": "2026-11-14T03:57:46.860Z",
+          "ok": true,
+          "readyMs": 6644,
+          "shellMs": 2382,
+          "elapsedMs": 6649,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 4075,
+              "startMs": 2048,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": 3800.77
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 4,
+          "at": "2026-11-14T03:57:53.728Z",
+          "ok": true,
+          "readyMs": 6624,
+          "shellMs": 2689,
+          "elapsedMs": 6630,
+          "longTaskMs": 62,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 3815,
+              "startMs": 2290,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": 3626.079
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 4,
+          "at": "2026-11-14T03:57:59.252Z",
+          "ok": true,
+          "readyMs": 5153,
+          "shellMs": 2129,
+          "elapsedMs": 5157,
+          "longTaskMs": 64,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 2821,
+              "startMs": 1819,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": 2516.772
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 4,
+          "at": "2026-11-14T03:58:09.009Z",
+          "ok": true,
+          "readyMs": 9528,
+          "shellMs": 2169,
+          "elapsedMs": 9532,
+          "longTaskMs": 60,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 3331,
+              "startMs": 1771,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": 3006.6639999999998,
+              "reviewSync": {
+                "state": "conflict",
+                "conflicts": 3,
+                "pulled": 60,
+                "written": 0,
+                "sourceTotal": 60,
+                "complete": true
+              }
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 5204,
+              "startMs": 1771,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": 4945.151999999999
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 7238,
+              "startMs": 1770,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": 6989.325
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 4,
+          "at": "2026-11-14T03:58:15.553Z",
+          "ok": true,
+          "readyMs": 6298,
+          "shellMs": 2168,
+          "elapsedMs": 6303,
+          "longTaskMs": 57,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 1171,
+              "startMs": 1752,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": 960.448
+            },
+            {
+              "action": "app_review_page",
+              "ms": 4039,
+              "startMs": 1753,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": 3824.497
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 5,
+          "at": "2026-11-14T03:58:25.013Z",
+          "ok": true,
+          "readyMs": 9175,
+          "shellMs": 2095,
+          "elapsedMs": 9180,
+          "longTaskMs": 60,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 6501,
+              "startMs": 1684,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": 6211.188
+            },
+            {
+              "action": "app_review_page",
+              "ms": 6972,
+              "startMs": 1685,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": 6749.662
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 5,
+          "at": "2026-11-14T03:58:43.154Z",
+          "ok": true,
+          "readyMs": 17898,
+          "shellMs": 1710,
+          "elapsedMs": 17902,
+          "longTaskMs": 59,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 462,
+              "startMs": 1652,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": 189.29399999999998
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 4960,
+              "startMs": 1653,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": 4694.089
+            },
+            {
+              "action": "app_review_page",
+              "ms": 15732,
+              "startMs": 1653,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": 15462.959,
+              "reviewSync": {
+                "state": "conflict",
+                "conflicts": 3,
+                "pulled": 60,
+                "written": 0,
+                "sourceTotal": 60,
+                "complete": true
+              }
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 5,
+          "at": "2026-11-14T03:58:46.552Z",
+          "ok": true,
+          "readyMs": 3136,
+          "shellMs": 2236,
+          "elapsedMs": 3141,
+          "longTaskMs": 60,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 676,
+              "startMs": 1960,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": 348.734
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 5,
+          "at": "2026-11-14T03:58:51.511Z",
+          "ok": true,
+          "readyMs": 4724,
+          "shellMs": 2235,
+          "elapsedMs": 4728,
+          "longTaskMs": 59,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 2351,
+              "startMs": 1872,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": 2179.7960000000003
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 6,
+          "at": "2026-11-14T03:58:54.868Z",
+          "ok": true,
+          "readyMs": 3123,
+          "shellMs": 2273,
+          "elapsedMs": 3128,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 647,
+              "startMs": 1973,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": 340.763
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 6,
+          "at": "2026-11-14T03:58:58.067Z",
+          "ok": true,
+          "readyMs": 2964,
+          "shellMs": 2189,
+          "elapsedMs": 2969,
+          "longTaskMs": 60,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 573,
+              "startMs": 1882,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": 367.798
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 6,
+          "at": "2026-11-14T03:59:10.617Z",
+          "ok": true,
+          "readyMs": 12306,
+          "shellMs": 1723,
+          "elapsedMs": 12310,
+          "longTaskMs": 60,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 525,
+              "startMs": 1665,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": 251.209
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 5227,
+              "startMs": 1666,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": 4960.721
+            },
+            {
+              "action": "app_review_page",
+              "ms": 10126,
+              "startMs": 1666,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": 9823.364000000001,
+              "reviewSync": {
+                "state": "conflict",
+                "conflicts": 3,
+                "pulled": 60,
+                "written": 0,
+                "sourceTotal": 60,
+                "complete": true
+              }
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 6,
+          "at": "2026-11-14T03:59:18.561Z",
+          "ok": true,
+          "readyMs": 7705,
+          "shellMs": 1823,
+          "elapsedMs": 7710,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 615,
+              "startMs": 1773,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": 340.204
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 5429,
+              "startMs": 1773,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": 5146.750999999999
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 7,
+          "at": "2026-11-14T03:59:25.619Z",
+          "ok": true,
+          "readyMs": 6801,
+          "shellMs": 1959,
+          "elapsedMs": 6806,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 421,
+              "startMs": 1907,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": 230.502
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 4395,
+              "startMs": 1907,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": 4217.751
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 7,
+          "at": "2026-11-14T03:59:36.964Z",
+          "ok": true,
+          "readyMs": 10997,
+          "shellMs": 1834,
+          "elapsedMs": 11003,
+          "longTaskMs": 59,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_account_overview",
+              "ms": 381,
+              "startMs": 1777,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": 136.865
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 2846,
+              "startMs": 1777,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": 2603.037
+            },
+            {
+              "action": "app_review_page",
+              "ms": 8703,
+              "startMs": 1778,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": 8436.053999999998,
+              "reviewSync": {
+                "state": "conflict",
+                "conflicts": 3,
+                "pulled": 60,
+                "written": 0,
+                "sourceTotal": 60,
+                "complete": true
+              }
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 7,
+          "at": "2026-11-14T03:59:40.347Z",
+          "ok": true,
+          "readyMs": 3142,
+          "shellMs": 2258,
+          "elapsedMs": 3146,
+          "longTaskMs": 59,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 619,
+              "startMs": 2005,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": 302.913
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 7,
+          "at": "2026-11-14T03:59:43.503Z",
+          "ok": true,
+          "readyMs": 2914,
+          "shellMs": 2252,
+          "elapsedMs": 2919,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 426,
+              "startMs": 1965,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": 208.418
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 8,
+          "at": "2026-11-14T03:59:49.417Z",
+          "ok": true,
+          "readyMs": 5682,
+          "shellMs": 2203,
+          "elapsedMs": 5687,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 3206,
+              "startMs": 1954,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": 2963.94
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 8,
+          "at": "2026-11-14T03:59:56.270Z",
+          "ok": true,
+          "readyMs": 6620,
+          "shellMs": 2657,
+          "elapsedMs": 6624,
+          "longTaskMs": 119,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 3796,
+              "startMs": 2321,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": 3488.5139999999997
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 8,
+          "at": "2026-11-14T04:00:06.777Z",
+          "ok": true,
+          "readyMs": 10268,
+          "shellMs": 2192,
+          "elapsedMs": 10273,
+          "longTaskMs": 60,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_account_overview",
+              "ms": 4990,
+              "startMs": 1636,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": 4729.702
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 6476,
+              "startMs": 1636,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": 6217.783
+            },
+            {
+              "action": "app_review_page",
+              "ms": 8112,
+              "startMs": 1637,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": 7838.794000000001,
+              "reviewSync": {
+                "state": "conflict",
+                "conflicts": 3,
+                "pulled": 60,
+                "written": 0,
+                "sourceTotal": 60,
+                "complete": true
+              }
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 8,
+          "at": "2026-11-14T04:00:12.881Z",
+          "ok": true,
+          "readyMs": 5865,
+          "shellMs": 2302,
+          "elapsedMs": 5870,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 503,
+              "startMs": 1940,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": 233.463
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 3407,
+              "startMs": 1939,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": 3153.188
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 9,
+          "at": "2026-11-14T04:00:20.726Z",
+          "ok": true,
+          "readyMs": 7617,
+          "shellMs": 2213,
+          "elapsedMs": 7622,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_review_page",
+              "ms": 720,
+              "startMs": 1813,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": 458.04100000000005
+            },
+            {
+              "action": "e_order_tongji",
+              "ms": 5275,
+              "startMs": 1813,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": 5018.3679999999995
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 9,
+          "at": "2026-11-14T04:00:35.296Z",
+          "ok": true,
+          "readyMs": 14321,
+          "shellMs": 1973,
+          "elapsedMs": 14326,
+          "longTaskMs": 59,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 665,
+              "startMs": 1918,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": 335.98299999999995
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 1462,
+              "startMs": 1918,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": 100.321
+            },
+            {
+              "action": "app_review_page",
+              "ms": 11890,
+              "startMs": 1919,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": 11541.218,
+              "reviewSync": {
+                "state": "conflict",
+                "conflicts": 3,
+                "pulled": 60,
+                "written": 0,
+                "sourceTotal": 60,
+                "complete": true
+              }
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 9,
+          "at": "2026-11-14T04:00:38.726Z",
+          "ok": true,
+          "readyMs": 3134,
+          "shellMs": 2287,
+          "elapsedMs": 3139,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 584,
+              "startMs": 2039,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": 313.897
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 9,
+          "at": "2026-11-14T04:00:45.122Z",
+          "ok": true,
+          "readyMs": 6158,
+          "shellMs": 2153,
+          "elapsedMs": 6163,
+          "longTaskMs": 59,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 3806,
+              "startMs": 1829,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": 3615.282
+            }
+          ]
+        },
+        {
+          "cohort": "student-course",
+          "run": 10,
+          "at": "2026-11-14T04:00:48.465Z",
+          "ok": true,
+          "readyMs": 3099,
+          "shellMs": 2338,
+          "elapsedMs": 3104,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 500,
+              "startMs": 2097,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 1574,
+              "requestToFirstByteMs": 233.26299999999998
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-course",
+          "run": 10,
+          "at": "2026-11-14T04:00:51.737Z",
+          "ok": true,
+          "readyMs": 3024,
+          "shellMs": 2243,
+          "elapsedMs": 3029,
+          "longTaskMs": 58,
+          "resourceCount": 24,
+          "resourceTransferBytes": 579388,
+          "reviewRows": 0,
+          "scheduleRows": 2,
+          "apis": [
+            {
+              "action": "app_companion_overview",
+              "ms": 522,
+              "startMs": 1997,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 12035,
+              "requestToFirstByteMs": 234.433
+            }
+          ]
+        },
+        {
+          "cohort": "student-home",
+          "run": 10,
+          "at": "2026-11-14T04:01:04.078Z",
+          "ok": true,
+          "readyMs": 12098,
+          "shellMs": 2551,
+          "elapsedMs": 12102,
+          "longTaskMs": 59,
+          "resourceCount": 22,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 0,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 425,
+              "startMs": 2195,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 118,
+              "requestToFirstByteMs": 171.002
+            },
+            {
+              "action": "app_account_overview",
+              "ms": 4307,
+              "startMs": 2195,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 520,
+              "requestToFirstByteMs": 4147.700000000001
+            },
+            {
+              "action": "app_review_page",
+              "ms": 9390,
+              "startMs": 2196,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 40477,
+              "requestToFirstByteMs": 9217.228000000001,
+              "reviewSync": {
+                "state": "conflict",
+                "conflicts": 3,
+                "pulled": 60,
+                "written": 0,
+                "sourceTotal": 60,
+                "complete": true
+              }
+            }
+          ]
+        },
+        {
+          "cohort": "teacher-home",
+          "run": 10,
+          "at": "2026-11-14T04:01:11.200Z",
+          "ok": true,
+          "readyMs": 6874,
+          "shellMs": 2293,
+          "elapsedMs": 6878,
+          "longTaskMs": 58,
+          "resourceCount": 21,
+          "resourceTransferBytes": 586525,
+          "reviewRows": 3,
+          "scheduleRows": 0,
+          "apis": [
+            {
+              "action": "e_order_tongji",
+              "ms": 1325,
+              "startMs": 1887,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 210,
+              "requestToFirstByteMs": 1054.296
+            },
+            {
+              "action": "app_review_page",
+              "ms": 4467,
+              "startMs": 1888,
+              "status": 200,
+              "retcode": 0,
+              "decodedBodyBytes": 6256,
+              "requestToFirstByteMs": 4193.467
+            }
+          ]
+        }
+      ],
+      "summary": {
+        "teacher-home": {
+          "runs": 10,
+          "readySuccess": 10,
+          "p50": 6874,
+          "p75": 7705,
+          "p95": 9175,
+          "shellP75": 2302,
+          "longTaskP75": 58,
+          "resourceBytesP75": 586525
+        },
+        "student-home": {
+          "runs": 10,
+          "readySuccess": 10,
+          "p50": 12098,
+          "p75": 14321,
+          "p95": 20344,
+          "shellP75": 2314,
+          "longTaskP75": 60,
+          "resourceBytesP75": 586525
+        },
+        "teacher-course": {
+          "runs": 10,
+          "readySuccess": 10,
+          "p50": 3136,
+          "p75": 5153,
+          "p95": 6620,
+          "shellP75": 2309,
+          "longTaskP75": 64,
+          "resourceBytesP75": 579388
+        },
+        "student-course": {
+          "runs": 10,
+          "readySuccess": 10,
+          "p50": 3123,
+          "p75": 6158,
+          "p95": 6644,
+          "shellP75": 2338,
+          "longTaskP75": 59,
+          "resourceBytesP75": 579388
+        }
+      }
+    }
+  },
+  "transport": {
+    "direct": [
+      {
+        "run": 1,
+        "label": "xiaoshu",
+        "metrics": "200 0.049269 0.094264 0.147598 0.211688 0.211807 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 1,
+        "label": "shared",
+        "metrics": "200 0.003634 0.125784 0.189531 0.247644 0.247749 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 2,
+        "label": "xiaoshu",
+        "metrics": "200 0.004429 0.047843 0.108351 0.167655 0.167755 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 2,
+        "label": "shared",
+        "metrics": "200 0.003993 0.048567 0.209324 0.299016 0.299126 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 3,
+        "label": "xiaoshu",
+        "metrics": "200 0.004306 0.048749 0.102681 0.170098 0.170204 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 3,
+        "label": "shared",
+        "metrics": "200 0.003909 0.042210 0.097809 0.207508 0.207602 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 4,
+        "label": "xiaoshu",
+        "metrics": "200 0.004563 0.046640 0.108425 0.172316 0.172421 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 4,
+        "label": "shared",
+        "metrics": "200 0.003663 0.070018 0.122779 0.189396 0.189509 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 5,
+        "label": "xiaoshu",
+        "metrics": "200 0.004410 0.138321 0.189711 0.253918 0.254029 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 5,
+        "label": "shared",
+        "metrics": "200 0.003506 0.044236 0.100463 0.166747 0.166854 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 6,
+        "label": "xiaoshu",
+        "metrics": "200 0.004302 0.045747 0.150864 0.210944 0.211052 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 6,
+        "label": "shared",
+        "metrics": "200 0.003752 0.049910 0.108095 0.237929 0.238050 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 7,
+        "label": "xiaoshu",
+        "metrics": "200 0.004379 0.042542 0.172685 0.243662 0.243768 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 7,
+        "label": "shared",
+        "metrics": "200 0.003551 0.052988 0.103075 0.210340 0.210449 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 8,
+        "label": "xiaoshu",
+        "metrics": "200 0.005025 0.049412 0.109051 0.294924 0.295064 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 8,
+        "label": "shared",
+        "metrics": "200 0.004284 0.063849 0.131476 0.216048 0.216211 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 9,
+        "label": "xiaoshu",
+        "metrics": "200 0.004475 0.059287 0.168721 0.273977 0.274085 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 9,
+        "label": "shared",
+        "metrics": "200 0.003731 0.063404 0.129986 0.191575 0.191703 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 10,
+        "label": "xiaoshu",
+        "metrics": "200 0.004131 0.060516 0.174765 0.232493 0.232606 139.159.253.131",
+        "code": 0,
+        "error": ""
+      },
+      {
+        "run": 10,
+        "label": "shared",
+        "metrics": "200 0.003926 0.071107 0.125521 0.185364 0.185477 139.159.253.131",
+        "code": 0,
+        "error": ""
+      }
+    ],
+    "proxyControls": [
+      {
+        "run": 1,
+        "label": "xiaoshu-health",
+        "ms": 304,
+        "status": 200,
+        "bytes": 15,
+        "error": null
+      },
+      {
+        "run": 1,
+        "label": "shared-health",
+        "ms": 169,
+        "status": 200,
+        "bytes": 3,
+        "error": null
+      },
+      {
+        "run": 1,
+        "label": "h5-version",
+        "ms": 254,
+        "status": 200,
+        "bytes": 14508,
+        "error": null
+      },
+      {
+        "run": 1,
+        "label": "network-control",
+        "ms": 276,
+        "status": 200,
+        "bytes": 983,
+        "error": null
+      },
+      {
+        "run": 2,
+        "label": "xiaoshu-health",
+        "ms": 263,
+        "status": 200,
+        "bytes": 15,
+        "error": null
+      },
+      {
+        "run": 2,
+        "label": "shared-health",
+        "ms": 189,
+        "status": 200,
+        "bytes": 3,
+        "error": null
+      },
+      {
+        "run": 2,
+        "label": "h5-version",
+        "ms": 248,
+        "status": 200,
+        "bytes": 14508,
+        "error": null
+      },
+      {
+        "run": 2,
+        "label": "network-control",
+        "ms": 125,
+        "status": 200,
+        "bytes": 989,
+        "error": null
+      },
+      {
+        "run": 3,
+        "label": "xiaoshu-health",
+        "ms": 191,
+        "status": 200,
+        "bytes": 15,
+        "error": null
+      },
+      {
+        "run": 3,
+        "label": "shared-health",
+        "ms": 284,
+        "status": 200,
+        "bytes": 3,
+        "error": null
+      },
+      {
+        "run": 3,
+        "label": "h5-version",
+        "ms": 168,
+        "status": 200,
+        "bytes": 14508,
+        "error": null
+      },
+      {
+        "run": 3,
+        "label": "network-control",
+        "ms": 153,
+        "status": 200,
+        "bytes": 989,
+        "error": null
+      },
+      {
+        "run": 4,
+        "label": "xiaoshu-health",
+        "ms": 293,
+        "status": 200,
+        "bytes": 15,
+        "error": null
+      },
+      {
+        "run": 4,
+        "label": "shared-health",
+        "ms": 168,
+        "status": 200,
+        "bytes": 3,
+        "error": null
+      },
+      {
+        "run": 4,
+        "label": "h5-version",
+        "ms": 258,
+        "status": 200,
+        "bytes": 14508,
+        "error": null
+      },
+      {
+        "run": 4,
+        "label": "network-control",
+        "ms": 162,
+        "status": 200,
+        "bytes": 988,
+        "error": null
+      },
+      {
+        "run": 5,
+        "label": "xiaoshu-health",
+        "ms": 311,
+        "status": 200,
+        "bytes": 15,
+        "error": null
+      },
+      {
+        "run": 5,
+        "label": "shared-health",
+        "ms": 161,
+        "status": 200,
+        "bytes": 3,
+        "error": null
+      },
+      {
+        "run": 5,
+        "label": "h5-version",
+        "ms": 203,
+        "status": 200,
+        "bytes": 14508,
+        "error": null
+      },
+      {
+        "run": 5,
+        "label": "network-control",
+        "ms": 212,
+        "status": 200,
+        "bytes": 985,
+        "error": null
+      },
+      {
+        "run": 6,
+        "label": "xiaoshu-health",
+        "ms": 1194,
+        "status": 200,
+        "bytes": 15,
+        "error": null
+      },
+      {
+        "run": 6,
+        "label": "shared-health",
+        "ms": 170,
+        "status": 200,
+        "bytes": 3,
+        "error": null
+      },
+      {
+        "run": 6,
+        "label": "h5-version",
+        "ms": 266,
+        "status": 200,
+        "bytes": 14508,
+        "error": null
+      },
+      {
+        "run": 6,
+        "label": "network-control",
+        "ms": 207,
+        "status": 200,
+        "bytes": 984,
+        "error": null
+      },
+      {
+        "run": 7,
+        "label": "xiaoshu-health",
+        "ms": 294,
+        "status": 200,
+        "bytes": 15,
+        "error": null
+      },
+      {
+        "run": 7,
+        "label": "shared-health",
+        "ms": 179,
+        "status": 200,
+        "bytes": 3,
+        "error": null
+      },
+      {
+        "run": 7,
+        "label": "h5-version",
+        "ms": 240,
+        "status": 200,
+        "bytes": 14508,
+        "error": null
+      },
+      {
+        "run": 7,
+        "label": "network-control",
+        "ms": 161,
+        "status": 200,
+        "bytes": 983,
+        "error": null
+      },
+      {
+        "run": 8,
+        "label": "xiaoshu-health",
+        "ms": 190,
+        "status": 200,
+        "bytes": 15,
+        "error": null
+      },
+      {
+        "run": 8,
+        "label": "shared-health",
+        "ms": 259,
+        "status": 200,
+        "bytes": 3,
+        "error": null
+      },
+      {
+        "run": 8,
+        "label": "h5-version",
+        "ms": 166,
+        "status": 200,
+        "bytes": 14508,
+        "error": null
+      },
+      {
+        "run": 8,
+        "label": "network-control",
+        "ms": 287,
+        "status": 200,
+        "bytes": 988,
+        "error": null
+      },
+      {
+        "run": 9,
+        "label": "xiaoshu-health",
+        "ms": 197,
+        "status": 200,
+        "bytes": 15,
+        "error": null
+      },
+      {
+        "run": 9,
+        "label": "shared-health",
+        "ms": 329,
+        "status": 200,
+        "bytes": 3,
+        "error": null
+      },
+      {
+        "run": 9,
+        "label": "h5-version",
+        "ms": 193,
+        "status": 200,
+        "bytes": 14508,
+        "error": null
+      },
+      {
+        "run": 9,
+        "label": "network-control",
+        "ms": 154,
+        "status": 200,
+        "bytes": 985,
+        "error": null
+      },
+      {
+        "run": 10,
+        "label": "xiaoshu-health",
+        "ms": 5006,
+        "status": null,
+        "bytes": 0,
+        "error": "URLError"
+      },
+      {
+        "run": 10,
+        "label": "shared-health",
+        "ms": 240,
+        "status": 200,
+        "bytes": 3,
+        "error": null
+      },
+      {
+        "run": 10,
+        "label": "h5-version",
+        "ms": 218,
+        "status": 200,
+        "bytes": 14508,
+        "error": null
+      },
+      {
+        "run": 10,
+        "label": "network-control",
+        "ms": 143,
+        "status": 200,
+        "bytes": 988,
+        "error": null
+      }
+    ],
+    "proxyFollowup": [
+      {
+        "at": "2026-11-14T11:52:23.351780",
+        "label": "xiaoshu-health",
+        "ms": 231,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:23.582775",
+        "label": "shared-health",
+        "ms": 291,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:23.873858",
+        "label": "xiaoshu-health",
+        "ms": 181,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:24.054865",
+        "label": "shared-health",
+        "ms": 222,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:24.276942",
+        "label": "xiaoshu-health",
+        "ms": 178,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:24.454803",
+        "label": "shared-health",
+        "ms": 170,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:24.624736",
+        "label": "xiaoshu-health",
+        "ms": 1253,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:25.877610",
+        "label": "shared-health",
+        "ms": 182,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:26.059197",
+        "label": "xiaoshu-health",
+        "ms": 201,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:26.259737",
+        "label": "shared-health",
+        "ms": 243,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:26.502723",
+        "label": "xiaoshu-health",
+        "ms": 166,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:26.668966",
+        "label": "shared-health",
+        "ms": 230,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:26.899195",
+        "label": "xiaoshu-health",
+        "ms": 5005,
+        "status": null,
+        "error": "URLError"
+      },
+      {
+        "at": "2026-11-14T11:52:31.903794",
+        "label": "shared-health",
+        "ms": 311,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:32.214765",
+        "label": "xiaoshu-health",
+        "ms": 167,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:32.382166",
+        "label": "shared-health",
+        "ms": 170,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:32.552650",
+        "label": "xiaoshu-health",
+        "ms": 267,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:32.819338",
+        "label": "shared-health",
+        "ms": 193,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:33.012553",
+        "label": "xiaoshu-health",
+        "ms": 347,
+        "status": 200,
+        "error": null
+      },
+      {
+        "at": "2026-11-14T11:52:33.359981",
+        "label": "shared-health",
+        "ms": 368,
+        "status": 200,
+        "error": null
+      }
+    ]
+  }
+}

+ 37 - 0
perf/recovery-performance-2026-11-14/benchmark.mjs

@@ -0,0 +1,37 @@
+// Read-only browser navigation; existing review endpoints can perform their normal legacy synchronization.
+// Run from repository root: DIRECT=1 RUNS=10 OUT=browser-direct node perf/recovery-performance-2026-11-14/benchmark.mjs /absolute/private/session-directory
+// Never place session files or raw responses in Git. This script does not log request payloads or tokens.
+import fs from 'node:fs';
+import {createRequire} from 'node:module';
+import path from 'node:path';
+const require=createRequire(path.resolve('package.json'));
+const {chromium}=require('playwright');
+const root=process.argv[2];
+if(!root || !path.isAbsolute(root))throw Error('Pass an absolute private evidence directory containing authorized teacher/student session files');
+const count=Number(process.env.RUNS||10), out=process.env.OUT||'browser-baseline';
+const browser=await chromium.launch({headless:true,executablePath:process.env.CHROME_PATH||'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',args:process.env.DIRECT==='1'?['--no-proxy-server']:[]});
+const results=[];
+try {for(let run=1;run<=count;run++) for(const cohort of (run%2?['teacher-home','student-home','teacher-course','student-course']:['student-course','teacher-course','student-home','teacher-home'])) {
+ const role=cohort.split('-')[0],course=cohort.endsWith('course');
+ const session=JSON.parse(fs.readFileSync(root+'/'+role+'-session-private.json'));
+ const context=await browser.newContext({viewport:{width:390,height:844},timezoneId:'Asia/Shanghai'});
+ await context.addInitScript(s=>{localStorage.setItem('xiaoshu.angular.session',JSON.stringify(s));window.__long=[];performance.setResourceTimingBufferSize(2000);new PerformanceObserver(l=>window.__long.push(...l.getEntries().map(x=>x.duration))).observe({type:'longtask',buffered:true});},session);
+ const page=await context.newPage(),cdp=await context.newCDPSession(page);
+ await cdp.send('Network.enable');await cdp.send('Network.emulateNetworkConditions',{offline:false,latency:20,downloadThroughput:4*1024*1024/8,uploadThroughput:3*1024*1024/8});
+ const start=Date.now(),apis=[],pending=[],starts=new Map();let shellMs=null;
+ page.on('request',req=>starts.set(req,Date.now()));
+ page.on('response',res=>{const req=res.request();if(!res.url().includes('/api/functions/')||req.method()==='OPTIONS')return;pending.push((async()=>{let action='unknown';try{action=req.postDataJSON()?.params?.action||'unknown'}catch{};await res.finished().catch(()=>{});let body;try{body=await res.body()}catch{};let d;try{d=JSON.parse(body)}catch{};apis.push({action,startMs:(starts.get(req)||start)-start,ms:Date.now()-(starts.get(req)||start),status:res.status(),retcode:d?.retcode,bytes:body?.length??null,timing:req.timing(),reviewMeta:d?.result?.legacyReviewSync?Object.fromEntries(Object.entries(d.result.legacyReviewSync).filter(([k])=>['state','pulled','written','sourceTotal','complete','conflicts'].includes(k))):undefined});})());});
+ let ok=false,error=null,readyMs=null,metrics=null;
+ try {await page.goto('https://h5.xiaoshu.pro/pages/home/'+(course?'shop':'index'),{waitUntil:'domcontentloaded',timeout:45000});
+ await page.waitForSelector(course?'.mobile-pagination':role==='teacher'?'.coach-hero':'.memory-hero',{timeout:45000});shellMs=Date.now()-start;
+ await page.waitForFunction(({role,course})=>{const q=s=>document.querySelector(s);let valid=false,key='';
+ if(course){const p=q('.mobile-pagination');valid=!!p&&!p.textContent.includes('—')&&!q('.center-state.error')&&!Array.from(document.querySelectorAll('button')).some(b=>b.textContent.trim()==='刷新课表'&&b.disabled);key=p?.textContent+'|'+document.querySelectorAll('[data-schedule-id]').length;}
+ else if(role==='teacher'){valid=!!q('.coach-grid:not(.loading)')&&!!q('.coach-memory-summary')&&!q('.coach-hero-error')&&!q('.coach-memory-state.error')&&!q('button[aria-label="刷新抗遗忘任务"]:disabled');key=q('.coach-memory-summary')?.textContent+'|'+document.querySelectorAll('.coach-memory-list article').length;}
+ else{valid=!!q('.memory-content')&&!!q('button[aria-label="刷新学习数据"]:not(:disabled)')&&!q('.hero-error');key=q('.student-stats')?.textContent+'|'+q('.today-panel')?.textContent;}
+ if(!valid){window.__ready=null;return false}if(window.__ready?.key!==key){window.__ready={key,at:performance.now()};return false}return performance.now()-window.__ready.at>=500;
+ },{role,course},{timeout:65000});readyMs=Date.now()-start;ok=true;
+ }catch(e){error=String(e.message).split('\n')[0];}
+ try{metrics=await page.evaluate(()=>({longTaskMs:window.__long?.reduce((a,b)=>a+b,0)||0,resources:performance.getEntriesByType('resource').map(r=>({name:r.name.split('?')[0],startMs:r.startTime,endMs:r.responseEnd,ms:r.duration,transferBytes:r.transferSize,encodedBytes:r.encodedBodySize,type:r.initiatorType})),reviewRows:document.querySelectorAll('.coach-memory-list article').length,scheduleRows:document.querySelectorAll('[data-schedule-id]').length,errors:Array.from(document.querySelectorAll('.center-state.error,.coach-hero-error,.coach-memory-state.error,.hero-error')).map(e=>e.textContent)}));}catch{}
+ await Promise.allSettled(pending);const row={cohort,run,at:new Date().toISOString(),ok,error,readyMs,shellMs,elapsedMs:Date.now()-start,apis,metrics};results.push(row);fs.writeFileSync(root+'/'+out+'.json',JSON.stringify(results,null,2),{mode:0o600});console.log(JSON.stringify({cohort,run,ok,readyMs,shellMs,apis:apis.map(({action,ms,status,retcode})=>({action,ms,status,retcode})),error}));await context.close();
+ if(results.slice(-4).filter(r=>!r.ok).length>=3)throw Error('Stop after repeated unavailable pages');
+ }}finally{await browser.close();}

+ 25 - 0
perf/recovery-performance-2026-11-14/production-readback.json

@@ -0,0 +1,25 @@
+{
+  "at": "2026-11-14T04:00:29.842Z",
+  "gateways": [
+    {
+      "path": "xiaoshu/ops/gateway-v3",
+      "updatedAt": "2026-11-14T00:38:27.640Z",
+      "unchanged": true,
+      "compat": true,
+      "sha256": "6f99a3826ab90bb3911d13bf33c2290ebbf850d77ac8163ac4c20b22c8518c0f"
+    },
+    {
+      "path": "xiaoshu/app/gateway",
+      "updatedAt": "2026-11-14T00:38:27.640Z",
+      "unchanged": true,
+      "compat": true,
+      "sha256": "000818f3add2578a1c9cc24a47121fc3dc4fd04914b09df31fa3b48bbd4bfc98"
+    }
+  ],
+  "mobileVersion": {
+    "application": "xiaoshu-mobile",
+    "releaseId": "mobile-course-word-speed-0b7d9d5f89c7-20261112T074222208Z",
+    "commit": "0b7d9d5f89c7f877859fcebdbcda914027185e38",
+    "builtAt": "2026-11-12T07:42:22.245Z"
+  }
+}

+ 34 - 0
perf/recovery-performance-2026-11-14/summarize.mjs

@@ -0,0 +1,34 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import {fileURLToPath} from 'node:url';
+const root=process.argv[2],out=path.dirname(fileURLToPath(import.meta.url));
+if(!root||!path.isAbsolute(root))throw Error('Pass the private evidence directory');
+const q=(a,p)=>{const s=a.filter(Number.isFinite).sort((a,b)=>a-b);return s.length?s[Math.ceil(s.length*p)-1]:null;};
+const labels={'teacher-home':'老师首页','student-home':'学生首页','teacher-course':'老师当天课表','student-course':'学生当天课表'};
+const data={method:{runsPerCohort:10,network:'Fast4G: added latency 20ms; download 4Mbps; upload 3Mbps',viewport:'390x844',cpu:1,cache:'new context each sample',readyStabilityMs:500,percentile:'nearest rank',scope:'presentation ready with existing data; source synchronization tracked separately'},groups:{},transport:{}};
+for(const [group,file] of [['system-proxy','browser-baseline.json'],['direct','browser-direct.json']]){
+ const raw=JSON.parse(fs.readFileSync(path.join(root,file)));
+ if(raw.length!==40)throw Error(`${group}: expected 40 samples, got ${raw.length}`);
+ const rows=raw.map(r=>({cohort:r.cohort,run:r.run,at:r.at,ok:r.ok,readyMs:r.readyMs,shellMs:r.shellMs,elapsedMs:r.elapsedMs,longTaskMs:r.metrics?.longTaskMs,resourceCount:r.metrics?.resources.length,resourceTransferBytes:r.metrics?.resources.reduce((n,x)=>n+x.transferBytes,0),reviewRows:r.metrics?.reviewRows,scheduleRows:r.metrics?.scheduleRows,apis:r.apis.map(a=>({action:a.action,ms:a.ms,startMs:a.startMs,status:a.status,retcode:a.retcode,decodedBodyBytes:a.bytes,requestToFirstByteMs:a.timing?a.timing.responseStart-a.timing.requestStart:null,reviewSync:a.reviewMeta}))}));
+ data.groups[group]={rows,summary:Object.fromEntries(Object.keys(labels).map(c=>{const a=rows.filter(r=>r.cohort===c);if(a.length!==10)throw Error('Invalid cohort size');return[c,{runs:a.length,readySuccess:a.filter(r=>r.ok).length,p50:q(a.map(r=>r.readyMs),.5),p75:q(a.map(r=>r.readyMs),.75),p95:q(a.map(r=>r.readyMs),.95),shellP75:q(a.map(r=>r.shellMs),.75),longTaskP75:q(a.map(r=>r.longTaskMs),.75),resourceBytesP75:q(a.map(r=>r.resourceTransferBytes),.75)}]}))};
+}
+data.transport.direct=JSON.parse(fs.readFileSync(path.join(root,'curl-health-direct.json')));
+data.transport.proxyControls=JSON.parse(fs.readFileSync(path.join(root,'transport-controls.json')));
+data.transport.proxyFollowup=JSON.parse(fs.readFileSync(path.join(root,'health-followup.json')));
+fs.writeFileSync(path.join(out,'baseline.json'),JSON.stringify(data,null,2)+'\n');
+const seconds=n=>n===null?'—':(n/1000).toFixed(2),direct=data.groups.direct;
+let md='# 恢复后性能基线\n\n2026-11-14;仅诊断,未部署优化。完整口径、限制及方案见 PLAN.md;脱敏逐次样本见 baseline.json。\n\n';
+for(const group of ['direct','system-proxy']){
+ const g=data.groups[group];md+=`## ${group==='direct'?'绕过代理:主要结论':'系统代理:辅助复现,不能与直连组作优化 A/B'}\n\n测量时段 UTC:${g.rows[0].at} 至 ${g.rows.at(-1).at}(北京时间 +8 小时)。\n\n| 页面 | 成功加载 | p50 秒 | p75 秒 | p95 秒 | 外壳 p75 秒 | 长任务累计 p75 毫秒 |\n|---|---:|---:|---:|---:|---:|---:|\n`;
+ for(const [c,s] of Object.entries(g.summary))md+=`| ${labels[c]} | ${s.readySuccess}/${s.runs} | ${seconds(s.p50)} | ${seconds(s.p75)} | ${seconds(s.p95)} | ${seconds(s.shellP75)} | ${s.longTaskP75} |\n`;
+ md+='\n';
+}
+md+='## 直连业务接口\n\n接口耗时包含网络与响应读取,不能等同于 SQL 执行时间;首字节等待包含网关、服务和网络。\n\n| 页面 / 接口 | 样本数 | p75 秒 | p95 秒 | 发出请求至首字节 p75 秒 |\n|---|---:|---:|---:|---:|\n';
+for(const c of Object.keys(labels))for(const action of [...new Set(direct.rows.filter(r=>r.cohort===c).flatMap(r=>r.apis.map(a=>a.action)))]){const a=direct.rows.filter(r=>r.cohort===c).flatMap(r=>r.apis.filter(a=>a.action===action));md+=`| ${labels[c]} / ${action} | ${a.length} | ${seconds(q(a.map(a=>a.ms),.75))} | ${seconds(q(a.map(a=>a.ms),.95))} | ${seconds(q(a.map(a=>a.requestToFirstByteMs),.75))} |\n`;}
+const sync=direct.rows.filter(r=>r.cohort==='student-home').flatMap(r=>r.apis.filter(a=>a.action==='app_review_page').map(a=>a.reviewSync));
+md+='\n学生复习同步状态计数:'+JSON.stringify(sync.reduce((a,s)=>{const k=s?.state||'not-captured';a[k]=(a[k]||0)+1;return a},{}))+'。HTTP 200 / 页面已显示数据不代表旧系统同步成功。\n\n';
+md+='## 网络对照与限制\n\n';
+for(const label of ['xiaoshu','shared']){const a=data.transport.direct.filter(r=>r.label===label),ok=a.filter(r=>r.code===0&&r.metrics.startsWith('200 '));md+=`- ${label} 直连健康检查:${ok.length}/${a.length} HTTP 200;总耗时 p75 ${seconds(q(ok.map(r=>Number(r.metrics.split(' ')[5])*1000),.75))} 秒。\n`;}
+md+='- 本机系统代理开启;代理路径曾出现约 5 秒的 URLError,没有取得服务端 HTTP 状态。不能据此宣称服务器又返回 503。绕过代理的页面仍慢,代理不是全部原因。\n- 冷启动所记录资源传输量约 0.58 MB;这是 Resource Timing 可见资源量,不含缺少跨域 Timing-Allow-Origin 的 API 字节,也不完整包含主文档。API 解码后响应大小另记,二者不可混称带宽用量。\n- 这不是设备端真实用户统计,没有 CrUX/RUM 的认证后页面数据;未做低端 CPU、热返回、开课或语音测量。\n- 页面样本全部完成与否按表列出;本脚本未完整收集 requestfailed 事件,不能用它宣布网络失败率为零。没有发布优化候选,因此没有优化收益百分比。\n';
+fs.writeFileSync(path.join(out,'BASELINE.md'),md);
+console.log(JSON.stringify(direct.summary,null,2));