R27 批 1:真机走查六个产品问题修复(语言广播 / 壳层语言 / 脏步骤不拖垮详情 / 设置分区失败态 / 待拍板同源 / 连字符) - #32
Merged
Merged
Conversation
真机走查:提议摘要里的「预计 24-48 小时」渲成了「预计 24 48 小时」。压平 markdown 的 那层把 `-` 和 `#*_`> 塞进同一个字符类无差别替换成空格,列表符被抹掉的同时数字区间、 连字词(e-mail、2026-09-06)也一起遭殃。 把这段逻辑收成一份 packages/ui/src/markdown-text.ts 的 stripMarkdownMarkers(此前 proposal/workitem/replay/gold-path 各抄了一份同样的正则):`-` 只在行首列表符/分隔线 位置当标记,行内一律原样保留。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
真机走查:agent_steps.phase 存了契约外的值,GET /api/pages/workitems/:id 直接返回 internal_contract_error,界面只剩「详情没加载出来 / 重试」。根因是 toAgentStepVm 用 `as` 强转 phase / control_signal,脏值一路带进 workItemDetailVmSchema,整页 parse 抛错; 库里 agent_steps.phase 是 varchar(32),没有 CHECK 约束拦得住。 改成逐步 safeParse:解析不了的那一步丢掉并留一条结构化 warn(含 run id / 步号 / 原始值), 其余步骤与整页照常渲染——同 evidenceRefsFromBindings / assigneeList 的既有取舍。 军团面板/总览的 recent_step 是同一类事故(同一列、同样 `as` 强转),一并收口:解析不了 退成 null(字段本就可空),卡片少一行而不是整页 500。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
真机走查:管理员在设置页既看不到插件/MCP 分区,也看不到任何一句错误。两头都有问题——
`/api/plugins`、`/api/mcp-servers` 的 VM 校验一失败就整条 500,而 routes/pages.ts 的
`catch {}` 又把它吞成「字段缺席」;而字段缺席在契约上恰恰是「你不是管理员,这一区不该
给你看」,两种情形长得一模一样。
(a) 设置页 VM 新增 failed_sections(结构化字段,不是缺席):缺席=不该看,列进来=该看
但这次没取到。桌面据此照渲这一区并仍去拉一次清单端点(落到既有的「没加载出来 + 重试」
那一行),网页渲一句说清现状的话(网页只读,不放没有处理器的假按钮)。路由侧顺带留一条
结构化 warn。
(b) 校验失败的形状:compat_report / precheck_report 都是没有 CHECK 约束的 jsonb,读回来
被 `as` 强转而不是 parse;mcp_servers.command 这一列在库里可空(给将来的非 stdio 传输留的
余地),读侧却拿 `?? ""` 伪造了一个契约明令禁止的空串。契约不放宽——stdio 行的启动命令确实
必填,一条没有命令的 stdio 行是坏数据不是合法状态;改的是读侧:两个清单端点逐行容错,
解析不了的那一行丢掉并留结构化 warn,其余照常列出。单行响应(安装/登记/启停之后)仍走
会抛的那条路径,那时候的行是本次刚写的,走样就该是 500。
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
真机走查:快捷入口「审批队列」写着「1 条待你拍板」时,工作台左上「待拍板」还是 「都处理完了」,直到会话里补了 proposal_opened 系统消息徽标才变成 1。 先纠正一处前提:两面读的本来就是同一个 GET /api/pages/attention(队列由服务端把 approval_requests / proposals / 升级 / 记忆冲突四个来源汇成一条),会话消息从不参与计数。 真正各说各话的是两件事: 一、计数各数各的。快捷入口副标题、聚焦盒角标、工作台徽标三处各写了一遍 `vm.queue?.length ?? 0`,任何一处改口径都会立刻分叉,且没有测试拦得住。收成 pending-decision-count.ts 一个函数,三处都经它。 二、刷新时机不对称。主窗那份角标随窗口可见性暂停/恢复(恢复即补刷一次)并在窗口重新 聚焦时再刷一遍;工作台这边只有一条裸 setInterval——窗口在后台被系统节流时可以很久不响, 用户把它切到前台也不触发任何刷新,徽标就停在旧值,直到一条决策类 SSE 事件把它推醒 (proposal.opened 正是白名单里的一条)。工作台改用同一套 startVisibilityAwarePolling 并补上 focus 补刷,卸载/登出时一并摘掉。 测试钉住同一份 attention VM 在快捷入口副标题与工作台徽标上是同一个数(空队列同理)。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
真机走查:英文系统上首启,「连接到你的服务器」屏与登录屏全是英文,`WORKHUB_LOCALE=zh-CN` 也救不了。那个变量只喂给壳层(托盘菜单 / 窗口标题 / 通知兜底文案),webview 这边压根没有 途径问到壳层当下用的是哪种语言,只能退回 navigator.language。 壳层那份 Mutex<WorkHubLocale> 本来就是「配置 → 系统语言」汇总后的单一事实源。新增一条 get_shell_locale 命令把它读出来,三扇窗口(主窗 / 工作台 / 桌宠)boot 时按 显式偏好(localStorage)> 壳层语言 > navigator.language 取值:这台设备真正表过态的那个值仍排第一,壳层只顶掉 navigator 那一级。问不到壳层 (浏览器 dev 预览 / 老壳层没有这条命令)照旧回落 navigator,行为不变。 主窗首帧仍旧同步渲占位盒,问壳层排在它之后,不拖慢窗口出画。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
真机走查:昵称登录成功后主窗立刻切中文,桌宠卡片仍是英文(Your call / Approval / Approve / Request changes / Delegate)夹着中文正文,重启客户端才对齐。 根因是身份语言只在**解析它的那扇窗口**里生效:applyIdentityLocale 把 /me 带回的语言写进 自己的 localStorage,而桌宠窗的 locale 是 boot 时算一次就不动的常量。桌宠确实订了 workhub-logged-in 并 reload,但那次 reload 跑在主窗拿到 /me、写下 zh-CN 之前——重读到的 还是旧值,于是整个会话都停在英文,直到下次启动才偶然读对。 主窗与工作台在身份语言落定后做两件事:先 set_shell_locale 让壳层那份单一事实源跟上 (托盘/标题/通知跟着换,后续任何一扇窗口 boot 也能问到对的语言),再广播 workhub-locale-changed(payload 带 source,发起方跳过自己那一条)。桌宠收到就地重读、 重渲并重取当前卡的文案(卡片文案是创建时按 locale 烘焙的,不重取会中英混语);工作台走 与 workhub-logged-in 同款的 reload 生效路径。语言没变就只同步壳层、不广播——既不让别的 窗口无谓刷新,也断掉互相唤醒的回环。 测试钉住「主窗登录后桌宠当前语言随之变化」,以及认不出的 payload 一律丢弃。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
R27 批 1:真机截图时撞到的六个产品问题(r27/device-feedback-fixes,7 commits)。
workhub-locale-changed(主窗/工作台先set_shell_locale再广播,发起方跳过自己),桌宠就地重读重渲并重取当前卡文案;语言没变不广播。get_shell_locale;三扇窗口 boot 按「显式偏好 > 壳层语言 > navigator.language」取值,问不到壳层行为不变。agent_steps.phase让任务详情整页 500:逐步safeParse,解析不了的那一步丢掉并留结构化 warn;军团面板的recent_step同列同修。failed_sections把「取数失败」与「非管理员缺席」分开,桌面照渲分区并仍去拉一次清单端点、失败落「没加载出来 + 重试」,网页渲一句说明。两个清单端点逐行容错:坏行丢掉 + warn,其余照常列出(契约不放宽:stdio 行的启动命令必填)。/api/pages/attention),病因是三处各写一遍计数 + 工作台只有裸setInterval(后台被节流、切前台不刷)。收成一个pendingDecisionCount+ 工作台改用同一套可见性感知轮询与 focus 补刷。stripMarkdown收成packages/ui/src/markdown-text.ts的stripMarkdownMarkers,-只在行首列表符/分隔线位置当标记。expected 基线:模型可见文本零变化(
pnpm gen:expected幂等)。验证:
pnpm -r typecheck全 Done;desktop-webview 1774 / api 2210 / ui 283 / contracts 208 全过;cargo fmt / test 198 / clippy 三门绿;audit ui-i18n / copy-terms / agent-notes / test-conventions 通过(基线未动)。遗留:
agent-runner.ts通知文案里还有第五份stripMarkdown拷贝;设置页permission_policies区的取数失败仍吞成缺席;决策队列扫描封顶导致三面口径仍不完全一致(服务端标量留后续);语言广播与设置页失败态未在真机复验。🤖 Generated with Claude Code