StartLogin 换码保护: 当 runLogin 观测到 wire 状态已进入 scaned/scaned_but_redirect/need_verifycode(confirmingPhase)时, 复用当前 loginSession 的 QR 而不重新 fetchQRCode/cancel 旧 poll, 避免 45s 自动刷新/恢复前台把已扫未确认的会话砍掉导致微信 confirm 丢失。 仍保留 qrReuseWindow: 未扫描(等待中)且超窗口才重取, 保留显式刷新二维码要新码。 runLogin 补 case scaned: setLoginState(LoginStatusWaiting, loginScannedDetail), 沿用 Waiting 不新增破坏性状态; 顺带在会话上记录 wire phase 供 StartLogin 判别。 可观测性: fetchQRCode 取码成功记 get_bot_qrcode ok(url 脱敏, 不含 qrcode), pollQRStatus 状态变化才记 get_qrcode_status(status), completeLogin/failLogin/ completeBindedRedirect 记结果; 均不落 qrcode/bot_token/user_id。 failLogin 修正: 被 re-mint superseded 的旧会话不再 clobber 新会话状态(不置 failed)。 新增测试: scaned 暴露到 LoginStatus; scaned 超窗口复用 QR 不重取; 等待中超窗口 重取; 日志脱敏断言。