@mzzsfy/dsh-bug-perf 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  # dsh-bug-perf 兼容性测试
2
2
 
3
- 包定位:宿主缺陷的浏览器半区兜底。四个补丁各自独立开关、独立失败;任何结构不匹配只记录原因,不阻断页面。仅停滞兜底有自绘提示条,其余无 UI;断言走配置路由 + 页面内 `window.__dshBugPerf` 报告 + 页面行为观察。
3
+ 包定位:宿主缺陷的运行期兜底与性能补丁。`restartCoalesce` / `terminalWatchdog` / `socketKeepAlive` / `stuckSession` / `jobStreamLimit` 在浏览器半区,`listSlim` 在宿主半区(包装 `sessionController.list`);各补丁独立开关、独立失败,结构不匹配时记录原因或静默失效/静默等待,不阻断页面。另有设置卡片注册官方槽,仅编辑配置;停滞兜底保留自绘提示条。`diag` 采集在浏览器半区,上报开关默认关闭。断言走配置路由 + 页面内 `window.__dshBugPerf` 报告 + 页面行为观察 + 宿主日志。
4
4
 
5
- ## 本轮状态(2026-11-08,新增四功能)
5
+ ## 本轮状态(2026-11-09,列表瘦身迁移 + 设置 UI + diag 开关)
6
6
 
7
7
  | 功能 | L1 | L2 装载 | L3 功能面 |
8
8
  |------|----|---------|-----------|
@@ -10,6 +10,9 @@
10
10
  | `socketKeepAlive` | 通过(13 用例) | 通过(0.2.2-rc.1 隔离工位,`--only dsh-bug-perf`,端口 9306) | 部分:已确认 `installed: true`、`window.WebSocket.name === 'KeepAliveSocket'`、空闲 5.2 秒发 3 帧且保持 OPEN、持续上行时 0 保活帧;未执行 #15(反代丢 pong)与 #16/#22 |
11
11
  | `stuckSession` | 通过(18 用例) | 通过(同上工位) | 通过(隔离工位):停滞 8 秒后 `session stalled, requesting reconnect #1`,宿主侧 `connection lost, retry #1` 真实重建,`performance.timeOrigin` 不变(未刷新页面),用尽 5 次后出现提示条,恢复后消失 |
12
12
  | `jobStreamLimit` | 通过(15 用例) | 通过(同上工位) | 通过(生产页面实测):`job/list` 361 → 22,`activeStreams` 368 → 29;3466 个会话里 2711 个子 agent 会话被识别且不占默认窗口,328 次子会话订阅被拒;最长长任务 565 ms → 179 ms,`blockedMs` 1832 ms → 未触发 |
