Merge pull request #1343 from pikasTech/fix/1342-duration-trend
fix: make sentinel trend chart show duration
This commit is contained in:
@@ -22,6 +22,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 刷新后终端内容没更新
|
||||
summaryZh: 后台已有新内容,但页面终端区域仍显示旧内容。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 10
|
||||
- code: WBC-002
|
||||
@@ -29,6 +30,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 终端记录缺失
|
||||
summaryZh: 会话已有过程记录,但终端区域没有显示出来。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 20
|
||||
- code: WBC-003
|
||||
@@ -36,6 +38,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 快速验证没有有效对话
|
||||
summaryZh: 快速验证没有看到稳定会话、过程记录或最终回复。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 30
|
||||
- code: WBC-004
|
||||
@@ -43,6 +46,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 快速验证步骤失败
|
||||
summaryZh: 快速验证的操作步骤没有完整执行。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 40
|
||||
- code: WBC-005
|
||||
@@ -50,6 +54,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 页面观察未启动
|
||||
summaryZh: 快速验证前未能打开页面观察环境。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 50
|
||||
- code: WBC-006
|
||||
@@ -57,6 +62,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 验证账号未配置
|
||||
summaryZh: 快速验证所需账号或密钥缺失。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 60
|
||||
- code: WBC-007
|
||||
@@ -64,6 +70,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 消息发送失败
|
||||
summaryZh: 用户消息提交后没有观察到成功发送结果。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 70
|
||||
- code: WBC-008
|
||||
@@ -71,6 +78,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 页面操作失败
|
||||
summaryZh: 自动页面操作没有成功执行。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 80
|
||||
- code: WBC-009
|
||||
@@ -78,6 +86,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 当前会话不一致
|
||||
summaryZh: 地址栏中的会话与页面当前会话不一致。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 90
|
||||
- code: WBC-010
|
||||
@@ -85,6 +94,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 返回页面后消息顺序异常
|
||||
summaryZh: 导航或刷新后,消息顺序看起来不符合对话顺序。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 100
|
||||
- code: WBC-011
|
||||
@@ -92,6 +102,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 两个页面内容不一致
|
||||
summaryZh: 同一会话在两个页面中显示了不同内容。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 110
|
||||
- code: WBC-012
|
||||
@@ -99,6 +110,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 页面切换时短暂不一致
|
||||
summaryZh: 页面切换附近短时间显示了不同内容。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 120
|
||||
- code: WBC-013
|
||||
@@ -106,6 +118,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 返回页面后内容短暂不同步
|
||||
summaryZh: 导航返回后,页面内容短时间没有完全同步。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 130
|
||||
- code: WBC-014
|
||||
@@ -113,6 +126,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 页面未完全打开导致差异
|
||||
summaryZh: 内容差异发生在页面主体尚未完全打开时。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 140
|
||||
- code: WBC-015
|
||||
@@ -120,6 +134,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 两个页面记录数量不同
|
||||
summaryZh: 两个页面显示的过程记录数量不同。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 150
|
||||
- code: WBC-016
|
||||
@@ -127,6 +142,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: Workbench 页面未打开完整
|
||||
summaryZh: Workbench 地址已打开,但主要工作区没有正常显示。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 160
|
||||
- code: WBC-017
|
||||
@@ -134,6 +150,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: Workbench 短暂未显示
|
||||
summaryZh: Workbench 打开过程中短时间没有显示主要工作区。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 170
|
||||
- code: WBC-018
|
||||
@@ -141,6 +158,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 过程记录缺少结束状态
|
||||
summaryZh: 页面显示了过程记录,但没有看到对应的结束状态。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 180
|
||||
- code: WBC-019
|
||||
@@ -148,6 +166,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 对话回合缺少追踪编号
|
||||
summaryZh: 页面显示了对话回合,但缺少可用于排查的编号。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 190
|
||||
- code: WBC-020
|
||||
@@ -155,6 +174,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 最终回复重复显示
|
||||
summaryZh: 页面上重复显示了助手最终回复。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 200
|
||||
- code: WBC-021
|
||||
@@ -162,6 +182,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 最终回复显示不稳定
|
||||
summaryZh: 最终回复在观察期间出现闪烁或变化。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 210
|
||||
- code: WBC-022
|
||||
@@ -169,6 +190,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 完成后无最终回复
|
||||
summaryZh: 回合完成后缺少最终回复内容。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 220
|
||||
- code: WBC-023
|
||||
@@ -176,6 +198,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 过程记录页面打不开
|
||||
summaryZh: 打开更早的过程记录时返回未找到。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 230
|
||||
- code: WBC-024
|
||||
@@ -183,6 +206,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 过程记录加载失败
|
||||
summaryZh: 打开更早的过程记录时页面返回错误。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 240
|
||||
- code: WBC-025
|
||||
@@ -190,6 +214,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 过程记录加载中断
|
||||
summaryZh: 打开更早的过程记录时网络请求中断。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 250
|
||||
- code: WBC-026
|
||||
@@ -197,6 +222,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 页面请求返回错误
|
||||
summaryZh: 页面加载过程中有请求返回错误状态。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 260
|
||||
- code: WBC-027
|
||||
@@ -204,6 +230,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 页面请求中断
|
||||
summaryZh: 页面加载过程中有网络请求未完成。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 270
|
||||
- code: WBC-028
|
||||
@@ -211,6 +238,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 页面出现错误提示
|
||||
summaryZh: 页面内容中出现错误或警告提示文本。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 280
|
||||
- code: WBC-029
|
||||
@@ -218,6 +246,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 任务执行失败
|
||||
summaryZh: Workbench 页面显示任务执行失败。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 290
|
||||
- code: WBC-030
|
||||
@@ -225,6 +254,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 浏览器记录到告警
|
||||
summaryZh: 浏览器运行日志记录到警告或错误。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 300
|
||||
- code: WBC-031
|
||||
@@ -232,6 +262,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 页面运行异常
|
||||
summaryZh: 页面运行过程中捕获到异常。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 310
|
||||
- code: WBC-032
|
||||
@@ -239,6 +270,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 页面响应过慢
|
||||
summaryZh: 页面加载数据的耗时超过配置预算。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 320
|
||||
- code: WBC-033
|
||||
@@ -246,6 +278,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 实时连接建立过慢
|
||||
summaryZh: 页面建立实时连接的耗时超过配置预算。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 330
|
||||
- code: WBC-034
|
||||
@@ -253,6 +286,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 页面存在实时连接
|
||||
summaryZh: 页面打开了用于持续更新内容的连接,作为上下文保留。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 340
|
||||
- code: WBC-035
|
||||
@@ -260,6 +294,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 页面版本发生切换
|
||||
summaryZh: 观察期间页面资源版本发生变化,排查时需要注意前后差异。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 350
|
||||
- code: WBC-036
|
||||
@@ -267,6 +302,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 已收集页面更新基线
|
||||
summaryZh: 已收集后台数据变化到页面显示变化的基础样本。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 360
|
||||
- code: WBC-037
|
||||
@@ -274,6 +310,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 页面更新可能滞后
|
||||
summaryZh: 后台数据变化后,页面显示可能存在滞后样本。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 370
|
||||
- code: WBC-038
|
||||
@@ -281,6 +318,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 总耗时突然归零
|
||||
summaryZh: 已显示的总耗时突然回到 0。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 380
|
||||
- code: WBC-039
|
||||
@@ -288,6 +326,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 总耗时倒退
|
||||
summaryZh: 相邻观察点中,总耗时变小。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 390
|
||||
- code: WBC-040
|
||||
@@ -295,6 +334,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 总耗时突然跳大
|
||||
summaryZh: 总耗时增长速度明显快于实际观察间隔。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 400
|
||||
- code: WBC-041
|
||||
@@ -302,6 +342,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 完成后耗时仍增长
|
||||
summaryZh: 回合完成后总耗时仍继续变化。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 410
|
||||
- code: WBC-042
|
||||
@@ -309,6 +350,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 最近更新跳变
|
||||
summaryZh: 最近更新时间显示出现异常跳变。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 420
|
||||
- code: WBC-043
|
||||
@@ -316,6 +358,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 回合耗时过长
|
||||
summaryZh: 回合总耗时超过配置的告警阈值。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 430
|
||||
- code: WBC-044
|
||||
@@ -323,6 +366,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 页面一直显示加载中
|
||||
summaryZh: 页面可见加载状态持续时间超过配置预算。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 440
|
||||
- code: WBC-045
|
||||
@@ -330,6 +374,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 页面同时显示多个加载中
|
||||
summaryZh: 同一时刻页面出现多个加载中提示。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 450
|
||||
- code: WBC-046
|
||||
@@ -337,6 +382,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 会话标题显示为兜底内容
|
||||
summaryZh: 会话栏没有显示正常标题,而是显示了兜底内容。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 460
|
||||
- code: WBC-047
|
||||
@@ -344,6 +390,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 页面滚动位置异常跳动
|
||||
summaryZh: 没有明显用户操作时,页面滚动位置跳到顶部附近。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 470
|
||||
- code: WBC-048
|
||||
@@ -351,6 +398,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 卡片耗时不一致
|
||||
summaryZh: 页面卡片上的耗时与实际观察到的耗时不一致。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 480
|
||||
- code: WBC-049
|
||||
@@ -358,6 +406,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 完成耗时不一致
|
||||
summaryZh: 回合完成状态前后的耗时显示不一致。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 490
|
||||
- code: WBC-050
|
||||
@@ -365,6 +414,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 完成后耗时变化
|
||||
summaryZh: 回合完成后仍出现耗时变化。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 500
|
||||
- code: WBC-051
|
||||
@@ -372,6 +422,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 完成后仍显示最近更新
|
||||
summaryZh: 回合完成后仍保留最近更新时间显示。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 510
|
||||
- code: WBC-052
|
||||
@@ -379,6 +430,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 没有采样数据
|
||||
summaryZh: 本次观察没有产生可分析的页面样本。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 520
|
||||
- code: WBC-053
|
||||
@@ -386,6 +438,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 样本文件读取失败
|
||||
summaryZh: 观察样本文件无法读取或解析。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 530
|
||||
- code: WBC-054
|
||||
@@ -393,6 +446,7 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 消息发送路径异常
|
||||
summaryZh: 用户消息走了非预期发送路径,需要确认上一回合状态。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 540
|
||||
- code: WBC-055
|
||||
@@ -400,6 +454,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 观察程序心跳过期
|
||||
summaryZh: 页面观察程序长时间没有更新心跳。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 550
|
||||
- code: WBC-056
|
||||
@@ -407,6 +462,7 @@ sentinel:
|
||||
level: error
|
||||
titleZh: 页面操作未被执行
|
||||
summaryZh: 存在等待执行但页面尚未处理的操作。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 560
|
||||
- code: WBC-057
|
||||
@@ -414,6 +470,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 历史页面操作遗留
|
||||
summaryZh: 观察过程中发现遗留的历史页面操作。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 570
|
||||
- code: WBC-058
|
||||
@@ -421,6 +478,7 @@ sentinel:
|
||||
level: info
|
||||
titleZh: 观察程序被强制停止
|
||||
summaryZh: 页面观察程序被控制面强制停止,作为上下文保留。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 580
|
||||
- code: WBC-059
|
||||
@@ -428,5 +486,294 @@ sentinel:
|
||||
level: warning
|
||||
titleZh: 项目入口请求失败
|
||||
summaryZh: 打开项目或进入 Workbench 的页面请求没有成功完成。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 590
|
||||
- code: WBC-060
|
||||
id: active-session-changed
|
||||
level: warning
|
||||
titleZh: 当前会话意外切换
|
||||
summaryZh: 页面当前会话在非预期窗口内发生切换。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 600
|
||||
- code: WBC-061
|
||||
id: code-agent-card-duration-underreported
|
||||
level: warning
|
||||
titleZh: 卡片耗时偏小
|
||||
summaryZh: 页面卡片显示的耗时小于观察到的实际耗时。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 610
|
||||
- code: WBC-062
|
||||
id: code-agent-card-elapsed-missing
|
||||
level: warning
|
||||
titleZh: 卡片未显示总耗时
|
||||
summaryZh: 页面运行卡片没有显示总耗时,影响判断等待时间。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 620
|
||||
- code: WBC-063
|
||||
id: code-agent-card-running-recent-update-missing
|
||||
level: warning
|
||||
titleZh: 卡片未显示最近更新
|
||||
summaryZh: 运行中的页面卡片没有显示最近更新时间。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 630
|
||||
- code: WBC-064
|
||||
id: frontend-browser-freeze-runner-blocker
|
||||
level: error
|
||||
titleZh: 浏览器冻结已阻塞
|
||||
summaryZh: 浏览器冻结策略已触发,巡检中止页面并报红。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 640
|
||||
- code: WBC-065
|
||||
id: frontend-browser-memory-growth-red
|
||||
level: error
|
||||
titleZh: 页面内存持续增长
|
||||
summaryZh: 页面有效内存在观察窗口内持续增长并超过配置预算。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 650
|
||||
- code: WBC-066
|
||||
id: frontend-browser-memory-rss-red
|
||||
level: error
|
||||
titleZh: 页面内存超出预算
|
||||
summaryZh: 页面有效内存超过配置红线,已按阻塞错误展示。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 660
|
||||
- code: WBC-067
|
||||
id: frontend-cdp-metrics-timeout-red
|
||||
level: error
|
||||
titleZh: 浏览器指标采集超时
|
||||
summaryZh: 浏览器侧指标连续采集超时,说明页面运行时可能已经无响应。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 670
|
||||
- code: WBC-068
|
||||
id: frontend-control-dom-evaluate-timeout-red
|
||||
level: error
|
||||
titleZh: 控制页面响应超时
|
||||
summaryZh: 控制页面的页面脚本执行连续超时,符合前端无响应特征。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 680
|
||||
- code: WBC-069
|
||||
id: frontend-observer-dom-evaluate-timeout-red
|
||||
level: error
|
||||
titleZh: 观察页面响应超时
|
||||
summaryZh: 观察页面的页面脚本执行连续超时,符合前端无响应特征。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 690
|
||||
- code: WBC-070
|
||||
id: frontend-page-error-red
|
||||
level: error
|
||||
titleZh: 页面错误连续出现
|
||||
summaryZh: 页面运行错误在观察窗口内连续出现,已按红色监测项展示。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 700
|
||||
- code: WBC-071
|
||||
id: frontend-playwright-responsiveness-red
|
||||
level: error
|
||||
titleZh: 页面响应探测超时
|
||||
summaryZh: 页面响应探测超过配置预算,已按前端卡死处理并报红。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 710
|
||||
- code: WBC-072
|
||||
id: frontend-screenshot-timeout-red
|
||||
level: error
|
||||
titleZh: 页面截图连续超时
|
||||
summaryZh: 页面截图在观察窗口内连续超时,说明页面可能已经无响应。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 720
|
||||
- code: WBC-073
|
||||
id: mdtodo-file-label-not-filename
|
||||
level: error
|
||||
titleZh: MDTODO 文件名显示异常
|
||||
summaryZh: MDTODO 文件下拉框当前选择项不是直接的 Markdown 文件名。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 730
|
||||
- code: WBC-074
|
||||
id: mdtodo-hwpod-node-disconnected
|
||||
level: error
|
||||
titleZh: HWPOD 节点未连接
|
||||
summaryZh: MDTODO 页面显示 HWPOD 节点连接不可用。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 740
|
||||
- code: WBC-075
|
||||
id: mdtodo-nondirect-files-visible
|
||||
level: error
|
||||
titleZh: MDTODO 文件列表混入非直接文件
|
||||
summaryZh: MDTODO 文件下拉框出现非直接文件或报告类条目。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 750
|
||||
- code: WBC-076
|
||||
id: mdtodo-pane-bottom-gap
|
||||
level: error
|
||||
titleZh: MDTODO 面板底部空白过大
|
||||
summaryZh: MDTODO 任务树、详情或报告区域存在影响操作的大块底部空白。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 760
|
||||
- code: WBC-077
|
||||
id: mdtodo-report-fullscreen-missing
|
||||
level: error
|
||||
titleZh: 报告全屏未打开
|
||||
summaryZh: 执行报告全屏操作后没有观察到全屏报告对话框。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 770
|
||||
- code: WBC-078
|
||||
id: mdtodo-report-preview-missing
|
||||
level: error
|
||||
titleZh: 报告预览未显示
|
||||
summaryZh: 页面有报告入口,但没有观察到 Markdown 报告预览。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 780
|
||||
- code: WBC-079
|
||||
id: mdtodo-report-projection-only
|
||||
level: error
|
||||
titleZh: 报告只显示投影内容
|
||||
summaryZh: MDTODO 报告预览只显示投影内容,没有打开源报告正文。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 790
|
||||
- code: WBC-080
|
||||
id: mdtodo-task-body-not-visible
|
||||
level: error
|
||||
titleZh: MDTODO 任务正文不可见
|
||||
summaryZh: 已选择 MDTODO 任务,但页面没有显示任务正文。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 800
|
||||
- code: WBC-081
|
||||
id: mdtodo-task-count-diverged
|
||||
level: warning
|
||||
titleZh: MDTODO 任务数量波动
|
||||
summaryZh: 观察期间 MDTODO 任务数量出现明显波动。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 810
|
||||
- code: WBC-082
|
||||
id: mdtodo-taskref-missing
|
||||
level: error
|
||||
titleZh: MDTODO 任务缺少稳定编号
|
||||
summaryZh: MDTODO 任务行可见,但缺少稳定任务引用编号。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 820
|
||||
- code: WBC-083
|
||||
id: mdtodo-workbench-launch-empty
|
||||
level: error
|
||||
titleZh: Workbench 启动后内容为空
|
||||
summaryZh: 从 MDTODO 启动 Workbench 后没有观察到对话或过程记录内容。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 830
|
||||
- code: WBC-084
|
||||
id: mdtodo-workbench-launch-failed
|
||||
level: error
|
||||
titleZh: Workbench 启动失败
|
||||
summaryZh: 从 MDTODO 启动 Workbench 的操作失败或返回错误。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 840
|
||||
- code: WBC-085
|
||||
id: mdtodo-workbench-launch-otel-trace-missing
|
||||
level: warning
|
||||
titleZh: Workbench 启动缺少追踪编号
|
||||
summaryZh: Workbench 启动成功,但没有采集到可用于链路排查的追踪编号。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 850
|
||||
- code: WBC-086
|
||||
id: project-management-api-slow
|
||||
level: error
|
||||
titleZh: 项目管理接口过慢
|
||||
summaryZh: 项目管理页面接口耗时超过配置预算。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 860
|
||||
- code: WBC-087
|
||||
id: project-management-hwpod-api-failed
|
||||
level: error
|
||||
titleZh: HWPOD 项目接口失败
|
||||
summaryZh: HWPOD 支撑的任务详情或报告接口返回服务错误。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 870
|
||||
- code: WBC-088
|
||||
id: project-management-route-not-ready
|
||||
level: error
|
||||
titleZh: 项目管理页面未就绪
|
||||
summaryZh: 已打开项目管理目标路径,但页面摘要没有正常出现。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 880
|
||||
- code: WBC-089
|
||||
id: session-route-changed
|
||||
level: warning
|
||||
titleZh: 地址栏会话意外切换
|
||||
summaryZh: 地址栏会话在非预期窗口内发生切换。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 890
|
||||
- code: WBC-090
|
||||
id: trace-completion-row-not-last
|
||||
level: error
|
||||
titleZh: 完成记录不是最后一行
|
||||
summaryZh: 过程记录中完成状态后仍出现后续记录,影响判断终态。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 900
|
||||
- code: WBC-091
|
||||
id: trace-row-order-nonmonotonic
|
||||
level: error
|
||||
titleZh: 过程记录顺序异常
|
||||
summaryZh: 过程记录的行顺序不是单调递增,影响排查和终态判断。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 910
|
||||
- code: WBC-092
|
||||
id: turn-terminal-zero-elapsed
|
||||
level: warning
|
||||
titleZh: 终态耗时显示为零
|
||||
summaryZh: 已完成回合的页面卡片仍显示总耗时为 0 秒。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 920
|
||||
- code: WBC-093
|
||||
id: uncommanded-visible-state-change
|
||||
level: warning
|
||||
titleZh: 页面状态无操作变化
|
||||
summaryZh: 没有对应用户操作时,页面可见消息或过程记录发生变化。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: false
|
||||
order: 930
|
||||
- code: WBC-094
|
||||
id: workbench-controlled-navigation-degraded-root-cause
|
||||
level: error
|
||||
titleZh: 受控导航后页面退化
|
||||
summaryZh: Workbench 受控导航后页面状态退化,影响后续观察。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 940
|
||||
- code: WBC-095
|
||||
id: workbench-launch-button-unavailable
|
||||
level: error
|
||||
titleZh: Workbench 启动按钮不可用
|
||||
summaryZh: MDTODO 任务可见,但 Workbench 启动按钮一直不可用。
|
||||
actionZh: 查看详情后处理。
|
||||
blocking: true
|
||||
order: 950
|
||||
|
||||
@@ -343,30 +343,12 @@ select {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.trend-red {
|
||||
fill: none;
|
||||
stroke: var(--red);
|
||||
stroke-width: 3;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.trend-warning {
|
||||
fill: none;
|
||||
stroke: var(--amber);
|
||||
stroke-width: 3;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.trend-total {
|
||||
.trend-duration {
|
||||
fill: none;
|
||||
stroke: var(--blue);
|
||||
stroke-width: 2;
|
||||
stroke-dasharray: 5 6;
|
||||
stroke-width: 3;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.trend-grid-line {
|
||||
@@ -374,12 +356,10 @@ select {
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.trend-dot-red {
|
||||
fill: var(--red);
|
||||
}
|
||||
|
||||
.trend-dot-warning {
|
||||
fill: var(--amber);
|
||||
.trend-dot-duration {
|
||||
fill: var(--blue);
|
||||
stroke: #ffffff;
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
.trend-dot-hit {
|
||||
@@ -450,6 +430,10 @@ select {
|
||||
background: var(--red);
|
||||
}
|
||||
|
||||
.legend-swatch.duration {
|
||||
background: var(--blue);
|
||||
}
|
||||
|
||||
.legend-swatch.warning {
|
||||
background: var(--amber);
|
||||
}
|
||||
|
||||
@@ -4,123 +4,6 @@ import { createApp, computed, onMounted, ref, watch } from "./vendor/vue.esm-bro
|
||||
|
||||
const bootstrap = readBootstrap();
|
||||
const internalTextPattern = /水合|投影|Trace|trace|Shell|API|DOM|Console|console|Runner|runner|JSONL|steer|facts|分页|HTTP|http|requestfailed|pageerror|Final Response|Code Agent|web-probe|observe|analyzer|终态/u;
|
||||
const checkDisplayCatalog = {
|
||||
"code-agent-card-elapsed-missing": {
|
||||
code: "CHECK-101",
|
||||
title: "耗时未显示",
|
||||
summary: "运行卡片没有显示总耗时,影响判断等待时间。",
|
||||
},
|
||||
"code-agent-card-running-recent-update-missing": {
|
||||
code: "CHECK-102",
|
||||
title: "最近更新时间未显示",
|
||||
summary: "运行中的卡片没有显示最近更新时间,影响判断是否仍在推进。",
|
||||
},
|
||||
"turn-timing-total-elapsed-decrease": {
|
||||
code: "CHECK-103",
|
||||
title: "耗时显示回退",
|
||||
summary: "相邻采样中的总耗时出现回退,作为非阻塞计时报警展示。",
|
||||
},
|
||||
"page-loading-concurrent": {
|
||||
code: "CHECK-201",
|
||||
title: "多个加载状态同时出现",
|
||||
summary: "同一采样点看到多个加载提示,用户可能难以判断当前页面是否已就绪。",
|
||||
},
|
||||
"trace-events-page-read-requestfailed-root-cause": {
|
||||
code: "CHECK-301",
|
||||
title: "运行事件读取失败",
|
||||
summary: "运行事件页面读取失败,需要结合服务端链路确认具体失败位置。",
|
||||
},
|
||||
"runtime-requestfailed": {
|
||||
code: "CHECK-302",
|
||||
title: "页面资源加载失败",
|
||||
summary: "巡检期间捕获到页面资源加载失败,可能影响用户看到的运行状态。",
|
||||
},
|
||||
"runtime-console-alerts": {
|
||||
code: "CHECK-303",
|
||||
title: "页面脚本报警",
|
||||
summary: "巡检期间捕获到页面脚本报警,需要评估是否影响用户操作。",
|
||||
},
|
||||
"workbench-app-shell-transient-not-ready": {
|
||||
code: "CHECK-304",
|
||||
title: "工作台短暂未就绪",
|
||||
summary: "工作台短时间内未完成主界面就绪,作为启动过程上下文保留。",
|
||||
},
|
||||
"cross-page-projection-divergence": {
|
||||
code: "CHECK-401",
|
||||
title: "多页面状态不一致",
|
||||
summary: "同一会话在两个页面中显示的状态持续不一致,可能影响用户判断。",
|
||||
},
|
||||
"cross-page-projection-transient-divergence": {
|
||||
code: "CHECK-402",
|
||||
title: "多页面短暂不一致",
|
||||
summary: "页面切换附近短暂出现显示差异,作为上下文保留。",
|
||||
},
|
||||
"cross-page-projection-controlled-navigation-hydration": {
|
||||
code: "CHECK-403",
|
||||
title: "跳转后页面短暂空白",
|
||||
summary: "页面跳转后短暂空白,当前按非阻塞上下文展示。",
|
||||
},
|
||||
"cross-page-trace-visibility-divergence": {
|
||||
code: "CHECK-404",
|
||||
title: "运行记录显示数量不一致",
|
||||
summary: "两个页面看到的运行记录数量不同,但未直接证明消息状态不一致。",
|
||||
},
|
||||
"page-performance-slow-same-origin-api": {
|
||||
code: "CHECK-501",
|
||||
title: "页面数据加载慢",
|
||||
summary: "页面数据加载超过配置预算,用户可能感觉等待时间过长。",
|
||||
},
|
||||
"page-performance-long-lived-streams": {
|
||||
code: "CHECK-502",
|
||||
title: "长连接持续保持",
|
||||
summary: "长时间连接单独统计,不直接作为页面加载慢处理。",
|
||||
},
|
||||
"natural-api-dom-lag-baseline": {
|
||||
code: "CHECK-503",
|
||||
title: "数据变化可关联",
|
||||
summary: "已采集到数据响应和页面变化样本,可用于分析显示延迟。",
|
||||
},
|
||||
"natural-api-dom-lag-candidates": {
|
||||
code: "CHECK-504",
|
||||
title: "数据更新显示偏慢",
|
||||
summary: "部分数据变化到页面显示的时间超过预算,作为非阻塞调查报警。",
|
||||
},
|
||||
"browser-console-or-page-errors": {
|
||||
code: "CHECK-601",
|
||||
title: "页面脚本错误",
|
||||
summary: "巡检期间捕获到页面脚本错误,需要确认是否影响用户流程。",
|
||||
},
|
||||
"quick-verify-no-business-turn": {
|
||||
code: "CHECK-701",
|
||||
title: "业务轮次未完成",
|
||||
summary: "巡检未确认到稳定的业务交互结果,不能作为恢复证据。",
|
||||
},
|
||||
"frontend-browser-memory-rss-red": {
|
||||
code: "CHECK-801",
|
||||
title: "页面内存超出预算",
|
||||
summary: "页面有效内存超过配置红线,已按阻塞错误展示。",
|
||||
},
|
||||
"frontend-browser-memory-growth-red": {
|
||||
code: "CHECK-802",
|
||||
title: "页面内存持续增长",
|
||||
summary: "页面有效内存在观察窗口内持续增长并超过配置预算,符合卡死风险特征。",
|
||||
},
|
||||
"frontend-browser-freeze-runner-blocker": {
|
||||
code: "CHECK-803",
|
||||
title: "浏览器冻结已阻塞",
|
||||
summary: "浏览器冻结策略已触发,巡检中止页面并报红,不能用刷新或兜底掩盖。",
|
||||
},
|
||||
"frontend-playwright-responsiveness-red": {
|
||||
code: "CHECK-804",
|
||||
title: "页面响应探测超时",
|
||||
summary: "页面响应探测超过配置预算,已按前端卡死处理并报红。",
|
||||
},
|
||||
"frontend-cdp-metrics-timeout-red": {
|
||||
code: "CHECK-805",
|
||||
title: "浏览器指标采集超时",
|
||||
summary: "浏览器侧指标连续采集超时,说明页面运行时可能已经无响应。",
|
||||
},
|
||||
};
|
||||
|
||||
createApp({
|
||||
setup() {
|
||||
@@ -165,19 +48,18 @@ createApp({
|
||||
const selectedRun = computed(() => runs.value.find((run) => run.id === selectedRunId.value) || latestRun.value);
|
||||
const trendRows = computed(() => runs.value.slice().sort((a, b) => Date.parse(a.updatedAt || a.createdAt || "") - Date.parse(b.updatedAt || b.createdAt || "")).slice(-48));
|
||||
const latestTrendRun = computed(() => trendRows.value.length > 0 ? trendRows.value[trendRows.value.length - 1] : latestRun.value);
|
||||
const trendMax = computed(() => Math.max(1, ...trendRows.value.flatMap((run) => [trendErrorCount(run), trendWarningCount(run), trendTotalCount(run)])));
|
||||
const trendDurationMax = computed(() => Math.max(0, ...trendRows.value.map((run) => trendDurationMinutes(run))));
|
||||
const trendMax = computed(() => Math.max(1, trendDurationMax.value));
|
||||
const trendPolylines = computed(() => ({
|
||||
red: trendPolyline((run) => trendErrorCount(run)),
|
||||
warning: trendPolyline((run) => trendWarningCount(run)),
|
||||
total: trendPolyline((run) => trendTotalCount(run)),
|
||||
duration: trendPolyline((run) => trendDurationMinutes(run)),
|
||||
}));
|
||||
const trendDots = computed(() => trendRows.value.map((run, index) => {
|
||||
const red = trendErrorCount(run);
|
||||
const warning = trendWarningCount(run);
|
||||
const total = trendTotalCount(run);
|
||||
const duration = trendDurationMinutes(run);
|
||||
const x = trendX(index, trendRows.value.length);
|
||||
const redY = trendY(red);
|
||||
const warningY = trendY(warning);
|
||||
const durationY = trendY(duration);
|
||||
const rawTime = run.updatedAt || run.createdAt || "";
|
||||
const durationText = runDurationText(run);
|
||||
const configTimingText = runTimingConfigText(run);
|
||||
@@ -185,10 +67,10 @@ createApp({
|
||||
id: run.id || String(index),
|
||||
runId: run.id || "",
|
||||
x,
|
||||
redY,
|
||||
warningY,
|
||||
durationY,
|
||||
duration,
|
||||
tooltipLeft: `${clamp((x / 720) * 100, 16, 84)}%`,
|
||||
tooltipTop: `${clamp(((Math.min(redY, warningY) + 18) / 142) * 100, 24, 76)}%`,
|
||||
tooltipTop: `${clamp(((durationY + 18) / 142) * 100, 24, 76)}%`,
|
||||
red,
|
||||
warning,
|
||||
total,
|
||||
@@ -363,6 +245,10 @@ createApp({
|
||||
return runCheckAlertCount(run);
|
||||
}
|
||||
|
||||
function trendDurationMinutes(run) {
|
||||
return number(run?.runDurationMinutes ?? run?.durationMinutes ?? run?.timing?.durationMinutes);
|
||||
}
|
||||
|
||||
function openCheckDetail(item) {
|
||||
activeCheckItem.value = item || null;
|
||||
}
|
||||
@@ -459,6 +345,7 @@ createApp({
|
||||
selectedRun,
|
||||
trendRows,
|
||||
latestTrendRun,
|
||||
trendDurationMax,
|
||||
trendPolylines,
|
||||
trendDots,
|
||||
timelineRuns,
|
||||
@@ -492,12 +379,14 @@ createApp({
|
||||
trendTotalCount,
|
||||
trendErrorCount,
|
||||
trendWarningCount,
|
||||
trendDurationMinutes,
|
||||
runDurationText,
|
||||
runTimingConfigText,
|
||||
severityClass,
|
||||
formatDate,
|
||||
formatAbsoluteDate,
|
||||
formatDuration,
|
||||
formatMinutes,
|
||||
shortId,
|
||||
rootCauseText,
|
||||
findingTitle,
|
||||
@@ -566,19 +455,17 @@ createApp({
|
||||
<section class="trend-panel" aria-labelledby="trend-heading">
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<h2 id="trend-heading">错误 / 告警监测项曲线</h2>
|
||||
<p>按运行更新时间展示最近 {{ trendRows.length }} 次变化,点位为单次运行监测项行数</p>
|
||||
<h2 id="trend-heading">运行耗时曲线</h2>
|
||||
<p>按运行更新时间展示最近 {{ trendRows.length }} 次巡检耗时,单位为分钟</p>
|
||||
</div>
|
||||
<span class="pill" :class="cadence.stale ? 'warning' : 'healthy'">{{ cadence.stale ? "非阻塞报警" : "新鲜" }}</span>
|
||||
</div>
|
||||
<div class="trend-chart-wrap">
|
||||
<svg class="trend-chart" viewBox="0 0 720 142" role="img" aria-label="错误和告警监测项数量趋势" data-monitor-trend-curve="true">
|
||||
<svg class="trend-chart" viewBox="0 0 720 142" role="img" aria-label="运行耗时分钟趋势" data-monitor-trend-curve="true">
|
||||
<line class="trend-grid-line" x1="24" x2="696" y1="24" y2="24"></line>
|
||||
<line class="trend-grid-line" x1="24" x2="696" y1="75" y2="75"></line>
|
||||
<line class="trend-grid-line" x1="24" x2="696" y1="126" y2="126"></line>
|
||||
<polyline v-if="trendPolylines.total" class="trend-total" :points="trendPolylines.total"></polyline>
|
||||
<polyline v-if="trendPolylines.warning" class="trend-warning" :points="trendPolylines.warning"></polyline>
|
||||
<polyline v-if="trendPolylines.red" class="trend-red" :points="trendPolylines.red"></polyline>
|
||||
<polyline v-if="trendPolylines.duration" class="trend-duration" :points="trendPolylines.duration"></polyline>
|
||||
<g
|
||||
v-for="dot in trendDots"
|
||||
:key="dot.id"
|
||||
@@ -591,11 +478,8 @@ createApp({
|
||||
@mouseleave="hideTrendTooltip"
|
||||
@focusout="hideTrendTooltip"
|
||||
>
|
||||
<circle class="trend-hit-area" :cx="dot.x" :cy="Math.min(dot.redY, dot.warningY)" r="12"></circle>
|
||||
<circle class="trend-dot-warning" :cx="dot.x" :cy="dot.warningY" r="3">
|
||||
<title>{{ dot.title }}</title>
|
||||
</circle>
|
||||
<circle class="trend-dot-red" :cx="dot.x" :cy="dot.redY" r="3">
|
||||
<circle class="trend-hit-area" :cx="dot.x" :cy="dot.durationY" r="12"></circle>
|
||||
<circle class="trend-dot-duration" :cx="dot.x" :cy="dot.durationY" r="4">
|
||||
<title>{{ dot.title }}</title>
|
||||
</circle>
|
||||
</g>
|
||||
@@ -617,9 +501,9 @@ createApp({
|
||||
<div v-if="trendRows.length === 0" class="trend-empty">暂无运行数据</div>
|
||||
</div>
|
||||
<div class="trend-legend">
|
||||
<span class="legend-item"><span class="legend-swatch red"></span>最新点错误 {{ trendErrorCount(latestTrendRun) }}</span>
|
||||
<span class="legend-item"><span class="legend-swatch warning"></span>最新点告警 {{ trendWarningCount(latestTrendRun) }}</span>
|
||||
<span class="legend-item"><span class="legend-swatch total"></span>最新点错误+告警合计 {{ trendTotalCount(latestTrendRun) }}</span>
|
||||
<span class="legend-item"><span class="legend-swatch duration"></span>最新运行耗时 {{ runDurationText(latestTrendRun) }}</span>
|
||||
<span class="legend-item">最近最高耗时 {{ formatMinutes(trendDurationMax) }}</span>
|
||||
<span class="legend-item">最新错误 {{ trendErrorCount(latestTrendRun) }} / 告警 {{ trendWarningCount(latestTrendRun) }}</span>
|
||||
<span class="legend-item">历史样本累计 错误 {{ redCount({ severityCounts: severityTotals }) }} / 告警 {{ warningCount({ severityCounts: severityTotals }) }}</span>
|
||||
<span class="legend-item">{{ cadence.alert }}</span>
|
||||
</div>
|
||||
@@ -1127,7 +1011,7 @@ function clamp(value, min, max) {
|
||||
function rootCauseText(item) {
|
||||
const display = checkDisplay(item);
|
||||
if (display.summary) return display.summary;
|
||||
const safeSummary = safeUserText(item?.checkSummaryZh || item?.summary || item?.evidenceSummary);
|
||||
const safeSummary = safeUserText(item?.checkSummaryZh || item?.check?.summaryZh);
|
||||
if (safeSummary) return safeSummary;
|
||||
if (item?.rootCause) return "已记录内部根因,见报告详情。";
|
||||
return "尚未记录用户可见问题摘要。";
|
||||
@@ -1201,7 +1085,8 @@ function checkTimeText(item) {
|
||||
}
|
||||
|
||||
function checkActionText(item) {
|
||||
return safeUserText(item?.nextAction || item?.action || item?.recommendation) || "查看详情后处理";
|
||||
const display = checkDisplay(item);
|
||||
return display.action || safeUserText(item?.checkActionZh || item?.check?.actionZh) || "查看详情后处理";
|
||||
}
|
||||
|
||||
function checkDetailRows(item) {
|
||||
@@ -1223,7 +1108,7 @@ function checkEvidenceRows(item) {
|
||||
if (!item) return [{ key: "empty", label: "状态", value: "未选择监测项" }];
|
||||
const evidence = item?.evidence && typeof item.evidence === "object" && !Array.isArray(item.evidence) ? item.evidence : {};
|
||||
const rows = [
|
||||
{ key: "summary", label: "证据摘要", value: safeUserText(item?.evidenceSummary || evidence.summary || item?.summary) || rootCauseText(item) },
|
||||
{ key: "summary", label: "证据摘要", value: rootCauseText(item) || safeUserText(item?.evidenceSummary || evidence.summary) },
|
||||
{ key: "sample", label: "样本序号", value: safeDetailValue(item?.sampleSeq ?? evidence.sampleSeq) },
|
||||
{ key: "page", label: "页面", value: safeDetailValue(item?.pageRole || evidence.pageRole) },
|
||||
{ key: "command", label: "命令编号", value: safeDetailValue(item?.commandId || evidence.commandId) },
|
||||
@@ -1254,20 +1139,12 @@ function safeDetailValue(value) {
|
||||
function checkDisplay(item) {
|
||||
const rawCode = rawCheckCode(item);
|
||||
const rawId = rawFindingId(item);
|
||||
const registered = checkDisplayCatalog[rawId] || checkDisplayCatalog[rawCode];
|
||||
const serviceCode = publicCheckCode(item?.checkCode || item?.check?.code);
|
||||
if (registered) {
|
||||
return {
|
||||
...registered,
|
||||
code: serviceCode || registered.code,
|
||||
title: safeUserText(item?.checkTitleZh || item?.check?.titleZh) || registered.title,
|
||||
summary: safeUserText(item?.checkSummaryZh || item?.summary || item?.evidenceSummary || item?.check?.summaryZh) || registered.summary,
|
||||
};
|
||||
}
|
||||
return {
|
||||
code: serviceCode || publicCheckCode(rawId || rawCode) || stableCheckCode(rawCode || rawId),
|
||||
title: safeUserText(item?.checkTitleZh || item?.check?.titleZh) || "未登记监测项",
|
||||
summary: safeUserText(item?.checkSummaryZh || item?.summary || item?.evidenceSummary) || "已记录监测项详情,见报告原文。",
|
||||
summary: safeUserText(item?.checkSummaryZh || item?.check?.summaryZh) || "已记录监测项详情,见报告原文。",
|
||||
action: safeUserText(item?.checkActionZh || item?.check?.actionZh) || "查看详情后处理",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPEC: PJ2026-01060508 Web哨兵 draft-2026-06-25-p0-web-probe-sentinel.
|
||||
// SPEC: PJ2026-01060508 Web哨兵 draft-2026-06-26-p9-multi-web-probe-sentinel.
|
||||
// Responsibility: Redacted YAML configRef graph for web-probe sentinel plan/status.
|
||||
import { readFileSync } from "node:fs";
|
||||
import { rootPath } from "./config";
|
||||
import { readWebProbeSentinelConfigRef } from "./hwlab-node-web-sentinel-config-ref";
|
||||
import { HWLAB_WEB_PROBE_SENTINEL_CONFIG_REF_KEYS, type HwlabRuntimeLaneSpec, type HwlabRuntimeWebProbeSentinelConfigRefKey } from "./hwlab-node-lanes";
|
||||
import { effectiveWebProbeSentinelPublicExposure, resolveWebProbeSentinel, webProbeSentinelRegistryRows, type WebProbeSentinelRegistryRow } from "./hwlab-node-web-sentinel-resolver";
|
||||
@@ -100,7 +102,7 @@ const REQUIRED_TARGET_SHAPES: Record<HwlabRuntimeWebProbeSentinelConfigRefKey, R
|
||||
},
|
||||
reportViews: {
|
||||
kind: "object",
|
||||
requiredPaths: ["defaultView", "views[0]", "pageSize", "maxPageSize", "rawAccess", "redaction.prompt", "redaction.secrets"],
|
||||
requiredPaths: ["defaultView", "views[0]", "pageSize", "maxPageSize", "rawAccess", "checkCatalogRef", "redaction.prompt", "redaction.secrets"],
|
||||
},
|
||||
publicExposure: {
|
||||
kind: "object",
|
||||
@@ -320,6 +322,7 @@ function crossReferenceConflicts(spec: HwlabRuntimeLaneSpec, refs: readonly Inte
|
||||
const runtime = recordTarget(byKey.get("runtime"));
|
||||
const scenarios = scenarioTargets(byKey.get("scenarios"));
|
||||
const promptSet = recordTarget(byKey.get("promptSet"));
|
||||
const reportViews = recordTarget(byKey.get("reportViews"));
|
||||
const cicd = recordTarget(byKey.get("cicd"));
|
||||
const secrets = recordTarget(byKey.get("secrets"));
|
||||
|
||||
@@ -350,6 +353,8 @@ function crossReferenceConflicts(spec: HwlabRuntimeLaneSpec, refs: readonly Inte
|
||||
conflicts.push(`${byKey.get("cicd")?.file}#${byKey.get("cicd")?.path}.targetValidation.scenarioId=${validationScenarioId} is not declared in scenarios`);
|
||||
}
|
||||
|
||||
validateReportViewsCheckCatalog(spec, conflicts, byKey.get("reportViews"), reportViews);
|
||||
|
||||
const runtimeNamespace = runtime === null ? null : stringAt(runtime, "namespace");
|
||||
const runtimeSecrets = secrets === null ? [] : arrayAt(secrets, "runtimeSecrets");
|
||||
if (runtimeNamespace !== null) {
|
||||
@@ -363,6 +368,74 @@ function crossReferenceConflicts(spec: HwlabRuntimeLaneSpec, refs: readonly Inte
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
function validateReportViewsCheckCatalog(spec: HwlabRuntimeLaneSpec, conflicts: string[], ref: InternalConfigRefStatus | undefined, reportViews: Record<string, unknown> | null): void {
|
||||
if (reportViews === null) return;
|
||||
const catalogRef = stringAt(reportViews, "checkCatalogRef");
|
||||
if (catalogRef === null) {
|
||||
conflicts.push(`${ref?.file ?? "-"}#${ref?.path ?? "-"}.checkCatalogRef is required`);
|
||||
return;
|
||||
}
|
||||
let catalog: Record<string, unknown>;
|
||||
try {
|
||||
const target = readWebProbeSentinelConfigRef(spec, catalogRef).target;
|
||||
catalog = isRecord(target) ? target : {};
|
||||
} catch (error) {
|
||||
conflicts.push(`${ref?.file ?? "-"}#${ref?.path ?? "-"}.checkCatalogRef=${catalogRef} is not readable: ${error instanceof Error ? error.message : String(error)}`);
|
||||
return;
|
||||
}
|
||||
const items = arrayAt(catalog, "items");
|
||||
if (items.length === 0) {
|
||||
conflicts.push(`${catalogRef}.items is empty`);
|
||||
return;
|
||||
}
|
||||
const byId = new Map<string, Record<string, unknown>>();
|
||||
const codes = new Set<string>();
|
||||
for (const [index, item] of items.entries()) {
|
||||
const itemId = stringAt(item, "id");
|
||||
const code = stringAt(item, "code");
|
||||
if (itemId === null) conflicts.push(`${catalogRef}.items[${index}].id is required`);
|
||||
else if (byId.has(itemId)) conflicts.push(`${catalogRef}.items id duplicated: ${itemId}`);
|
||||
else byId.set(itemId, item);
|
||||
if (code === null) conflicts.push(`${catalogRef}.items[${index}].code is required`);
|
||||
else if (codes.has(code)) conflicts.push(`${catalogRef}.items code duplicated: ${code}`);
|
||||
else codes.add(code);
|
||||
for (const field of ["titleZh", "summaryZh", "actionZh"]) {
|
||||
const text = stringAt(item, field);
|
||||
if (text === null) {
|
||||
conflicts.push(`${catalogRef}.items[${index}].${field} is required`);
|
||||
} else if (!containsChinese(text)) {
|
||||
conflicts.push(`${catalogRef}.items[${index}].${field} must contain Chinese text`);
|
||||
}
|
||||
}
|
||||
}
|
||||
const requiredIds = knownWebProbeFindingIds();
|
||||
const missing = requiredIds.filter((id) => !byId.has(id));
|
||||
if (missing.length > 0) {
|
||||
conflicts.push(`${catalogRef}.items missing analyzer finding ids: ${missing.slice(0, 24).join(",")}${missing.length > 24 ? `,+${missing.length - 24}` : ""}`);
|
||||
}
|
||||
}
|
||||
|
||||
function knownWebProbeFindingIds(): string[] {
|
||||
const ids = new Set<string>();
|
||||
for (const file of [
|
||||
"scripts/src/hwlab-node-web-observe-analyzer-source.ts",
|
||||
"scripts/src/hwlab-node-web-sentinel-p5-observe.ts",
|
||||
]) {
|
||||
let source = "";
|
||||
try {
|
||||
source = readFileSync(rootPath(file), "utf8");
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
for (const match of source.matchAll(/\bid:\s*["`]([A-Za-z0-9_.:-]+)["`]/gu)) ids.add(match[1]);
|
||||
}
|
||||
return Array.from(ids).sort();
|
||||
}
|
||||
|
||||
function containsChinese(value: string): boolean {
|
||||
return /[\u3400-\u9fff]/u.test(value);
|
||||
}
|
||||
|
||||
function requireReadableConfigRef(spec: HwlabRuntimeLaneSpec, conflicts: string[], ref: InternalConfigRefStatus | undefined, path: string, value: unknown): void {
|
||||
if (typeof value !== "string" || value.length === 0) return;
|
||||
try {
|
||||
|
||||
@@ -552,7 +552,7 @@ await page.evaluate(() => {
|
||||
await page.waitForTimeout(150);
|
||||
|
||||
const trendHoverPoint = await page.evaluate(() => {
|
||||
const target = document.querySelector(".trend-dot-hit .trend-dot-red") || document.querySelector(".trend-dot-hit .trend-dot-warning");
|
||||
const target = document.querySelector(".trend-dot-hit .trend-dot-duration");
|
||||
if (!(target instanceof SVGElement)) return null;
|
||||
const rect = target.getBoundingClientRect();
|
||||
if (rect.width <= 0 || rect.height <= 0) return null;
|
||||
@@ -600,17 +600,15 @@ const dom = await page.evaluate(async ({ expectedRoutePrefix, expectedSentinelId
|
||||
const legendTexts = Array.from(document.querySelectorAll(".trend-legend .legend-item")).map((item) => String(item.textContent || "").replace(/\s+/g, " ").trim());
|
||||
const legendNumber = (label) => {
|
||||
const row = legendTexts.find((item) => item.includes(label)) || "";
|
||||
const match = /(\d+)/u.exec(row);
|
||||
const match = /(\d+(?:\.\d+)?)/u.exec(row);
|
||||
return match ? Number(match[1]) : null;
|
||||
};
|
||||
const chartCounts = {
|
||||
error: legendNumber("最新点错误"),
|
||||
warning: legendNumber("最新点告警"),
|
||||
total: legendNumber("错误+告警合计"),
|
||||
const chartTiming = {
|
||||
latestMinutes: legendNumber("最新运行耗时"),
|
||||
maxMinutes: legendNumber("最近最高耗时"),
|
||||
title: text("#trend-heading"),
|
||||
legendHasDuration: legendTexts.some((item) => item.includes("最新运行耗时")),
|
||||
};
|
||||
chartCounts.ok = typeof chartCounts.error === "number" && typeof chartCounts.warning === "number" && typeof chartCounts.total === "number"
|
||||
? chartCounts.total === chartCounts.error + chartCounts.warning
|
||||
: false;
|
||||
const apiUrl = (path) => {
|
||||
const basePath = root?.getAttribute("data-base-path") || expectedRoutePrefix || "";
|
||||
const prefix = basePath.replace(/\/+$/u, "");
|
||||
@@ -769,10 +767,9 @@ const dom = await page.evaluate(async ({ expectedRoutePrefix, expectedSentinelId
|
||||
total: errorSampleCount(overviewCounts) + warningSampleCount(overviewCounts),
|
||||
allSamples: allSampleCount(overviewCounts),
|
||||
};
|
||||
chartCounts.matchesLatestRun = chartCounts.ok === true
|
||||
&& chartCounts.error === latestRunCounts.error
|
||||
&& chartCounts.warning === latestRunCounts.warning
|
||||
&& chartCounts.total === latestRunCounts.total;
|
||||
chartTiming.ok = chartTiming.title.includes("运行耗时") && chartTiming.legendHasDuration === true && Number.isFinite(chartTiming.latestMinutes);
|
||||
chartTiming.matchesLatestRun = chartTiming.ok === true
|
||||
&& Math.abs(Number(chartTiming.latestMinutes) - Number(latestRunCounts.durationMinutes)) < 0.02;
|
||||
const trendPanel = document.querySelector(".trend-panel");
|
||||
const trendLegend = document.querySelector(".trend-panel .trend-legend");
|
||||
const trendPanelRect = trendPanel?.getBoundingClientRect();
|
||||
@@ -870,7 +867,7 @@ const dom = await page.evaluate(async ({ expectedRoutePrefix, expectedSentinelId
|
||||
trendDotCount: document.querySelectorAll(".trend-dot-hit").length,
|
||||
trendTooltip: trendTooltipSummary,
|
||||
trendPanelText: text("#trend-heading"),
|
||||
chartCounts,
|
||||
chartTiming,
|
||||
latestRunCounts,
|
||||
latestDetailSummary,
|
||||
timingVisibility,
|
||||
@@ -881,7 +878,7 @@ const dom = await page.evaluate(async ({ expectedRoutePrefix, expectedSentinelId
|
||||
overviewSamples,
|
||||
panelHeights,
|
||||
scopeLabels: {
|
||||
latestPointLegend: legendTexts.some((item) => item.includes("最新点")),
|
||||
latestPointLegend: legendTexts.some((item) => item.includes("最新运行耗时")),
|
||||
historicalSamples: legendTexts.some((item) => item.includes("历史样本累计")) || statusText.includes("历史错误样本"),
|
||||
},
|
||||
timelineItems: document.querySelectorAll(".timeline-list .timeline-item").length,
|
||||
@@ -1067,8 +1064,8 @@ const ok = !navigationError
|
||||
&& dom.sentinelBoundary?.routePrefixMatches === true
|
||||
&& dom.errorVisible !== true
|
||||
&& dom.trendCurve === true
|
||||
&& dom.chartCounts?.ok === true
|
||||
&& dom.chartCounts?.matchesLatestRun === true
|
||||
&& dom.chartTiming?.ok === true
|
||||
&& dom.chartTiming?.matchesLatestRun === true
|
||||
&& dom.checkScope?.matchesLatestRun === true
|
||||
&& dom.checkScope?.matchesRunDetail === true
|
||||
&& dom.selectedRunTags?.matchesRunDetail === true
|
||||
@@ -1533,7 +1530,7 @@ function renderDashboardResult(result: Record<string, unknown>): string {
|
||||
const dom = record(page.dom);
|
||||
const dataset = record(dom.dataset);
|
||||
const layout = record(dom.layout);
|
||||
const chartCounts = record(dom.chartCounts);
|
||||
const chartTiming = record(dom.chartTiming);
|
||||
const latestRunCounts = record(dom.latestRunCounts);
|
||||
const latestDetailSummary = record(dom.latestDetailSummary);
|
||||
const timingVisibility = record(dom.timingVisibility);
|
||||
@@ -1570,12 +1567,11 @@ function renderDashboardResult(result: Record<string, unknown>): string {
|
||||
"",
|
||||
table(["TITLE", "STATUS_TEXT", "CONTRACT", "BASE_PATH"], [[dom.title, dom.statusText, dataset.contractVersion, dataset.basePath ?? "-"]]),
|
||||
"",
|
||||
table(["TREND_ERR_TYPES", "TREND_ALERT_TYPES", "TREND_TOTAL_TYPES", "TREND_EXACT", "MATCH_LATEST", "BAD_TITLE", "BAD_BODY"], [[
|
||||
chartCounts.error ?? "-",
|
||||
chartCounts.warning ?? "-",
|
||||
chartCounts.total ?? "-",
|
||||
chartCounts.ok ?? "-",
|
||||
chartCounts.matchesLatestRun ?? "-",
|
||||
table(["TREND_LATEST_MIN", "TREND_MAX_MIN", "TREND_DURATION", "MATCH_LATEST", "BAD_TITLE", "BAD_BODY"], [[
|
||||
chartTiming.latestMinutes ?? "-",
|
||||
chartTiming.maxMinutes ?? "-",
|
||||
chartTiming.ok ?? "-",
|
||||
chartTiming.matchesLatestRun ?? "-",
|
||||
dom.badCardTitleCount ?? "-",
|
||||
dom.badCardBodyCount ?? "-",
|
||||
]]),
|
||||
|
||||
@@ -1316,6 +1316,7 @@ function enrichFindingWithCheck(config: WebProbeSentinelServiceConfig, value: Re
|
||||
checkLevel,
|
||||
checkTitleZh: stringOrNull(check.titleZh),
|
||||
checkSummaryZh: stringOrNull(check.summaryZh),
|
||||
checkActionZh: stringOrNull(check.actionZh),
|
||||
checkRegistered: check.registered === true,
|
||||
blocking: value.blocking === true || check.blocking === true,
|
||||
valuesRedacted: true,
|
||||
@@ -1327,13 +1328,13 @@ function checkForFinding(config: WebProbeSentinelServiceConfig, value: Record<st
|
||||
const entry = checkCatalogById(config).get(findingId) ?? null;
|
||||
const rawLevel = normalizeCheckLevel(stringOrNull(value.severity) ?? stringOrNull(value.level));
|
||||
if (entry === null) {
|
||||
const summary = stringOrNull(value.summary) ?? stringOrNull(value.message) ?? findingId;
|
||||
return {
|
||||
id: findingId,
|
||||
code: null,
|
||||
level: rawLevel ?? "unknown",
|
||||
titleZh: findingId,
|
||||
summaryZh: summary.slice(0, 160),
|
||||
titleZh: "未登记监测项",
|
||||
summaryZh: "该监测项未在 YAML 中登记,配置校验需要补齐中文说明。",
|
||||
actionZh: "补齐 YAML 监测项说明后重新验证。",
|
||||
blocking: value.blocking === true,
|
||||
order: 10000,
|
||||
registered: false,
|
||||
@@ -1345,7 +1346,8 @@ function checkForFinding(config: WebProbeSentinelServiceConfig, value: Record<st
|
||||
code: stringOrNull(entry.code),
|
||||
level: normalizeCheckLevel(stringOrNull(entry.level)) ?? rawLevel ?? "unknown",
|
||||
titleZh: stringOrNull(entry.titleZh) ?? findingId,
|
||||
summaryZh: stringOrNull(entry.summaryZh) ?? stringOrNull(value.summary) ?? stringOrNull(value.message) ?? findingId,
|
||||
summaryZh: stringOrNull(entry.summaryZh) ?? "已记录监测项详情。",
|
||||
actionZh: stringOrNull(entry.actionZh) ?? "查看详情后处理。",
|
||||
blocking: entry.blocking === true,
|
||||
order: numberOr(entry.order, 10000),
|
||||
registered: true,
|
||||
|
||||
Reference in New Issue
Block a user