Files
dudu/doc/desktop-integration-acceptance.html
T
wangjia 45e40ccd13
ci / server (push) Failing after 11s
ci / design-tokens (push) Failing after 10s
desktop: 联调发现的透明窗口修复 + 联调验收报告与文档索引
- tauri.conf.json 启用 macOSPrivateApi、Cargo.toml 加 macos-private-api feature:
  overlay/tray 为 transparent 窗口,macOS 上 WKWebView 透明必须开启该项,
  否则浮层带不透明底色(tauri dev 启动日志明确告警)
- doc/desktop-integration-acceptance.html:#12/#1C 联调验收报告
  (mac 全链路通过、12B 延迟基线与短句问题、12C 四场景全过、商业链路通过、遗留项清单)
- doc/index.html:项目文档索引(全局文档规范要求)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 12:18:22 +08:00

221 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>dudu — 桌面端联调验收报告(#12 / #1C)</title>
<style>
:root {
--accent: #4F6EF7;
--accent-text: #3D58DB;
--accent-soft: #EEF1FE;
--bg: #F6F7FA;
--card: #FFFFFF;
--text-1: #1B1E26;
--text-2: #5A6072;
--text-3: #A6ABB8;
--border-1: #E4E6EB;
--positive: #16A34A;
--warning: #E8890C;
--danger: #DC2626;
--code-bg: #1B1E26;
--code-text: #D6DCEA;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif;
background: var(--bg); color: var(--text-1); line-height: 1.75;
}
.container { max-width: 980px; margin: 0 auto; padding: 0 24px 80px; }
header.hero { background: var(--accent); color: #fff; padding: 48px 24px 40px; text-align: center; }
header.hero h1 { margin: 0 0 6px; font-size: 30px; }
header.hero p { margin: 0; opacity: .85; font-size: 15px; }
.chips { margin-top: 16px; }
.chip { display: inline-block; padding: 3px 14px; margin: 3px; background: rgba(255,255,255,.16); border-radius: 999px; font-size: 13px; }
section.card {
background: var(--card); border: 1px solid var(--border-1); border-radius: 14px;
padding: 28px 32px; margin-top: 24px; box-shadow: 0 1px 3px rgba(17,19,26,.05);
}
h2 { font-size: 21px; margin: 0 0 14px; padding-bottom: 8px; border-bottom: 2px solid var(--accent); display: inline-block; }
h3 { font-size: 16px; margin: 22px 0 8px; color: var(--accent-text); }
table { width: 100%; border-collapse: collapse; margin: 10px 0; font-size: 13.5px; }
th, td { border: 1px solid var(--border-1); padding: 7px 11px; text-align: left; vertical-align: top; }
th { background: #F0F1F4; font-weight: 600; }
tr:nth-child(even) td { background: #FCFCFD; }
pre.code {
background: var(--code-bg); color: var(--code-text); padding: 16px 18px; border-radius: 10px;
overflow-x: auto; font-family: "SF Mono", Menlo, Consolas, monospace; font-size: 12.5px; line-height: 1.55;
}
code.inline { background: var(--accent-soft); color: var(--accent-text); padding: 1px 6px; border-radius: 4px; font-family: "SF Mono", Menlo, monospace; font-size: 12.5px; }
.callout { border-left: 4px solid var(--accent); background: var(--accent-soft); padding: 11px 16px; border-radius: 0 8px 8px 0; margin: 12px 0; font-size: 13.5px; }
.callout.warn { border-color: var(--warning); background: #FCEFD7; }
.tag { display: inline-block; font-size: 12px; padding: 1px 10px; border-radius: 999px; margin-right: 6px; font-weight: 600; }
.tag.green { background: #DCFCE7; color: var(--positive); }
.tag.orange { background: #FCEFD7; color: var(--warning); }
.tag.red { background: #FEE2E2; color: var(--danger); }
.tag.blue { background: var(--accent-soft); color: var(--accent-text); }
ul, ol { padding-left: 22px; }
li { margin: 3px 0; }
footer { text-align: center; color: var(--text-3); font-size: 13px; margin-top: 44px; }
</style>
</head>
<body>
<header class="hero">
<h1>桌面端联调验收报告</h1>
<p>TODO #12(联调与验收)+ #1CmacOS 注入与浮层)· 2026-07-10</p>
<div class="chips">
<span class="chip">macOS 实测</span>
<span class="chip">gummy 真实 provider</span>
<span class="chip">无头网关压测</span>
</div>
</header>
<div class="container">
<section class="card">
<h2>一、结论速览</h2>
<table>
<tr><th>验收项</th><th>结果</th><th>说明</th></tr>
<tr><td>12A mac 全链路(快捷键→采集→流式→浮层→注入)</td><td><span class="tag green">通过</span></td><td>真实 App + 模拟快捷键,mock 文本成功注入 TextEdit,计费准确</td></tr>
<tr><td>12A Windows 全链路</td><td><span class="tag red">未执行</span></td><td>Windows 机(ssh windows)缺 Rust/Node 工具链,需先装环境</td></tr>
<tr><td>12B release_to_commit &lt; 300ms</td><td><span class="tag orange">部分达标</span></td><td>P50 261ms ✅ / P95 918ms ❌(受两轮 provider 异常拖累)</td></tr>
<tr><td>12B first_partial P95 &lt; 500ms</td><td><span class="tag red">未达标</span></td><td>P50 845ms / P95 3870ms——gummy partial 下发节奏本身 ~750-850ms,目标需重新校准</td></tr>
<tr><td>12C 断连重建</td><td><span class="tag green">通过</span></td><td>服务端重启后桌面端数秒内自动重连(18E 生效)</td></tr>
<tr><td>12C SESSION_LIMIT3 分钟截断)</td><td><span class="tag green">通过</span></td><td>198s 推流在 180s 准时截断:先定稿下发全部 final,再发 SESSION_LIMIT</td></tr>
<tr><td>12C RATE_LIMITED30 次/30 分钟)</td><td><span class="tag green">通过</span></td><td>第 31 个会话被精确拒绝,前 30 个正常</td></tr>
<tr><td>12C QUOTA_EXCEEDED(试用/余额用尽)</td><td><span class="tag green">通过</span></td><td>扣穿当句不掐断、final 不丢;再次 start 预检拒绝(帧序备注见 §五)</td></tr>
<tr><td>1C 浮层不抢焦点 + 注入</td><td><span class="tag green">TextEdit 通过</span></td><td>会话期间焦点保持在目标 App,注入成功;微信/浏览器/IDE 三目标待人工点验</td></tr>
<tr><td>商业链路(登录/购买/入账)</td><td><span class="tag green">通过</span></td><td>mock 扫码登录、下单、回调入账、回调重放幂等、订单状态全部正确</td></tr>
</table>
<div class="callout warn">
<b>联调中发现并已修复:</b>overlay/tray 为 <code class="inline">transparent: true</code> 窗口,但未启用
<code class="inline">macOSPrivateApi</code>——macOS 上 WKWebView 透明必须开启该项,否则浮层带不透明底色。
本次已在 <code class="inline">tauri.conf.json</code><code class="inline">"macOSPrivateApi": true</code>
<code class="inline">Cargo.toml</code><code class="inline">macos-private-api</code> featurecargo check 通过),
<b>视觉效果需真机目测确认</b>
</div>
</section>
<section class="card">
<h2>二、测试环境与方法</h2>
<table>
<tr><th></th><th></th></tr>
<tr><td>服务端</td><td>本机 <code class="inline">go run ./cmd/server</code>:8080+ docker compose pg/redis;先 mock 后切 <b>gummy 真实 provider</b>(key 经 rbw 管道注入环境,未落盘)</td></tr>
<tr><td>桌面端</td><td><code class="inline">npm run tauri dev</code> 调试构建,settings.json 预置 mock 登录 token 指向 localhost</td></tr>
<tr><td>快捷键模拟</td><td>osascript System Events 按住/松开 Cmd+Shift+Space3s</td></tr>
<tr><td>延迟/异常压测</td><td>自制无头 WS 客户端 <code class="inline">wslat</code>Go + gorilla),按协议 100ms/3200B 实时推流真实中文语音(macOS say 合成 8.6s / 1s / 198s 三种)走 <code class="inline">/v1/asr/stream</code> 真实网关路径</td></tr>
<tr><td>测试账号</td><td>mock 微信登录建两个 trial 用户;用户一经 mock 支付购入 pack_1006000s 余额)</td></tr>
</table>
<h3>延迟指标口径</h3>
<ul>
<li><b>first_partial</b>:首帧音频发出 → 收到首个 partial(客户端视角,含网关中继与 provider 全链路)</li>
<li><b>release_to_commit</b>:发出 stop → 收到定稿 final(对应桌面端「松开→注入」的服务端部分)</li>
</ul>
</section>
<section class="card">
<h2>三、12A 全链路(mac</h2>
<ol>
<li>mock 扫码登录:<code class="inline">POST /v1/auth/qr</code> → 手动打回调(模拟扫码)→ 轮询 confirmed 拿 JWT ✅</li>
<li>App 启动即与服务端建立 WS 预连接 + REST 轮询(lsof 确认 4 条连接)✅</li>
<li>TextEdit 聚焦 → 模拟按住快捷键 3s → 松开 → mock provider 脚本文本「帮我把这份周报整理一下,重点突出本周的进展。」完整注入 TextEdit ✅</li>
<li>会话期间前台应用保持为目标 App(浮层 <code class="inline">focusable:false</code> 生效,即 1C 验证点)✅</li>
<li>计费:3s 会话后 <code class="inline">/v1/me</code> 的 trial_used_today 精确 +3 ✅</li>
</ol>
<div class="callout">Windows 侧同方法可复用:装好 rustup + Node + VS Build Tools 后 clone 仓库 <code class="inline">npm i &amp;&amp; npm run tauri dev</code>,注入走 SendInput10F)。</div>
</section>
<section class="card">
<h2>四、12B 延迟基线(gummy 真实 provider10 轮 × 8.6s</h2>
<table>
<tr><th>指标</th><th>P50</th><th>P95</th><th>目标</th><th>判定</th></tr>
<tr><td>first_partial</td><td>845ms</td><td>3870ms</td><td>P95 &lt; 500ms</td><td><span class="tag red">未达标</span></td></tr>
<tr><td>release_to_commit</td><td>261ms</td><td>918ms</td><td>&lt; 300ms</td><td><span class="tag orange">P50 达标 / P95 超</span></td></tr>
</table>
<ul>
<li>10 轮 final 文本完全一致且正确(含标点/数字 ITN:「今天下午3点,我们开个短会,…」),识别质量稳定</li>
<li>8/10 轮 first_partial 集中在 840-944ms——与 gummy partial 下发节奏(约 0.75-0.85s/个)一致,<b>首包时延已贴近 provider 下限,非网关开销</b></li>
<li>2/10 轮异常(3302/3870msrelease 同步劣化到 592/918ms),服务端无任何告警日志——疑似 DashScope 会话建立耗时波动</li>
</ul>
<h3>超短句补充数据(RATE 测试顺带产出,1s 语音 × 30 轮)</h3>
<ul>
<li>release_to_commit <b>P50 = 2192ms / P95 = 3732ms</b>——远高于长句的 261ms</li>
<li>原因:短句常在 provider 尚未出 partial 时就 stop30 轮中 16 轮 0 partial),定稿要等 provider 收尾 flush</li>
<li>体验含义:说「好的」这类两三字短语,松开后约 2 秒才上屏,是当前链路最明显的体验短板</li>
</ul>
<h3>建议(已入 backlog</h3>
<ul>
<li>first_partial P95&lt;500ms 目标与 gummy 实际下发节奏矛盾,建议重校准为「P50≤900ms / P95≤1500ms」或换更快首包的 provider 档位</li>
<li>短句定稿慢(P50 2.2s):浮层在 stop 后无 final 期间应有「定稿中」状态;调研 gummy 快速定稿参数或 stop 时本地提交最后 partial 的策略</li>
<li>网关为 provider 会话建立耗时与 partial 间隔加观测日志/metrics,否则线上无法定位此类波动</li>
<li>排查慢会话(3 轮 3.2-3.9s 首包):确认是否 DashScope 冷启动,可考虑 provider 侧连接预热</li>
</ul>
</section>
<section class="card">
<h2>五、12C 异常路径</h2>
<table>
<tr><th>场景</th><th>做法</th><th>观察</th><th>判定</th></tr>
<tr>
<td>断连重建</td>
<td>App 保持连接时重启服务端进程</td>
<td>桌面端数秒内自动重连(lsof 确认新连接),无需用户操作</td>
<td><span class="tag green">通过</span></td>
</tr>
<tr>
<td>SESSION_LIMIT<br>3 分钟截断</td>
<td>余额账号推 198s 长音频</td>
<td>180s 准时截断:219 个 partial、全部 final 先定稿下发,随后 <code class="inline">SESSION_LIMIT:单次最长 3 分钟,松开后可继续</code>,会话关闭</td>
<td><span class="tag green">通过</span></td>
</tr>
<tr>
<td>RATE_LIMITED<br>30 次/30 分钟</td>
<td>同设备连发 31 个 1s 短会话</td>
<td>第 1-30 个会话全部正常识别并计费;第 31 个 start 被拒:<code class="inline">RATE_LIMITED:操作过于频繁,稍后再试</code>——滑动窗口精确在第 31 次生效</td>
<td><span class="tag green">通过</span></td>
</tr>
<tr>
<td>QUOTA_EXCEEDED<br>试用+余额用尽</td>
<td>Redis 置试用已用 177/180s 后推 8.6s 音频;再次 start</td>
<td>剩 3s 时 start 预检放行 → 推流中扣穿 → 下发 <code class="inline">QUOTA_EXCEEDED:今日试用已用完,去购买时长</code><b>随后仍 flush 当句 final</b>(已识别内容不丢,实测收到截至扣穿点的定稿文本);再次 start 在预检被直接拒绝</td>
<td><span class="tag green">通过</span></td>
</tr>
</table>
<div class="callout">以上为协议/服务端行为验证;桌面端 overlay 对各错误码的<b>文案呈现</b>19C 实现)需人工目测一遍。</div>
<h3>QUOTA 帧序备注(跨端确认项)</h3>
<ul>
<li>实现顺序为「先发 QUOTA_EXCEEDED 错误帧 → 再 Close provider flush 当句 final」,与 16E 文案(「本句 final 后下发」)顺序相反,但内容不丢</li>
<li>桌面端已核对无碍:<code class="inline">on_server_msg</code> 对 error 帧不丢弃会话,错误帧之后的 final 照常进 CommitBuffer,松键时注入</li>
<li><b>Android / iOS 键盘需各自确认</b>:收到 error 帧后不立即关闭会话/连接,仍处理后续 final 并 commitText 上屏,否则移动端会「扣了费但字没上屏」</li>
</ul>
</section>
<section class="card">
<h2>六、商业链路(登录 → 购买 → 入账)</h2>
<ol>
<li><code class="inline">GET /v1/packs</code>:三档时长包(100/500/2000 分钟)正常返回 ✅</li>
<li><code class="inline">POST /v1/orders</code>:下单返回 native <code class="inline">code_url</code></li>
<li><code class="inline">POST /v1/pay/notify</code>mock 明文回调):SUCCESS,余额 +6000s,订单转 paid,账号 trial→ok ✅</li>
<li><b>回调重放幂等</b>:同 transaction_id 二次回调返回 SUCCESS 但余额不重复入账 ✅</li>
</ol>
<div class="callout warn">再次强调(17I 已标注):MockPay 不验签,<code class="inline">/v1/pay/notify</code> 现等于公开充值接口,<b>上线前必须换 wechatpay-go 真实验签</b></div>
</section>
<section class="card">
<h2>七、遗留项(需人工 / 后续)</h2>
<table>
<tr><th></th><th>负责</th><th>说明</th></tr>
<tr><td>真人麦克风实说验证</td><td>人工 · 2 分钟</td><td>App 正在运行且已登录:任意输入框按住 Cmd+Shift+Space 说话即可(服务端 gummy</td></tr>
<tr><td>1C 三目标注入点验</td><td>人工 · 3 分钟</td><td>微信 / 浏览器 / IDE 各注入一次;同时目测浮层深色玻璃是否透明(本次修复效果)</td></tr>
<tr><td>辅助功能/麦克风权限引导</td><td>人工</td><td>正式打包后首启流程(11F)在无权限干净环境走一遍</td></tr>
<tr><td>Windows 全链路</td><td>装环境后复测</td><td>ssh windows 可达但缺 rustup/Node/VS Build Tools</td></tr>
<tr><td>overlay 错误态文案目测</td><td>人工</td><td>断网/超限场景下浮层文案(19C</td></tr>
<tr><td>first_partial 目标重校准 + provider 观测日志</td><td>开发</td><td>见 §四建议,建议并入 #22 backlog</td></tr>
</table>
</section>
<footer>dudu · 桌面端联调验收报告 · 2026-07-10 · 详细原始数据见本次联调分支提交说明</footer>
</div>
</body>
</html>