13
+ | `listSlim` | 通过(27 用例 + 3 条宿主接线) | 部分:smoke 通过;2026-11-09 隔离 boot 页面/激活通过(脚本整体 FAIL 因宿主 anthropic userId 缺失,与本包无关),listSlim 装载日志未落盘 | 部分:#33/#34 通过(隔离宿主进程内同构 invocation 多主体);#28 成功装载日志未执行;#29-#32 未执行;#35 的卸载/透传由 L1 覆盖,`/wrapped` 标记检查未执行(真实 Liveshare server 未部署) |
14
+ | 设置 UI | 通过(4 用例:槽注册/缺依赖/七节同源/样式契约) | 通过(2026-11-09 隔离工位,插件详情页当时渲染 1 张卡片、六节、7 开关、11 数值输入;新增 `diag` 节后未复测) | 部分:六节页面交互已通过;新增 `diag` 节尚未页面复测 |
15
+ | `diag` 上报 | 通过(编号断言 #41-#46 六条,来自 client-diag 4 条 + config 2 条;client 另 1 条异步失败;host 3 条回归:合法载荷/坏载荷/legacy 仅存 diag) | 部分:默认配置真实页面等满 75 秒(超过默认首个周期)请求 0;开启 `reportEvery=2` 的临时隔离 home 15 秒 1 条请求并落单行文件;2 MB 轮转未实测 | 未执行(文件轮转与重启持久化未单独取证) |
13
16
 
14
17
  - 隔离工位为临时目录,未入库;生产宿主已加载本插件,`window.__dshBugPerf` 在场。
15
18
  - 下文的 2026-11-07 实测记录只覆盖 `restartCoalesce` / `terminalWatchdog`,不代表新增功能。
@@ -18,10 +21,10 @@
18
21
 
19
22
  | 层 | 内容 | 手段 |
20
23
  |----|------|------|
21
- | L1 单元层 | test/ 七个文件 88 用例(配置归一化 10、重启合并 11、看门狗判定与安装 11、host 路由 10、会话流保活 13、加载停滞兜底 18、任务流上限 15) | 包目录 `node --test "test/*.test.mjs"` |
24
+ | L1 单元层 | test/ 十个文件 137 用例(配置归一化 13、重启合并 11、看门狗判定与安装 11、host 路由/配置保存与列表瘦身接线 20、会话流保活 13、加载停滞兜底 18、任务流上限 15、列表瘦身 27、设置 UI 4、诊断上报 5;diag 相关另散落 config 内 2 条、host 内 3 条) | 包目录 `node --test "test/*.test.mjs"` |
22
25
  | L2 装载层 | 仓库 smoke 含本包;隔离环境 boot 无装载错误,console 出现 `[dsh-bug-perf] applied` | 仓库根 `node scripts/smoke-load.mjs` + 隔离 boot |
23
- | L3 功能面层 | 下节断言:配置路由、默认安装、独立关闭、冻结自愈、合并计数 | 隔离环境 + playwright 页面探针 |
24
- | L4 共存层 | 与全家桶共启,页面无 `Failed to load plugins`,四个补丁仍在报告 installed(新增两功能在本轮只完成单包工位装载,见文首状态表) | 隔离环境全 bundle boot |
26
+ | L3 功能面层 | 下节断言:配置路由与设置 UI #1/#2/#36-#40、默认安装、独立关闭、冻结自愈、合并计数;列表瘦身面 #33/#34 已执行,#28 成功装载日志与 #29-#32 未执行,#35 的卸载/透传由 L1 覆盖,页面 `/wrapped` 标记未执行 | 隔离环境 + playwright 页面探针 |
27
+ | L4 共存层 | 与全家桶共启,页面无 `Failed to load plugins`,各补丁仍在报告 installed(socketKeepAlive / stuckSession 只完成单包工位装载;listSlim 已单独做隔离多主体与旧包共存取证,未重跑全家桶) | 隔离环境全 bundle boot |
25
28
 
26
29
  执行顺序:L1 → L2 → L3 → L4,前层失败即止。
27
30
 
@@ -29,13 +32,36 @@
29
32
 
30
33
  | 文件 | 用例数 | 覆盖点 |
31
34
  |------|--------|--------|
32
- | test/config.test.mjs | 10 | 缺省默认全开;部分覆盖;功能关闭保留阈值;非法类型回退默认;越界收敛;未知字段丢弃;保活与停滞默认值;新增补丁非法值回退;新增补丁越界收敛;任务流上限开关与回退 |
35
+ | test/config.test.mjs | 13 | 缺省默认值;部分覆盖;功能关闭保留阈值;非法类型回退默认;越界收敛;未知字段丢弃;保活与停滞默认值;新增补丁非法值回退;新增补丁越界收敛;任务流上限开关与回退;列表瘦身开关与回退;诊断上报默认关闭;诊断上报开关/边界/未知字段 |
33
36
  | test/client-restart.test.mjs | 11 | 窗口内连发尾随一次;窗口为零时逐次执行(关闭合并);窗口外逐次;实例隔离;重复安装幂等;结构缺失跳过;释放后触发不抛;客户端内联配置与宿主同源;缺失远程配置默认值;缺模块记录原因;经模块表安装 |
34
37
  | test/client-watchdog.test.mjs | 11 | 未武装不触发;已武装停滞触发;持续新帧不触发;冷却期不重复;页面隐藏不触发;待渲染/无流不触发;未连接不触发;新建视图自动重连;既有视图进入监控;结构缺失跳过;重复安装幂等 |
35
38
  | test/client-keepalive.test.mjs | 13 | 空闲发合法 item 帧;按间隔持续发送且 streamId 互不相同;有上行活动不补帧;间隔重配对既有连接生效;非 OPEN 不发送;非会话流连接不发送;关闭后不包装;连接关闭清理定时器;普通断线不熔断;未发保活帧的协议关闭不计数;协议关闭连续命中熔断并恢复原构造器;健康存活清零累计;包装后保持实例与静态常量语义 |
36
39
  | test/client-stuck.test.mjs | 18 | 未到阈值不重连;超阈值请求重连;主线程阻塞同样触发重连;重连间隔内不重复;用尽次数后显示提示;恢复后重置并隐藏;无 connection 服务直接提示;重连抛错退化为提示;关闭重连只提示;正文含文案且有消息节点不触发;仅分组行仍判定停滞;隐藏行或空行仍判定停滞;隐藏祖先内的行仍判定停滞;无会话视图不触发;重复安装幂等;重复轮询提示幂等;样式注入带插件标记;样式被删后重装重新注入 |
37
40
  | test/client-jobs.test.mjs | 15 | 主会话窗口内放行;超窗口拒绝;子会话不占窗口;点击子会话放行;点击主会话放行;到上限淘汰最老;点击已在窗口不重复建流;点击非会话行忽略;释放后额度回收;重复释放只扣一次;重复安装幂等;服务缺失跳过;摘要缺失按主会话处理;重复订阅只建一次;卸载释放全部流 |
38
- | test/host.test.mjs | 10 | 注册配置与采样两条路由;缺省返回默认;部分覆盖返回归一化;volatile 解箱;无 webServer 干净跳过;注册失败不抛;注入声明等待 webServer;Config 默认值与共享默认一致;采样上报接受合法载荷;采样上报拒绝坏载荷 |
41
+ | test/host.test.mjs | 20 | 注册配置与采样两条路由;缺省返回默认;部分覆盖返回归一化;volatile 解箱;无 webServer 干净跳过;注册失败不抛;注入声明等待 webServer;Config 默认值与共享默认一致(含 diag);列表瘦身按配置接管列表接口并缓存;列表瘦身关闭时原样透传;列表瘦身热切换开关即时生效;采样上报接受合法载荷;采样上报拒绝坏载荷;legacy settings 仅存 diag 时读取生效;POST 配置 settings 持久化;数值越界收敛;configEditor 行配置写入;坏 JSON/非法 config 拒绝;配置服务缺失 503;未知方法 405 |
42
+ | test/client-settings.test.mjs | 4 | 两个官方槽位注册与 key;无 React/slots 静默跳过;七节字段与共享默认同源;样式注入 data-plugin 与开关选择器契约 |
43
+ | test/client-diag.test.mjs | 5 | 默认关闭只采样不上报且阻塞探测工作;开启按一个周期恰好一次请求且 payload 字段完整;reportEvery 改小后频率变化;fetch 缺失或同步抛错静默;异步拒绝/非 2xx 静默 |
44
+ | test/list-slim.test.mjs | 27 | 投影白名单裁剪;条目形状不符原样返回;开关关闭时包装保留并透传;宿主无 sessionController 静默等待;controller 缺 list 记录原因;缓存命中不重建;TTL 过期重建;会话增删失效;并发共享一次构建;不同 signal 独立取消不影响共享构建;原方法抛错透传;响应形状不符不缓存;request 原样传递;预热构建一次;卸载恢复原方法;卸载不摘后装包装;服务代理每次返回新引用时仍按包装标记卸载恢复;effect 注册失败回滚包装;不摘掉其它实例的包装;所有调用者取消后中止共享构建;卸载中止在途构建;重复装载不叠加;包装保留 receiver(非 owner 由宿主过滤);非 owner 不命中 owner 缓存;预热缓存不对非 owner 生效;在途构建遇失效后新调用重建;旧构建结果不写回 |
45
+
46
+ ### diag L1 用例
47
+
48
+ | # | 用例 | 预期 |
49
+ |---|------|------|
50
+ | 41 | 缺省配置归一化 | `diag` 为 `{enabled:false, reportEvery:12}` |
51
+ | 42 | diag 非法类型/越界/未知字段 | 非法类型回退默认;`reportEvery` 收敛到 `[1,720]`;未知字段丢弃 |
52
+ | 43 | 默认关闭推进数分钟 | `fetch` 0 次;`diag.samples` 增长;`blockedAt` 探测仍写值 |
53
+ | 44 | 开启后推进一个上报周期 | 恰好 1 次请求;URL 前缀正确;payload 含 `at/path/totals/last/blockedMs/longTasks/errors` |
54
+ | 45 | `reportEvery` 改小 | 请求次数随周期增加 |
55
+ | 46 | fetch 缺失或抛错 | 静默跳过,无未捕获异常 |
56
+
57
+ 补充:client-diag 文件另有 1 条“异步拒绝/非 2xx 静默”用例,未占用编号;host 的 3 条 diag 回归也未占用 #41-#46,因此 diag 相关总数不是编号总数。
58
+
59
+ ### L2 用例
60
+
61
+ | # | 用例 | 预期 |
62
+ |---|------|------|
63
+ | 47 | 默认配置打开页面,DevTools Network 过滤 `/api/dsh-bug-perf/diag` | 通过(2026-11-09 隔离工位):等满默认首个上报周期(75 秒 > 12×5 秒),`diag.enabled=false`,请求 0,`diag.samples` 1 -> 16;截图 `.compat/0.2.2-rc.1/diag-default-long.png` |
64
+ | 48 | 行配置开启 diag 并等待约 `reportEvery×5` 秒,检查临时目录 | 部分执行(2026-11-09 临时隔离 home,`reportEvery=2`):15 秒内恰好 1 条请求,临时文件出现且为单行 JSON;2 MB 轮转未实测;截图 `.compat/0.2.2-rc.1/diag-enabled.png`、样本 `.compat/0.2.2-rc.1/diag-page.jsonl` |
39
65
 
40
66
  ### L2 判据
41
67
 
@@ -46,6 +72,14 @@
46
72
 
47
73
  0.2.1-rc.2 槽位实测(2026-11-07,`--only dsh-bug-perf --seed-gateway`):`activation live=true findings=0`、`browser ok=true consoleErrors=[]`、`importFailures=[]`、LLM 双协议往返 true;脚本判定 FAIL 的唯一原因是 `anthropicUpstream.userId` 为 `null`(judgeLlm 要求 `dsh:<40hex>` 的 gateway 标记断言,属 0.2.1-rc.2 宿主注释行为,与本包无关)。同工位功能探针:两功能 installed、20 次 `restart()`→3 次 attach、冻结 `revision` 26→27 自愈 + `terminal stalled` 日志 + `echo after-heal` 回显。据此 `dsh.hostMin` 定为 `0.2.1-rc.2`,`dshReleases."0.2.1-rc.2"` 记 `compatible`。
48
74
 
75
+ 2026-11-09 迁移后复核(0.2.2-rc.1,`--only dsh-bug-perf --seed-gateway`,端口 9310):`activation live=true findings=0`、`browser ok=true hasFailBanner=false`、`consoleErrors=[]`、LLM 双协议往返 true;脚本整体 FAIL 仅因 `anthropicUpstream.userId=null`(同上,与本包无关)。宿主 boot 日志未落盘,`[dsh-bug-perf] 列表瘦身 已装载` 未取证;列表瘦身多主体见下两段。
76
+
77
+ 2026-11-09 设置 UI 隔离取证(0.2.2-rc.1,端口 9311,隔离 profile):插件详情页实际渲染 1 张 `.bp-card`、6 个 `.bp-section`、7 个开关、11 个数值输入;`plugins.bundle.config` 槽进入 ready 并注册成功。展开卡片切换 `listSlim.enabled` 关闭 → 保存 → `GET /api/dsh-bug-perf/config` 返回 `{"enabled":false}`;刷新页面后重新打开卡片,该开关为 `checked:false`;恢复开启 → 保存 → 回读 `{"enabled":true}`。亮/暗主题截图:`.compat/0.2.2-rc.1/ui-card3.png`、`.compat/0.2.2-rc.1/ui-dark.png`;settings 持久化分支由 L1 的 `宿主_配置保存_settings持久化` 覆盖。该取证早于 diag 节;当前源码为七节、8 开关、12 数值输入,diag 节未页面复测。
78
+
79
+ 2026-11-09 多主体隔离取证(0.2.2-rc.1,端口 9311,临时探针插件,不入库):在隔离宿主进程内注册真实 `remoteAccess` 的 `share-viewer` 策略,用与 gateway 同构的 invocation 调用真实 `sessionController.list`。结果:viewer 先于 owner 且策略为空 → `[]`;owner → 2 条;策略仅允许第 1 条 → viewer 1 条;owner 再调用命中缓存后 viewer 仍 1 条;`sessionController.list[Symbol.for('@mzzsfy/dsh-bug-perf/list-slim/wrapped')] === true`。结论:#33/#34 通过(宿主逐项过滤与 owner 缓存隔离成立);Liveshare server 未部署,未走真实网络转发。取证:`.work/l3-host-viewer-isolation.json`。
80
+
81
+ 2026-11-09 旧包共存隔离取证(同一工位,临时安装 `@mzzsfy/dsh-session-manager@0.10.0`):旧包 + 新 bug-perf 下 viewer 策略仅允许 1 条时返回全部 2 条会话,证实旧 arrow 包装绕过宿主过滤;该组合不得发布,session-manager 必须同批 0.11.0。取证:`.work/l3-old-coexist.json`。
82
+
49
83
  ## L3 功能面断言
50
84
 
51
85
  约定:`<port>` = 隔离环境端口,`<T>` = boot 日志 `token=` 之后的值。
@@ -56,7 +90,7 @@
56
90
 
57
91
  | # | 操作 | 预期 |
58
92
  |---|------|------|
59
- | 1 | `curl.exe -s -c cookie.txt -o NUL "http://127.0.0.1:<port>/?token=<T>"` 换取 cookie,再 `curl.exe -s -b cookie.txt "http://127.0.0.1:<port>/api/dsh-bug-perf/config"` | 200,`content-type: application/json`,`config` 四节(restartCoalesce / terminalWatchdog / socketKeepAlive / stuckSession)与 README 默认值逐字段一致 |
93
+ | 1 | `curl.exe -s -c cookie.txt -o NUL "http://127.0.0.1:<port>/?token=<T>"` 换取 cookie,再 `curl.exe -s -b cookie.txt "http://127.0.0.1:<port>/api/dsh-bug-perf/config"` | 200,`content-type: application/json`,`config` 七节(restartCoalesce / terminalWatchdog / socketKeepAlive / stuckSession / jobStreamLimit / listSlim / diag)与 README 默认值逐字段一致 |
60
94
  | 2 | 隔离 profile 行加 `config: {terminalWatchdog: {enabled: false}}` 后等热重载(约 1s),再请求 #1 | `terminalWatchdog.enabled` 为 `false`,`restartCoalesce` 保持默认 |
61
95
 
62
96
  ### 二、默认安装面
@@ -72,7 +106,7 @@
72
106
  |---|------|------|
73
107
  | 5 | 行配置 `restartCoalesce: {enabled: false}` 后刷新页面 | `features.restartCoalesce.reason === 'disabled'`;`RemoteStream.prototype.restart` 保持官方原名(未包装) |
74
108
  | 6 | 行配置 `terminalWatchdog: {enabled: false}` 后刷新页面,打开终端 | `features.terminalWatchdog.reason === 'disabled'`;`webTerminals.view` 未被包装(冻结场景不会自愈) |
75
- | 7 | 四个功能都关闭后刷新页面 | 页面正常,console 无错误,`window.__dshBugPerf.features` 四节均为 disabled |
109
+ | 7 | 客户端五个功能都关闭、`listSlim.enabled: false` 后刷新页面 | 页面正常,console 无错误,`window.__dshBugPerf.features` 各节均为 disabled;列表投影完整(列表瘦身包装保留,每次调用透传原方法) |
76
110
 
77
111
  ### 四、重启合并面
78
112
 
@@ -114,9 +148,35 @@
114
148
  | 26 | 点击一个未被订阅的会话 | 该会话出现 `job/list` 流,`state.clicked` 增加;总数超过 `max` 时 `state.evicted` 增加且总数不变 |
115
149
  | 27 | 折叠/展开侧边栏或切换工作区 | `job/list` 流保持稳定,不出现重复流(`watchRows` 同一会话只建一条) |
116
150
 
151
+ ### 八、列表瘦身面(宿主半区,隔离验证)
152
+
153
+ | # | 操作 | 预期 |
154
+ |---|------|------|
155
+ | 28 | 打开页面后读取宿主日志(boot 日志/宿主进程 stdout),并检查会话列表行 | 宿主日志出现 `[dsh-bug-perf] 列表瘦身 已装载 (keep=... ttl=...)`;列表行标题、工作区徽标、任务状态与未开启时一致 |
156
+ | 29 | 在会话列表响应上比对开启前后的投影键集合(DevTools Network 或宿主探针) | 开启后单条投影只剩 `title` / `sessionListMetadata` / `inbox` / `modelSelection` / `tokenUsage`;响应体积明显下降;打开某个会话详情,完整投影仍可取回 |
157
+ | 30 | 行配置 `listSlim: {enabled: false}` 后等热重载,刷新页面 | 列表投影恢复完整字段;包装仍保留,每次调用透传原方法(宿主日志的装载行不随开关变化) |
158
+ | 31 | 连续刷新页面 3 次,用 DevTools Network/宿主侧耗时对比列表首屏响应 | 缓存命中时宿主不重复重建列表(以响应耗时对比为准;实现无 cache hit/miss 日志);会话增删后下一次列表请求重建一次 |
159
+ | 32 | 构造宿主缺 `sessionController` 的旧版本(或注销该服务) | 插件其余补丁照常装载;列表瘦身静默等待服务就绪,列表行为等同原生,页面无报错;服务就绪后自动接管 |
160
+ | 33 | 用非 owner 主体(liveshare viewer 或等价 principal)打开同一页面,对照 owner 的列表 | 包装后仍由宿主按 invocation 逐项鉴权:viewer 只看到被授权会话,owner 看到全量;viewer 请求不会造成 owner 列表缺项 |
161
+ | 34 | 先让 owner 加载列表并触发预热(等待 10 秒以上),再让非 owner 打开页面 | 非 owner 不命中 owner 缓存,只看到授权会话;反向顺序(非 owner 先)时 owner 仍看到全量 |
162
+ | 35 | 宿主侧用 `Symbol.for('@mzzsfy/dsh-bug-perf/list-slim/wrapped')` 检查 `sessionController.list` 是否带包装标记(服务代理每次读取可能返回新引用,不能只比较引用);再对比开关开/关与卸载后的列表投影 | 装载后标记为 true 且开启时投影被裁剪、关闭时完整;卸载后标记消失,开关开/关都返回完整投影;另一个插件后装包装时,本插件卸载不摘掉后装包装且链上透传 |
163
+
164
+ 执行状态:#33/#34 已通过;#28 的成功装载日志未执行;#29-#32 未执行;#35 的卸载/透传由 L1 覆盖,页面 `/wrapped` 标记检查未执行。
165
+
166
+ ### 九、设置 UI 面
167
+
168
+ | # | 操作 | 预期 |
169
+ |---|------|------|
170
+ | 36 | 页面打开插件详情页,展开「缺陷兜底与性能补丁」卡片 | 卡片注册自 `plugins.bundle.config`(0.2.2-rc.1)或 `settings.plugin.item`(旧宿主);七节、8 个开关、12 个数值输入;不新增独立设置页或导航项;diag 节新增后未页面复测 |
171
+ | 37 | 切换 `listSlim.enabled` 关闭后点「保存」 | POST 200;GET 回读 `false`;卡片底部显示「已保存,刷新页面生效」;无未捕获异常 |
172
+ | 38 | 刷新页面并重新打开卡片 | `listSlim` 开关为 `checked:false`(配置已落 profile,不是仅前端状态) |
173
+ | 39 | 恢复开启并保存 | GET 回读 `true`;刷新后开关为 `checked:true` |
174
+ | 40 | 亮/暗主题各打开一次卡片 | 卡片底/字/边框/开关均随 `--dsw-alias-*` 切换;无裸 hex 与 `var()` 字面 fallback;开关 34×19、卡片圆角 8px |
175
+
117
176
  ## L4 共存层
118
177
 
119
- - 全家桶 bundles 共启:页面无 `Failed to load plugins`,四个补丁 report 仍 installed,终端与流式回复正常;保活帧不引发额外重连。
178
+ - 全家桶 bundles 共启:页面无 `Failed to load plugins`,各补丁 report 仍 installed,终端与流式回复正常;保活帧不引发额外重连;列表瘦身与归档 / 删除等宿主侧插件互不改写列表语义。
179
+ - 旧版 `dsh-session-manager`(0.10.0 及更早,仍带 arrow 包装)共存:不得发布这种组合;隔离工位实测(旧包 0.10.0 + 新 bug-perf,viewer 策略仅允许 1 条)返回全部 2 条会话,证实旧包装绕过宿主过滤;发布必须同批升级 session-manager 到 0.11.0。
120
180
  - 与 `@mzzsfy/dsh-shared-terminal` 共存:shared-terminal 的只读自愈与本包看门狗互不干扰(前者点「接管输入」,后者调 `view.connect()`),同一终端不出现重复重连风暴。
121
181
 
122
182
  ### 本轮实测记录(2026-11-07,0.2.2-rc.1,22 bundles)
@@ -152,48 +212,49 @@
152
212
 
153
213
  | 维度 | 标记 | 本包落点(检查点/证据) |
154
214
  |---|---|---|
155
- | D01 宿主代际与 API 契约 | M | 依赖宿主浏览器内部形态:`RemoteStream.prototype.restart`、`webTerminals` 视图、client 模块表、`/api/remote.mux` 路径与 `item` 帧协议(未知 streamId 被忽略)、`[data-chat-flow]` 容器与加载提示文案、全局 `WebSocket` 可包装;`hostMin=0.2.1-rc.2`,但 `socketKeepAlive`/`stuckSession` 目前只在 0.2.2-rc.1 验证;`installed: true` 只表示包装装上,不等于对既有连接生效;结构不匹配只记录原因或静默失效 |
156
- | D02 运行平台与架构 | N | 纯浏览器半区补丁,无平台分支、文件、子进程与端口;host 半区只做配置分发 |
215
+ | D01 宿主代际与 API 契约 | M | 依赖宿主浏览器内部形态:`RemoteStream.prototype.restart`、`webTerminals` 视图、client 模块表、`/api/remote.mux` 路径与 `item` 帧协议(未知 streamId 被忽略)、`[data-chat-flow]` 容器与加载提示文案、全局 `WebSocket` 可包装;宿主半区依赖 `sessionController.list`、列表投影形状与 `ctx.invocation.peer.principal` 主体判定;`hostMin=0.2.1-rc.2`,但 `socketKeepAlive`/`stuckSession` 目前只在 0.2.2-rc.1 验证,`listSlim` 迁移后完成 L1 与 smoke,并在隔离宿主做同构 invocation 多主体取证(#33/#34)与旧包共存取证;真实 Liveshare 网络链路未部署,`installed: true` 只表示包装装上,不等于对既有连接生效;结构不匹配只记录原因或静默失效 |
216
+ | D02 运行平台与架构 | N | 浏览器半区补丁无平台分支、文件、子进程与端口;`listSlim` 在宿主半区执行,仅为内存级方法包装,无平台分支;host 半区另做配置分发与采样落盘 |
157
217
  | D03 Web 客户端形态 | M | Chromium 真机;终端 xterm 视图与 attach 流;页面隐藏/可见、待渲染/无流/未连接分支;窄屏与刷新 |
158
- | D04 宿主部署与配置形态 | C | 触发条件 = 行配置变更。落点:独立开关经行 config 分发,宿主路由热重载约 1s 生效;有宿主按 `Config` 自动生成的插件详情配置表单,无自绘 UI;客户端开关在页面加载时读取一次,修改后刷新页面生效(与宿主路由热重载不同) |
218
+ | D04 宿主部署与配置形态 | C | 触发条件 = 行配置变更。落点:设置卡片注册官方 `plugins.bundle.config` / `settings.plugin.item` 槽,保存经 `POST /api/dsh-bug-perf/config` 写回 profile 行配置;GET 返回归一化配置,0.2.2-rc.1 实测保存后刷新仍生效;客户端补丁在页面加载时读取一次,修改保存后刷新页面生效;`listSlim` 在宿主每次列表调用时读取行配置,0.1.7+ 保存即热更,legacy 宿主需重载插件 |
159
219
  | D05 插件互操作与组合 | M | 与官方模块/其他终端补丁(shared-terminal 只读自愈)共存;同一终端不出现重复重连风暴;全家桶无 `Failed to load plugins`;新功能与惰性保活帧不影响其它补丁(共享 WS 只多出 item 帧) |
160
- | D06 生命周期 | M | 安装幂等;关闭开关恢复官方原方法;刷新页面后包装撤销,运行中禁用不撤销(已知行为);HMR 后不叠加包装;释放后迟到触发不抛 |
220
+ | D06 生命周期 | M | 客户端补丁安装幂等;关闭开关恢复官方原方法;刷新页面后包装撤销,运行中禁用不撤销(已知行为);HMR 后不叠加包装;释放后迟到触发不抛;`listSlim` 关闭后包装保留、每次调用透传原方法,插件卸载时恢复原方法 |
161
221
  | D07 多实例与并发 | C | 触发条件 = 多窗口/多终端。落点:实例隔离、重复安装幂等、同一 stream 并发 restart 合并、每视图独立看门狗 |
162
- | D08 持久化代际与迁移 | N | 无自有持久化;配置在宿主 profile 行,由宿主管理 |
222
+ | D08 持久化代际与迁移 | N | 无自有持久化;配置在宿主 profile 行,由宿主管理;列表瘦身缓存与去重状态均为进程内内存态,重启即失效 |
163
223
  | D09 数据规模与异常数据 | N | 无用户数据面;只处理流与终端事件,不落库 |
164
- | D10 配置读写与默认值 | M | 缺省默认全开;部分覆盖;功能关闭保留阈值;非法类型回退默认;越界收敛;未知字段丢弃;volatile 解箱;四节字段齐全 |
165
- | D11 降级与错误路径 | M | 模块/视图缺失跳过并记录原因,不影响页面;DOM/协议形态缺失(会话流路径、加载提示结构)时静默失效,由 D01 复核发现;未武装/未连接/页面隐藏不触发;重连失败有冷却;熔断后恢复原始构造器并把原因写回 report |
166
- | D12 安全边界与信任 | C | 触发条件 = 路由对外可达。落点:只读 GET `/api/dsh-bug-perf/config`(exact 路由),无写面/密钥;exact 路由不经 connection 的 `/api` 前缀闸门,认证由宿主 startup-auth 承担(本窗口未验证);不设自有认证层 |
167
- | D13 性能与资源 | M | 包装调用开销、合并窗口(默认 100ms)、看门狗冷却与重连频率;保活每条被覆盖连接一条 500ms 检查节拍、默认约 40 帧/分钟;停滞检查每 2s 读一次有效消息行;主动重建默认最多 5 次、间隔 15s;不得形成重连风暴与请求风暴;关闭后零包装开销 |
168
- | D14 呈现与可访问性 | C | 触发条件 = 停滞提示条出现。落点:固定顶部提示条 + 「刷新页面」按钮,`role="status"`,文案固定中文(插件无 i18n 设施),校验亮/暗主题、窄屏、键盘可达与对比度 |
169
- | D15 观测与判定面 | M | `window.__dshBugPerf.features` report(installed/reason)、`[dsh-bug-perf] applied`/stalled 日志、配置路由回读、console 0(`/login` 404 属宿主噪声,按总纲 G8 豁免) |
224
+ | D10 配置读写与默认值 | M | 缺省默认值(诊断上报默认关闭);部分覆盖;功能关闭保留阈值;非法类型回退默认;越界收敛;未知字段丢弃;volatile 解箱;七节字段齐全;diag 的 `enabled` 非布尔回退、`reportEvery` 非数回退、有限数收敛到 `[1,720]`、未知字段丢弃 |
225
+ | D11 降级与错误路径 | M | 模块/视图缺失跳过并记录原因,不影响页面;DOM/协议形态缺失(会话流路径、加载提示结构)时静默失效,由 D01 复核发现;未武装/未连接/页面隐藏不触发;重连失败有冷却;熔断后恢复原始构造器并把原因写回 report;缺 `sessionController` 时静默等待服务就绪、不接管列表,服务在场但缺 `list` 时记录原因并跳过;列表响应形状不符时本次原样透传且不缓存 |
226
+ | D12 安全边界与信任 | C | 触发条件 = 路由对外可达。落点:GET/POST `/api/dsh-bug-perf/config`(exact 路由),POST 仅接受 JSON 对象且限制 64 KiB,归一化后写配置;GET `/api/dsh-bug-perf/diag` 是本包唯一带写副作用的 GET,把 query 中的摘要追加到宿主临时文件,受 2 MB 轮转上限约束,开关关闭时宿主仍接受写入(避免两端配置竞态),这是默认关闭的原因之一。本包无自有认证层,认证由宿主 cookie/startup-auth 承担;不写密钥、不执行请求内容。列表瘦身必须保留调用方 receiver,由宿主 `remoteAccess.allows` 按 invocation 逐项鉴权;缓存只服务 owner/本地调用,非 owner 不读写缓存,避免跨主体泄漏或可见性反转 |
227
+ | D13 性能与资源 | M | 包装调用开销、合并窗口(默认 100ms)、看门狗冷却与重连频率;保活每条被覆盖连接一条 500ms 检查节拍、默认约 40 帧/分钟;停滞检查每 2s 读一次有效消息行;主动重建默认最多 5 次、间隔 15s;列表瘦身按白名单裁剪并按 TTL 缓存、会话增删即时失效,命中时跳过宿主列表重建;不得形成重连风暴与请求风暴;客户端补丁关闭后零包装开销,`listSlim` 关闭后仍有逐次透传的包装调用开销 |
228
+ | D14 呈现与可访问性 | C | 触发条件 = 设置卡片或停滞提示条出现。落点:设置卡片注册官方槽,七节(含 diag)开关 + 数值输入,开关 34×19、卡片圆角 8px,焦点环与亮/暗主题经宿主别名;停滞提示条固定顶部 + 「刷新页面」按钮,`role="status"`,文案固定中文(插件无 i18n 设施),校验窄屏、键盘可达与对比度;diag 节新增后尚未页面复测 |
229
+ | D15 观测与判定面 | M | `window.__dshBugPerf.features` report(installed/reason)、`window.__dshBugPerf.diag.enabled` 实际上报状态、`[dsh-bug-perf] applied`/stalled 日志、宿主 `[dsh-bug-perf] 列表瘦身` 装载日志与缺 `list` 的降级日志、配置路由回读、console 0(`/login` 404 属宿主噪声,按总纲 G8 豁免) |
170
230
 
171
231
  ## 维度检查点(补充)
172
232
 
173
233
  1. **官方形态复核**:宿主升级后逐项核对 `RemoteStream.restart`、`webTerminals.view`、client 模块表、`/api/remote.mux` 路径与 `item` 帧协议、`[data-chat-flow]`/`[data-chat-flow-key]` 结构、加载提示文案、全局 `WebSocket` 可包装性;模块/视图缺失时该补丁记 `waiting for ...` 或 `reason`,页面不报错;DOM/协议形态缺失时静默失效,须按 L3 #13-#23 复核。
174
- 2. **开关往返**:关闭 → 官方原名/未包装 → 重开 → 包装恢复;刷新页面后不残留包装,运行中禁用不撤销(已知行为)。
234
+ 2. **开关往返**:客户端补丁关闭 → 官方原名/未包装 → 重开 → 包装恢复;刷新页面后不残留包装,运行中禁用不撤销(已知行为);`listSlim` 关闭后包装保留、每次调用透传原方法。
175
235
  3. **合并边界**:窗口内 20 次 restart → 首次立即 + 一次尾随(约 2-3 次 open);窗口外逐次;不同 stream 不互相合并。
176
236
  4. **看门狗边界**:未武装、页面隐藏、待渲染、无流、未连接均不触发;持续新帧不触发;冷却期不重复;新建视图自动武装。
177
237
  5. **共存**:与 shared-terminal 同装时只读自愈走「接管输入」、看门狗走 `view.connect()`,两条路径不得同时抢同一终端。
178
- 6. **已知盲区**:本包是官方修复前的兜底,不是兼容性承诺;宿主已修复时应移除补丁而不是继续叠加。
238
+ 6. **列表瘦身**:开关关闭、宿主缺 `sessionController`、响应形状不符三种路径都必须原样透传;白名单覆盖列表行当前消费的投影字段;会话增删后下一次列表请求必须重建;包装必须保留调用方 receiver(非 owner 由宿主逐项过滤),非 owner 不得命中 owner 缓存。
239
+ 7. **已知盲区**:本包是官方修复前的兜底,不是兼容性承诺;宿主已修复时应移除补丁而不是继续叠加。
179
240
 
180
241
  ## 实测记录(维度面)
181
242
 
182
- 2026-11-07,0.2.2-rc.1 隔离工位:配置路由、默认安装、独立开关、合并计数、冻结自愈与真实有头浏览器复核均已执行(见上两节);D07 多窗口并发、D13 关闭后开销未单独取证,执行后在此登记。
243
+ 2026-11-07,0.2.2-rc.1 隔离工位:配置路由、默认安装、独立开关、合并计数、冻结自愈与真实有头浏览器复核均已执行(见上两节);D07 多窗口并发、D13 关闭后开销未单独取证,执行后在此登记。2026-11-08 `listSlim` 从 dsh-session-manager 迁入:完成 L1(27 用例 + 3 条宿主接线)、配置归一化与仓库 smoke(20 包 OK);迁移审查修复了包装丢失调用方 receiver、缓存跨主体共享两项安全缺陷,并补服务代理卸载标记、共享构建与独立取消、失效后在途重建、effect 失败回滚、全取消中止构建与多实例卸载保护;隔离宿主多主体与旧包共存另行取证。
183
244
 
184
245
  ## 本包验证点(最小判定)
185
246
 
186
247
  | 维度 | 验证点(操作→预期) | 证据 | 级别 |
187
248
  |---|---|---|---|
188
- | D01 | 隔离工位冷启动后,等 `window.__dshBugPerf.config` 出现(配置异步到达)再读 `features` → `restartCoalesce`/`socketKeepAlive`/`stuckSession` 均 `installed: true`,`window.WebSocket.name` 为 `KeepAliveSocket`;打开终端后 `terminalWatchdog` 转为 `installed: true`(冷启动先 `waiting for webTerminals`);模块/视图缺失时该节转 `waiting for ...` 或 `reason`,页面不报错;`/api/remote.mux` 或加载提示结构缺失时保活/停滞兜底静默失效(`installed` 仍为 true),须在宿主升级后按 L3 #13-#23 复核 | `window.__dshBugPerf` JSON 快照;console 0 错误 | B |
249
+ | D01 | 隔离工位冷启动后,等 `window.__dshBugPerf.config` 出现(配置异步到达)再读 `features` → `restartCoalesce`/`socketKeepAlive`/`stuckSession` 均 `installed: true`,`window.WebSocket.name` 为 `KeepAliveSocket`;打开终端后 `terminalWatchdog` 转为 `installed: true`(冷启动先 `waiting for webTerminals`);模块/视图缺失时该节转 `waiting for ...` 或 `reason`,页面不报错;宿主日志出现 `[dsh-bug-perf] 列表瘦身 已装载`,服务在场但缺 `list` 时记录降级原因;`/api/remote.mux` 或加载提示结构缺失时保活/停滞兜底静默失效(`installed` 仍为 true),须在宿主升级后按 L3 #13-#35 复核 | `window.__dshBugPerf` JSON 快照;宿主日志;console 0 错误 | B |
189
250
  | D03 | Chromium 真机开终端,切页面隐藏/可见、缩窄视口、刷新后重开 xterm 视图 → 终端可写、attach 流正常;页面隐藏不触发看门狗;刷新后包装按页面加载重建;无 `Failed to load plugins` | 页面截图;console 日志;features 报告 | B |
190
- | D04 | 触发 = 行配置变更。行加 `config: {terminalWatchdog: {enabled: false}}` 等宿主路由热重载约 1s 后 `GET /api/dsh-bug-perf/config`,再刷新页面读 report → 路由回读 `terminalWatchdog.enabled === false` 且 `restartCoalesce` 保持默认;客户端开关需刷新页面才生效(与路由热重载不同) | 配置路由响应 JSON;report 前后对照 | C |
251
+ | D04 | 触发 = 行配置或设置卡片变更。行加 `config: {terminalWatchdog: {enabled: false}}` 等宿主路由热重载约 1s 后 `GET /api/dsh-bug-perf/config`,再刷新页面读 report → 路由回读 `terminalWatchdog.enabled === false` 且 `restartCoalesce` 保持默认;设置卡片改 `listSlim` 保存 → POST 200、GET 回读、刷新后开关保持;客户端开关需刷新页面才生效;`listSlim` 热改后列表投影恢复完整(包装保留、透传原方法) | 配置路由响应 JSON;report 前后对照;设置卡片截图;列表响应 | C |
191
252
  | D05 | 与 `@mzzsfy/dsh-shared-terminal` 及全家桶同载,同一终端点「接管输入」并注入冻结 → 只读自愈与看门狗不抢同一终端,无重复重连风暴;`style[data-plugin="@mzzsfy/dsh-shared-terminal"]` 在场;无 `Failed to load plugins`。P:2026-11-07 工位终端始终可写,只读自愈路径未触发,该分支待补 | console 重连日志条数;页面截图 | B |
192
253
  | D06 | 重复加载页面、关开关后刷新、运行中禁用不刷新 → 安装幂等不叠加;关闭后 `RemoteStream.prototype.restart` 为官方原名、`webTerminals.view` 未包装;刷新后包装撤销;运行中禁用不撤销属已知行为 | `m.stream.restart` 函数体首行;report 的 installed/reason | B |
193
254
  | D07 | 触发 = 多窗口/多终端。开两个终端与两个窗口,在同一 stream 并发 `restart()`(5ms 间隔 20 次),另一窗口独立操作 → 同 stream 合并为约 2-3 次 open;不同 stream 不互相合并;每视图看门狗独立、重复安装幂等 | WebSocket `terminal/attach` open 帧计数 | C |
194
- | D10 | 分别写入非法类型、越界、未知字段、部分覆盖的 config 后 `GET /api/dsh-bug-perf/config` → 非法类型回退默认、越界收敛、未知字段丢弃、功能关闭保留阈值、volatile 解箱、缺省默认全开 | 配置路由响应 JSON(四节:restartCoalesce / terminalWatchdog / socketKeepAlive / stuckSession) | B |
255
+ | D10 | 分别写入非法类型、越界、未知字段、部分覆盖的 config 后 `GET /api/dsh-bug-perf/config` → 非法类型回退默认、越界收敛、未知字段丢弃、功能关闭保留阈值、volatile 解箱、缺省默认值且 diag 默认关闭 | 配置路由响应 JSON(七节:restartCoalesce / terminalWatchdog / socketKeepAlive / stuckSession / jobStreamLimit / listSlim / diag) | B |
195
256
  | D11 | 人为移除被包装面(模块表缺 `RemoteStream`)、令 `webTerminals` 未就绪、页面隐藏、重连失败 → 结构缺失跳过并记录原因且页面不报错;未武装/未连接/页面隐藏不触发;重连失败有冷却 | report 的 reason 字符串;console 日志 | B |
196
- | D12 | 触发 = 路由对外可达。带会话 cookie `GET /api/dsh-bug-perf/config`,再伪造 Host 头直连同一路由 → 只读 GET 返回配置(exact 路由不经 connection 的 `/api` 前缀闸门),无写面与密钥;认证由宿主 startup-auth 承担,伪造 Host 不判缺陷 | 响应 JSON;状态码 | C |
197
- | D13 | 同一 stream 连打 20 次 `restart()`(5ms 间隔),再以 150ms 间隔打 3 次,关闭功能后重复 20 次 → 窗口内首次立即 + 一次尾随(实测 3 次 open),窗口外 3 次逐次重开;关闭后零包装开销(20 次 → 20 次 open);会话流空闲 30 秒保活帧约 20 条且无额外 HTTP 请求;无重连风暴 | `terminal/attach` open 帧计数;WS Messages 帧计数 | B |
198
- | D14 | 触发 = 提示条出现。在亮/暗主题与窄屏下触发停滞 → 提示条固定顶部不遮挡输入区,文本与按钮对比可读,按钮可 Tab 聚焦并回车触发刷新,`role="status"`;英文界面下提示文案仍为中文(插件无 i18n,已知限制) | 亮暗截图;键盘操作描述 | C |
199
- | D15 | 冷启动后查 console、`window.__dshBugPerf`、配置路由回读与 boot.log → 出现 `[dsh-bug-perf] applied`,看门狗就绪后 `[dsh-bug-perf] terminal watchdog installed`,冻结自愈打印 `[dsh-bug-perf] terminal stalled, reconnecting`;console 错误 0(`/login` 404 按总纲 G8 豁免) | result.json 的 `browser ok`/`hasFailBanner` 字段;日志截图;report JSON | B |
257
+ | D12 | 触发 = 路由对外可达。带会话 cookie `GET /api/dsh-bug-perf/config`,再伪造 Host 头直连同一路由 → GET 返回配置(exact 路由不经 connection 的 `/api` 前缀闸门),无密钥;`POST` 仅写归一化配置,非 JSON/超大/非法 config 返回 400,配置服务缺失返回 503;`GET /api/dsh-bug-perf/diag?d=<json>` 追加临时文件,缺 `d`/坏 JSON 400,关闭 diag 时仍接受写入;文件按 2 MB 轮转且只保留 `.1`;认证由宿主 cookie/startup-auth 承担,伪造 Host 不判缺陷。另以 owner 与非 owner(viewer)两个主体先后加载列表 → viewer 只看到授权会话,预热后仍不命中 owner 缓存;包装函数保留调用方 receiver(宿主按 invocation 逐项鉴权) | 响应 JSON;状态码;两主体列表响应;临时文件;宿主日志 | C |
258
+ | D13 | 同一 stream 连打 20 次 `restart()`(5ms 间隔),再以 150ms 间隔打 3 次,关闭功能后重复 20 次 → 窗口内首次立即 + 一次尾随(实测 3 次 open),窗口外 3 次逐次重开;关闭后零包装开销(20 次 → 20 次 open);会话流空闲 30 秒保活帧约 20 条且无额外 HTTP 请求;列表瘦身命中缓存时宿主不重复重建、会话增删后重建一次;无重连风暴 | `terminal/attach` open 帧计数;WS Messages 帧计数;宿主列表重建日志/耗时 | B |
259
+ | D14 | 触发 = 设置卡片或提示条出现。打开插件详情页展开卡片,亮/暗主题与窄屏下检查七节、开关与数值输入 → 卡片不溢出,开关 34×19、圆角 8px,焦点环可见,文本对比可读;触发停滞 → 提示条固定顶部不遮挡输入区,按钮可 Tab 聚焦并回车触发刷新,`role="status"`;英文界面下提示文案仍为中文(插件无 i18n,已知限制);diag 节尚未页面复测 | 亮暗截图;键盘操作描述 | C |
260
+ | D15 | 冷启动后查 console、`window.__dshBugPerf`、配置路由回读、宿主日志与 boot.log → 出现 `[dsh-bug-perf] applied`,`window.__dshBugPerf.diag.enabled` 默认 false,开启并刷新后为 true;看门狗就绪后 `[dsh-bug-perf] terminal watchdog installed`,冻结自愈打印 `[dsh-bug-perf] terminal stalled, reconnecting`,宿主侧打印列表瘦身装载行与缺 `list` 降级行;console 错误 0(`/login` 404 按总纲 G8 豁免) | result.json 的 `browser ok`/`hasFailBanner` 字段;日志截图;report JSON | B |